mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-05-26 23:17:50 +08:00
支持服务端抽稀和服务发布
This commit is contained in:
parent
2a5435c810
commit
311b59870c
@ -50,6 +50,7 @@ public class VideoManagerConstants {
|
|||||||
public static final String WAITE_SEND_PUSH_STREAM = "VMP_WAITE_SEND_PUSH_STREAM:";
|
public static final String WAITE_SEND_PUSH_STREAM = "VMP_WAITE_SEND_PUSH_STREAM:";
|
||||||
public static final String START_SEND_PUSH_STREAM = "VMP_START_SEND_PUSH_STREAM:";
|
public static final String START_SEND_PUSH_STREAM = "VMP_START_SEND_PUSH_STREAM:";
|
||||||
public static final String SSE_TASK_KEY = "SSE_TASK_";
|
public static final String SSE_TASK_KEY = "SSE_TASK_";
|
||||||
|
public static final String DRAW_THIN_PROCESS_PREFIX = "VMP_DRAW_THIN_PROCESS_";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.genersoft.iot.vmp.gb28181.bean;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DrawThinProcess {
|
||||||
|
|
||||||
|
private double process;
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
public DrawThinProcess(double process, String msg) {
|
||||||
|
this.process = process;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -502,7 +502,37 @@ public class ChannelController {
|
|||||||
channelService.resetLevel();
|
channelService.resetLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "为地图提供标准的mvt图层", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
@Operation(summary = "执行抽稀", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||||
|
@PostMapping("/map/thin/draw")
|
||||||
|
public String drawThin(@RequestBody DrawThinParam param){
|
||||||
|
if(param == null || param.getZoomParam() == null || param.getZoomParam().isEmpty()) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR400);
|
||||||
|
}
|
||||||
|
return channelService.drawThin(param.getZoomParam(), param.getExtent(), param.getGeoCoordSys());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "清除未保存的抽稀结果", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||||
|
@Parameter(name = "id", description = "抽稀ID", required = true)
|
||||||
|
@GetMapping("/map/thin/clear")
|
||||||
|
public void clearThin(String id){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "保存的抽稀结果", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||||
|
@Parameter(name = "id", description = "抽稀ID", required = true)
|
||||||
|
@GetMapping("/map/thin/save")
|
||||||
|
public void saveThin(String id){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "获取抽稀执行的进度", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||||
|
@Parameter(name = "id", description = "抽稀ID", required = true)
|
||||||
|
@GetMapping("/map/thin/progress")
|
||||||
|
public DrawThinProcess thinProgress(String id){
|
||||||
|
return channelService.thinProgress(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "为地图提供标准mvt图层", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||||
@GetMapping(value = "/map/tile/{z}/{x}/{y}", produces = "application/x-protobuf")
|
@GetMapping(value = "/map/tile/{z}/{x}/{y}", produces = "application/x-protobuf")
|
||||||
@Parameter(name = "geoCoordSys", description = "地理坐标系, WGS84/GCJ02")
|
@Parameter(name = "geoCoordSys", description = "地理坐标系, WGS84/GCJ02")
|
||||||
public ResponseEntity<byte[]> getTile(@PathVariable int z, @PathVariable int x, @PathVariable int y, String geoCoordSys){
|
public ResponseEntity<byte[]> getTile(@PathVariable int z, @PathVariable int x, @PathVariable int y, String geoCoordSys){
|
||||||
@ -519,5 +549,24 @@ public class ChannelController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "为地图提供经过抽稀的标准mvt图层", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||||
|
@GetMapping(value = "/map/thin/tile/{z}/{x}/{y}", produces = "application/x-protobuf")
|
||||||
|
@Parameter(name = "geoCoordSys", description = "地理坐标系, WGS84/GCJ02")
|
||||||
|
@Parameter(name = "thinId", description = "抽稀结果ID")
|
||||||
|
public ResponseEntity<byte[]> getThinTile(@PathVariable int z, @PathVariable int x, @PathVariable int y,
|
||||||
|
String geoCoordSys, @RequestParam(required = false) String thinId){
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] mvt = channelService.getTile(z, x, y, geoCoordSys);
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.parseMediaType("application/x-protobuf"));
|
||||||
|
headers.setContentLength(mvt.length);
|
||||||
|
return new ResponseEntity<>(mvt, headers, HttpStatus.OK);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("构建矢量瓦片失败: z: {}, x: {}, y:{}", z, x, y, e);
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.genersoft.iot.vmp.gb28181.controller.bean;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DrawThinParam {
|
||||||
|
private Map<Integer, Double> zoomParam;
|
||||||
|
private Extent extent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 地理坐标系, WGS84/GCJ02, 用来标识 extent 参数的坐标系
|
||||||
|
*/
|
||||||
|
private String geoCoordSys;
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.genersoft.iot.vmp.gb28181.controller.bean;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Extent {
|
||||||
|
private Double minLng;
|
||||||
|
private Double maxLng;
|
||||||
|
private Double minLat;
|
||||||
|
private Double maxLat;
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.dao;
|
package com.genersoft.iot.vmp.gb28181.dao;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.controller.bean.Extent;
|
||||||
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin;
|
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin;
|
||||||
import com.genersoft.iot.vmp.gb28181.dao.provider.ChannelProvider;
|
import com.genersoft.iot.vmp.gb28181.dao.provider.ChannelProvider;
|
||||||
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
||||||
@ -676,4 +677,20 @@ public interface CommonGBChannelMapper {
|
|||||||
@SelectProvider(type = ChannelProvider.class, method = "queryCameraChannelInBox")
|
@SelectProvider(type = ChannelProvider.class, method = "queryCameraChannelInBox")
|
||||||
List<CommonGBChannel> queryCameraChannelInBox(@Param("minLon") double minLon, @Param("maxLon") double maxLon,
|
List<CommonGBChannel> queryCameraChannelInBox(@Param("minLon") double minLon, @Param("maxLon") double maxLon,
|
||||||
@Param("minLat") double minLat, @Param("maxLat") double maxLat);
|
@Param("minLat") double minLat, @Param("maxLat") double maxLat);
|
||||||
|
|
||||||
|
@Select("select " +
|
||||||
|
"MAX(coalesce(gb_longitude, longitude)) as maxLng, " +
|
||||||
|
"MIN(coalesce(gb_longitude, longitude)) as minLng, " +
|
||||||
|
"MAX(coalesce(gb_latitude, latitude)) as maxLat, " +
|
||||||
|
"MIN(coalesce(gb_latitude, latitude)) as minLat " +
|
||||||
|
" from wvp_device_channel " +
|
||||||
|
" where channel_type = 0")
|
||||||
|
Extent queryExtent();
|
||||||
|
|
||||||
|
@SelectProvider(type = ChannelProvider.class, method = "queryAllWithPosition")
|
||||||
|
List<CommonGBChannel> queryAllWithPosition();
|
||||||
|
|
||||||
|
@SelectProvider(type = ChannelProvider.class, method = "queryListInExtent")
|
||||||
|
List<CommonGBChannel> queryListInExtent(Extent extent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -307,14 +307,14 @@ public interface GroupMapper {
|
|||||||
Group queryGroupByAliasAndBusinessGroup(@Param("alias") String alias, @Param("deviceId") String businessGroup);
|
Group queryGroupByAliasAndBusinessGroup(@Param("alias") String alias, @Param("deviceId") String businessGroup);
|
||||||
|
|
||||||
|
|
||||||
@Select(" <script>" +
|
@Select("<script>" +
|
||||||
" SELECT " +
|
" SELECT " +
|
||||||
" ANY_VALUE(coalesce( wdc.gb_parent_id, wdc.parent_id)) as deviceId," +
|
" ANY_VALUE(coalesce( wdc.gb_parent_id, wdc.parent_id)) as deviceId," +
|
||||||
" COUNT(*) AS allCount," +
|
" COUNT(*) AS allCount," +
|
||||||
" SUM(CASE WHEN coalesce( wdc.gb_status, wdc.status) = 'ON' THEN 1 ELSE 0 END) AS onlineCount" +
|
" SUM(CASE WHEN coalesce( wdc.gb_status, wdc.status) = 'ON' THEN 1 ELSE 0 END) AS onlineCount" +
|
||||||
" FROM " +
|
" FROM " +
|
||||||
" wvp_device_channel wdc " +
|
" wvp_device_channel wdc " +
|
||||||
" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) " +
|
" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
|
||||||
" AND coalesce( wdc.gb_parent_id, wdc.parent_id) in " +
|
" AND coalesce( wdc.gb_parent_id, wdc.parent_id) in " +
|
||||||
" <foreach collection='groupList' item='item' open='(' separator=',' close=')' > #{item.deviceId}</foreach>" +
|
" <foreach collection='groupList' item='item' open='(' separator=',' close=')' > #{item.deviceId}</foreach>" +
|
||||||
" GROUP BY coalesce(wdc.gb_parent_id, wdc.parent_id)" +
|
" GROUP BY coalesce(wdc.gb_parent_id, wdc.parent_id)" +
|
||||||
|
|||||||
@ -583,7 +583,7 @@ public class ChannelProvider {
|
|||||||
public String queryListForSy(Map<String, Object> params ){
|
public String queryListForSy(Map<String, Object> params ){
|
||||||
StringBuilder sqlBuild = new StringBuilder();
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
||||||
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) AND coalesce(wdc.gb_parent_id, wdc.parent_id) = #{groupDeviceId}");
|
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) AND coalesce(wdc.gb_parent_id, wdc.parent_id) = #{groupDeviceId}");
|
||||||
if (params.get("online") != null && (Boolean)params.get("online")) {
|
if (params.get("online") != null && (Boolean)params.get("online")) {
|
||||||
sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'ON'");
|
sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'ON'");
|
||||||
}
|
}
|
||||||
@ -598,7 +598,7 @@ public class ChannelProvider {
|
|||||||
public String queryListWithChildForSy(Map<String, Object> params ){
|
public String queryListWithChildForSy(Map<String, Object> params ){
|
||||||
StringBuilder sqlBuild = new StringBuilder();
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
||||||
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) ");
|
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) ");
|
||||||
|
|
||||||
|
|
||||||
List<CameraGroup> groupList = (List<CameraGroup>)params.get("groupList");
|
List<CameraGroup> groupList = (List<CameraGroup>)params.get("groupList");
|
||||||
@ -672,7 +672,7 @@ public class ChannelProvider {
|
|||||||
public String queryListInBox(Map<String, Object> params ){
|
public String queryListInBox(Map<String, Object> params ){
|
||||||
StringBuilder sqlBuild = new StringBuilder();
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
||||||
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) " +
|
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
|
||||||
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
||||||
|
|
||||||
sqlBuild.append(" ");
|
sqlBuild.append(" ");
|
||||||
@ -700,7 +700,7 @@ public class ChannelProvider {
|
|||||||
public String queryListInCircleForMysql(Map<String, Object> params ){
|
public String queryListInCircleForMysql(Map<String, Object> params ){
|
||||||
StringBuilder sqlBuild = new StringBuilder();
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
||||||
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) " +
|
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
|
||||||
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
||||||
|
|
||||||
sqlBuild.append(" ");
|
sqlBuild.append(" ");
|
||||||
@ -729,7 +729,7 @@ public class ChannelProvider {
|
|||||||
public String queryListInCircleForKingBase(Map<String, Object> params ){
|
public String queryListInCircleForKingBase(Map<String, Object> params ){
|
||||||
StringBuilder sqlBuild = new StringBuilder();
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
||||||
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) " +
|
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
|
||||||
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
||||||
|
|
||||||
sqlBuild.append(" ");
|
sqlBuild.append(" ");
|
||||||
@ -758,7 +758,7 @@ public class ChannelProvider {
|
|||||||
public String queryListInPolygonForMysql(Map<String, Object> params ){
|
public String queryListInPolygonForMysql(Map<String, Object> params ){
|
||||||
StringBuilder sqlBuild = new StringBuilder();
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
||||||
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) " +
|
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
|
||||||
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
||||||
|
|
||||||
sqlBuild.append(" ");
|
sqlBuild.append(" ");
|
||||||
@ -796,7 +796,7 @@ public class ChannelProvider {
|
|||||||
public String queryListInPolygonForKingBase(Map<String, Object> params ){
|
public String queryListInPolygonForKingBase(Map<String, Object> params ){
|
||||||
StringBuilder sqlBuild = new StringBuilder();
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
|
||||||
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 && wdc.gb_ptz_type != 99)) " +
|
sqlBuild.append(" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
|
||||||
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
" AND coalesce(wdc.gb_parent_id, wdc.parent_id) in (");
|
||||||
|
|
||||||
sqlBuild.append(" ");
|
sqlBuild.append(" ");
|
||||||
@ -901,4 +901,22 @@ public class ChannelProvider {
|
|||||||
public String queryCameraChannelById(Map<String, Object> params ){
|
public String queryCameraChannelById(Map<String, Object> params ){
|
||||||
return BASE_SQL_FOR_CAMERA_DEVICE + " where wdc.id = #{gbId}";
|
return BASE_SQL_FOR_CAMERA_DEVICE + " where wdc.id = #{gbId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String queryAllWithPosition(Map<String, Object> params ){
|
||||||
|
return BASE_SQL + " where channel_type = 0 " +
|
||||||
|
" AND coalesce(gb_longitude, longitude) > 0" +
|
||||||
|
" AND coalesce(gb_latitude, latitude) > 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String queryListInExtent(Map<String, Object> params ){
|
||||||
|
StringBuilder sqlBuild = new StringBuilder();
|
||||||
|
sqlBuild.append(BASE_SQL);
|
||||||
|
sqlBuild.append(" where channel_type = 0 " +
|
||||||
|
"AND coalesce(gb_longitude, longitude) > #{minLng} " +
|
||||||
|
"AND coalesce(gb_longitude, longitude) <= #{maxLng} " +
|
||||||
|
"AND coalesce(gb_latitude, latitude) > #{minLat} " +
|
||||||
|
"AND coalesce(gb_latitude, latitude) <= #{maxLat}");
|
||||||
|
return sqlBuild.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.genersoft.iot.vmp.gb28181.service;
|
package com.genersoft.iot.vmp.gb28181.service;
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.controller.bean.Extent;
|
||||||
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin;
|
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin;
|
||||||
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
||||||
import com.genersoft.iot.vmp.streamPush.bean.StreamPush;
|
import com.genersoft.iot.vmp.streamPush.bean.StreamPush;
|
||||||
@ -8,6 +9,7 @@ import com.github.pagehelper.PageInfo;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface IGbChannelService {
|
public interface IGbChannelService {
|
||||||
|
|
||||||
@ -109,4 +111,7 @@ public interface IGbChannelService {
|
|||||||
|
|
||||||
byte[] getTile(int z, int x, int y, String geoCoordSys);
|
byte[] getTile(int z, int x, int y, String geoCoordSys);
|
||||||
|
|
||||||
|
String drawThin(Map<Integer, Double> zoomParam, Extent extent, String geoCoordSys);
|
||||||
|
|
||||||
|
DrawThinProcess thinProgress(String id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,12 @@ package com.genersoft.iot.vmp.gb28181.service.impl;
|
|||||||
|
|
||||||
import com.alibaba.excel.support.cglib.beans.BeanMap;
|
import com.alibaba.excel.support.cglib.beans.BeanMap;
|
||||||
import com.alibaba.excel.util.BeanMapUtils;
|
import com.alibaba.excel.util.BeanMapUtils;
|
||||||
|
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||||
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
|
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
|
||||||
|
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.controller.bean.Extent;
|
||||||
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin;
|
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin;
|
||||||
import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper;
|
import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper;
|
||||||
import com.genersoft.iot.vmp.gb28181.dao.GroupMapper;
|
import com.genersoft.iot.vmp.gb28181.dao.GroupMapper;
|
||||||
@ -14,10 +17,12 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
|||||||
import com.genersoft.iot.vmp.gb28181.event.channel.ChannelEvent;
|
import com.genersoft.iot.vmp.gb28181.event.channel.ChannelEvent;
|
||||||
import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
|
import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
|
||||||
import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService;
|
import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.utils.VectorTileUtils;
|
||||||
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
||||||
import com.genersoft.iot.vmp.streamPush.bean.StreamPush;
|
import com.genersoft.iot.vmp.streamPush.bean.StreamPush;
|
||||||
import com.genersoft.iot.vmp.utils.Coordtransform;
|
import com.genersoft.iot.vmp.utils.Coordtransform;
|
||||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
|
import com.genersoft.iot.vmp.utils.TileUtils;
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
@ -26,14 +31,16 @@ import no.ecc.vectortile.VectorTileEncoder;
|
|||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.jts.geom.GeometryFactory;
|
import org.locationtech.jts.geom.GeometryFactory;
|
||||||
import org.locationtech.jts.geom.Point;
|
import org.locationtech.jts.geom.Point;
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -57,6 +64,12 @@ public class GbChannelServiceImpl implements IGbChannelService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private GroupMapper groupMapper;
|
private GroupMapper groupMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DynamicTask dynamicTask;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
|
|
||||||
private final GeometryFactory geometryFactory = new GeometryFactory();
|
private final GeometryFactory geometryFactory = new GeometryFactory();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -157,6 +170,20 @@ public class GbChannelServiceImpl implements IGbChannelService {
|
|||||||
try {
|
try {
|
||||||
// 发送通知
|
// 发送通知
|
||||||
eventPublisher.channelEventPublishForUpdate(commonGBChannel, oldChannel);
|
eventPublisher.channelEventPublishForUpdate(commonGBChannel, oldChannel);
|
||||||
|
|
||||||
|
if (commonGBChannel.getGbLongitude() != null && !Objects.equals(oldChannel.getGbLongitude(), commonGBChannel.getGbLongitude())
|
||||||
|
&& commonGBChannel.getGbLatitude() != null && !Objects.equals(oldChannel.getGbLatitude(), commonGBChannel.getGbLatitude())) {
|
||||||
|
MobilePosition mobilePosition = new MobilePosition();
|
||||||
|
mobilePosition.setDeviceId(commonGBChannel.getGbDeviceId());
|
||||||
|
mobilePosition.setChannelId(commonGBChannel.getGbId());
|
||||||
|
mobilePosition.setDeviceName(commonGBChannel.getGbName());
|
||||||
|
mobilePosition.setCreateTime(DateUtil.getNow());
|
||||||
|
mobilePosition.setTime(DateUtil.getNow());
|
||||||
|
mobilePosition.setLongitude(commonGBChannel.getGbLongitude());
|
||||||
|
mobilePosition.setLatitude(commonGBChannel.getGbLatitude());
|
||||||
|
eventPublisher.mobilePositionEventPublish(mobilePosition);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("[更新通道通知] 发送失败,{}", commonGBChannel.getGbDeviceId(), e);
|
log.warn("[更新通道通知] 发送失败,{}", commonGBChannel.getGbDeviceId(), e);
|
||||||
}
|
}
|
||||||
@ -906,13 +933,6 @@ public class GbChannelServiceImpl implements IGbChannelService {
|
|||||||
Point pointGeom = geometryFactory.createPoint(new Coordinate(px[0], px[1]));
|
Point pointGeom = geometryFactory.createPoint(new Coordinate(px[0], px[1]));
|
||||||
|
|
||||||
BeanMap beanMap = BeanMapUtils.create(commonGBChannel);
|
BeanMap beanMap = BeanMapUtils.create(commonGBChannel);
|
||||||
|
|
||||||
// Map<String, Object> props = new HashMap<>();
|
|
||||||
// props.put("id", commonGBChannel.getGbId());
|
|
||||||
// props.put("name", commonGBChannel.getGbName());
|
|
||||||
// props.put("deviceId", commonGBChannel.getGbDeviceId());
|
|
||||||
// props.put("status", commonGBChannel.getGbStatus());
|
|
||||||
|
|
||||||
encoder.addFeature("points", beanMap, pointGeom);
|
encoder.addFeature("points", beanMap, pointGeom);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -951,4 +971,148 @@ public class GbChannelServiceImpl implements IGbChannelService {
|
|||||||
|
|
||||||
return new double[] { pixelX, pixelY };
|
return new double[] { pixelX, pixelY };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String drawThin(Map<Integer, Double> zoomParam, Extent extent, String geoCoordSys) {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
|
String id = UUID.randomUUID().toString();
|
||||||
|
List<CommonGBChannel> channelList;
|
||||||
|
if (extent == null) {
|
||||||
|
log.info("[抽稀] ID: {}, 未设置范围,从数据库读取摄像头的范围", id);
|
||||||
|
extent = commonGBChannelMapper.queryExtent();
|
||||||
|
channelList = commonGBChannelMapper.queryAllWithPosition();
|
||||||
|
|
||||||
|
}else {
|
||||||
|
if (geoCoordSys != null && geoCoordSys.equalsIgnoreCase("GCJ02")) {
|
||||||
|
Double[] maxPosition = Coordtransform.GCJ02ToWGS84(extent.getMaxLng(), extent.getMaxLng());
|
||||||
|
Double[] minPosition = Coordtransform.GCJ02ToWGS84(extent.getMinLng(), extent.getMinLat());
|
||||||
|
|
||||||
|
extent.setMaxLng(maxPosition[0]);
|
||||||
|
extent.setMaxLat(maxPosition[1]);
|
||||||
|
|
||||||
|
extent.setMinLng(minPosition[0]);
|
||||||
|
extent.setMinLat(minPosition[1]);
|
||||||
|
}
|
||||||
|
// 获取数据源
|
||||||
|
channelList = commonGBChannelMapper.queryListInExtent(extent);
|
||||||
|
}
|
||||||
|
Assert.isTrue(!channelList.isEmpty(), "通道数据为空");
|
||||||
|
|
||||||
|
log.info("[开始抽稀] ID: {}, 范围,[{}, {}, {}, {}]", id, extent.getMinLng(), extent.getMinLat(), extent.getMaxLng(), extent.getMaxLat());
|
||||||
|
|
||||||
|
Extent finalExtent = extent;
|
||||||
|
// 记录进度
|
||||||
|
saveProcess(id, 0, "开始抽稀");
|
||||||
|
dynamicTask.startDelay(id, () -> {
|
||||||
|
try {
|
||||||
|
// 存储每层的抽稀结果, key为层级(zoom),value为摄像头数组
|
||||||
|
Map<Integer, Collection<CommonGBChannel>> zoomCameraMap = new HashMap<>();
|
||||||
|
|
||||||
|
// 冗余一份已经处理过的摄像头的数据, 避免多次循环获取
|
||||||
|
Map<Integer, CommonGBChannel> useCameraMap = new HashMap<>();
|
||||||
|
AtomicReference<Double> process = new AtomicReference<>((double) 0);
|
||||||
|
for (Integer zoom : zoomParam.keySet()) {
|
||||||
|
Double diff = zoomParam.get(zoom);
|
||||||
|
// 对这个层级展开抽稀
|
||||||
|
log.info("[抽稀] ID:{},当前层级: {}, 坐标间隔: {}", id, zoom, diff);
|
||||||
|
Map<String, CommonGBChannel> useCameraMapForZoom = new HashMap<>();
|
||||||
|
Map<String, CommonGBChannel> cameraMapForZoom = new HashMap<>();
|
||||||
|
// 更新上级图层的数据到当前层级,确保当前层级展示时考虑到之前层级的数据
|
||||||
|
for (CommonGBChannel channel : useCameraMap.values()) {
|
||||||
|
int lngGrid = (int)(channel.getGbLongitude() / diff);
|
||||||
|
int latGrid = (int)(channel.getGbLatitude() / diff);
|
||||||
|
String gridKey = latGrid + ":" + lngGrid;
|
||||||
|
useCameraMapForZoom.put(gridKey, channel);
|
||||||
|
}
|
||||||
|
// 对数据开始执行抽稀
|
||||||
|
for (CommonGBChannel channel : channelList) {
|
||||||
|
if (useCameraMap.containsKey(channel.getGbId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int lngGrid = (int)(channel.getGbLongitude() / diff);
|
||||||
|
int latGrid = (int)(channel.getGbLatitude() / diff);
|
||||||
|
// 数据网格Id
|
||||||
|
String gridKey = latGrid + ":" + lngGrid;
|
||||||
|
if (useCameraMapForZoom.containsKey(gridKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cameraMapForZoom.containsKey(gridKey)) {
|
||||||
|
CommonGBChannel oldChannel = cameraMapForZoom.get(gridKey);
|
||||||
|
// 如果一个网格存在多个数据,则选择最接近中心点的, 目前只选择了经度方向作为参考
|
||||||
|
if (channel.getGbLongitude() % diff < oldChannel.getGbLongitude() % diff) {
|
||||||
|
cameraMapForZoom.put(gridKey, channel);
|
||||||
|
useCameraMap.put(channel.getGbId(), channel);
|
||||||
|
useCameraMap.remove(oldChannel.getGbId());
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
cameraMapForZoom.put(gridKey, channel);
|
||||||
|
useCameraMap.put(channel.getGbId(), channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储
|
||||||
|
zoomCameraMap.put(zoom, cameraMapForZoom.values());
|
||||||
|
process.updateAndGet(v -> new Double((double) (v + 0.5 / zoomParam.size())));
|
||||||
|
saveProcess(id, process.get(), "抽稀图层: " + zoom);
|
||||||
|
}
|
||||||
|
// 抽稀完成, 对数据生成mvt矢量瓦片
|
||||||
|
zoomCameraMap.forEach((key, value) -> {
|
||||||
|
log.info("[抽稀-生成mvt矢量瓦片] ID:{},当前层级: {}", id, key);
|
||||||
|
// 按照 z/x/y 数据组织数据, 矢量数据暂时保存在内存中
|
||||||
|
// 按照范围生成 x y范围,
|
||||||
|
List<TileUtils.TileCoord> tileCoords = TileUtils.tilesForBoxAtZoom(finalExtent, key);
|
||||||
|
for (TileUtils.TileCoord tileCoord : tileCoords) {
|
||||||
|
saveTile(id, tileCoord.z, tileCoord.x, tileCoord.y, "WGS84", value);
|
||||||
|
saveTile(id, tileCoord.z, tileCoord.x, tileCoord.y, "GCJ02", value);
|
||||||
|
process.updateAndGet(v -> (v + 0.5 / zoomParam.size() / tileCoords.size()));
|
||||||
|
saveProcess(id, process.get(), "发布矢量瓦片: " + key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log.info("[抽稀完成] ID:{}, 耗时: {}ms", id, (System.currentTimeMillis() - time));
|
||||||
|
saveProcess(id, 1, "抽稀完成");
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 1);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveTile(String id, int z, int x, int y, String geoCoordSys, Collection<CommonGBChannel> commonGBChannelList ) {
|
||||||
|
VectorTileEncoder encoder = new VectorTileEncoder();
|
||||||
|
commonGBChannelList.forEach(commonGBChannel -> {
|
||||||
|
double lon = commonGBChannel.getGbLongitude();
|
||||||
|
double lat = commonGBChannel.getGbLatitude();
|
||||||
|
if (geoCoordSys != null && geoCoordSys.equalsIgnoreCase("GCJ02")) {
|
||||||
|
Double[] minPosition = Coordtransform.WGS84ToGCJ02(lon, lat);
|
||||||
|
lon = minPosition[0];
|
||||||
|
lat = minPosition[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 lon/lat 转为瓦片内像素坐标(0..256)
|
||||||
|
double[] px = lonLatToTilePixel(lon, lat, z, x, y);
|
||||||
|
Point pointGeom = geometryFactory.createPoint(new Coordinate(px[0], px[1]));
|
||||||
|
|
||||||
|
BeanMap beanMap = BeanMapUtils.create(commonGBChannel);
|
||||||
|
encoder.addFeature("points", beanMap, pointGeom);
|
||||||
|
});
|
||||||
|
|
||||||
|
byte[] encode = encoder.encode();
|
||||||
|
String catchKey = id + "_" + z + "_" + x + "_" + y + "_" + geoCoordSys;
|
||||||
|
VectorTileUtils.INSTANCE.addVectorTile(catchKey, encode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveProcess(String id, double process, String msg) {
|
||||||
|
String key = VideoManagerConstants.DRAW_THIN_PROCESS_PREFIX + id;
|
||||||
|
Duration duration = Duration.ofMinutes(30);
|
||||||
|
redisTemplate.opsForValue().set(key, new DrawThinProcess(process, msg), duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DrawThinProcess thinProgress(String id) {
|
||||||
|
String key = VideoManagerConstants.DRAW_THIN_PROCESS_PREFIX + id;
|
||||||
|
return (DrawThinProcess) redisTemplate.opsForValue().get(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.genersoft.iot.vmp.gb28181.utils;
|
||||||
|
|
||||||
|
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public enum VectorTileUtils {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
private Map<String, byte[]> vectorTileMap = new ConcurrentReferenceHashMap<>();
|
||||||
|
|
||||||
|
public void addVectorTile(String key, byte[] content) {
|
||||||
|
vectorTileMap.put(key, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getVectorTile(String key) {
|
||||||
|
return vectorTileMap.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,8 +10,6 @@ public class GpsUtil {
|
|||||||
|
|
||||||
|
|
||||||
public static BaiduPoint Wgs84ToBd09(String xx, String yy) {
|
public static BaiduPoint Wgs84ToBd09(String xx, String yy) {
|
||||||
|
|
||||||
|
|
||||||
double lng = Double.parseDouble(xx);
|
double lng = Double.parseDouble(xx);
|
||||||
double lat = Double.parseDouble(yy);
|
double lat = Double.parseDouble(yy);
|
||||||
Double[] gcj02 = Coordtransform.WGS84ToGCJ02(lng, lat);
|
Double[] gcj02 = Coordtransform.WGS84ToGCJ02(lng, lat);
|
||||||
|
|||||||
122
src/main/java/com/genersoft/iot/vmp/utils/TileUtils.java
Normal file
122
src/main/java/com/genersoft/iot/vmp/utils/TileUtils.java
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package com.genersoft.iot.vmp.utils;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.gb28181.controller.bean.Extent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TileUtils {
|
||||||
|
private static final double MAX_LATITUDE = 85.05112878;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据坐标获取指定层级的x y 值
|
||||||
|
*
|
||||||
|
* @param lon 经度
|
||||||
|
* @param lat 纬度
|
||||||
|
* @param z 层级
|
||||||
|
* @return double[2] = {xTileFloat, yTileFloat}
|
||||||
|
*/
|
||||||
|
public static double[] lonLatToTileXY(double lon, double lat, int z) {
|
||||||
|
double n = Math.pow(2.0, z);
|
||||||
|
double x = (lon + 180.0) / 360.0 * n;
|
||||||
|
|
||||||
|
// clamp latitude to WebMercator bounds
|
||||||
|
double latClamped = Math.max(Math.min(lat, MAX_LATITUDE), -MAX_LATITUDE);
|
||||||
|
double latRad = Math.toRadians(latClamped);
|
||||||
|
double y = (1.0 - (Math.log(Math.tan(latRad) + 1.0 / Math.cos(latRad)) / Math.PI)) / 2.0 * n;
|
||||||
|
|
||||||
|
return new double[]{x, y};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据坐标范围获取指定层级的x y 范围
|
||||||
|
*
|
||||||
|
* @param bbox array length 4: {minLon, minLat, maxLon, maxLat}
|
||||||
|
* @param z zoom level
|
||||||
|
* @return TileRange object with xMin,xMax,yMin,yMax,z
|
||||||
|
*/
|
||||||
|
public static TileRange bboxToTileRange(double[] bbox, int z) {
|
||||||
|
double minLon = bbox[0], minLat = bbox[1], maxLon = bbox[2], maxLat = bbox[3];
|
||||||
|
|
||||||
|
// If bbox crosses antimeridian (minLon > maxLon), caller should split into two bboxes.
|
||||||
|
if (minLon > maxLon) {
|
||||||
|
throw new IllegalArgumentException("bbox crosses antimeridian; split it before calling bboxToTileRange.");
|
||||||
|
}
|
||||||
|
|
||||||
|
double[] tMin = lonLatToTileXY(minLon, maxLat, z); // top-left (use maxLat)
|
||||||
|
double[] tMax = lonLatToTileXY(maxLon, minLat, z); // bottom-right (use minLat)
|
||||||
|
|
||||||
|
int xMin = (int) Math.floor(Math.min(tMin[0], tMax[0]));
|
||||||
|
int xMax = (int) Math.floor(Math.max(tMin[0], tMax[0]));
|
||||||
|
int yMin = (int) Math.floor(Math.min(tMin[1], tMax[1]));
|
||||||
|
int yMax = (int) Math.floor(Math.max(tMin[1], tMax[1]));
|
||||||
|
|
||||||
|
int maxIndex = ((int) Math.pow(2, z)) - 1;
|
||||||
|
xMin = clamp(xMin, 0, maxIndex);
|
||||||
|
xMax = clamp(xMax, 0, maxIndex);
|
||||||
|
yMin = clamp(yMin, 0, maxIndex);
|
||||||
|
yMax = clamp(yMax, 0, maxIndex);
|
||||||
|
|
||||||
|
return new TileRange(xMin, xMax, yMin, yMax, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If bbox crosses antimeridian (minLon > maxLon), split into two bboxes:
|
||||||
|
* [minLon, minLat, 180, maxLat] and [-180, minLat, maxLon, maxLat]
|
||||||
|
*
|
||||||
|
* @param bbox input bbox array length 4
|
||||||
|
* @return list of 1 or 2 bboxes (each double[4])
|
||||||
|
*/
|
||||||
|
public static List<double[]> splitAntimeridian(double[] bbox) {
|
||||||
|
double minLon = bbox[0], minLat = bbox[1], maxLon = bbox[2], maxLat = bbox[3];
|
||||||
|
List<double[]> parts = new ArrayList<>();
|
||||||
|
if (minLon <= maxLon) {
|
||||||
|
parts.add(new double[]{minLon, minLat, maxLon, maxLat});
|
||||||
|
} else {
|
||||||
|
parts.add(new double[]{minLon, minLat, 180.0, maxLat});
|
||||||
|
parts.add(new double[]{-180.0, minLat, maxLon, maxLat});
|
||||||
|
}
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int clamp(int v, int a, int b) {
|
||||||
|
return Math.max(a, Math.min(b, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return list of tile coordinates (x,y,z) covering bbox at zoom z.
|
||||||
|
* Be careful: the number of tiles can be large for high zooms & big bbox.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static List<TileCoord> tilesForBoxAtZoom(Extent extent, int z) {
|
||||||
|
List<TileCoord> tiles = new ArrayList<>();
|
||||||
|
List<double[]> parts = splitAntimeridian(new double[]{extent.getMinLng(), extent.getMinLat(),
|
||||||
|
extent.getMaxLng(), extent.getMaxLat()});
|
||||||
|
for (double[] part : parts) {
|
||||||
|
TileRange range = bboxToTileRange(part, z);
|
||||||
|
for (int x = range.xMin; x <= range.xMax; x++) {
|
||||||
|
for (int y = range.yMin; y <= range.yMax; y++) {
|
||||||
|
tiles.add(new TileCoord(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple helper classes
|
||||||
|
public static class TileRange {
|
||||||
|
public final int xMin, xMax, yMin, yMax, z;
|
||||||
|
public TileRange(int xMin, int xMax, int yMin, int yMax, int z) {
|
||||||
|
this.xMin = xMin; this.xMax = xMax; this.yMin = yMin; this.yMax = yMax; this.z = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TileCoord {
|
||||||
|
public final int x, y, z;
|
||||||
|
public TileCoord(int x, int y, int z) { this.x = x; this.y = y; this.z = z; }
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" + "z=" + z + ", x=" + x + ", y=" + y + '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -613,6 +613,40 @@ export function resetLevel() {
|
|||||||
url: '/api/common/channel/map/reset-level'
|
url: '/api/common/channel/map/reset-level'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
export function clearThin(id) {
|
||||||
|
return request({
|
||||||
|
method: 'get',
|
||||||
|
url: '/api/common/channel/map/thin/clear',
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function thinProgress(id) {
|
||||||
|
return request({
|
||||||
|
method: 'get',
|
||||||
|
url: '/api/common/channel/map/thin/progress',
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function saveThin(id) {
|
||||||
|
return request({
|
||||||
|
method: 'get',
|
||||||
|
url: '/api/common/channel/map/thin/save',
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function drawThin(data) {
|
||||||
|
return request({
|
||||||
|
method: 'post',
|
||||||
|
url: '/api/common/channel/map/thin/draw',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
export function test() {
|
export function test() {
|
||||||
return request({
|
return request({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
|||||||
@ -2,6 +2,7 @@ const getters = {
|
|||||||
sidebar: state => state.app.sidebar,
|
sidebar: state => state.app.sidebar,
|
||||||
device: state => state.app.device,
|
device: state => state.app.device,
|
||||||
token: state => state.user.token,
|
token: state => state.user.token,
|
||||||
|
showConfirmBoxForLoginLose: state => state.user.showConfirmBoxForLoginLose,
|
||||||
serverId: state => state.user.serverId,
|
serverId: state => state.user.serverId,
|
||||||
name: state => state.user.name,
|
name: state => state.user.name,
|
||||||
visitedViews: state => state.tagsView.visitedViews,
|
visitedViews: state => state.tagsView.visitedViews,
|
||||||
|
|||||||
@ -48,7 +48,7 @@ import {
|
|||||||
stopPlayback,
|
stopPlayback,
|
||||||
pausePlayback,
|
pausePlayback,
|
||||||
resumePlayback,
|
resumePlayback,
|
||||||
seekPlayback, speedPlayback, getAllForMap, test, saveLevel, resetLevel
|
seekPlayback, speedPlayback, getAllForMap, test, saveLevel, resetLevel, clearThin, thinProgress, drawThin, saveThin
|
||||||
} from '@/api/commonChannel'
|
} from '@/api/commonChannel'
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
@ -592,6 +592,47 @@ const actions = {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
clearThin({ commit }, id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
clearThin(id).then(response => {
|
||||||
|
const { data } = response
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
thinProgress({ commit }, id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
thinProgress(id).then(response => {
|
||||||
|
const { data } = response
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
saveThin({ commit }, id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
saveThin(id).then(response => {
|
||||||
|
const { data } = response
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
drawThin({ commit }, param) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
drawThin(param).then(response => {
|
||||||
|
const { data } = response
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
test({ commit }) {
|
test({ commit }) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
test().then(response => {
|
test().then(response => {
|
||||||
|
|||||||
@ -25,7 +25,8 @@ const getDefaultState = () => {
|
|||||||
return {
|
return {
|
||||||
token: getToken(),
|
token: getToken(),
|
||||||
name: '',
|
name: '',
|
||||||
serverId: ''
|
serverId: '',
|
||||||
|
showConfirmBoxForLoginLose: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +44,9 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
SET_SERVER_ID: (state, serverId) => {
|
SET_SERVER_ID: (state, serverId) => {
|
||||||
state.serverId = serverId
|
state.serverId = serverId
|
||||||
|
},
|
||||||
|
SET_CONFIRM_BOX: (state, status) => {
|
||||||
|
state.showConfirmBoxForLoginLose = status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +63,7 @@ const actions = {
|
|||||||
commit('SET_TOKEN', data.accessToken)
|
commit('SET_TOKEN', data.accessToken)
|
||||||
commit('SET_NAME', data.username)
|
commit('SET_NAME', data.username)
|
||||||
commit('SET_SERVER_ID', data.serverId)
|
commit('SET_SERVER_ID', data.serverId)
|
||||||
|
commit('SET_CONFIRM_BOX', true)
|
||||||
setToken(data.accessToken)
|
setToken(data.accessToken)
|
||||||
setName(data.username)
|
setName(data.username)
|
||||||
setServerId(data.serverId)
|
setServerId(data.serverId)
|
||||||
@ -168,6 +173,9 @@ const actions = {
|
|||||||
reject(error)
|
reject(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
closeConfirmBoxForLoginLose({ commit }) {
|
||||||
|
commit('SET_CONFIRM_BOX', false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { MessageBox, Message } from 'element-ui'
|
|||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
|
|
||||||
|
let showLoginConfirm = false
|
||||||
|
|
||||||
// create an axios instance
|
// create an axios instance
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||||
@ -44,9 +46,8 @@ service.interceptors.response.use(
|
|||||||
}
|
}
|
||||||
const res = response.data
|
const res = response.data
|
||||||
if (res.code && res.code !== 0) {
|
if (res.code && res.code !== 0) {
|
||||||
Message({
|
Message.error({
|
||||||
message: res.msg,
|
message: res.msg,
|
||||||
type: 'error',
|
|
||||||
duration: 5 * 1000
|
duration: 5 * 1000
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -55,8 +56,9 @@ service.interceptors.response.use(
|
|||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log(error) // for debug
|
console.log(error) // for debug
|
||||||
if (error.response.status === 401) {
|
if (error.response.status === 401 && !showLoginConfirm && store.getters.showConfirmBoxForLoginLose) {
|
||||||
// to re-login
|
// to re-login
|
||||||
|
showLoginConfirm = true
|
||||||
MessageBox.confirm('登录已经到期, 是否重新登录', '登录确认', {
|
MessageBox.confirm('登录已经到期, 是否重新登录', '登录确认', {
|
||||||
confirmButtonText: '重新登录',
|
confirmButtonText: '重新登录',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
@ -65,13 +67,31 @@ service.interceptors.response.use(
|
|||||||
store.dispatch('user/resetToken').then(() => {
|
store.dispatch('user/resetToken').then(() => {
|
||||||
location.reload()
|
location.reload()
|
||||||
})
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
store.dispatch('user/closeConfirmBoxForLoginLose')
|
||||||
|
Message.warning({
|
||||||
|
type: 'warning',
|
||||||
|
message: '登录过期提示已经关闭,请注销后重新登录'
|
||||||
|
})
|
||||||
|
// 清除token, 后续请求不再继续
|
||||||
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Message({
|
if (!store.getters.showConfirmBoxForLoginLose) {
|
||||||
message: error.message,
|
return
|
||||||
type: 'error',
|
}
|
||||||
duration: 5 * 1000
|
let data = error.response.data
|
||||||
})
|
if (data && data.msg) {
|
||||||
|
Message.error({
|
||||||
|
message: data.msg,
|
||||||
|
showClose: true
|
||||||
|
})
|
||||||
|
}else {
|
||||||
|
Message.error({
|
||||||
|
message: error.message,
|
||||||
|
showClose: true
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// return Promise.reject(error)
|
// return Promise.reject(error)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<el-page-header content="编辑通道" @back="close" />
|
<el-page-header content="编辑通道" @back="close" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CommonChannelEdit :id="id" ref="commonChannelEdit" :save-success="close" :cancel="close" />
|
<CommonChannelEdit :id="id" ref="commonChannelEdit" :showCancel="true" @submitSuccess="close" @cancel="close" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="CommonChannelEdit" v-loading="loading" style="width: 100%">
|
<div id="CommonChannelEdit" v-loading="loading" style="width: 100%; overflow: auto; height: calc(-148px + 100vh);">
|
||||||
<el-form ref="channelForm" :model="form" :rules="rules" status-icon label-width="160px" class="channel-form" size="medium">
|
<el-form ref="channelForm" :model="form" :rules="rules" status-icon label-width="160px" class="channel-form" size="medium">
|
||||||
<div class="form-box">
|
<div class="form-box">
|
||||||
<el-form-item label="名称" prop="gbName">
|
<el-form-item label="名称" prop="gbName">
|
||||||
@ -13,7 +13,7 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="设备厂商">
|
<el-form-item label="设备厂商">
|
||||||
<el-input v-model="gbManufacturer" placeholder="请输入设备厂商" />
|
<el-input v-model="form.gbManufacturer" placeholder="请输入设备厂商" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="设备型号">
|
<el-form-item label="设备型号">
|
||||||
<el-autocomplete
|
<el-autocomplete
|
||||||
@ -252,7 +252,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div style="text-align: right">
|
<div style="text-align: right">
|
||||||
<el-button type="primary" @click="onSubmit" >保存</el-button>
|
<el-button type="primary" @click="onSubmit" >保存</el-button>
|
||||||
<el-button v-if="cancel" @click="cancelSubmit" >取消</el-button>
|
<el-button v-if="showCancel" @click="cancelSubmit" >取消</el-button>
|
||||||
<el-button v-if="form.dataType === 1" @click="reset">重置</el-button>
|
<el-button v-if="form.dataType === 1" @click="reset">重置</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -276,7 +276,7 @@ export default {
|
|||||||
ChooseGroup,
|
ChooseGroup,
|
||||||
channelCode
|
channelCode
|
||||||
},
|
},
|
||||||
props: ['id', 'dataForm', 'saveSuccess', 'cancel'],
|
props: ['id', 'dataForm', 'showCancel'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
rules: {
|
rules: {
|
||||||
@ -303,7 +303,7 @@ export default {
|
|||||||
created() {
|
created() {
|
||||||
// 获取完整信息
|
// 获取完整信息
|
||||||
if (this.id) {
|
if (this.id) {
|
||||||
this.getCommonChannel()
|
this.getCommonChannel(this.id)
|
||||||
} else {
|
} else {
|
||||||
if (!this.dataForm.gbDeviceId) {
|
if (!this.dataForm.gbDeviceId) {
|
||||||
this.dataForm.gbDeviceId = ''
|
this.dataForm.gbDeviceId = ''
|
||||||
@ -335,9 +335,7 @@ export default {
|
|||||||
showClose: true,
|
showClose: true,
|
||||||
message: '保存成功'
|
message: '保存成功'
|
||||||
})
|
})
|
||||||
if (this.saveSuccess) {
|
this.$emit('submitSuccess')
|
||||||
this.saveSuccess()
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
@ -378,7 +376,7 @@ export default {
|
|||||||
showClose: true,
|
showClose: true,
|
||||||
message: '重置成功 已保存'
|
message: '重置成功 已保存'
|
||||||
})
|
})
|
||||||
this.getCommonChannel()
|
this.getCommonChannel(this.form.gbId)
|
||||||
}
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@ -389,9 +387,9 @@ export default {
|
|||||||
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getCommonChannel: function() {
|
getCommonChannel: function(id) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.$store.dispatch('commonChanel/queryOne', this.id)
|
this.$store.dispatch('commonChanel/queryOne', id)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.gbDownloadSpeed) {
|
if (data.gbDownloadSpeed) {
|
||||||
data.gbDownloadSpeedArray = data.gbDownloadSpeed.split('/')
|
data.gbDownloadSpeedArray = data.gbDownloadSpeed.split('/')
|
||||||
@ -422,9 +420,7 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
cancelSubmit: function() {
|
cancelSubmit: function() {
|
||||||
if (this.cancel) {
|
this.$emit('cancel')
|
||||||
this.cancel()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
getPaths: function() {
|
getPaths: function() {
|
||||||
this.parentPath = []
|
this.parentPath = []
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import { fromLonLat, toLonLat } from './map/TransformLonLat'
|
|||||||
|
|
||||||
import { v4 } from 'uuid'
|
import { v4 } from 'uuid'
|
||||||
import { getUid } from 'ol'
|
import { getUid } from 'ol'
|
||||||
import {Fill} from "ol/style";
|
import { Fill } from 'ol/style'
|
||||||
|
|
||||||
let olMap, tileLayer = null
|
let olMap, tileLayer = null
|
||||||
export default {
|
export default {
|
||||||
@ -158,6 +158,9 @@ export default {
|
|||||||
source: source,
|
source: source,
|
||||||
style: function(feature) {
|
style: function(feature) {
|
||||||
let status = feature.properties_.gbStatus
|
let status = feature.properties_.gbStatus
|
||||||
|
if (layer.get('hideFeatures').includes(feature.properties_.gbId)) {
|
||||||
|
return new Style()
|
||||||
|
}
|
||||||
if (status === 'ON') {
|
if (status === 'ON') {
|
||||||
return new Style({
|
return new Style({
|
||||||
image: new Icon({
|
image: new Icon({
|
||||||
@ -203,6 +206,7 @@ export default {
|
|||||||
// // ]
|
// // ]
|
||||||
// }
|
// }
|
||||||
})
|
})
|
||||||
|
layer.set('hideFeatures', [])
|
||||||
olMap.addLayer(layer)
|
olMap.addLayer(layer)
|
||||||
if (clickEvent) {
|
if (clickEvent) {
|
||||||
layer.on('click', (event) => {
|
layer.on('click', (event) => {
|
||||||
@ -363,8 +367,6 @@ export default {
|
|||||||
return vectorLayer
|
return vectorLayer
|
||||||
},
|
},
|
||||||
createPointLayer(data, clickEvent, option){
|
createPointLayer(data, clickEvent, option){
|
||||||
console.log(444)
|
|
||||||
console.log(data)
|
|
||||||
const features = []
|
const features = []
|
||||||
let maxZoom = (option && option.maxZoom) ? option.maxZoom : olMap.getView().getMaxZoom()
|
let maxZoom = (option && option.maxZoom) ? option.maxZoom : olMap.getView().getMaxZoom()
|
||||||
let minZoom = (option && option.minZoom) ? option.minZoom : olMap.getView().getMinZoom()
|
let minZoom = (option && option.minZoom) ? option.minZoom : olMap.getView().getMinZoom()
|
||||||
@ -498,7 +500,7 @@ export default {
|
|||||||
updatePointLayer(layer, data, postponement) {
|
updatePointLayer(layer, data, postponement) {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
layer.getSource().clear(true)
|
layer.getSource().clear(true)
|
||||||
if (!data || data.length == 0) {
|
if (!data || data.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const features = []
|
const features = []
|
||||||
@ -567,12 +569,15 @@ export default {
|
|||||||
feature.setStyle(style)
|
feature.setStyle(style)
|
||||||
olMap.render()
|
olMap.render()
|
||||||
},
|
},
|
||||||
|
hideFeature(layer, featureId) {
|
||||||
|
layer.get('hideFeatures').add(featureId)
|
||||||
|
},
|
||||||
|
cancelHideFeature(layer, featureId) {
|
||||||
|
let index = layer.get('hideFeatures').indexOf(featureId)
|
||||||
|
layer.get('hideFeatures').splice(index, 1)
|
||||||
|
},
|
||||||
setFeaturePositionById(layer, featureId, data) {
|
setFeaturePositionById(layer, featureId, data) {
|
||||||
if (layer instanceof LayerGroup) {
|
|
||||||
|
|
||||||
}else {
|
|
||||||
|
|
||||||
}
|
|
||||||
let featureOld = layer.getSource().getFeatureById(featureId)
|
let featureOld = layer.getSource().getFeatureById(featureId)
|
||||||
if (featureOld) {
|
if (featureOld) {
|
||||||
layer.getSource().removeFeature(featureOld)
|
layer.getSource().removeFeature(featureOld)
|
||||||
@ -743,6 +748,11 @@ export default {
|
|||||||
},
|
},
|
||||||
getCoordSys(){
|
getCoordSys(){
|
||||||
return this.mapTileList[this.mapTileIndex].coordinateSystem
|
return this.mapTileList[this.mapTileIndex].coordinateSystem
|
||||||
|
},
|
||||||
|
refreshLayer(layer){
|
||||||
|
if (layer && layer.getSource()) {
|
||||||
|
layer.getSource().refresh()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<el-page-header content="编辑通道" @back="close" />
|
<el-page-header content="编辑通道" @back="close" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CommonChannelEdit :id="id" ref="commonChannelEdit" :save-success="close" :cancel="close" />
|
<CommonChannelEdit :id="id" ref="commonChannelEdit" :showCancel="true" @submitSuccess="close" @cancel="close" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
78
web/src/views/dialog/commonChannelEditDialog.vue
Executable file
78
web/src/views/dialog/commonChannelEditDialog.vue
Executable file
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<div id="commonChannelEditDialog">
|
||||||
|
<el-dialog
|
||||||
|
v-el-drag-dialog
|
||||||
|
title="通道编辑"
|
||||||
|
width="90%"
|
||||||
|
top="2rem"
|
||||||
|
:append-to-body="true"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:visible.sync="showDialog"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
@close="close()"
|
||||||
|
>
|
||||||
|
<CommonChannelEdit style="overflow: auto !important;" ref="commonChannelEdit" :showCancel="true" :id="channelId" @cancel="close" @submitSuccess="close"></CommonChannelEdit>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import elDragDialog from '@/directive/el-drag-dialog'
|
||||||
|
import CommonChannelEdit from '../common/CommonChannelEdit.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CommonChannelEditDialog',
|
||||||
|
components: { CommonChannelEdit },
|
||||||
|
directives: { elDragDialog },
|
||||||
|
props: ['platformId', 'platformDeviceId'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
submitCallback: null,
|
||||||
|
showDialog: false,
|
||||||
|
channelId: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
created() {},
|
||||||
|
methods: {
|
||||||
|
openDialog: function(id) {
|
||||||
|
console.log(id)
|
||||||
|
this.channelId = id
|
||||||
|
this.showDialog = true
|
||||||
|
this.$refs.commonChannelEdit.getCommonChannel(this.channelId)
|
||||||
|
},
|
||||||
|
onSubmit: function() {
|
||||||
|
this.$refs['form'].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.$axios({
|
||||||
|
method: 'post',
|
||||||
|
url: `/api/platform/catalog/${!this.isEdit ? 'add' : 'edit'}`,
|
||||||
|
data: this.form
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
if (this.submitCallback) this.submitCallback(this.form)
|
||||||
|
} else {
|
||||||
|
this.$message({
|
||||||
|
showClose: true,
|
||||||
|
message: res.data.msg,
|
||||||
|
type: 'error'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.close()
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
this.channelId = null
|
||||||
|
this.showDialog = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="国标通道配置">
|
<el-tab-pane label="国标通道配置">
|
||||||
<CommonChannelEdit :id="jtChannel.gbId" ref="commonChannelEdit" :data-form="jtChannel" :cancel="close" />
|
<CommonChannelEdit :id="jtChannel.gbId" ref="commonChannelEdit" :data-form="jtChannel" @cancel="close" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
84
web/src/views/map/dialog/drawThinProgress.vue
Executable file
84
web/src/views/map/dialog/drawThinProgress.vue
Executable file
@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<div id="drawThinProgress" v-loading="isLoging">
|
||||||
|
<el-dialog
|
||||||
|
v-el-drag-dialog
|
||||||
|
width="240px"
|
||||||
|
top="13%"
|
||||||
|
:append-to-body="true"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:visible.sync="showDialog"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
:show-close="true"
|
||||||
|
style="text-align: center"
|
||||||
|
@close="close()"
|
||||||
|
>
|
||||||
|
<el-progress type="circle" :percentage="percentage" />
|
||||||
|
<div style="text-align: center">
|
||||||
|
{{ msg }}
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import elDragDialog from '@/directive/el-drag-dialog'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'drawThinProgress',
|
||||||
|
directives: { elDragDialog },
|
||||||
|
props: ['platformId'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
endCallBack: null,
|
||||||
|
syncStatus: null,
|
||||||
|
percentage: 0,
|
||||||
|
showDialog: false,
|
||||||
|
isLoging: false,
|
||||||
|
syncFlag: false,
|
||||||
|
drawThinId: null,
|
||||||
|
timer: null,
|
||||||
|
errorTimer: null,
|
||||||
|
msg: '正在同步'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
created() {},
|
||||||
|
methods: {
|
||||||
|
openDialog: function(drawThinId, endCallBack) {
|
||||||
|
console.log('drawThinId: ' + drawThinId)
|
||||||
|
this.drawThinId = drawThinId
|
||||||
|
this.showDialog = true
|
||||||
|
this.msg = ''
|
||||||
|
this.percentage = 0
|
||||||
|
this.syncFlag = false
|
||||||
|
this.syncStatus = null
|
||||||
|
this.endCallBack = endCallBack
|
||||||
|
this.getProgress()
|
||||||
|
},
|
||||||
|
getProgress() {
|
||||||
|
this.$store.dispatch('commonChanel/thinProgress', this.drawThinId)
|
||||||
|
.then(({ data }) => {
|
||||||
|
this.syncFlag = true
|
||||||
|
this.percentage = data.process * 100
|
||||||
|
this.msg = data.msg
|
||||||
|
console.log('drawThinId: ' + data.drawThinId)
|
||||||
|
this.timer = setTimeout(this.getProgress, 300)
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
this.syncStatus = 'error'
|
||||||
|
this.msg = error
|
||||||
|
window.clearTimeout(this.errorTimer)
|
||||||
|
this.errorTimer = setTimeout(() => {
|
||||||
|
this.showDialog = false
|
||||||
|
}, 2000)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
if (this.endCallBack) {
|
||||||
|
this.endCallBack()
|
||||||
|
}
|
||||||
|
window.clearTimeout(this.timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -11,31 +11,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-tool-btn-group" v-if="mapTileList.length > 0">
|
<div class="map-tool-btn-group" v-if="mapTileList.length > 0">
|
||||||
<el-dropdown placement="top" @command="changeLayerStyle">
|
<el-dropdown placement="top" @command="changeLayerType">
|
||||||
<div class="el-dropdown-link map-tool-btn">
|
<div class="el-dropdown-link map-tool-btn">
|
||||||
<i class="iconfont icon-mti-jutai"></i>
|
<i class="iconfont icon-mti-jutai"></i>
|
||||||
</div>
|
</div>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item :command="0" >
|
<el-dropdown-item :command="0" >
|
||||||
<span v-if="layerStyle !== 0">图层关闭</span>
|
<span v-if="layerType !== 0">图层关闭</span>
|
||||||
<span v-if="layerStyle === 0" style="color: rgb(64, 158, 255);">图层关闭</span>
|
<span v-if="layerType === 0" style="color: rgb(64, 158, 255);">图层关闭</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item :command="1" >
|
<el-dropdown-item :command="1" >
|
||||||
<span v-if="layerStyle !== 1">直接展示</span>
|
<span v-if="layerType !== 1">直接展示</span>
|
||||||
<span v-if="layerStyle === 1" style="color: rgb(64, 158, 255);">直接展示</span>
|
<span v-if="layerType === 1" style="color: rgb(64, 158, 255);">直接展示</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item :command="2">
|
<el-dropdown-item :command="2">
|
||||||
<span v-if="layerStyle !== 2">碰撞检测</span>
|
<span v-if="layerType !== 2">抽稀图层</span>
|
||||||
<span v-if="layerStyle === 2" style="color: rgb(64, 158, 255);">碰撞检测</span>
|
<span v-if="layerType === 2" style="color: rgb(64, 158, 255);">抽稀图层</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item :command="3">
|
|
||||||
<span v-if="layerStyle !== 3">抽稀图层</span>
|
|
||||||
<span v-if="layerStyle === 3" style="color: rgb(64, 158, 255);">抽稀图层</span>
|
|
||||||
</el-dropdown-item>
|
|
||||||
<!-- <el-dropdown-item :command="4">-->
|
|
||||||
<!-- <span v-if="layerStyle !== 4">聚合图层</span>-->
|
|
||||||
<!-- <span v-if="layerStyle === 4" style="color: rgb(64, 158, 255);">聚合图层</span>-->
|
|
||||||
<!-- </el-dropdown-item>-->
|
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</div>
|
</div>
|
||||||
@ -77,7 +69,7 @@
|
|||||||
<el-slider v-model="diffPixels" show-input :min="10" :max="200" input-size="mini" ></el-slider>
|
<el-slider v-model="diffPixels" show-input :min="10" :max="200" input-size="mini" ></el-slider>
|
||||||
<div style="margin-left: 10px; line-height: 38px;">
|
<div style="margin-left: 10px; line-height: 38px;">
|
||||||
<el-button :loading="quicklyDrawThinLoading" @click="quicklyDrawThin" size="mini">快速抽稀</el-button>
|
<el-button :loading="quicklyDrawThinLoading" @click="quicklyDrawThin" size="mini">快速抽稀</el-button>
|
||||||
<el-button size="mini" @click="boxDrawThin" >局部抽稀</el-button>
|
<el-button :loading="boxDrawThinLoading" size="mini" @click="boxDrawThin" >局部抽稀</el-button>
|
||||||
<el-button size="mini" @click="resetDrawThinData()">数据还原</el-button>
|
<el-button size="mini" @click="resetDrawThinData()">数据还原</el-button>
|
||||||
<el-button :loading="saveDrawThinLoading" type="primary" :disabled="!layerGroupSource" size="mini" @click="saveDrawThin()">保存</el-button>
|
<el-button :loading="saveDrawThinLoading" type="primary" :disabled="!layerGroupSource" size="mini" @click="saveDrawThin()">保存</el-button>
|
||||||
<el-button type="warning" size="mini" @click="showDrawThinBox(false)">取消</el-button>
|
<el-button type="warning" size="mini" @click="showDrawThinBox(false)">取消</el-button>
|
||||||
@ -107,7 +99,8 @@
|
|||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<div style="padding-top: 10px; margin: 0 auto; width: fit-content;">
|
<div style="padding-top: 10px; margin: 0 auto; width: fit-content;">
|
||||||
<el-button v-bind:disabled="channel.gbStatus !== 'ON'" type="primary" size="small" title="播放" icon="el-icon-video-play" @click="play(channel)">播放</el-button>
|
<el-button v-bind:disabled="channel.gbStatus !== 'ON'" type="primary" size="small" title="播放" icon="el-icon-video-play" @click="play(channel)">播放</el-button>
|
||||||
<el-button type="primary" size="small" title="编辑位置" icon="el-icon-edit" @click="edit(channel)">编辑</el-button>
|
<el-button type="primary" size="small" title="编辑" icon="el-icon-edit" @click="edit(channel)">编辑</el-button>
|
||||||
|
<el-button type="primary" size="small" title="位置" icon="el-icon-coordinate" @click="editPosition(channel)">位置</el-button>
|
||||||
<!-- <el-button type="primary" size="small" title="轨迹查询" icon="el-icon-map-location" @click="getTrace(channel)">轨迹</el-button>-->
|
<!-- <el-button type="primary" size="small" title="轨迹查询" icon="el-icon-map-location" @click="getTrace(channel)">轨迹</el-button>-->
|
||||||
</div>
|
</div>
|
||||||
<span class="infobox-close el-icon-close" @click="closeInfoBox"></span>
|
<span class="infobox-close el-icon-close" @click="closeInfoBox"></span>
|
||||||
@ -119,7 +112,7 @@
|
|||||||
<div ref="infoboxForEdit">
|
<div ref="infoboxForEdit">
|
||||||
<transition name="el-zoom-in-center">
|
<transition name="el-zoom-in-center">
|
||||||
<div class="infobox-edit-content" v-if="dragChannel">
|
<div class="infobox-edit-content" v-if="dragChannel">
|
||||||
<div style="width: 100%; height: 2rem; line-height: 1.5rem; font-size: 14px">{{dragChannel.gbName}} ({{dragChannel.gbDeviceId}})</div>
|
<div style="width: 100%; line-height: 1.5rem; font-size: 14px">{{dragChannel.gbName}} ({{dragChannel.gbDeviceId}})</div>
|
||||||
<span style="font-size: 14px">经度:</span> <el-input v-model="dragChannel.gbLongitude" placeholder="请输入经度" style="width: 7rem; margin-right: 10px"></el-input>
|
<span style="font-size: 14px">经度:</span> <el-input v-model="dragChannel.gbLongitude" placeholder="请输入经度" style="width: 7rem; margin-right: 10px"></el-input>
|
||||||
<span style="font-size: 14px">纬度: </span> <el-input v-model="dragChannel.gbLatitude" placeholder="请输入纬度" style="width: 7rem; "></el-input>
|
<span style="font-size: 14px">纬度: </span> <el-input v-model="dragChannel.gbLatitude" placeholder="请输入纬度" style="width: 7rem; "></el-input>
|
||||||
<el-button icon="el-icon-close" size="medium" type="text" @click="cancelEdit(dragChannel)" style="margin-left: 1rem; font-size: 18px; color: #2b2f3a"></el-button>
|
<el-button icon="el-icon-close" size="medium" type="text" @click="cancelEdit(dragChannel)" style="margin-left: 1rem; font-size: 18px; color: #2b2f3a"></el-button>
|
||||||
@ -129,6 +122,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<devicePlayer ref="devicePlayer" ></devicePlayer>
|
<devicePlayer ref="devicePlayer" ></devicePlayer>
|
||||||
<queryTrace ref="queryTrace" ></queryTrace>
|
<queryTrace ref="queryTrace" ></queryTrace>
|
||||||
|
<CommonChannelEditDialog ref="commonChannelEditDialog" ></CommonChannelEditDialog>
|
||||||
|
<DrawThinProgress ref="drawThinProgress" ></DrawThinProgress>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -137,15 +132,19 @@ import DeviceTree from '../common/DeviceTree.vue'
|
|||||||
import queryTrace from './queryTrace.vue'
|
import queryTrace from './queryTrace.vue'
|
||||||
import MapComponent from '../common/MapComponent.vue'
|
import MapComponent from '../common/MapComponent.vue'
|
||||||
import devicePlayer from '../common/channelPlayer/index.vue'
|
import devicePlayer from '../common/channelPlayer/index.vue'
|
||||||
|
import CommonChannelEditDialog from '../dialog/commonChannelEditDialog.vue'
|
||||||
|
import DrawThinProgress from './dialog/drawThinProgress.vue'
|
||||||
|
|
||||||
let cameraListForSource = []
|
let cameraListForSource = []
|
||||||
let cameraList = []
|
let cameraList = []
|
||||||
let cameraListForLevelMap = new Map()
|
let cameraListForLevelMap = new Map()
|
||||||
let cameraLayerExtent = []
|
let cameraLayerExtent = []
|
||||||
let channelLayer = null
|
let channelLayer, channelTileLayer = null
|
||||||
export default {
|
export default {
|
||||||
name: 'Map',
|
name: 'Map',
|
||||||
components: {
|
components: {
|
||||||
|
DrawThinProgress,
|
||||||
|
CommonChannelEditDialog,
|
||||||
DeviceTree,
|
DeviceTree,
|
||||||
devicePlayer,
|
devicePlayer,
|
||||||
queryTrace,
|
queryTrace,
|
||||||
@ -170,9 +169,11 @@ export default {
|
|||||||
zoomValue: 10,
|
zoomValue: 10,
|
||||||
showDrawThin: false,
|
showDrawThin: false,
|
||||||
quicklyDrawThinLoading: false,
|
quicklyDrawThinLoading: false,
|
||||||
saveDrawThinLoading: false,
|
boxDrawThinLoading: false,
|
||||||
layerStyle: 0,
|
drawThinId: null,
|
||||||
drawThinLayer: null,
|
drawThinLayer: null,
|
||||||
|
saveDrawThinLoading: false,
|
||||||
|
layerType: 0,
|
||||||
layerGroupSource: null
|
layerGroupSource: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -184,64 +185,32 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initChannelLayer: function () {
|
initChannelLayer: function () {
|
||||||
|
|
||||||
this.mapTileList = this.$refs.mapComponent.mapTileList
|
this.mapTileList = this.$refs.mapComponent.mapTileList
|
||||||
// 获取所有有位置的通道
|
// 获取所有有位置的通道
|
||||||
this.closeInfoBox()
|
this.closeInfoBox()
|
||||||
this.$store.dispatch('commonChanel/getAllForMap', {}).then(data => {
|
|
||||||
cameraListForSource = data
|
let clientEvent = data => {
|
||||||
console.log(data.length)
|
this.closeInfoBox()
|
||||||
let minLng = data[0].gbLongitude
|
this.$nextTick(() => {
|
||||||
let maxLng = data[0].gbLongitude
|
if (data[0].edit) {
|
||||||
let minLat = data[0].gbLatitude
|
this.showEditInfo(data[0])
|
||||||
let maxLat = data[0].gbLatitude
|
}else {
|
||||||
for (let i = 1; i < data.length; i++) {
|
this.showChannelInfo(data[0])
|
||||||
let item = data[i]
|
|
||||||
if (item.gbLongitude < minLng) {
|
|
||||||
minLng = item.gbLongitude
|
|
||||||
}
|
}
|
||||||
if (item.gbLongitude > maxLng) {
|
})
|
||||||
maxLng = item.gbLongitude
|
}
|
||||||
}
|
|
||||||
if (item.gbLatitude < minLat) {
|
channelLayer = this.$refs.mapComponent.addPointLayer([], clientEvent, null)
|
||||||
minLat = item.gbLatitude
|
|
||||||
}
|
|
||||||
if (item.gbLatitude > maxLat) {
|
|
||||||
maxLat = item.gbLatitude
|
|
||||||
}
|
|
||||||
if (item.gbLongitude && item.gbLatitude) {
|
|
||||||
let position = [item.gbLongitude, item.gbLatitude]
|
|
||||||
let cameraData = {
|
|
||||||
id: item.gbId,
|
|
||||||
position: position,
|
|
||||||
status: item.gbStatus,
|
|
||||||
data: item,
|
|
||||||
image: {
|
|
||||||
anchor: [0.5, 1],
|
|
||||||
src: this.getImageByChannel(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cameraList.push(cameraData)
|
|
||||||
if (item.mapLevel) {
|
|
||||||
if (cameraListForLevelMap.has(item.mapLevel)) {
|
|
||||||
let list = cameraListForLevelMap.get(item.mapLevel)
|
|
||||||
list.push(cameraData)
|
|
||||||
}else {
|
|
||||||
cameraListForLevelMap.set(item.mapLevel, [cameraData])
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
cameraListForLevelMap.set(0, [cameraData])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cameraLayerExtent = [minLng, minLat, maxLng, maxLat]
|
|
||||||
this.updateChannelLayer()
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
refreshLayer(){
|
refreshLayer(){
|
||||||
this.closeInfoBox()
|
this.closeInfoBox()
|
||||||
this.$refs.mapComponent.clearLayer(channelLayer)
|
// 刷新瓦片图层
|
||||||
this.initChannelLayer()
|
if (channelLayer) {
|
||||||
|
this.$refs.mapComponent.refreshLayer(channelLayer)
|
||||||
|
}
|
||||||
|
if (channelTileLayer) {
|
||||||
|
this.$refs.mapComponent.refreshLayer(channelTileLayer)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
treeChannelClickEvent: function (id) {
|
treeChannelClickEvent: function (id) {
|
||||||
this.closeInfoBox()
|
this.closeInfoBox()
|
||||||
@ -281,7 +250,18 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '编辑位置',
|
label: '修改位置',
|
||||||
|
icon: 'el-icon-coordinate',
|
||||||
|
type: 1,
|
||||||
|
onClick: (event, data, node) => {
|
||||||
|
this.$store.dispatch('commonChanel/queryOne', data.id)
|
||||||
|
.then(data => {
|
||||||
|
this.editPosition(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '编辑通道',
|
||||||
icon: 'el-icon-edit',
|
icon: 'el-icon-edit',
|
||||||
type: 1,
|
type: 1,
|
||||||
onClick: (event, data, node) => {
|
onClick: (event, data, node) => {
|
||||||
@ -291,15 +271,6 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ,
|
|
||||||
// {
|
|
||||||
// label: '轨迹查询',
|
|
||||||
// icon: 'el-icon-map-location',
|
|
||||||
// type: 1,
|
|
||||||
// onClick: (event, data, node) => {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
showChannelInfo: function(data) {
|
showChannelInfo: function(data) {
|
||||||
@ -312,9 +283,8 @@ export default {
|
|||||||
data: data,
|
data: data,
|
||||||
status: data.gbStatus
|
status: data.gbStatus
|
||||||
}
|
}
|
||||||
if (!this.$refs.mapComponent.hasFeature(channelLayer, data.gbId)) {
|
this.$refs.mapComponent.addFeature(channelLayer, cameraData)
|
||||||
this.$refs.mapComponent.addFeature(channelLayer, cameraData)
|
|
||||||
}
|
|
||||||
this.infoBoxId = this.$refs.mapComponent.openInfoBox(position, this.$refs.infobox, [0, -50])
|
this.infoBoxId = this.$refs.mapComponent.openInfoBox(position, this.$refs.infobox, [0, -50])
|
||||||
},
|
},
|
||||||
zoomChange: function(zoom) {},
|
zoomChange: function(zoom) {},
|
||||||
@ -329,74 +299,37 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$refs.mapComponent.changeMapTile(index)
|
this.$refs.mapComponent.changeMapTile(index)
|
||||||
},
|
},
|
||||||
changeLayerStyle: function (index) {
|
clientEvent(data){
|
||||||
if (this.layerStyle === index) {
|
this.closeInfoBox()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (data[0].edit) {
|
||||||
|
this.showEditInfo(data[0])
|
||||||
|
}else {
|
||||||
|
this.showChannelInfo(data[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changeLayerType: function (index) {
|
||||||
|
if (this.layerType === index) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.layerStyle = index
|
this.layerType = index
|
||||||
this.$refs.mapComponent.removeLayer(channelLayer)
|
if (index === 0) {
|
||||||
this.channelLayer = null
|
this.$refs.mapComponent.removeLayer(channelTileLayer)
|
||||||
this.updateChannelLayer()
|
|
||||||
},
|
|
||||||
updateChannelLayer: function() {
|
|
||||||
let clientEvent = data => {
|
|
||||||
this.closeInfoBox()
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (data[0].edit) {
|
|
||||||
this.showEditInfo(data[0])
|
|
||||||
}else {
|
|
||||||
this.showChannelInfo(data[0])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this.layerStyle) {
|
let geoCoordSys = this.$refs.mapComponent.getCoordSys()
|
||||||
case 0:
|
const baseUrl = window.baseUrl ? window.baseUrl : ''
|
||||||
channelLayer = this.$refs.mapComponent.addPointLayer([], clientEvent, null)
|
let baseApi = ((process.env.NODE_ENV === 'development') ? process.env.VUE_APP_BASE_API : baseUrl)
|
||||||
|
let tileUrl = null
|
||||||
break
|
if (index === 1) {
|
||||||
case 1:
|
tileUrl = baseApi + `/api/common/channel/map/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&accessToken=${this.$store.getters.token}`
|
||||||
console.log(22221112222)
|
}else if (index === 2) {
|
||||||
console.log(channelLayer)
|
tileUrl = baseApi + `/api/common/channel/map/thin/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&accessToken=${this.$store.getters.token}`
|
||||||
// 直接展示
|
}else {
|
||||||
if (channelLayer) {
|
return
|
||||||
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
|
|
||||||
}else {
|
|
||||||
console.log(cameraList.length)
|
|
||||||
setTimeout(() => {
|
|
||||||
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, null)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 2:
|
|
||||||
// 碰撞检测
|
|
||||||
if (channelLayer) {
|
|
||||||
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
|
|
||||||
}else {
|
|
||||||
setTimeout(() => {
|
|
||||||
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, {
|
|
||||||
declutter: true
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 3:
|
|
||||||
// 抽稀图层
|
|
||||||
this.$refs.mapComponent.removeLayer(channelLayer)
|
|
||||||
channelLayer = this.$refs.mapComponent.addPointLayerGroup(cameraListForLevelMap, clientEvent)
|
|
||||||
break
|
|
||||||
// case 4:
|
|
||||||
// // 聚合图层
|
|
||||||
//
|
|
||||||
// break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getImageByChannel: function (channel) {
|
|
||||||
if (channel.gbStatus === 'ON') {
|
|
||||||
return 'static/images/gis/camera1.png'
|
|
||||||
} else {
|
|
||||||
return 'static/images/gis/camera1-offline.png'
|
|
||||||
}
|
}
|
||||||
|
channelTileLayer = this.$refs.mapComponent.addVectorTileLayer(tileUrl. this.clientEvent)
|
||||||
},
|
},
|
||||||
closeInfoBox: function () {
|
closeInfoBox: function () {
|
||||||
if (this.infoBoxId !== null) {
|
if (this.infoBoxId !== null) {
|
||||||
@ -423,6 +356,9 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
edit: function (channel) {
|
edit: function (channel) {
|
||||||
|
this.$refs.commonChannelEditDialog.openDialog(channel.gbId)
|
||||||
|
},
|
||||||
|
editPosition: function (channel) {
|
||||||
this.closeInfoBox()
|
this.closeInfoBox()
|
||||||
// 开启图标可拖动
|
// 开启图标可拖动
|
||||||
this.$refs.mapComponent.dragInteraction.addFeatureId(channel.gbId,
|
this.$refs.mapComponent.dragInteraction.addFeatureId(channel.gbId,
|
||||||
@ -459,6 +395,7 @@ export default {
|
|||||||
}else {
|
}else {
|
||||||
this.showEditInfo(channel)
|
this.showEditInfo(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记可编辑图标为红色
|
// 标记可编辑图标为红色
|
||||||
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
|
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
|
||||||
id: channel.gbId,
|
id: channel.gbId,
|
||||||
@ -466,6 +403,10 @@ export default {
|
|||||||
data: channel,
|
data: channel,
|
||||||
status: 'checked'
|
status: 'checked'
|
||||||
})
|
})
|
||||||
|
// 如果开启了瓦片图层,此时应该让瓦片图层不再显示这个feature
|
||||||
|
if (channelTileLayer) {
|
||||||
|
this.$refs.mapComponent.hideFeature(channelTileLayer, channel.gbId)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
showEditInfo: function(data) {
|
showEditInfo: function(data) {
|
||||||
this.dragChannel = data
|
this.dragChannel = data
|
||||||
@ -483,6 +424,9 @@ export default {
|
|||||||
data: channel,
|
data: channel,
|
||||||
status: channel.gbStatus
|
status: channel.gbStatus
|
||||||
})
|
})
|
||||||
|
if (channelTileLayer) {
|
||||||
|
this.$refs.mapComponent.cancelHideFeature(channelTileLayer, channel.gbId)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
submitEdit: function(channel) {
|
submitEdit: function(channel) {
|
||||||
let position = [channel.gbLongitude, channel.gbLatitude]
|
let position = [channel.gbLongitude, channel.gbLatitude]
|
||||||
@ -507,89 +451,65 @@ export default {
|
|||||||
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getTrace: function (data) {
|
|
||||||
this.clean()
|
|
||||||
this.$refs.queryTrace.openDialog(data, (channelPositions) => {
|
|
||||||
if (channelPositions.length === 0) {
|
|
||||||
this.$message.warning({
|
|
||||||
showClose: true,
|
|
||||||
message: '未查询到轨迹信息'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let positions = []
|
|
||||||
for (let i = 0; i < channelPositions.length; i++) {
|
|
||||||
if (channelPositions[i][this.longitudeStr] * channelPositions[i][this.latitudeStr] > 0) {
|
|
||||||
positions.push([channelPositions[i][this.longitudeStr], channelPositions[i][this.latitudeStr]])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (positions.length === 0) {
|
|
||||||
this.$message.warning({
|
|
||||||
showClose: true,
|
|
||||||
message: '未查询到轨迹信息'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
clean: function (){
|
|
||||||
if (this.infoBoxId !== null) {
|
|
||||||
this.$refs.mapComponent.closeInfoBox(this.infoBoxId)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
testArray: function (){
|
|
||||||
this.$store.dispatch('commonChanel/test')
|
|
||||||
},
|
|
||||||
showDrawThinBox: function(show){
|
showDrawThinBox: function(show){
|
||||||
this.showDrawThin = show
|
this.showDrawThin = show
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!show) {
|
if (!show) {
|
||||||
// 关闭抽稀预览
|
// 关闭抽稀预览
|
||||||
|
if (this.drawThinId !== null) {
|
||||||
|
// 发送消息 清空抽稀结果
|
||||||
|
this.$store.dispatch('commonChanel/clearThin', this.drawThinId)
|
||||||
|
this.drawThinId = null
|
||||||
|
}
|
||||||
if (this.drawThinLayer !== null) {
|
if (this.drawThinLayer !== null) {
|
||||||
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
||||||
this.drawThinLayer = null
|
this.drawThinLayer = null
|
||||||
}
|
}
|
||||||
// 清空预览数据
|
|
||||||
this.layerGroupSource = null
|
|
||||||
this.updateChannelLayer()
|
|
||||||
}else {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
}, 1)
|
}, 1)
|
||||||
},
|
},
|
||||||
quicklyDrawThin: function (){
|
quicklyDrawThin: function (){
|
||||||
if (this.channelLayer) {
|
if (channelLayer) {
|
||||||
this.$refs.mapComponent.removeLayer(channelLayer)
|
this.$refs.mapComponent.removeLayer(channelLayer)
|
||||||
}
|
}
|
||||||
|
if (channelTileLayer) {
|
||||||
|
this.$refs.mapComponent.removeLayer(channelTileLayer)
|
||||||
|
}
|
||||||
if (this.drawThinLayer !== null) {
|
if (this.drawThinLayer !== null) {
|
||||||
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
||||||
this.drawThinLayer = null
|
this.drawThinLayer = null
|
||||||
}
|
}
|
||||||
// 获取待抽稀数据
|
|
||||||
let cameraList = cameraListForSource.slice()
|
|
||||||
|
|
||||||
this.quicklyDrawThinLoading = true
|
this.quicklyDrawThinLoading = true
|
||||||
setTimeout(() => {
|
console.log(222)
|
||||||
this.drawThin(cameraList).then((layerGroupSource) => {
|
console.log(this.getDrawThinParam())
|
||||||
this.layerGroupSource = layerGroupSource
|
// 获取每一个图层的抽稀参数
|
||||||
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
|
this.$store.dispatch('commonChanel/drawThin', {
|
||||||
|
zoomParam: this.getDrawThinParam()
|
||||||
|
})
|
||||||
|
.then(drawThinId => {
|
||||||
|
// 显示抽稀进度
|
||||||
|
this.drawThinId = drawThinId
|
||||||
|
this.$refs.drawThinProgress.openDialog(drawThinId, () => {
|
||||||
this.closeInfoBox()
|
this.closeInfoBox()
|
||||||
// this.$nextTick(() => {
|
this.$message.success({
|
||||||
// if (data[0].edit) {
|
showClose: true,
|
||||||
// this.showEditInfo(data[0])
|
message: '抽稀完成,请预览无误后保存抽稀结果'
|
||||||
// }else {
|
})
|
||||||
// this.showChannelInfo(data[0])
|
// 展示抽稀结果
|
||||||
// }
|
this.showDrawThinLayer(drawThinId)
|
||||||
// })
|
|
||||||
})
|
|
||||||
this.quicklyDrawThinLoading = false
|
|
||||||
this.$message.success({
|
|
||||||
showClose: true,
|
|
||||||
message: '抽稀完成,请预览无误后保存抽稀结果'
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
.finally(() => {
|
||||||
|
this.quicklyDrawThinLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
showDrawThinLayer(thinId) {
|
||||||
|
// 展示抽稀结果
|
||||||
|
let geoCoordSys = this.$refs.mapComponent.getCoordSys()
|
||||||
|
const baseUrl = window.baseUrl ? window.baseUrl : ''
|
||||||
|
let baseApi = ((process.env.NODE_ENV === 'development') ? process.env.VUE_APP_BASE_API : baseUrl)
|
||||||
|
let tileUrl = baseApi + `/api/common/channel/map/thin/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&thinId=${thinId}&accessToken=${this.$store.getters.token}`
|
||||||
|
this.drawThinLayer = this.$refs.mapComponent.addVectorTileLayer(tileUrl, null)
|
||||||
},
|
},
|
||||||
boxDrawThin: function (){
|
boxDrawThin: function (){
|
||||||
this.$message.warning({
|
this.$message.warning({
|
||||||
@ -601,92 +521,54 @@ export default {
|
|||||||
|
|
||||||
// 清理默认的摄像头图层
|
// 清理默认的摄像头图层
|
||||||
if (channelLayer) {
|
if (channelLayer) {
|
||||||
this.$refs.mapComponent.clearLayer(channelLayer)
|
this.$refs.mapComponent.removeLayer(channelLayer)
|
||||||
}
|
}
|
||||||
this.$message.warning({
|
if (channelTileLayer) {
|
||||||
showClose: true,
|
this.$refs.mapComponent.removeLayer(channelTileLayer)
|
||||||
message: '正在抽稀,请稍等'
|
}
|
||||||
|
if (this.drawThinLayer !== null) {
|
||||||
|
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
||||||
|
this.drawThinLayer = null
|
||||||
|
}
|
||||||
|
this.boxDrawThinLoading = true
|
||||||
|
// 获取每一个图层的抽稀参数
|
||||||
|
this.$store.dispatch('commonChanel/drawThin', {
|
||||||
|
zoomParam: this.getDrawThinParam(),
|
||||||
|
extent: extent
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
.then(drawThinId => {
|
||||||
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
|
// 显示抽稀进度
|
||||||
let cameraListInExtent = []
|
this.drawThinId = drawThinId
|
||||||
let cameraListOutExtent = []
|
this.$refs.drawThinProgress.openDialog(drawThinId, () => {
|
||||||
if (this.layerGroupSource !== null) {
|
|
||||||
// 从当前预览的数据里,获取待抽稀的数据
|
|
||||||
let sourceCameraList = this.layerGroupSource.get(0)
|
|
||||||
console.log(sourceCameraList)
|
|
||||||
if (!sourceCameraList) {
|
|
||||||
this.$message.warning({
|
|
||||||
showClose: true,
|
|
||||||
message: '数据已经全部抽稀'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for (let i = 0; i < sourceCameraList.length; i++) {
|
|
||||||
let value = sourceCameraList[i]
|
|
||||||
if (!value.data.gbLongitude || !value.data.gbLatitude) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (value.data.gbLongitude >= extent[0] && value.data.gbLongitude <= extent[2]
|
|
||||||
&& value.data.gbLatitude >= extent[1] && value.data.gbLatitude <= extent[3]) {
|
|
||||||
cameraListInExtent.push(value.data)
|
|
||||||
}else {
|
|
||||||
cameraListOutExtent.push(value.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
for (let i = 0; i < cameraListForSource.length; i++) {
|
|
||||||
let value = cameraListForSource[i]
|
|
||||||
if (!value.gbLongitude || !value.gbLatitude) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (value.gbLongitude >= extent[0] && value.gbLongitude <= extent[2]
|
|
||||||
&& value.gbLatitude >= extent[1] && value.gbLatitude <= extent[3]) {
|
|
||||||
cameraListInExtent.push(value)
|
|
||||||
}else {
|
|
||||||
cameraListOutExtent.push(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果已经在预览,清理预览图层
|
|
||||||
if (this.drawThinLayer !== null) {
|
|
||||||
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
|
||||||
this.drawThinLayer = null
|
|
||||||
}
|
|
||||||
this.drawThin(cameraListInExtent).then((layerGroupSource) => {
|
|
||||||
if (this.layerGroupSource !== null) {
|
|
||||||
let zoom = zoomExtent[0]
|
|
||||||
// 按照层级合并每次的抽稀结果
|
|
||||||
while (zoom < zoomExtent[1]) {
|
|
||||||
Array.prototype.push.apply(layerGroupSource.get(zoom), this.layerGroupSource.get(zoom))
|
|
||||||
zoom += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cameraListOutExtent.length > 0) {
|
|
||||||
let layerSourceForOutExtent = this.createZoomLayerSource(cameraListOutExtent, zoomExtent[0])
|
|
||||||
layerGroupSource.set(0, layerSourceForOutExtent)
|
|
||||||
}
|
|
||||||
this.layerGroupSource = layerGroupSource
|
|
||||||
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
|
|
||||||
this.closeInfoBox()
|
this.closeInfoBox()
|
||||||
// this.$nextTick(() => {
|
this.$message.success({
|
||||||
// if (data[0].edit) {
|
showClose: true,
|
||||||
// this.showEditInfo(data[0])
|
message: '抽稀完成,请预览无误后保存抽稀结果'
|
||||||
// }else {
|
})
|
||||||
// this.showChannelInfo(data[0])
|
// 展示抽稀结果
|
||||||
// }
|
this.showDrawThinLayer(drawThinId)
|
||||||
// })
|
|
||||||
})
|
|
||||||
this.$message.success({
|
|
||||||
showClose: true,
|
|
||||||
message: '抽稀完成,请预览无误后保存抽稀结果,如需继续,请再次点击局部抽稀按钮'
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, 100)
|
.finally(() => {
|
||||||
|
this.boxDrawThinLoading = false
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
getDrawThinParam() {
|
||||||
|
// 获取全部层级
|
||||||
|
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
|
||||||
|
let zoomMap = {}
|
||||||
|
let zoom = zoomExtent[0]
|
||||||
|
while (zoom < zoomExtent[1]) {
|
||||||
|
// 计算经纬度差值
|
||||||
|
let diff = this.$refs.mapComponent.computeDiff(this.diffPixels, zoom)
|
||||||
|
if (diff && diff > 0) {
|
||||||
|
zoomMap[zoom] = diff
|
||||||
|
}
|
||||||
|
zoom += 1
|
||||||
|
}
|
||||||
|
return zoomMap
|
||||||
|
},
|
||||||
drawThin: function (cameraListInExtent){
|
drawThin: function (cameraListInExtent){
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
@ -778,30 +660,10 @@ export default {
|
|||||||
return dataArray
|
return dataArray
|
||||||
},
|
},
|
||||||
saveDrawThin: function(){
|
saveDrawThin: function(){
|
||||||
if (!this.layerGroupSource) {
|
if (!this.drawThinId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.saveDrawThinLoading = true
|
this.$store.dispatch('commonChanel/saveThin', this.drawThinId)
|
||||||
let param = []
|
|
||||||
let keys = Array.from(this.layerGroupSource.keys())
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
|
||||||
let zoom = keys[i]
|
|
||||||
let values = this.layerGroupSource.get(zoom)
|
|
||||||
for (let j = 0; j < values.length; j++) {
|
|
||||||
let value = values[j]
|
|
||||||
if (zoom === 0) {
|
|
||||||
param.push({
|
|
||||||
gbId: value.id
|
|
||||||
})
|
|
||||||
}else {
|
|
||||||
param.push({
|
|
||||||
gbId: value.id,
|
|
||||||
mapLevel: zoom
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.$store.dispatch('commonChanel/saveLevel', param)
|
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.$message.success({
|
this.$message.success({
|
||||||
showClose: true,
|
showClose: true,
|
||||||
@ -812,7 +674,6 @@ export default {
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.saveDrawThinLoading = false
|
this.saveDrawThinLoading = false
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
resetDrawThinData(){
|
resetDrawThinData(){
|
||||||
this.$confirm('确定移除抽稀结果?', '操作提示', {
|
this.$confirm('确定移除抽稀结果?', '操作提示', {
|
||||||
|
|||||||
989
web/src/views/map/index2.vue
Executable file
989
web/src/views/map/index2.vue
Executable file
@ -0,0 +1,989 @@
|
|||||||
|
<template>
|
||||||
|
<div id="devicePosition" style="height: calc(100vh - 84px);width: 100%;">
|
||||||
|
<div style="height: 100%; display: grid; grid-template-columns: 360px auto">
|
||||||
|
<DeviceTree ref="deviceTree" @clickEvent="treeChannelClickEvent" :showPosition="true" :contextmenu="getContextmenu()"/>
|
||||||
|
<MapComponent ref="mapComponent" @loaded="initChannelLayer" @coordinateSystemChange="initChannelLayer" @zoomChange="zoomChange"></MapComponent>
|
||||||
|
</div>
|
||||||
|
<div class="map-tool-box-bottom-right">
|
||||||
|
<div class="map-tool-btn-group">
|
||||||
|
<div class="el-dropdown-link map-tool-btn" @click="addVectorTileLayer">
|
||||||
|
<i class="iconfont icon-mti-jutai"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="map-tool-btn-group" v-if="mapTileList.length > 0">
|
||||||
|
<el-dropdown placement="top" @command="changeLayerStyle">
|
||||||
|
<div class="el-dropdown-link map-tool-btn">
|
||||||
|
<i class="iconfont icon-mti-jutai"></i>
|
||||||
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item :command="0" >
|
||||||
|
<span v-if="layerStyle !== 0">图层关闭</span>
|
||||||
|
<span v-if="layerStyle === 0" style="color: rgb(64, 158, 255);">图层关闭</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item :command="1" >
|
||||||
|
<span v-if="layerStyle !== 1">直接展示</span>
|
||||||
|
<span v-if="layerStyle === 1" style="color: rgb(64, 158, 255);">直接展示</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item :command="2">
|
||||||
|
<span v-if="layerStyle !== 2">碰撞检测</span>
|
||||||
|
<span v-if="layerStyle === 2" style="color: rgb(64, 158, 255);">碰撞检测</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item :command="3">
|
||||||
|
<span v-if="layerStyle !== 3">抽稀图层</span>
|
||||||
|
<span v-if="layerStyle === 3" style="color: rgb(64, 158, 255);">抽稀图层</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<!-- <el-dropdown-item :command="4">-->
|
||||||
|
<!-- <span v-if="layerStyle !== 4">聚合图层</span>-->
|
||||||
|
<!-- <span v-if="layerStyle === 4" style="color: rgb(64, 158, 255);">聚合图层</span>-->
|
||||||
|
<!-- </el-dropdown-item>-->
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="map-tool-btn-group" v-if="mapTileList && mapTileList.length > 1">
|
||||||
|
<el-dropdown placement="top" @command="changeMapTile">
|
||||||
|
<div class="el-dropdown-link map-tool-btn">
|
||||||
|
<i class="iconfont icon-tuceng"></i>
|
||||||
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item v-for="(item,index) in mapTileList" :key="index" :command="index">{{item.name}}</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="map-tool-btn-group">
|
||||||
|
<div class="map-tool-btn" @click="refreshLayer">
|
||||||
|
<i class="iconfont icon-shuaxin3"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="map-tool-btn-group">
|
||||||
|
<div class="map-tool-btn" @click="zoomIn">
|
||||||
|
<i class="iconfont icon-plus1"></i>
|
||||||
|
</div>
|
||||||
|
<div class="map-tool-btn" @click="zoomOut">
|
||||||
|
<i class="iconfont icon-minus1"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="map-tool-box-top-left">
|
||||||
|
<div class="map-tool-btn-group">
|
||||||
|
<div class="map-tool-btn" title="图层抽稀" @click="showDrawThinBox(true)">
|
||||||
|
<i class="iconfont icon-mti-sandian"></i> <span>图层抽稀</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<transition name="el-zoom-in-top">
|
||||||
|
<div v-show="showDrawThin" class="map-tool-draw-thin">
|
||||||
|
<div class="map-tool-draw-thin-density">
|
||||||
|
<span style="line-height: 36px; font-size: 15px">间隔: </span>
|
||||||
|
<el-slider v-model="diffPixels" show-input :min="10" :max="200" input-size="mini" ></el-slider>
|
||||||
|
<div style="margin-left: 10px; line-height: 38px;">
|
||||||
|
<el-button :loading="quicklyDrawThinLoading" @click="quicklyDrawThin" size="mini">快速抽稀</el-button>
|
||||||
|
<el-button size="mini" @click="boxDrawThin" >局部抽稀</el-button>
|
||||||
|
<el-button size="mini" @click="resetDrawThinData()">数据还原</el-button>
|
||||||
|
<el-button :loading="saveDrawThinLoading" type="primary" :disabled="!layerGroupSource" size="mini" @click="saveDrawThin()">保存</el-button>
|
||||||
|
<el-button type="warning" size="mini" @click="showDrawThinBox(false)">取消</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<!-- <div class="map-tool-box-top-right">-->
|
||||||
|
<!-- <div class="map-tool-btn-group">-->
|
||||||
|
<!-- <div class="map-tool-btn" title="抽稀">-->
|
||||||
|
<!-- <i class="iconfont icon-mti-sandian"></i>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="map-tool-btn" title="聚合">-->
|
||||||
|
<!-- <i class="iconfont icon-mti-jutai"></i>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<div ref="infobox">
|
||||||
|
<transition name="el-zoom-in-center">
|
||||||
|
<div class="infobox-content" v-if="channel">
|
||||||
|
<el-descriptions class="margin-top" :title="channel.gbName" :column="1" :colon="true" size="mini" :labelStyle="labelStyle" >
|
||||||
|
<el-descriptions-item label="编号" >{{channel.gbDeviceId}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="生产厂商">{{channel.gbManufacture}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="安装地址" >{{channel.gbAddress == null?'未知': channel.gbAddress}}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<div style="padding-top: 10px; margin: 0 auto; width: fit-content;">
|
||||||
|
<el-button v-bind:disabled="channel.gbStatus !== 'ON'" type="primary" size="small" title="播放" icon="el-icon-video-play" @click="play(channel)">播放</el-button>
|
||||||
|
<el-button type="primary" size="small" title="编辑" icon="el-icon-edit" @click="edit(channel)">编辑</el-button>
|
||||||
|
<el-button type="primary" size="small" title="位置" icon="el-icon-coordinate" @click="editPosition(channel)">位置</el-button>
|
||||||
|
<!-- <el-button type="primary" size="small" title="轨迹查询" icon="el-icon-map-location" @click="getTrace(channel)">轨迹</el-button>-->
|
||||||
|
</div>
|
||||||
|
<span class="infobox-close el-icon-close" @click="closeInfoBox"></span>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ref="infoboxForEdit">
|
||||||
|
<transition name="el-zoom-in-center">
|
||||||
|
<div class="infobox-edit-content" v-if="dragChannel">
|
||||||
|
<div style="width: 100%; line-height: 1.5rem; font-size: 14px">{{dragChannel.gbName}} ({{dragChannel.gbDeviceId}})</div>
|
||||||
|
<span style="font-size: 14px">经度:</span> <el-input v-model="dragChannel.gbLongitude" placeholder="请输入经度" style="width: 7rem; margin-right: 10px"></el-input>
|
||||||
|
<span style="font-size: 14px">纬度: </span> <el-input v-model="dragChannel.gbLatitude" placeholder="请输入纬度" style="width: 7rem; "></el-input>
|
||||||
|
<el-button icon="el-icon-close" size="medium" type="text" @click="cancelEdit(dragChannel)" style="margin-left: 1rem; font-size: 18px; color: #2b2f3a"></el-button>
|
||||||
|
<el-button icon="el-icon-check" size="medium" type="text" @click="submitEdit(dragChannel)" style="font-size: 18px; color: #0842e2"></el-button>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
<devicePlayer ref="devicePlayer" ></devicePlayer>
|
||||||
|
<queryTrace ref="queryTrace" ></queryTrace>
|
||||||
|
<CommonChannelEditDialog ref="commonChannelEditDialog" ></CommonChannelEditDialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DeviceTree from '../common/DeviceTree.vue'
|
||||||
|
import queryTrace from './queryTrace.vue'
|
||||||
|
import MapComponent from '../common/MapComponent.vue'
|
||||||
|
import devicePlayer from '../common/channelPlayer/index.vue'
|
||||||
|
import CommonChannelEditDialog from "@/views/dialog/commonChannelEditDialog.vue";
|
||||||
|
|
||||||
|
let cameraListForSource = []
|
||||||
|
let cameraList = []
|
||||||
|
let cameraListForLevelMap = new Map()
|
||||||
|
let cameraLayerExtent = []
|
||||||
|
let channelLayer = null
|
||||||
|
export default {
|
||||||
|
name: 'Map',
|
||||||
|
components: {
|
||||||
|
CommonChannelEditDialog,
|
||||||
|
DeviceTree,
|
||||||
|
devicePlayer,
|
||||||
|
queryTrace,
|
||||||
|
MapComponent
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
layer: null,
|
||||||
|
channel: null,
|
||||||
|
dragChannel: {},
|
||||||
|
feature: null,
|
||||||
|
device: null,
|
||||||
|
infoBoxId: null,
|
||||||
|
labelStyle: {
|
||||||
|
width: '56px'
|
||||||
|
},
|
||||||
|
isLoging: false,
|
||||||
|
longitudeStr: 'longitude',
|
||||||
|
latitudeStr: 'latitude',
|
||||||
|
mapTileList: [],
|
||||||
|
diffPixels: 60,
|
||||||
|
zoomValue: 10,
|
||||||
|
showDrawThin: false,
|
||||||
|
quicklyDrawThinLoading: false,
|
||||||
|
saveDrawThinLoading: false,
|
||||||
|
layerStyle: 0,
|
||||||
|
drawThinLayer: null,
|
||||||
|
layerGroupSource: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initChannelLayer: function () {
|
||||||
|
|
||||||
|
this.mapTileList = this.$refs.mapComponent.mapTileList
|
||||||
|
// 获取所有有位置的通道
|
||||||
|
this.closeInfoBox()
|
||||||
|
this.$store.dispatch('commonChanel/getAllForMap', {}).then(data => {
|
||||||
|
cameraListForSource = data
|
||||||
|
console.log(data.length)
|
||||||
|
let minLng = data[0].gbLongitude
|
||||||
|
let maxLng = data[0].gbLongitude
|
||||||
|
let minLat = data[0].gbLatitude
|
||||||
|
let maxLat = data[0].gbLatitude
|
||||||
|
for (let i = 1; i < data.length; i++) {
|
||||||
|
let item = data[i]
|
||||||
|
if (item.gbLongitude < minLng) {
|
||||||
|
minLng = item.gbLongitude
|
||||||
|
}
|
||||||
|
if (item.gbLongitude > maxLng) {
|
||||||
|
maxLng = item.gbLongitude
|
||||||
|
}
|
||||||
|
if (item.gbLatitude < minLat) {
|
||||||
|
minLat = item.gbLatitude
|
||||||
|
}
|
||||||
|
if (item.gbLatitude > maxLat) {
|
||||||
|
maxLat = item.gbLatitude
|
||||||
|
}
|
||||||
|
if (item.gbLongitude && item.gbLatitude) {
|
||||||
|
let position = [item.gbLongitude, item.gbLatitude]
|
||||||
|
let cameraData = {
|
||||||
|
id: item.gbId,
|
||||||
|
position: position,
|
||||||
|
status: item.gbStatus,
|
||||||
|
data: item,
|
||||||
|
image: {
|
||||||
|
anchor: [0.5, 1],
|
||||||
|
src: this.getImageByChannel(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cameraList.push(cameraData)
|
||||||
|
if (item.mapLevel) {
|
||||||
|
if (cameraListForLevelMap.has(item.mapLevel)) {
|
||||||
|
let list = cameraListForLevelMap.get(item.mapLevel)
|
||||||
|
list.push(cameraData)
|
||||||
|
}else {
|
||||||
|
cameraListForLevelMap.set(item.mapLevel, [cameraData])
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
cameraListForLevelMap.set(0, [cameraData])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cameraLayerExtent = [minLng, minLat, maxLng, maxLat]
|
||||||
|
this.updateChannelLayer()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshLayer(){
|
||||||
|
this.closeInfoBox()
|
||||||
|
this.$refs.mapComponent.clearLayer(channelLayer)
|
||||||
|
this.initChannelLayer()
|
||||||
|
},
|
||||||
|
treeChannelClickEvent: function (id) {
|
||||||
|
this.closeInfoBox()
|
||||||
|
this.$store.dispatch('commonChanel/queryOne', id)
|
||||||
|
.then(data => {
|
||||||
|
if (!data.gbLongitude || data.gbLongitude < 0 || !data.gbLatitude || data.gbLatitude < 0) {
|
||||||
|
this.$message.warning({
|
||||||
|
showClose: true,
|
||||||
|
message: '无位置信息'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
|
||||||
|
this.$refs.mapComponent.panTo([data.gbLongitude, data.gbLatitude], zoomExtent[1], () => {
|
||||||
|
this.showChannelInfo(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
zoomIn: function() {
|
||||||
|
this.$refs.mapComponent.zoomIn()
|
||||||
|
},
|
||||||
|
zoomOut: function() {
|
||||||
|
this.$refs.mapComponent.zoomOut()
|
||||||
|
},
|
||||||
|
getContextmenu: function (event) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '播放通道',
|
||||||
|
icon: 'el-icon-video-play',
|
||||||
|
type: 1,
|
||||||
|
onClick: (event, data, node) => {
|
||||||
|
console.log(data)
|
||||||
|
this.$store.dispatch('commonChanel/queryOne', data.id)
|
||||||
|
.then(data => {
|
||||||
|
this.play(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '编辑位置',
|
||||||
|
icon: 'el-icon-edit',
|
||||||
|
type: 1,
|
||||||
|
onClick: (event, data, node) => {
|
||||||
|
this.$store.dispatch('commonChanel/queryOne', data.id)
|
||||||
|
.then(data => {
|
||||||
|
this.edit(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ,
|
||||||
|
// {
|
||||||
|
// label: '轨迹查询',
|
||||||
|
// icon: 'el-icon-map-location',
|
||||||
|
// type: 1,
|
||||||
|
// onClick: (event, data, node) => {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
showChannelInfo: function(data) {
|
||||||
|
this.channel = data
|
||||||
|
// 此时增加临时图标
|
||||||
|
let position = [data.gbLongitude, data.gbLatitude]
|
||||||
|
let cameraData = {
|
||||||
|
id: data.gbId,
|
||||||
|
position: position,
|
||||||
|
data: data,
|
||||||
|
status: data.gbStatus
|
||||||
|
}
|
||||||
|
if (!this.$refs.mapComponent.hasFeature(channelLayer, data.gbId)) {
|
||||||
|
this.$refs.mapComponent.addFeature(channelLayer, cameraData)
|
||||||
|
}
|
||||||
|
this.infoBoxId = this.$refs.mapComponent.openInfoBox(position, this.$refs.infobox, [0, -50])
|
||||||
|
},
|
||||||
|
zoomChange: function(zoom) {},
|
||||||
|
|
||||||
|
changeMapTile: function (index) {
|
||||||
|
if (this.showDrawThin) {
|
||||||
|
this.$message.warning({
|
||||||
|
showClose: true,
|
||||||
|
message: '抽稀操作进行中,禁止切换图层'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$refs.mapComponent.changeMapTile(index)
|
||||||
|
},
|
||||||
|
changeLayerStyle: function (index) {
|
||||||
|
if (this.layerStyle === index) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.layerStyle = index
|
||||||
|
this.$refs.mapComponent.removeLayer(channelLayer)
|
||||||
|
this.channelLayer = null
|
||||||
|
this.updateChannelLayer()
|
||||||
|
},
|
||||||
|
updateChannelLayer: function() {
|
||||||
|
let clientEvent = data => {
|
||||||
|
this.closeInfoBox()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (data[0].edit) {
|
||||||
|
this.showEditInfo(data[0])
|
||||||
|
}else {
|
||||||
|
this.showChannelInfo(data[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.layerStyle) {
|
||||||
|
case 0:
|
||||||
|
channelLayer = this.$refs.mapComponent.addPointLayer([], clientEvent, null)
|
||||||
|
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
console.log(22221112222)
|
||||||
|
console.log(channelLayer)
|
||||||
|
// 直接展示
|
||||||
|
if (channelLayer) {
|
||||||
|
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
|
||||||
|
}else {
|
||||||
|
console.log(cameraList.length)
|
||||||
|
setTimeout(() => {
|
||||||
|
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, null)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
// 碰撞检测
|
||||||
|
if (channelLayer) {
|
||||||
|
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
|
||||||
|
}else {
|
||||||
|
setTimeout(() => {
|
||||||
|
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, {
|
||||||
|
declutter: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
// 抽稀图层
|
||||||
|
this.$refs.mapComponent.removeLayer(channelLayer)
|
||||||
|
channelLayer = this.$refs.mapComponent.addPointLayerGroup(cameraListForLevelMap, clientEvent)
|
||||||
|
break
|
||||||
|
// case 4:
|
||||||
|
// // 聚合图层
|
||||||
|
//
|
||||||
|
// break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getImageByChannel: function (channel) {
|
||||||
|
if (channel.gbStatus === 'ON') {
|
||||||
|
return 'static/images/gis/camera1.png'
|
||||||
|
} else {
|
||||||
|
return 'static/images/gis/camera1-offline.png'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeInfoBox: function () {
|
||||||
|
if (this.infoBoxId !== null) {
|
||||||
|
this.$refs.mapComponent.closeInfoBox(this.infoBoxId)
|
||||||
|
}
|
||||||
|
this.channel = null
|
||||||
|
this.dragChannel = null
|
||||||
|
},
|
||||||
|
play: function (channel) {
|
||||||
|
const loading = this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '正在请求视频',
|
||||||
|
spinner: 'el-icon-loading',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
})
|
||||||
|
this.$store.dispatch('commonChanel/playChannel', channel.gbId)
|
||||||
|
.then((data) => {
|
||||||
|
this.$refs.devicePlayer.openDialog('media', channel.gbId, {
|
||||||
|
streamInfo: data,
|
||||||
|
hasAudio: channel.hasAudio
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
loading.close()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
edit: function (channel) {
|
||||||
|
this.$refs.commonChannelEditDialog.openDialog(channel.gbId)
|
||||||
|
},
|
||||||
|
editPosition: function (channel) {
|
||||||
|
this.closeInfoBox()
|
||||||
|
// 开启图标可拖动
|
||||||
|
this.$refs.mapComponent.dragInteraction.addFeatureId(channel.gbId,
|
||||||
|
{
|
||||||
|
startEvent: event => {
|
||||||
|
this.closeInfoBox()
|
||||||
|
},
|
||||||
|
endEvent: event => {
|
||||||
|
channel.gbLongitude = event.lonLat[0]
|
||||||
|
channel.gbLatitude = event.lonLat[1]
|
||||||
|
this.showEditInfo(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let position = null
|
||||||
|
if (!!channel.gbLongitude && !!channel.gbLatitude && channel.gbLongitude > 0 && channel.gbLatitude > 0) {
|
||||||
|
position = [channel.gbLongitude, channel.gbLatitude]
|
||||||
|
channel['oldLongitude'] = channel.gbLongitude
|
||||||
|
channel['oldLatitude'] = channel.gbLatitude
|
||||||
|
}else {
|
||||||
|
position = this.$refs.mapComponent.getCenter()
|
||||||
|
channel['oldLongitude'] = channel.gbLongitude
|
||||||
|
channel['oldLatitude'] = channel.gbLatitude
|
||||||
|
channel.gbLongitude = position[0]
|
||||||
|
channel.gbLatitude = position[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
channel['edit'] = true
|
||||||
|
if (!this.$refs.mapComponent.coordinateInView(position)) {
|
||||||
|
this.$refs.mapComponent.panTo(position, 16, () => {
|
||||||
|
this.showEditInfo(channel)
|
||||||
|
})
|
||||||
|
}else {
|
||||||
|
this.showEditInfo(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记可编辑图标为红色
|
||||||
|
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
|
||||||
|
id: channel.gbId,
|
||||||
|
position: position,
|
||||||
|
data: channel,
|
||||||
|
status: 'checked'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
showEditInfo: function(data) {
|
||||||
|
this.dragChannel = data
|
||||||
|
this.infoBoxId = this.$refs.mapComponent.openInfoBox([data.gbLongitude, data.gbLatitude], this.$refs.infoboxForEdit, [0, -50])
|
||||||
|
},
|
||||||
|
cancelEdit: function(channel) {
|
||||||
|
this.closeInfoBox()
|
||||||
|
this.$refs.mapComponent.dragInteraction.removeFeatureId(channel.gbId)
|
||||||
|
channel.gbLongitude = channel.oldLongitude
|
||||||
|
channel.gbLatitude = channel.oldLatitude
|
||||||
|
channel['edit'] = false
|
||||||
|
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
|
||||||
|
id: channel.gbId,
|
||||||
|
position: [channel.gbLongitude, channel.gbLatitude],
|
||||||
|
data: channel,
|
||||||
|
status: channel.gbStatus
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitEdit: function(channel) {
|
||||||
|
let position = [channel.gbLongitude, channel.gbLatitude]
|
||||||
|
this.$store.dispatch('commonChanel/update', channel)
|
||||||
|
.then(data => {
|
||||||
|
this.$message.success({
|
||||||
|
showClose: true,
|
||||||
|
message: '保存成功'
|
||||||
|
})
|
||||||
|
this.closeInfoBox()
|
||||||
|
channel['edit'] = false
|
||||||
|
this.$refs.mapComponent.dragInteraction.removeFeatureId(channel.gbId)
|
||||||
|
|
||||||
|
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
|
||||||
|
id: channel.gbId,
|
||||||
|
position: position,
|
||||||
|
data: channel,
|
||||||
|
status: channel.gbStatus
|
||||||
|
})
|
||||||
|
// 刷星树菜单
|
||||||
|
this.$refs.deviceTree.refresh('channel' + channel.gbId)
|
||||||
|
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getTrace: function (data) {
|
||||||
|
this.clean()
|
||||||
|
this.$refs.queryTrace.openDialog(data, (channelPositions) => {
|
||||||
|
if (channelPositions.length === 0) {
|
||||||
|
this.$message.warning({
|
||||||
|
showClose: true,
|
||||||
|
message: '未查询到轨迹信息'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let positions = []
|
||||||
|
for (let i = 0; i < channelPositions.length; i++) {
|
||||||
|
if (channelPositions[i][this.longitudeStr] * channelPositions[i][this.latitudeStr] > 0) {
|
||||||
|
positions.push([channelPositions[i][this.longitudeStr], channelPositions[i][this.latitudeStr]])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (positions.length === 0) {
|
||||||
|
this.$message.warning({
|
||||||
|
showClose: true,
|
||||||
|
message: '未查询到轨迹信息'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
clean: function (){
|
||||||
|
if (this.infoBoxId !== null) {
|
||||||
|
this.$refs.mapComponent.closeInfoBox(this.infoBoxId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
testArray: function (){
|
||||||
|
this.$store.dispatch('commonChanel/test')
|
||||||
|
},
|
||||||
|
showDrawThinBox: function(show){
|
||||||
|
this.showDrawThin = show
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!show) {
|
||||||
|
// 关闭抽稀预览
|
||||||
|
if (this.drawThinLayer !== null) {
|
||||||
|
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
||||||
|
this.drawThinLayer = null
|
||||||
|
}
|
||||||
|
// 清空预览数据
|
||||||
|
this.layerGroupSource = null
|
||||||
|
this.updateChannelLayer()
|
||||||
|
}else {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}, 1)
|
||||||
|
},
|
||||||
|
quicklyDrawThin: function (){
|
||||||
|
if (this.channelLayer) {
|
||||||
|
this.$refs.mapComponent.removeLayer(channelLayer)
|
||||||
|
}
|
||||||
|
if (this.drawThinLayer !== null) {
|
||||||
|
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
||||||
|
this.drawThinLayer = null
|
||||||
|
}
|
||||||
|
// 获取待抽稀数据
|
||||||
|
let cameraList = cameraListForSource.slice()
|
||||||
|
|
||||||
|
this.quicklyDrawThinLoading = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.drawThin(cameraList).then((layerGroupSource) => {
|
||||||
|
this.layerGroupSource = layerGroupSource
|
||||||
|
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
|
||||||
|
this.closeInfoBox()
|
||||||
|
// this.$nextTick(() => {
|
||||||
|
// if (data[0].edit) {
|
||||||
|
// this.showEditInfo(data[0])
|
||||||
|
// }else {
|
||||||
|
// this.showChannelInfo(data[0])
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
this.quicklyDrawThinLoading = false
|
||||||
|
this.$message.success({
|
||||||
|
showClose: true,
|
||||||
|
message: '抽稀完成,请预览无误后保存抽稀结果'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
boxDrawThin: function (){
|
||||||
|
this.$message.warning({
|
||||||
|
showClose: true,
|
||||||
|
message: '点击地图进行框选'
|
||||||
|
})
|
||||||
|
// 绘制框
|
||||||
|
this.$refs.mapComponent.startDrawBox((extent) => {
|
||||||
|
|
||||||
|
// 清理默认的摄像头图层
|
||||||
|
if (channelLayer) {
|
||||||
|
this.$refs.mapComponent.clearLayer(channelLayer)
|
||||||
|
}
|
||||||
|
this.$message.warning({
|
||||||
|
showClose: true,
|
||||||
|
message: '正在抽稀,请稍等'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
|
||||||
|
let cameraListInExtent = []
|
||||||
|
let cameraListOutExtent = []
|
||||||
|
if (this.layerGroupSource !== null) {
|
||||||
|
// 从当前预览的数据里,获取待抽稀的数据
|
||||||
|
let sourceCameraList = this.layerGroupSource.get(0)
|
||||||
|
console.log(sourceCameraList)
|
||||||
|
if (!sourceCameraList) {
|
||||||
|
this.$message.warning({
|
||||||
|
showClose: true,
|
||||||
|
message: '数据已经全部抽稀'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (let i = 0; i < sourceCameraList.length; i++) {
|
||||||
|
let value = sourceCameraList[i]
|
||||||
|
if (!value.data.gbLongitude || !value.data.gbLatitude) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (value.data.gbLongitude >= extent[0] && value.data.gbLongitude <= extent[2]
|
||||||
|
&& value.data.gbLatitude >= extent[1] && value.data.gbLatitude <= extent[3]) {
|
||||||
|
cameraListInExtent.push(value.data)
|
||||||
|
}else {
|
||||||
|
cameraListOutExtent.push(value.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
for (let i = 0; i < cameraListForSource.length; i++) {
|
||||||
|
let value = cameraListForSource[i]
|
||||||
|
if (!value.gbLongitude || !value.gbLatitude) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (value.gbLongitude >= extent[0] && value.gbLongitude <= extent[2]
|
||||||
|
&& value.gbLatitude >= extent[1] && value.gbLatitude <= extent[3]) {
|
||||||
|
cameraListInExtent.push(value)
|
||||||
|
}else {
|
||||||
|
cameraListOutExtent.push(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果已经在预览,清理预览图层
|
||||||
|
if (this.drawThinLayer !== null) {
|
||||||
|
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
|
||||||
|
this.drawThinLayer = null
|
||||||
|
}
|
||||||
|
this.drawThin(cameraListInExtent).then((layerGroupSource) => {
|
||||||
|
if (this.layerGroupSource !== null) {
|
||||||
|
let zoom = zoomExtent[0]
|
||||||
|
// 按照层级合并每次的抽稀结果
|
||||||
|
while (zoom < zoomExtent[1]) {
|
||||||
|
Array.prototype.push.apply(layerGroupSource.get(zoom), this.layerGroupSource.get(zoom))
|
||||||
|
zoom += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cameraListOutExtent.length > 0) {
|
||||||
|
let layerSourceForOutExtent = this.createZoomLayerSource(cameraListOutExtent, zoomExtent[0])
|
||||||
|
layerGroupSource.set(0, layerSourceForOutExtent)
|
||||||
|
}
|
||||||
|
this.layerGroupSource = layerGroupSource
|
||||||
|
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
|
||||||
|
this.closeInfoBox()
|
||||||
|
// this.$nextTick(() => {
|
||||||
|
// if (data[0].edit) {
|
||||||
|
// this.showEditInfo(data[0])
|
||||||
|
// }else {
|
||||||
|
// this.showChannelInfo(data[0])
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
this.$message.success({
|
||||||
|
showClose: true,
|
||||||
|
message: '抽稀完成,请预览无误后保存抽稀结果,如需继续,请再次点击局部抽稀按钮'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
},
|
||||||
|
drawThin: function (cameraListInExtent){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
let layerGroupSource = new Map()
|
||||||
|
// 获取全部层级
|
||||||
|
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
|
||||||
|
let zoom = zoomExtent[0]
|
||||||
|
let zoomCameraMap = new Map()
|
||||||
|
let useCameraMap = new Map()
|
||||||
|
|
||||||
|
while (zoom < zoomExtent[1]) {
|
||||||
|
// 计算经纬度差值
|
||||||
|
let diff = this.$refs.mapComponent.computeDiff(this.diffPixels, zoom)
|
||||||
|
let cameraMapForZoom = new Map()
|
||||||
|
let useCameraMapForZoom = new Map()
|
||||||
|
let useCameraList = Array.from(useCameraMap.values())
|
||||||
|
for (let i = 0; i < useCameraList.length; i++) {
|
||||||
|
let value = useCameraList[i]
|
||||||
|
let lngGrid = Math.trunc(value.gbLongitude / diff)
|
||||||
|
let latGrid = Math.trunc(value.gbLatitude / diff)
|
||||||
|
let gridKey = latGrid + ':' + lngGrid
|
||||||
|
useCameraMapForZoom.set(gridKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < cameraListInExtent.length; i++) {
|
||||||
|
let value = cameraListInExtent[i]
|
||||||
|
if (useCameraMap.has(value.gbId) || !value.gbLongitude || !value.gbLatitude) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let lngGrid = Math.trunc(value.gbLongitude / diff)
|
||||||
|
let latGrid = Math.trunc(value.gbLatitude / diff)
|
||||||
|
let gridKey = latGrid + ':' + lngGrid
|
||||||
|
if (useCameraMapForZoom.has(gridKey)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (cameraMapForZoom.has(gridKey)) {
|
||||||
|
let oldValue = cameraMapForZoom.get(gridKey)
|
||||||
|
if (value.gbLongitude % diff < oldValue.gbLongitude % diff) {
|
||||||
|
cameraMapForZoom.set(gridKey, value)
|
||||||
|
useCameraMap.set(value.gbId, value)
|
||||||
|
useCameraMap.delete(oldValue.gbId)
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
cameraMapForZoom.set(gridKey, value)
|
||||||
|
useCameraMap.set(value.gbId, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cameraArray = Array.from(cameraMapForZoom.values())
|
||||||
|
zoomCameraMap.set(zoom, cameraArray)
|
||||||
|
let layerSource = this.createZoomLayerSource(cameraArray)
|
||||||
|
layerGroupSource.set(zoom - 1, layerSource)
|
||||||
|
zoom += 1
|
||||||
|
}
|
||||||
|
let cameraArray = []
|
||||||
|
for (let i = 0; i < cameraListInExtent.length; i++) {
|
||||||
|
let value = cameraListInExtent[i]
|
||||||
|
if (useCameraMap.has(value.gbId) || !value.gbLongitude || !value.gbLatitude) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cameraArray.push(value)
|
||||||
|
}
|
||||||
|
let layerSource = this.createZoomLayerSource(cameraArray)
|
||||||
|
layerGroupSource.set(zoomExtent[1] - 1, layerSource)
|
||||||
|
|
||||||
|
resolve(layerGroupSource)
|
||||||
|
}catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
createZoomLayerSource(cameraArray) {
|
||||||
|
let dataArray = []
|
||||||
|
for (let i = 0; i < cameraArray.length; i++) {
|
||||||
|
let item = cameraArray[i]
|
||||||
|
let position = [item.gbLongitude, item.gbLatitude]
|
||||||
|
dataArray.push({
|
||||||
|
id: item.gbId,
|
||||||
|
position: position,
|
||||||
|
data: item,
|
||||||
|
status: item.gbStatus,
|
||||||
|
image: {
|
||||||
|
anchor: [0.5, 1],
|
||||||
|
src: this.getImageByChannel(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return dataArray
|
||||||
|
},
|
||||||
|
saveDrawThin: function(){
|
||||||
|
if (!this.layerGroupSource) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.saveDrawThinLoading = true
|
||||||
|
let param = []
|
||||||
|
let keys = Array.from(this.layerGroupSource.keys())
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
let zoom = keys[i]
|
||||||
|
let values = this.layerGroupSource.get(zoom)
|
||||||
|
for (let j = 0; j < values.length; j++) {
|
||||||
|
let value = values[j]
|
||||||
|
if (zoom === 0) {
|
||||||
|
param.push({
|
||||||
|
gbId: value.id
|
||||||
|
})
|
||||||
|
}else {
|
||||||
|
param.push({
|
||||||
|
gbId: value.id,
|
||||||
|
mapLevel: zoom
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$store.dispatch('commonChanel/saveLevel', param)
|
||||||
|
.then((data) => {
|
||||||
|
this.$message.success({
|
||||||
|
showClose: true,
|
||||||
|
message: '保存成功'
|
||||||
|
})
|
||||||
|
this.showDrawThin = false
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.saveDrawThinLoading = false
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
resetDrawThinData(){
|
||||||
|
this.$confirm('确定移除抽稀结果?', '操作提示', {
|
||||||
|
confirmButtonText: '确认',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
this.$store.dispatch('commonChanel/resetLevel')
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success({
|
||||||
|
showClose: true,
|
||||||
|
message: '数据还原成功'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addVectorTileLayer() {
|
||||||
|
let geoCoordSys = this.$refs.mapComponent.getCoordSys()
|
||||||
|
const baseUrl = window.baseUrl ? window.baseUrl : ''
|
||||||
|
let tileUrl = ((process.env.NODE_ENV === 'development') ? process.env.VUE_APP_BASE_API : baseUrl)
|
||||||
|
+ `/api/common/channel/map/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&accessToken=${this.$store.getters.token}`
|
||||||
|
|
||||||
|
let clientEvent = data => {
|
||||||
|
this.closeInfoBox()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.showChannelInfo(data[0])
|
||||||
|
// if (data[0].edit) {
|
||||||
|
// this.showEditInfo(data[0])
|
||||||
|
// }else {
|
||||||
|
// this.showChannelInfo(data[0])
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let tileEvent = error => {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
let tileLayer = this.$refs.mapComponent.addVectorTileLayer(tileUrl, clientEvent, tileEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.map-tool-box-bottom-right {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
}
|
||||||
|
.map-tool-box-top-right {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 20px;
|
||||||
|
}
|
||||||
|
.map-tool-box-top-left {
|
||||||
|
position: absolute;
|
||||||
|
left: 380px;
|
||||||
|
top: 20px;
|
||||||
|
}
|
||||||
|
.map-tool-btn-group {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border-radius: 3px;
|
||||||
|
user-select: none;
|
||||||
|
box-shadow: 0 2px 2px rgba(0, 0, 0, .15);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.map-tool-box-top-left .map-tool-btn-group {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.map-tool-box-top-right .map-tool-btn-group {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.map-tool-box-top-left .map-tool-btn {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
.map-tool-box-top-right .map-tool-btn {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
.map-tool-btn {
|
||||||
|
border-bottom: 1px #dfdfdf solid;
|
||||||
|
border-right: 1px #dfdfdf solid;
|
||||||
|
width: fit-content;
|
||||||
|
min-width: 33px;
|
||||||
|
height: 36px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 36px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.map-tool-btn i {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.map-tool-btn-group:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
.map-tool-draw-thin {
|
||||||
|
position: absolute;
|
||||||
|
top: 63px;
|
||||||
|
left: 380px;
|
||||||
|
border: 1px solid #dfdfdf;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
.map-tool-draw-thin-density {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50px 400px auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infobox-content{
|
||||||
|
width: 270px;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #868686;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infobox-content::after {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -11px;
|
||||||
|
left: calc(50% - 8px);
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background: url('/static/images/arrow.png') no-repeat center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infobox-edit-content{
|
||||||
|
width: 400px;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #868686;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infobox-edit-content::after {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -11px;
|
||||||
|
left: calc(50% - 8px);
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background: url('/static/images/arrow.png') no-repeat center;
|
||||||
|
}
|
||||||
|
.infobox-close {
|
||||||
|
position: absolute;
|
||||||
|
right: 1rem;
|
||||||
|
top: 1rem;
|
||||||
|
color: #000000;
|
||||||
|
cursor:pointer
|
||||||
|
}
|
||||||
|
.el-descriptions__title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 20px 20px 0px 23px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -98,7 +98,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane v-if="streamProxy.id" label="国标通道配置">
|
<el-tab-pane v-if="streamProxy.id" label="国标通道配置">
|
||||||
<CommonChannelEdit ref="commonChannelEdit" :data-form="streamProxy" :cancel="close" />
|
<CommonChannelEdit ref="commonChannelEdit" :showCancel="true" :data-form="streamProxy" @cancel="close" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane v-if="streamPush.id" label="国标通道配置">
|
<el-tab-pane v-if="streamPush.id" label="国标通道配置">
|
||||||
<CommonChannelEdit ref="commonChannelEdit" :data-form="streamPush" :cancel="close" />
|
<CommonChannelEdit ref="commonChannelEdit" :showCancel="true" :data-form="streamPush" @cancel="close" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user