diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java index 30ca522f0..ee3a2d61c 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java @@ -9,9 +9,9 @@ import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupByGbDevicePar import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupParam; import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToRegionByGbDeviceParam; import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToRegionParam; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelFrontEndService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; -import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.Assert; @@ -31,7 +32,6 @@ import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; -import jakarta.servlet.http.HttpServletRequest; import java.net.MalformedURLException; import java.net.URL; import java.util.List; @@ -51,10 +51,10 @@ public class ChannelController { private IGbChannelService channelService; @Autowired - private IMediaServerService mediaServerService; + private IGbChannelPlayService channelPlayService; @Autowired - private IGbChannelPlayService channelPlayService; + private IGbChannelFrontEndService channelFrontEndService; @Autowired private UserSetting userSetting; @@ -464,4 +464,371 @@ public class ChannelController { Assert.notNull(channel, "通道不存在"); channelPlayService.playbackSpeed(channel, stream, speed); } + + + @Operation(summary = "云台控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "command", description = "控制指令,允许值: left, right, up, down, upleft, upright, downleft, downright, zoomin, zoomout, stop", required = true) + @Parameter(name = "horizonSpeed", description = "水平速度(0-255)", required = true) + @Parameter(name = "verticalSpeed", description = "垂直速度(0-255)", required = true) + @Parameter(name = "zoomSpeed", description = "缩放速度(0-15)", required = true) + @GetMapping("/ptz") + public void ptz(Integer channelId, String command, Integer horizonSpeed, Integer verticalSpeed, Integer zoomSpeed){ + + if (log.isDebugEnabled()) { + log.debug(String.format("设备云台控制 API调用,channelId:%s ,command:%s ,horizonSpeed:%d ,verticalSpeed:%d ,zoomSpeed:%d",channelId, command, horizonSpeed, verticalSpeed, zoomSpeed)); + } + + if (horizonSpeed == null) { + horizonSpeed = 100; + }else if (horizonSpeed < 0 || horizonSpeed > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "horizonSpeed 为 0-255的数字"); + } + if (verticalSpeed == null) { + verticalSpeed = 100; + }else if (verticalSpeed < 0 || verticalSpeed > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "verticalSpeed 为 0-255的数字"); + } + if (zoomSpeed == null) { + zoomSpeed = 16; + }else if (zoomSpeed < 0 || zoomSpeed > 15) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "zoomSpeed 为 0-15的数字"); + } + + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.ptz(channel, command, horizonSpeed, verticalSpeed, zoomSpeed); + } + + + @Operation(summary = "光圈控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "command", description = "控制指令,允许值: in, out, stop", required = true) + @Parameter(name = "speed", description = "光圈速度(0-255)", required = true) + @GetMapping("/fi/iris") + public void iris(Integer channelId, String command, Integer speed){ + + if (log.isDebugEnabled()) { + log.debug("设备光圈控制 API调用,channelId:{} ,command:{} ,speed:{} ",channelId, command, speed); + } + + if (speed == null) { + speed = 100; + }else if (speed < 0 || speed > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "speed 为 0-255的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.iris(channel, command, speed); + } + + @Operation(summary = "聚焦控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "command", description = "控制指令,允许值: near, far, stop", required = true) + @Parameter(name = "speed", description = "聚焦速度(0-255)", required = true) + @GetMapping("/fi/focus") + public void focus(Integer channelId, String command, Integer speed){ + + if (log.isDebugEnabled()) { + log.debug("设备聚焦控制 API调用,channelId:{} ,command:{} ,speed:{} ",channelId, command, speed); + } + + if (speed == null) { + speed = 100; + }else if (speed < 0 || speed > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "speed 为 0-255的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.focus(channel, command, speed); + } + + @Operation(summary = "查询预置位", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @GetMapping("/preset/query") + public DeferredResult> queryPreset(Integer channelId) { + if (log.isDebugEnabled()) { + log.debug("设备预置位查询API调用"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + DeferredResult> deferredResult = new DeferredResult<> (3 * 1000L); + channelFrontEndService.queryPreset(channel, (code, msg, data) -> { + deferredResult.setResult(new WVPResult<>(code, msg, data)); + }); + + deferredResult.onTimeout(()->{ + log.warn("[获取设备预置位] 超时, {}", channelId); + deferredResult.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "超时")); + }); + return deferredResult; + } + + @Operation(summary = "预置位指令-设置预置位", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "presetId", description = "预置位编号(1-255)", required = true) + @GetMapping("/preset/add") + public void addPreset(Integer channelId, Integer presetId) { + if (presetId == null || presetId < 1 || presetId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "预置位编号必须为1-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.addPreset(channel, presetId); + } + + @Operation(summary = "预置位指令-调用预置位", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "presetId", description = "预置位编号(1-255)", required = true) + @GetMapping("/preset/call") + public void callPreset(Integer channelId, Integer presetId) { + if (presetId == null || presetId < 1 || presetId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "预置位编号必须为1-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.callPreset(channel, presetId); + } + + @Operation(summary = "预置位指令-删除预置位", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "presetId", description = "预置位编号(1-255)", required = true) + @GetMapping("/preset/delete") + public void deletePreset(Integer channelId, Integer presetId) { + if (presetId == null || presetId < 1 || presetId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "预置位编号必须为1-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.deletePreset(channel, presetId); + } + + @Operation(summary = "巡航指令-加入巡航点", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "cruiseId", description = "巡航组号(0-255)", required = true) + @Parameter(name = "presetId", description = "预置位编号(1-255)", required = true) + @GetMapping("/cruise/point/add") + public void addCruisePoint(Integer channelId, Integer cruiseId, Integer presetId) { + if (presetId == null || cruiseId == null || presetId < 1 || presetId > 255 || cruiseId < 0 || cruiseId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "编号必须为1-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.addCruisePoint(channel, cruiseId, presetId); + } + + @Operation(summary = "巡航指令-删除一个巡航点", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "cruiseId", description = "巡航组号(1-255)", required = true) + @Parameter(name = "presetId", description = "预置位编号(0-255, 为0时删除整个巡航)", required = true) + @GetMapping("/cruise/point/delete") + public void deleteCruisePoint(Integer channelId, Integer cruiseId, Integer presetId) { + if (presetId == null || presetId < 0 || presetId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "预置位编号必须为0-255之间的数字, 为0时删除整个巡航"); + } + if (cruiseId == null || cruiseId < 0 || cruiseId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "巡航组号必须为0-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.deleteCruisePoint(channel, cruiseId, presetId); + } + + @Operation(summary = "巡航指令-设置巡航速度", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "cruiseId", description = "巡航组号(0-255)", required = true) + @Parameter(name = "speed", description = "巡航速度(1-4095)", required = true) + @GetMapping("/cruise/speed") + public void setCruiseSpeed(Integer channelId, Integer cruiseId, Integer speed) { + if (cruiseId == null || cruiseId < 0 || cruiseId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "巡航组号必须为0-255之间的数字"); + } + if (speed == null || speed < 1 || speed > 4095) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "巡航速度必须为1-4095之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.setCruiseSpeed(channel, cruiseId, speed); + } + + @Operation(summary = "巡航指令-设置巡航停留时间", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "cruiseId", description = "巡航组号", required = true) + @Parameter(name = "time", description = "巡航停留时间(1-4095)", required = true) + @GetMapping("/cruise/time") + public void setCruiseTime(Integer channelId, Integer cruiseId, Integer time) { + if (cruiseId == null || cruiseId < 0 || cruiseId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "巡航组号必须为0-255之间的数字"); + } + if (time == null || time < 1 || time > 4095) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "巡航停留时间必须为1-4095之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.setCruiseTime(channel, cruiseId, time); + } + + @Operation(summary = "巡航指令-开始巡航", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "cruiseId", description = "巡航组号)", required = true) + @GetMapping("/cruise/start") + public void startCruise(Integer channelId, Integer cruiseId) { + if (cruiseId == null || cruiseId < 0 || cruiseId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "巡航组号必须为0-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.startCruise(channel, cruiseId); + } + + @Operation(summary = "巡航指令-停止巡航", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "cruiseId", description = "巡航组号", required = true) + @GetMapping("/cruise/stop") + public void stopCruise(Integer channelId, Integer cruiseId) { + if (cruiseId == null || cruiseId < 0 || cruiseId > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "巡航组号必须为0-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.stopCruise(channel, cruiseId); + } + + @Operation(summary = "扫描指令-开始自动扫描", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "scanId", description = "扫描组号(0-255)", required = true) + @GetMapping("/scan/start") + public void startScan(Integer channelId, Integer scanId) { + if (scanId == null || scanId < 0 || scanId > 255 ) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "扫描组号必须为0-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.startScan(channel, scanId); + } + + @Operation(summary = "扫描指令-停止自动扫描", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "scanId", description = "扫描组号(0-255)", required = true) + @GetMapping("/scan/stop") + public void stopScan(Integer channelId, Integer scanId) { + if (scanId == null || scanId < 0 || scanId > 255 ) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "扫描组号必须为0-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.stopScan(channel, scanId); + } + + @Operation(summary = "扫描指令-设置自动扫描左边界", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "scanId", description = "扫描组号(0-255)", required = true) + @GetMapping("/scan/set/left") + public void setScanLeft(Integer channelId, Integer scanId) { + if (scanId == null || scanId < 0 || scanId > 255 ) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "扫描组号必须为0-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.setScanLeft(channel, scanId); + } + + @Operation(summary = "扫描指令-设置自动扫描右边界", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "scanId", description = "扫描组号(0-255)", required = true) + @GetMapping("/scan/set/right") + public void setScanRight(Integer channelId, Integer scanId) { + if (scanId == null || scanId < 0 || scanId > 255 ) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "扫描组号必须为0-255之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.setScanRight(channel, scanId); + } + + + @Operation(summary = "扫描指令-设置自动扫描速度", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "scanId", description = "扫描组号(0-255)", required = true) + @Parameter(name = "speed", description = "自动扫描速度(1-4095)", required = true) + @GetMapping("/scan/set/speed") + public void setScanSpeed(Integer channelId, Integer scanId, Integer speed) { + if (scanId == null || scanId < 0 || scanId > 255 ) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "扫描组号必须为0-255之间的数字"); + } + if (speed == null || speed < 1 || speed > 4095) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "自动扫描速度必须为1-4095之间的数字"); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.setScanSpeed(channel, scanId, speed); + } + + + @Operation(summary = "辅助开关控制指令-雨刷控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "command", description = "控制指令,允许值: on, off", required = true) + @GetMapping("/wiper") + public void wiper(Integer channelId, String command){ + + if (log.isDebugEnabled()) { + log.debug("辅助开关控制指令-雨刷控制 API调用,channelId:{} ,command:{}",channelId, command); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.wiper(channel, command); + } + + @Operation(summary = "辅助开关控制指令", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "channelId", description = "通道ID", required = true) + @Parameter(name = "command", description = "控制指令,允许值: on, off", required = true) + @Parameter(name = "switchId", description = "开关编号", required = true) + @GetMapping("/auxiliary") + public void auxiliarySwitch(Integer channelId, String command, Integer switchId){ + + if (log.isDebugEnabled()) { + log.debug("辅助开关控制指令-雨刷控制 API调用,channelId:{} ,command:{}, switchId: {}", channelId, command, switchId); + } + CommonGBChannel channel = channelService.getOne(channelId); + Assert.notNull(channel, "通道不存在"); + + channelFrontEndService.auxiliarySwitch(channel, command, switchId); + } + + @Operation(summary = "为地图获取通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "query", description = "查询内容") + @Parameter(name = "online", description = "是否在线") + @Parameter(name = "hasRecordPlan", description = "是否已设置录制计划") + @Parameter(name = "channelType", description = "通道类型, 0:国标设备,1:推流设备,2:拉流代理") + @Parameter(name = "geoCoordSys", description = "地理坐标系, WGS84/GCJ02") + @GetMapping("/map/list") + public List queryListForMap( + @RequestParam(required = false) String query, + @RequestParam(required = false) Boolean online, + @RequestParam(required = false) Boolean hasRecordPlan, + @RequestParam(required = false) Integer channelType){ + if (ObjectUtils.isEmpty(query)){ + query = null; + } + return channelService.queryListForMap(query, online, hasRecordPlan, channelType); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelFrontEndService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelFrontEndService.java new file mode 100644 index 000000000..0ef813bd6 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelFrontEndService.java @@ -0,0 +1,52 @@ +package com.genersoft.iot.vmp.gb28181.service; + +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.Preset; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; + +import java.util.List; + +public interface IGbChannelFrontEndService { + + + void ptz(CommonGBChannel channel, String command, Integer horizonSpeed, Integer verticalSpeed, Integer zoomSpeed); + + void iris(CommonGBChannel channel, String command, Integer speed); + + void focus(CommonGBChannel channel, String command, Integer speed); + + void queryPreset(CommonGBChannel channel, ErrorCallback> callback); + + void addPreset(CommonGBChannel channel, Integer presetId); + + void callPreset(CommonGBChannel channel, Integer presetId); + + void deletePreset(CommonGBChannel channel, Integer presetId); + + void addCruisePoint(CommonGBChannel channel, Integer cruiseId, Integer presetId); + + void deleteCruisePoint(CommonGBChannel channel, Integer cruiseId, Integer presetId); + + void setCruiseSpeed(CommonGBChannel channel, Integer cruiseId, Integer speed); + + void setCruiseTime(CommonGBChannel channel, Integer cruiseId, Integer time); + + void startCruise(CommonGBChannel channel, Integer cruiseId); + + void stopCruise(CommonGBChannel channel, Integer cruiseId); + + void startScan(CommonGBChannel channel, Integer scanId); + + void stopScan(CommonGBChannel channel, Integer scanId); + + void setScanLeft(CommonGBChannel channel, Integer scanId); + + void setScanRight(CommonGBChannel channel, Integer scanId); + + void setScanSpeed(CommonGBChannel channel, Integer scanId, Integer speed); + + void wiper(CommonGBChannel channel, String command); + + void auxiliarySwitch(CommonGBChannel channel, String command, Integer switchId); + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java index 4fd1cbe3a..b5c2f97a9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java @@ -97,4 +97,6 @@ public interface IGbChannelService { void updateGPSFromGPSMsgInfo(List gpsMsgInfoList); void updateGPS(List channelList); + + List queryListForMap(String query, Boolean online, Boolean hasRecordPlan, Integer channelType); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelFrontEndServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelFrontEndServiceImpl.java new file mode 100644 index 000000000..12891a761 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelFrontEndServiceImpl.java @@ -0,0 +1,534 @@ +package com.genersoft.iot.vmp.gb28181.service.impl; + +import com.genersoft.iot.vmp.common.enums.ChannelDataType; +import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelFrontEndService; +import com.genersoft.iot.vmp.gb28181.service.IPTZService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +import javax.sip.message.Response; +import java.util.List; + +@Slf4j +@Service +public class GbChannelFrontEndServiceImpl implements IGbChannelFrontEndService { + + @Autowired + private IPTZService ptzService; + + @Autowired + private IDeviceService deviceService; + + @Autowired + private IDeviceChannelService deviceChannelService; + + private void frontEndCommand(CommonGBChannel channel, Integer cmdCode, Integer parameter1, Integer parameter2, Integer combindCode2){ + + Assert.isTrue(channel.getDataType() == ChannelDataType.GB28181, "类型获取错误"); + + Device device = deviceService.getDevice(channel.getDataDeviceId()); + Assert.notNull(device, "设备不存在"); + + DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); + Assert.notNull(device, "原始通道不存在"); + + ptzService.frontEndCommand(device, deviceChannel.getDeviceId(), cmdCode, parameter1, parameter2, combindCode2); + } + + @Override + public void ptz(CommonGBChannel channel, String command, Integer horizonSpeed, Integer verticalSpeed, Integer zoomSpeed) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int cmdCode = 0; + switch (command){ + case "left": + cmdCode = 2; + break; + case "right": + cmdCode = 1; + break; + case "up": + cmdCode = 8; + break; + case "down": + cmdCode = 4; + break; + case "upleft": + cmdCode = 10; + break; + case "upright": + cmdCode = 9; + break; + case "downleft": + cmdCode = 6; + break; + case "downright": + cmdCode = 5; + break; + case "zoomin": + cmdCode = 16; + break; + case "zoomout": + cmdCode = 32; + break; + case "stop": + horizonSpeed = 0; + verticalSpeed = 0; + zoomSpeed = 0; + break; + default: + break; + } + frontEndCommand(channel, cmdCode, horizonSpeed, verticalSpeed, zoomSpeed); + + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void iris(CommonGBChannel channel, String command, Integer speed) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int cmdCode = 0x40; + switch (command){ + case "in": + cmdCode = 0x44; + break; + case "out": + cmdCode = 0x48; + break; + case "stop": + speed = 0; + break; + default: + break; + } + frontEndCommand(channel, cmdCode, 0, speed, 0); + + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void focus(CommonGBChannel channel, String command, Integer speed) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int cmdCode = 0x40; + switch (command){ + case "near": + cmdCode = 0x42; + break; + case "far": + cmdCode = 0x41; + break; + case "stop": + speed = 0; + break; + default: + break; + } + frontEndCommand(channel, cmdCode, speed, 0, 0); + + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + + } + + @Override + public void queryPreset(CommonGBChannel channel, ErrorCallback> callback) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + + Device device = deviceService.getDevice(channel.getDataDeviceId()); + Assert.notNull(device, "设备不存在"); + + DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); + Assert.notNull(device, "原始通道不存在"); + + deviceService.queryPreset(device, deviceChannel.getDeviceId(), callback); + + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void addPreset(CommonGBChannel channel, Integer presetId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x81, 1, presetId, 0); + + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void callPreset(CommonGBChannel channel, Integer presetId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x82, 1, presetId, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void deletePreset(CommonGBChannel channel, Integer presetId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x83, 1, presetId, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void addCruisePoint(CommonGBChannel channel, Integer cruiseId, Integer presetId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x84, cruiseId, presetId, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void deleteCruisePoint(CommonGBChannel channel, Integer cruiseId, Integer presetId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x85, cruiseId, presetId, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void setCruiseSpeed(CommonGBChannel channel, Integer cruiseId, Integer speed) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int parameter2 = speed & 0xFF; + int combindCode2 = speed >> 8; + frontEndCommand(channel, 0x86, cruiseId, parameter2, combindCode2); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void setCruiseTime(CommonGBChannel channel, Integer cruiseId, Integer time) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int parameter2 = time & 0xFF; + int combindCode2 = time >> 8; + frontEndCommand(channel, 0x87, cruiseId, parameter2, combindCode2); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void startCruise(CommonGBChannel channel, Integer cruiseId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x88, cruiseId, 0, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void stopCruise(CommonGBChannel channel, Integer cruiseId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0, 0, 0, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void startScan(CommonGBChannel channel, Integer scanId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x89, scanId, 0, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void stopScan(CommonGBChannel channel, Integer scanId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0, 0, 0, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void setScanLeft(CommonGBChannel channel, Integer scanId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x89, scanId, 1, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void setScanRight(CommonGBChannel channel, Integer scanId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + frontEndCommand(channel, 0x89, scanId, 2, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void setScanSpeed(CommonGBChannel channel, Integer scanId, Integer speed) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int parameter2 = speed & 0xFF; + int combindCode2 = speed >> 8; + frontEndCommand(channel, 0x8A, scanId, parameter2, combindCode2); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void wiper(CommonGBChannel channel, String command) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int cmdCode = 0; + switch (command){ + case "on": + cmdCode = 0x8c; + break; + case "off": + cmdCode = 0x8d; + break; + default: + break; + } + frontEndCommand(channel, cmdCode, 1, 0, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void auxiliarySwitch(CommonGBChannel channel, String command, Integer switchId) { + Assert.notNull(channel, "通道不存在"); + if (channel.getDataType() == ChannelDataType.GB28181) { + // 国标通道 + int cmdCode = 0; + switch (command){ + case "on": + cmdCode = 0x8c; + break; + case "off": + cmdCode = 0x8d; + break; + default: + break; + } + frontEndCommand(channel, cmdCode, switchId, 0, 0); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH) { + // 拉流代理 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持此操作"); + } else { + // 通道数据异常 + log.error("[通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java index 3e99d18a6..41c0570de 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java @@ -12,7 +12,6 @@ import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; -import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.genersoft.iot.vmp.utils.DateUtil; @@ -26,7 +25,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; -import javax.sip.message.Response; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -788,4 +786,9 @@ public class GbChannelServiceImpl implements IGbChannelService { commonGBChannelMapper.updateGps(commonGBChannels); } } + + @Override + public List queryListForMap(String query, Boolean online, Boolean hasRecordPlan, Integer channelType) { + return commonGBChannelMapper.queryList(query, online, hasRecordPlan, channelType); + } } diff --git a/web/package.json b/web/package.json index 51122c1eb..3ac213819 100644 --- a/web/package.json +++ b/web/package.json @@ -21,6 +21,7 @@ "dayjs": "^1.11.13", "echarts": "^4.9.0", "element-ui": "^2.15.14", + "gcoord": "^1.0.7", "js-cookie": "2.2.0", "moment": "^2.29.1", "moment-duration-format": "^2.3.2", diff --git a/web/public/static/images/gis/camera1-red.png b/web/public/static/images/gis/camera1-red.png new file mode 100644 index 000000000..04346f333 Binary files /dev/null and b/web/public/static/images/gis/camera1-red.png differ diff --git a/web/src/api/commonChannel.js b/web/src/api/commonChannel.js index 0a9db6178..e46821083 100644 --- a/web/src/api/commonChannel.js +++ b/web/src/api/commonChannel.js @@ -586,3 +586,15 @@ export function speedPlayback({ channelId, stream, speed}) { } }) } +export function getAllForMap({ query, online, hasRecordPlan, channelType }) { + return request({ + method: 'get', + url: '/api/common/channel/map/list', + params: { + query: query, + online: online, + hasRecordPlan: hasRecordPlan, + channelType: channelType + } + }) +} diff --git a/web/src/icons/svg/map.svg b/web/src/icons/svg/map.svg new file mode 100644 index 000000000..48479ae36 --- /dev/null +++ b/web/src/icons/svg/map.svg @@ -0,0 +1 @@ + diff --git a/web/src/router/index.js b/web/src/router/index.js index fd6f29702..1d844fa93 100644 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -85,6 +85,17 @@ export const constantRoutes = [ } ] }, + { + path: '/map', + component: Layout, + redirect: '/map', + children: [{ + path: '', + name: 'Map', + component: () => import('@/views/map/index'), + meta: { title: '电子地图', icon: 'map' } + }] + }, { path: '/device', component: Layout, diff --git a/web/src/store/modules/commonChanel.js b/web/src/store/modules/commonChanel.js index e1a84442b..6b665e032 100644 --- a/web/src/store/modules/commonChanel.js +++ b/web/src/store/modules/commonChanel.js @@ -48,7 +48,7 @@ import { stopPlayback, pausePlayback, resumePlayback, - seekPlayback, speedPlayback + seekPlayback, speedPlayback, getAllForMap } from '@/api/commonChannel' const actions = { @@ -561,6 +561,16 @@ const actions = { reject(error) }) }) + }, + getAllForMap({ commit }, params) { + return new Promise((resolve, reject) => { + getAllForMap(params).then(response => { + const { data } = response + resolve(data) + }).catch(error => { + reject(error) + }) + }) } } diff --git a/web/src/views/common/DeviceTree.vue b/web/src/views/common/DeviceTree.vue index fe99ca76d..ac474e1bd 100755 --- a/web/src/views/common/DeviceTree.vue +++ b/web/src/views/common/DeviceTree.vue @@ -19,7 +19,9 @@ ref="regionTree" :edit="false" :show-header="false" + :show-position="showPosition" :has-channel="true" + :contextmenu="contextmenu" @clickEvent="treeNodeClickEvent" :default-expanded-keys="[]" /> @@ -28,7 +30,9 @@ ref="groupTree" :edit="false" :show-header="false" + :show-position="showPosition" :has-channel="true" + :contextmenu="contextmenu" @clickEvent="treeNodeClickEvent" :default-expanded-keys="[]" /> @@ -56,6 +60,14 @@ export default { contextMenuEvent: { type: Function, default: null + }, + showPosition: { + type: Boolean, + default: false + }, + contextmenu: { + type: Array, + default: null } }, data() { @@ -135,6 +147,14 @@ export default { if (data.leaf) { this.$emit('clickEvent', data.id) } + }, + refresh: function(id) { + console.log(id) + if (this.showRegion) { + this.$refs.regionTree.refresh(id) + }else { + this.$refs.groupTree.refresh(id) + } } } } diff --git a/web/src/views/common/GroupTree.vue b/web/src/views/common/GroupTree.vue index cb336db06..194f3dcec 100755 --- a/web/src/views/common/GroupTree.vue +++ b/web/src/views/common/GroupTree.vue @@ -65,6 +65,7 @@ style=" padding-left: 1px" :title="node.data.deviceId" >{{ node.label }} + @@ -130,7 +131,7 @@ export default { GbChannelSelect, VueEasyTree, groupEdit, gbDeviceSelect }, - props: ['edit', 'enableAddChannel', 'showHeader', 'hasChannel', 'addChannelToGroup', 'treeHeight'], + props: ['edit', 'enableAddChannel', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToGroup', 'treeHeight', 'showPosition', 'contextmenu'], data() { return { props: { @@ -231,90 +232,111 @@ export default { this.$forceUpdate() }, contextmenuEventHandler: function(event, data, node, element) { - if (!this.edit) { + if (!this.edit && !this.contextmenu) { return } + const allMenuItem = [] if (node.data.type === 0) { - const menuItem = [ - { - label: '刷新节点', - icon: 'el-icon-refresh', - disabled: false, - onClick: () => { - this.refreshNode(node) - } - }, - { - label: '新建节点', - icon: 'el-icon-plus', - disabled: false, - onClick: () => { - this.addGroup(data.id, node) - } - }, - { - label: '编辑节点', - icon: 'el-icon-edit', - disabled: node.level === 1, - onClick: () => { - this.editGroup(data, node) - } - }, - { - label: '删除节点', - icon: 'el-icon-delete', - disabled: node.level === 1, - divided: true, - onClick: () => { - this.$confirm('确定删除?', '提示', { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: 'warning' - }).then(() => { - this.removeGroup(data.id, node) - }).catch(() => { + if (this.edit) { + const menuItem = [ + { + label: '刷新节点', + icon: 'el-icon-refresh', + disabled: false, + onClick: () => { + this.refreshNode(node) + } + }, + { + label: '新建节点', + icon: 'el-icon-plus', + disabled: false, + onClick: () => { + this.addGroup(data.id, node) + } + }, + { + label: '编辑节点', + icon: 'el-icon-edit', + disabled: node.level === 1, + onClick: () => { + this.editGroup(data, node) + } + }, + { + label: '删除节点', + icon: 'el-icon-delete', + disabled: node.level === 1, + divided: true, + onClick: () => { + this.$confirm('确定删除?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.removeGroup(data.id, node) + }).catch(() => { + }) + } + } + ] + + if (this.enableAddChannel) { + menuItem.push( + { + label: '添加设备', + icon: 'el-icon-plus', + disabled: node.level <= 2, + onClick: () => { + this.addChannelFormDevice(data.id, node) + } + } + ) + menuItem.push( + { + label: '移除设备', + icon: 'el-icon-delete', + disabled: node.level <= 2, + divided: true, + onClick: () => { + this.removeChannelFormDevice(data.id, node) + } + } + ) + menuItem.push( + { + label: '添加通道', + icon: 'el-icon-plus', + disabled: node.level <= 2, + onClick: () => { + this.addChannel(data.id, node) + } + } + ) + } + allMenuItem.push(...menuItem) + } + if (this.contextmenu) { + for (let i = 0; i < this.contextmenu.length; i++) { + let item = this.contextmenu[i] + if (item.type === node.data.type) { + allMenuItem.push({ + label: item.label, + icon: item.icon, + onClick: () => { + item.onClick(event, data, node) + } }) } } - ] - - if (this.enableAddChannel) { - menuItem.push( - { - label: '添加设备', - icon: 'el-icon-plus', - disabled: node.level <= 2, - onClick: () => { - this.addChannelFormDevice(data.id, node) - } - } - ) - menuItem.push( - { - label: '移除设备', - icon: 'el-icon-delete', - disabled: node.level <= 2, - divided: true, - onClick: () => { - this.removeChannelFormDevice(data.id, node) - } - } - ) - menuItem.push( - { - label: '添加通道', - icon: 'el-icon-plus', - disabled: node.level <= 2, - onClick: () => { - this.addChannel(data.id, node) - } - } - ) + } + if (allMenuItem.length === 0) { + return } this.$contextmenu({ - items: menuItem, + items: allMenuItem, event, // 鼠标事件信息 customClass: 'custom-class', // 自定义菜单 class zIndex: 3000 // 菜单样式 z-index diff --git a/web/src/views/common/MapComponent.vue b/web/src/views/common/MapComponent.vue index 9261b6e5a..cb2570938 100755 --- a/web/src/views/common/MapComponent.vue +++ b/web/src/views/common/MapComponent.vue @@ -17,11 +17,16 @@ import View from 'ol/View' import Feature from 'ol/Feature' import Overlay from 'ol/Overlay' import { Point, LineString } from 'ol/geom' -import { get as getProj, fromLonLat } from 'ol/proj' -import { ZoomSlider, Zoom } from 'ol/control' +import { get as getProj } from 'ol/proj' import { containsCoordinate } from 'ol/extent' +import { + defaults as defaultInteractions +} from 'ol/interaction' +import DragInteraction from './map/DragInteraction' +import { fromLonLat, toLonLat } from './map/TransformLonLat' import { v4 } from 'uuid' +import { getUid } from 'ol' let olMap = null @@ -30,7 +35,8 @@ export default { props: [], data() { return { - + overlayId: null, + dragInteraction: new DragInteraction() } }, created() { @@ -44,34 +50,28 @@ export default { }, destroyed() { - // if (this.jessibuca) { - // this.jessibuca.destroy(); - // } - // this.playing = false; - // this.loaded = false; - // this.performance = ""; }, methods: { init() { let center = fromLonLat([116.41020, 39.915119]) - if (mapParam.center) { - center = fromLonLat(mapParam.center) + if (window.mapParam.center) { + center = fromLonLat(window.mapParam.center) } const view = new View({ center: center, - zoom: mapParam.zoom || 10, + zoom: window.mapParam.zoom || 10, projection: this.projection, - maxZoom: mapParam.maxZoom || 19, - minZoom: mapParam.minZoom || 1 + maxZoom: window.mapParam.maxZoom || 19, + minZoom: window.mapParam.minZoom || 1 }) let tileLayer = null - if (mapParam.tilesUrl) { + if (window.mapParam.tilesUrl) { tileLayer = new Tile({ source: new XYZ({ projection: getProj('EPSG:3857'), wrapX: false, - tileSize: 256 || mapParam.tileSize, - url: mapParam.tilesUrl + tileSize: 256 || window.mapParam.tileSize, + url: window.mapParam.tilesUrl }) }) } else { @@ -81,18 +81,48 @@ export default { }) } olMap = new Map({ + interactions: defaultInteractions().extend([this.dragInteraction]), target: this.$refs.mapContainer, // 容器ID layers: [tileLayer], // 默认图层 view: view, // 视图 controls: [ // 控件 - // new ZoomSlider(), - new Zoom() ] }) - console.log(3222) + olMap.once('loadend', event => { + this.$emit('loaded') + }) + olMap.on('click', event => { + let features = {} + let layers = {} + // 单个元素事件传递 + olMap.forEachFeatureAtPixel(event.pixel, (featureAtPixel, layerAtPixel) => { + + if (layerAtPixel) { + let ol_uid = 'key' + getUid(layerAtPixel) + layers[ol_uid] = layerAtPixel + if (Object.hasOwn(features, ol_uid)) { + features[ol_uid].push(featureAtPixel) + } else { + features[ol_uid] = new Array(featureAtPixel) + } + } + }) + // 遍历图层,传递事件 + for (const key in layers) { + if (Object.hasOwn(layers, key)) { + var layer = layers[key] + layer.dispatchEvent({ type: 'click', event: event, features: features[key], outParam: { layersCount: Object.keys(layers).length } }); + } + } + features = {} + layer = {} + }) }, setCenter(point) { + }, + getCenter() { + return toLonLat(olMap.getView().getCenter()) }, zoomIn(zoom) { @@ -110,23 +140,33 @@ export default { duration: duration }) }, - panTo(point, zoom) { - const duration = 800 + coordinateInView: function(point) { + return containsCoordinate(olMap.getView().calculateExtent(), fromLonLat(point)) + }, + panTo(point, zoom, endCallback) { + const duration = 1500 + var coordinate = fromLonLat(point) + if (containsCoordinate(olMap.getView().calculateExtent(), coordinate)) { + olMap.getView().setCenter(coordinate) + if (endCallback) { + endCallback() + } + return + } olMap.getView().cancelAnimations() olMap.getView().animate({ - center: fromLonLat(point), + center: coordinate, duration: duration }) - if (!containsCoordinate(olMap.getView().calculateExtent(), fromLonLat(point))) { - olMap.getView().animate({ - zoom: olMap.getView().getZoom() - 1, - duration: duration / 2 - }, { - zoom: zoom || olMap.getView().getZoom(), - duration: duration / 2 - }) - } + olMap.getView().animate({ + zoom: 12, + duration: duration / 2 + }, { + zoom: zoom || olMap.getView().getZoom(), + duration: duration / 2 + }) + setTimeout(endCallback, duration + 100) }, fit(layer) { const extent = layer.getSource().getExtent() @@ -138,10 +178,15 @@ export default { } }, openInfoBox(position, content, offset) { + if (this.overlayId !== null) { + console.log(this.overlayId) + this.closeInfoBox(this.overlayId) + this.overlayId = null + } const id = v4() - // let infoBox = document.createElement("div"); - // infoBox.innerHTML = content ; - // infoBox.setAttribute("infoBoxId", id) + // let infoBox = document.createElement('div') + // infoBox.setAttribute('id', id) + // infoBox.innerHTML = content const overlay = new Overlay({ id: id, autoPan: true, @@ -150,16 +195,23 @@ export default { }, element: content, positioning: 'bottom-center', - offset: offset + offset: offset, + position: fromLonLat(position) // className:overlayStyle.className }) olMap.addOverlay(overlay) - overlay.setPosition(fromLonLat(position)) + this.overlayId = id return id }, closeInfoBox(id) { - olMap.getOverlayById(id).setPosition(undefined) - // olMap.removeOverlay(olMap.getOverlayById(id)) + let overlay = olMap.getOverlayById(id) + if (overlay) { + olMap.removeOverlay(overlay) + } + var element = document.getElementById(id) + if (element) { + element.remove() + } }, /** * 添加图层 @@ -178,13 +230,13 @@ export default { * ] */ addLayer(data, clickEvent) { - const style = new Style() if (data.length > 0) { const features = [] for (let i = 0; i < data.length; i++) { const feature = new Feature(new Point(fromLonLat(data[i].position))) + feature.setId(data[i].id) feature.customData = data[i].data - const cloneStyle = style.clone() + const cloneStyle = new Style() cloneStyle.setImage(new Icon({ anchor: data[i].image.anchor, crossOrigin: 'Anonymous', @@ -197,31 +249,88 @@ export default { source.addFeatures(features) const vectorLayer = new VectorLayer({ source: source, - style: style, renderMode: 'image', declutter: false }) olMap.addLayer(vectorLayer) if (typeof clickEvent === 'function') { - olMap.on('click', (event) => { - vectorLayer.getFeatures(event.pixel).then((features) => { - if (features.length > 0) { - const items = [] - for (let i = 0; i < features.length; i++) { - items.push(features[i].customData) - } - clickEvent(items) + vectorLayer.on('click', (event) => { + + if (event.features.length > 0) { + const items = [] + for (let i = 0; i < event.features.length; i++) { + items.push(event.features[i].customData) } - }) + clickEvent(items) + } }) } return vectorLayer } }, + updateLayer(layer, data, postponement) { + console.log(layer) + layer.getSource().clear(true) + const features = [] + for (let i = 0; i < data.length; i++) { + const feature = new Feature(new Point(fromLonLat(data[i].position))) + feature.setId(data[i].id) + feature.customData = data[i].data + const cloneStyle = new Style() + cloneStyle.setImage(new Icon({ + anchor: data[i].image.anchor, + crossOrigin: 'Anonymous', + src: data[i].image.src + })) + feature.setStyle(cloneStyle) + features.push(feature) + } + layer.getSource().addFeatures(features) + if (postponement) { + olMap.removeLayer(layer) + setTimeout(() => { + olMap.addLayer(layer) + }, 100) + } + return layer + }, removeLayer(layer) { olMap.removeLayer(layer) }, + setFeatureImageById(layer, featureId, image) { + let feature = layer.getSource().getFeatureById(featureId) + if (!feature) { + console.error('更改feature的图标时未找到图标') + return + } + let style = feature.getStyle() + style.setImage(new Icon({ + anchor: image.anchor, + crossOrigin: 'Anonymous', + src: image.src + })) + feature.setStyle(style) + olMap.render() + }, + setFeaturePositionById(layer, featureId, data) { + let featureOld = layer.getSource().getFeatureById(featureId) + if (featureOld) { + layer.getSource().removeFeature(featureOld) + } + + const feature = new Feature(new Point(fromLonLat(data.position))) + feature.setId(data.id) + feature.customData = data.data + const style = new Style() + style.setImage(new Icon({ + anchor: data.image.anchor, + crossOrigin: 'Anonymous', + src: data.image.src + })) + feature.setStyle(style) + layer.getSource().addFeature(feature) + }, addLineLayer(positions) { if (positions.length > 0) { diff --git a/web/src/views/common/RegionTree.vue b/web/src/views/common/RegionTree.vue index e51019059..a7f48f255 100755 --- a/web/src/views/common/RegionTree.vue +++ b/web/src/views/common/RegionTree.vue @@ -56,15 +56,11 @@ class="iconfont icon-shexiangtou2" /> {{ node.label }}(编号:{{ node.data.deviceId }}) - {{ node.label }} + (编号:{{ node.data.deviceId }}) + @@ -131,7 +127,7 @@ export default { GbChannelSelect, VueEasyTree, regionEdit, gbDeviceSelect }, - props: ['edit', 'enableAddChannel', 'showHeader', 'hasChannel', 'addChannelToCivilCode', 'treeHeight'], + props: ['edit', 'enableAddChannel', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToCivilCode', 'treeHeight', 'showPosition', 'contextmenu'], data() { return { props: { @@ -236,95 +232,115 @@ export default { this.$forceUpdate() }, contextmenuEventHandler: function(event, data, node, element) { - if (!this.edit) { + if (!this.edit && !this.contextmenu) { return } + const allMenuItem = [] if (node.data.type === 0) { - const menuItem = [ - { - label: '刷新节点', - icon: 'el-icon-refresh', - disabled: false, - onClick: () => { - this.refreshNode(node) - } - }, - { - label: '新建节点', - icon: 'el-icon-plus', - disabled: false, - onClick: () => { - this.addRegion(data.id, node) - } - }, - { - label: '编辑节点', - icon: 'el-icon-edit', - disabled: node.level === 1, - onClick: () => { - this.editCatalog(data, node) - } - }, - { - label: '删除节点', - icon: 'el-icon-delete', - disabled: node.level === 1, - divided: true, - onClick: () => { - this.$confirm('确定删除?', '提示', { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: 'warning' - }).then(() => { - this.removeRegion(data.id, node) - }).catch(() => { + if (this.edit) { - }) - } - } - ] - if (this.enableAddChannel) { - menuItem.push( + const menuItem = [ { - label: '添加设备', + label: '刷新节点', + icon: 'el-icon-refresh', + disabled: false, + onClick: () => { + this.refreshNode(node) + } + }, + { + label: '新建节点', icon: 'el-icon-plus', + disabled: false, + onClick: () => { + this.addRegion(data.id, node) + } + }, + { + label: '编辑节点', + icon: 'el-icon-edit', disabled: node.level === 1, onClick: () => { - this.addChannelFormDevice(data.id, node) + this.editCatalog(data, node) } - } - ) - menuItem.push( + }, { - label: '移除设备', + label: '删除节点', icon: 'el-icon-delete', disabled: node.level === 1, divided: true, onClick: () => { - this.removeChannelFormDevice(data.id, node) + this.$confirm('确定删除?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.removeRegion(data.id, node) + }).catch(() => { + + }) } } - ) - menuItem.push( - { - label: '添加通道', - icon: 'el-icon-plus', - disabled: node.level === 1, - onClick: () => { - this.addChannel(data.id, node) + ] + if (this.enableAddChannel) { + menuItem.push( + { + label: '添加设备', + icon: 'el-icon-plus', + disabled: node.level === 1, + onClick: () => { + this.addChannelFormDevice(data.id, node) + } } - } - ) + ) + menuItem.push( + { + label: '移除设备', + icon: 'el-icon-delete', + disabled: node.level === 1, + divided: true, + onClick: () => { + this.removeChannelFormDevice(data.id, node) + } + } + ) + menuItem.push( + { + label: '添加通道', + icon: 'el-icon-plus', + disabled: node.level === 1, + onClick: () => { + this.addChannel(data.id, node) + } + } + ) + } + allMenuItem.push(...menuItem) } - - this.$contextmenu({ - items: menuItem, - event, // 鼠标事件信息 - customClass: 'custom-class', // 自定义菜单 class - zIndex: 3000 // 菜单样式 z-index - }) } - + if (this.contextmenu) { + for (let i = 0; i < this.contextmenu.length; i++) { + let item = this.contextmenu[i] + if (item.type === node.data.type) { + allMenuItem.push({ + label: item.label, + icon: item.icon, + onClick: () => { + item.onClick(event, data, node) + } + }) + } + } + } + if (allMenuItem.length === 0) { + return + } + this.$contextmenu({ + items: allMenuItem, + event, // 鼠标事件信息 + customClass: 'custom-class', // 自定义菜单 class + zIndex: 3000 // 菜单样式 z-index + }) return false }, removeRegion: function(id, node) { @@ -396,12 +412,16 @@ export default { node.expand() }, refresh: function(id) { - console.log(id) // 查询node const node = this.$refs.veTree.getNode(id) if (node) { - node.loaded = false - node.expand() + if (id.includes('channel') >= 0) { + node.parent.loaded = false + node.parent.expand() + }else { + node.loaded = false + node.expand() + } } }, addRegion: function(id, node) { diff --git a/web/src/views/common/map/DragInteraction.js b/web/src/views/common/map/DragInteraction.js new file mode 100644 index 000000000..ee536ecbd --- /dev/null +++ b/web/src/views/common/map/DragInteraction.js @@ -0,0 +1,116 @@ +import PointerInteraction from 'ol/interaction/Pointer' +import { toLonLat } from './TransformLonLat' + +class DragInteraction extends PointerInteraction { + constructor() { + super({ + handleDownEvent: (evt) => { + const map = evt.map + + const feature = map.forEachFeatureAtPixel(evt.pixel, (feature) => { + if (this.featureIdMap_.has(feature.getId())) { + return feature + }else { + return null + } + }) + if (feature) { + this.coordinate_ = evt.coordinate + this.feature_ = feature + let eventCallback = this.featureIdMap_.get(this.feature_.getId()) + if (eventCallback && eventCallback.startEvent) { + eventCallback.startEvent(evt) + } + return !!feature + } + }, + handleDragEvent: (evt) => { + const deltaX = evt.coordinate[0] - this.coordinate_[0] + const deltaY = evt.coordinate[1] - this.coordinate_[1] + + const geometry = this.feature_.getGeometry() + geometry.translate(deltaX, deltaY) + + this.coordinate_[0] = evt.coordinate[0] + this.coordinate_[1] = evt.coordinate[1] + + let eventCallback = this.featureIdMap_.get(this.feature_.getId()) + if (eventCallback && eventCallback.moveEvent) { + eventCallback.moveEvent(evt) + } + + }, + handleMoveEvent: (evt) => { + if (this.cursor_) { + const map = evt.map + const feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { + return feature + }) + const element = evt.map.getTargetElement() + if (feature) { + if (element.style.cursor != this.cursor_) { + this.previousCursor_ = element.style.cursor + element.style.cursor = this.cursor_ + } + } else if (this.previousCursor_ !== undefined) { + element.style.cursor = this.previousCursor_ + this.previousCursor_ = undefined + } + } + }, + handleUpEvent: (evt) => { + let eventCallback = this.featureIdMap_.get(this.feature_.getId()) + if (eventCallback && eventCallback.endEvent) { + evt.lonLat = toLonLat(this.feature_.getGeometry().getCoordinates()) + eventCallback.endEvent(evt) + } + this.coordinate_ = null + this.feature_ = null + return false + } + }) + + /** + * @type {import('../src/ol/coordinate.js').Coordinate} + * @private + */ + this.coordinate_ = null + + /** + * @type {string|undefined} + * @private + */ + this.cursor_ = 'pointer' + + /** + * @type {Feature} + * @private + */ + this.feature_ = null + + /** + * @type {string|undefined} + * @private + */ + this.previousCursor_ = undefined + + this.featureIdMap_ = new Map() + + this.addFeatureId = (id, moveEndEvent) => { + if (this.featureIdMap_.has(id)) { + return + } + this.featureIdMap_.set(id, moveEndEvent) + } + + this.removeFeatureId= (id) => { + this.featureIdMap_.delete(id) + } + + this.hasFeatureId= (id) => { + this.featureIdMap_.has(id) + } + } +} + +export default DragInteraction diff --git a/web/src/views/common/map/TransformLonLat.js b/web/src/views/common/map/TransformLonLat.js new file mode 100644 index 000000000..94161fc22 --- /dev/null +++ b/web/src/views/common/map/TransformLonLat.js @@ -0,0 +1,9 @@ +import { fromLonLat as projFromLonLat, toLonLat as projToLonLat } from 'ol/proj' +import gcoord from 'gcoord' + +export function fromLonLat(coordinate) { + return projFromLonLat(gcoord.transform(coordinate, gcoord.WGS84, gcoord.GCJ02)) +} +export function toLonLat(coordinate) { + return gcoord.transform(projToLonLat(coordinate), gcoord.GCJ02, gcoord.WGS84) +} diff --git a/web/src/views/map/index.vue b/web/src/views/map/index.vue new file mode 100755 index 000000000..537d43051 --- /dev/null +++ b/web/src/views/map/index.vue @@ -0,0 +1,433 @@ + + + + + diff --git a/web/src/views/map/queryTrace.vue b/web/src/views/map/queryTrace.vue new file mode 100755 index 000000000..d712eb8fc --- /dev/null +++ b/web/src/views/map/queryTrace.vue @@ -0,0 +1,105 @@ + + +