Przeglądaj źródła

补充视频导出防护配置、实时电子巡检配置相关接口

hanzhengyi 6 dni temu
rodzic
commit
69019bc422
16 zmienionych plików z 521 dodań i 10 usunięć
  1. 18 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/config/SasMultipartExceptionHandler.java
  2. 65 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasPatrolEventController.java
  3. 65 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasUsbEventController.java
  4. 44 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/enums/EventLevelEnum.java
  5. 14 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasMapService.java
  6. 26 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasPatrolEventService.java
  7. 26 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasUsbEventService.java
  8. 2 4
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasDeviceServiceImpl.java
  9. 2 3
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasEventTypeGroupServiceImpl.java
  10. 127 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasMapServiceImpl.java
  11. 30 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasPatrolEventServiceImpl.java
  12. 30 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasUsbEventServiceImpl.java
  13. 1 1
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/DeviceBatchAddRequest.java
  14. 1 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/DeviceConfigSaveRequest.java
  15. 2 2
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/DeviceImportTemplateVO.java
  16. 68 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/MapInfoVo.java

+ 18 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/config/SasMultipartExceptionHandler.java

@@ -0,0 +1,18 @@
+package com.usky.sas.config;
+
+import com.usky.common.core.exception.BusinessException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.multipart.MultipartException;
+
+/**
+ * 统一处理 SAS 模块的 multipart 相关异常,避免 500,返回明确提示
+ */
+@RestControllerAdvice(basePackages = "com.usky.sas.controller")
+public class SasMultipartExceptionHandler {
+
+    @ExceptionHandler(MultipartException.class)
+    public void handleMultipartException(MultipartException e) {
+        throw new BusinessException("请使用 multipart/form-data 方式上传文件,表单字段名为 file");
+    }
+}

+ 65 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasPatrolEventController.java

@@ -0,0 +1,65 @@
+package com.usky.sas.controller.web;
+
+import com.usky.common.core.bean.ApiResult;
+import com.usky.sas.service.SasPatrolEventService;
+import com.usky.sas.service.vo.MapSaveRequest;
+import com.usky.sas.service.vo.MapTreeItem;
+import com.usky.sas.service.vo.MapInfoVo;
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 实时电子巡检模块接口
+ *
+ * GET  /prod-api/service-sas/event/patrol/map/tree  获取地图树(仅 type=1008)
+ * GET  /prod-api/service-sas/event/patrol/map/info  获取地图详情(仅 type=1008)
+ * POST /prod-api/service-sas/event/patrol/map       新增地图(type 固定为 1008 实时电子巡检)
+ */
+@RestController
+@RequestMapping("/event/patrol")
+public class SasPatrolEventController {
+
+    @Autowired
+    private SasPatrolEventService sasPatrolEventService;
+
+    /**
+     * 新增地图(实时电子巡检模块专用,地图 type 固定为 1008)
+     */
+    @PostMapping("/map")
+    public ApiResult<AddMapResponse> addMap(@RequestBody MapSaveRequest request) {
+        String id = sasPatrolEventService.addMap(request);
+        AddMapResponse resp = new AddMapResponse();
+        resp.setId(id);
+        return ApiResult.success(resp);
+    }
+
+    /**
+     * 获取地图导航树形列表(仅实时电子巡检 type=1008 的地图)
+     */
+    @GetMapping("/map/tree")
+    public ApiResult<List<MapTreeItem>> getMapTree() {
+        return ApiResult.success(sasPatrolEventService.getMapTree());
+    }
+
+    /**
+     * 获取地图详情(仅实时电子巡检 type=1008 的地图,含背景图 URL、设备点位及设备信息)
+     */
+    @GetMapping("/map/info")
+    public ApiResult<MapInfoVo> getMapInfo(@RequestParam String mapId) {
+        MapInfoVo vo = sasPatrolEventService.getMapInfo(mapId);
+        return ApiResult.success(vo);
+    }
+
+    @Data
+    public static class AddMapResponse {
+        private String id;
+    }
+}

+ 65 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasUsbEventController.java

@@ -0,0 +1,65 @@
+package com.usky.sas.controller.web;
+
+import com.usky.common.core.bean.ApiResult;
+import com.usky.sas.service.SasUsbEventService;
+import com.usky.sas.service.vo.MapSaveRequest;
+import com.usky.sas.service.vo.MapTreeItem;
+import com.usky.sas.service.vo.MapInfoVo;
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 视频导出防护(USB)模块接口
+ *
+ * GET  /prod-api/service-sas/event/usb/map/tree   获取地图树(仅 type=1003)
+ * GET  /prod-api/service-sas/event/usb/map/info  获取地图详情(仅 type=1003)
+ * POST /prod-api/service-sas/event/usb/map       新增地图(type 固定为 1003 视频导出防护)
+ */
+@RestController
+@RequestMapping("/event/usb")
+public class SasUsbEventController {
+
+    @Autowired
+    private SasUsbEventService sasUsbEventService;
+
+    /**
+     * 新增地图(视频导出防护模块专用,地图 type 固定为 1003)
+     */
+    @PostMapping("/map")
+    public ApiResult<AddMapResponse> addMap(@RequestBody MapSaveRequest request) {
+        String id = sasUsbEventService.addMap(request);
+        AddMapResponse resp = new AddMapResponse();
+        resp.setId(id);
+        return ApiResult.success(resp);
+    }
+
+    /**
+     * 获取地图导航树形列表(仅视频导出防护 type=1003 的地图)
+     */
+    @GetMapping("/map/tree")
+    public ApiResult<List<MapTreeItem>> getMapTree() {
+        return ApiResult.success(sasUsbEventService.getMapTree());
+    }
+
+    /**
+     * 获取地图详情(仅视频导出防护 type=1003 的地图,含背景图 URL、设备点位及设备信息)
+     */
+    @GetMapping("/map/info")
+    public ApiResult<MapInfoVo> getMapInfo(@RequestParam String mapId) {
+        MapInfoVo vo = sasUsbEventService.getMapInfo(mapId);
+        return ApiResult.success(vo);
+    }
+
+    @Data
+    public static class AddMapResponse {
+        private String id;
+    }
+}

+ 44 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/enums/EventLevelEnum.java

@@ -0,0 +1,44 @@
+package com.usky.sas.enums;
+
+/**
+ * 事件等级编码枚举(与事件组 event_level、事件优先级配置一致)
+ * 1: 紧急, 2: 高, 3: 普通, 其他: 无
+ */
+public enum EventLevelEnum {
+
+    URGENT(1, "紧急"),
+    HIGH(2, "高"),
+    NORMAL(3, "普通"),
+    NONE(null, "无");
+
+    private final Integer code;
+    private final String name;
+
+    EventLevelEnum(Integer code, String name) {
+        this.code = code;
+        this.name = name;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * 根据编码获取显示名称,未匹配或 null 返回「无」
+     */
+    public static String getNameByCode(Integer code) {
+        if (code == null) {
+            return NONE.getName();
+        }
+        for (EventLevelEnum e : values()) {
+            if (e.code != null && e.code.equals(code)) {
+                return e.getName();
+            }
+        }
+        return NONE.getName();
+    }
+}

+ 14 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasMapService.java

@@ -9,6 +9,7 @@ import com.usky.sas.service.vo.MapPageRequest;
 import com.usky.sas.service.vo.MapSaveRequest;
 import com.usky.sas.service.vo.MapSaveWithDevicesRequest;
 import com.usky.sas.service.vo.MapTreeItem;
+import com.usky.sas.service.vo.MapInfoVo;
 
 public interface SasMapService extends CrudService<SasMaps> {
 
@@ -33,5 +34,18 @@ public interface SasMapService extends CrudService<SasMaps> {
      * 获取地图导航树形列表
      */
     java.util.List<MapTreeItem> getMapTree();
+
+    /**
+     * 按类型获取地图导航树形列表(如视频导出防护 type=1003)
+     */
+    java.util.List<MapTreeItem> getMapTreeByType(Integer type);
+
+    /**
+     * 获取地图详细信息(含背景图 URL、设备点位及设备信息、点位图标 URL)
+     *
+     * @param mapId 地图主键
+     * @return 地图详情,不存在则 null
+     */
+    MapInfoVo getMapInfo(String mapId);
 }
 

+ 26 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasPatrolEventService.java

@@ -2,9 +2,35 @@ package com.usky.sas.service;
 
 import com.usky.common.mybatis.core.CrudService;
 import com.usky.sas.domain.SasPatrolEvent;
+import com.usky.sas.service.vo.MapSaveRequest;
+import com.usky.sas.service.vo.MapTreeItem;
+import com.usky.sas.service.vo.MapInfoVo;
+
+import java.util.List;
 
 /**
  * 实时电子巡检事件服务接口
  */
 public interface SasPatrolEventService extends CrudService<SasPatrolEvent> {
+
+    /**
+     * 新增实时电子巡检模块下的地图,type 固定为 patrol(1008)
+     *
+     * @param request 地图保存参数(type 会被覆盖为 1008)
+     * @return 新建地图主键 id
+     */
+    String addMap(MapSaveRequest request);
+
+    /**
+     * 获取实时电子巡检模块的地图导航树形列表(仅 type=1008 的地图)
+     */
+    List<MapTreeItem> getMapTree();
+
+    /**
+     * 获取地图详情(仅当地图 type=1008 实时电子巡检时返回,否则返回 null)
+     *
+     * @param mapId 地图 id
+     * @return 地图详情(含背景图 URL、设备点位及设备信息),非巡检地图返回 null
+     */
+    MapInfoVo getMapInfo(String mapId);
 }

+ 26 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasUsbEventService.java

@@ -2,9 +2,35 @@ package com.usky.sas.service;
 
 import com.usky.common.mybatis.core.CrudService;
 import com.usky.sas.domain.SasUsbEvent;
+import com.usky.sas.service.vo.MapInfoVo;
+import com.usky.sas.service.vo.MapSaveRequest;
+import com.usky.sas.service.vo.MapTreeItem;
+
+import java.util.List;
 
 /**
  * USB事件服务接口
  */
 public interface SasUsbEventService extends CrudService<SasUsbEvent> {
+
+    /**
+     * 新增视频导出防护(USB)模块下的地图,type 固定为 usbalarm(1003)
+     *
+     * @param request 地图保存参数(type 会被覆盖为 1003)
+     * @return 新建地图主键 id
+     */
+    String addMap(MapSaveRequest request);
+
+    /**
+     * 获取视频导出防护(USB)模块的地图导航树形列表(仅 type=1003 的地图)
+     */
+    List<MapTreeItem> getMapTree();
+
+    /**
+     * 获取地图详情(仅当地图 type=1003 视频导出防护时返回,否则返回 null)
+     *
+     * @param mapId 地图 id
+     * @return 地图详情(含背景图 URL、设备点位及设备信息),非 USB 地图返回 null
+     */
+    MapInfoVo getMapInfo(String mapId);
 }

+ 2 - 4
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasDeviceServiceImpl.java

@@ -553,10 +553,9 @@ public class SasDeviceServiceImpl extends AbstractCrudService<SasDeviceMapper, S
         if (request == null
                 || request.getDeviceId() == null || request.getDeviceId().isEmpty()
                 || request.getDeviceType() == null
-                || request.getIpAddr() == null || request.getIpAddr().isEmpty()
                 || request.getPort() == null
                 || request.getChannels() == null || request.getChannels() <= 0) {
-            throw new BusinessException("批量新增设备参数不完整,设备编号、设备类型、IP、端口、通道数量为必填");
+            throw new BusinessException("批量新增设备参数不完整,设备编号、设备类型、端口、通道数量为必填");
         }
         int channels = request.getChannels();
         for (int ch = 0; ch < channels; ch++) {
@@ -611,9 +610,8 @@ public class SasDeviceServiceImpl extends AbstractCrudService<SasDeviceMapper, S
                 index++;
                 if (row.getDeviceType() == null
                         || row.getDeviceId() == null || row.getDeviceId().isEmpty()
-                        || row.getIpAddr() == null || row.getIpAddr().isEmpty()
                         || row.getPort() == null) {
-                    throw new BusinessException("第" + (index + 1) + "行数据导入失败,设备类型、设备编号、设备IP、端口为必填");
+                    throw new BusinessException("第" + (index + 1) + "行数据导入失败,设备类型、设备编号、端口为必填");
                 }
                 int channel = row.getChannel() != null ? row.getChannel() : 0;
                 LambdaQueryWrapper<SasDevice> wrapper = new LambdaQueryWrapper<>();

+ 2 - 3
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasEventTypeGroupServiceImpl.java

@@ -9,6 +9,7 @@ import com.usky.common.mybatis.core.AbstractCrudService;
 import com.usky.sas.domain.SasEventTypeGroup;
 import com.usky.sas.domain.SasSystemActivation;
 import com.usky.sas.enums.SystemTypeCodeEnum;
+import com.usky.sas.enums.EventLevelEnum;
 import com.usky.sas.mapper.SasEventTypeGroupMapper;
 import com.usky.sas.service.SasEventCodeService;
 import com.usky.sas.service.SasEventTypeGroupService;
@@ -75,9 +76,7 @@ public class SasEventTypeGroupServiceImpl extends AbstractCrudService<SasEventTy
             info.setDeviceTypeName(typeEnum.getMessage());
         }
 
-        if (group.getEventLevel() != null) {
-            info.setEventLevelName(String.valueOf(group.getEventLevel()));
-        }
+        info.setEventLevelName(EventLevelEnum.getNameByCode(group.getEventLevel()));
 
         if (StrUtil.isNotBlank(group.getEventCodes())) {
             List<Integer> codes = Arrays.stream(group.getEventCodes().split(","))

+ 127 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasMapServiceImpl.java

@@ -7,8 +7,14 @@ import com.usky.common.core.bean.CommonPage;
 import com.usky.common.mybatis.core.AbstractCrudService;
 import com.usky.sas.domain.SasMapDevice;
 import com.usky.sas.domain.SasMaps;
+import com.usky.sas.domain.SasDevice;
+import com.usky.sas.domain.SasPic;
+import com.usky.sas.enums.SystemTypeCodeEnum;
 import com.usky.sas.mapper.SasMapDeviceMapper;
 import com.usky.sas.mapper.SasMapsMapper;
+import com.usky.sas.mapper.SasPicMapper;
+import com.usky.sas.mapper.SasDeviceMapper;
+import com.usky.sas.common.util.GetIpUtils;
 import com.usky.sas.service.SasMapService;
 import com.usky.sas.service.vo.MapDeviceBindRequest;
 import com.usky.sas.service.vo.MapListItem;
@@ -16,7 +22,10 @@ import com.usky.sas.service.vo.MapPageRequest;
 import com.usky.sas.service.vo.MapSaveRequest;
 import com.usky.sas.service.vo.MapSaveWithDevicesRequest;
 import com.usky.sas.service.vo.MapTreeItem;
+import com.usky.sas.service.vo.MapInfoVo;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -37,6 +46,18 @@ public class SasMapServiceImpl extends AbstractCrudService<SasMapsMapper, SasMap
     @Autowired
     private SasMapDeviceMapper mapDeviceMapper;
 
+    @Autowired
+    private SasPicMapper sasPicMapper;
+
+    @Autowired
+    private SasDeviceMapper sasDeviceMapper;
+
+    @Value("${server.protocol:http}")
+    private String protocol;
+
+    @Value("${server.port:8080}")
+    private String port;
+
     @Override
     public CommonPage<MapListItem> page(MapPageRequest request) {
         IPage<SasMaps> page = new Page<>(request.getCurrent(), request.getSize());
@@ -308,6 +329,112 @@ public class SasMapServiceImpl extends AbstractCrudService<SasMapsMapper, SasMap
         return roots;
     }
 
+    @Override
+    public List<MapTreeItem> getMapTreeByType(Integer type) {
+        if (type == null) {
+            return Collections.emptyList();
+        }
+        LambdaQueryWrapper<SasMaps> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SasMaps::getType, type);
+        List<SasMaps> maps = this.list(wrapper);
+        if (maps == null || maps.isEmpty()) {
+            return Collections.emptyList();
+        }
+        Map<String, MapTreeItem> nodeMap = new HashMap<>();
+        for (SasMaps m : maps) {
+            MapTreeItem node = new MapTreeItem();
+            node.setId(m.getId());
+            node.setName(m.getName());
+            node.setType(m.getType());
+            node.setRemark(m.getRemark());
+            node.setParentId(m.getParentId());
+            node.setWidth(m.getWidth());
+            node.setHeight(m.getHeight());
+            node.setIsMask(m.getIsMask());
+            node.setBackImgId(m.getBackImgId());
+            node.setCreateTime(m.getCreateTime());
+            node.setUpdateTime(m.getUpdateTime());
+            nodeMap.put(m.getId(), node);
+        }
+        List<MapTreeItem> roots = new java.util.ArrayList<>();
+        for (SasMaps m : maps) {
+            MapTreeItem node = nodeMap.get(m.getId());
+            if (m.getParentId() == null || m.getParentId().isEmpty()) {
+                roots.add(node);
+            } else {
+                MapTreeItem parent = nodeMap.get(m.getParentId());
+                if (parent != null) {
+                    parent.getChildren().add(node);
+                } else {
+                    roots.add(node);
+                }
+            }
+        }
+        return roots;
+    }
+
+    @Override
+    public MapInfoVo getMapInfo(String mapId) {
+        SasMaps maps = getById(mapId);
+        if (maps == null) {
+            return null;
+        }
+        MapInfoVo vo = new MapInfoVo();
+        BeanUtils.copyProperties(maps, vo);
+        if (maps.getBackImgId() != null && !maps.getBackImgId().isEmpty()) {
+            SasPic pic = sasPicMapper.selectById(maps.getBackImgId());
+            if (pic != null) {
+                String baseUrl = protocol + "://" + GetIpUtils.getServerIP() + ":" + port;
+                String path = (pic.getUrl() != null ? pic.getUrl() : "") + (pic.getPath() != null ? pic.getPath() : "");
+                vo.setBackImgUrl(baseUrl + path);
+            }
+        }
+        LambdaQueryWrapper<SasMapDevice> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SasMapDevice::getMapId, mapId);
+        List<SasMapDevice> list = mapDeviceMapper.selectList(wrapper);
+        List<MapInfoVo.MapDeviceInfoVo> collect = list.stream().map(mapDevice -> {
+            MapInfoVo.MapDeviceInfoVo dvo = new MapInfoVo.MapDeviceInfoVo();
+            dvo.setId(mapDevice.getId());
+            dvo.setDeviceId(mapDevice.getDeviceId());
+            dvo.setMapId(mapDevice.getMapId());
+            dvo.setImgId(mapDevice.getImgId());
+            dvo.setType(mapDevice.getType());
+            dvo.setX(mapDevice.getX());
+            dvo.setY(mapDevice.getY());
+            dvo.setWidth(mapDevice.getWidth());
+            dvo.setHeight(mapDevice.getHeight());
+            dvo.setAngle(mapDevice.getAngle());
+            dvo.setText(mapDevice.getText());
+            dvo.setCreateTime(mapDevice.getCreateTime());
+            dvo.setUpdateTime(mapDevice.getUpdateTime());
+            SasDevice device = sasDeviceMapper.selectById(mapDevice.getDeviceId());
+            if (device != null) {
+                MapInfoVo.DeviceInfoVo deviceInfo = new MapInfoVo.DeviceInfoVo();
+                deviceInfo.setId(device.getId());
+                deviceInfo.setDeviceId(device.getDeviceId());
+                deviceInfo.setChannel(device.getChannel());
+                deviceInfo.setIpAddr(device.getIpAddr());
+                deviceInfo.setPort(device.getPort());
+                deviceInfo.setAddress(device.getAddress());
+                deviceInfo.setNote(device.getNote());
+                SystemTypeCodeEnum typeEnum = SystemTypeCodeEnum.getByCode(device.getDeviceType());
+                deviceInfo.setDeviceType(typeEnum != null ? typeEnum.getMessage() : null);
+                dvo.setDeviceInfo(deviceInfo);
+            }
+            if (mapDevice.getImgId() != null && !mapDevice.getImgId().isEmpty()) {
+                SasPic imgPic = sasPicMapper.selectById(mapDevice.getImgId());
+                if (imgPic != null) {
+                    String baseUrl = protocol + "://" + GetIpUtils.getServerIP() + ":" + port;
+                    String path = (imgPic.getUrl() != null ? imgPic.getUrl() : "") + (imgPic.getPath() != null ? imgPic.getPath() : "");
+                    dvo.setImgUrl(baseUrl + path);
+                }
+            }
+            return dvo;
+        }).collect(Collectors.toList());
+        vo.setDeviceList(collect);
+        return vo;
+    }
+
     /**
      * 递归删除地图及其子地图,同时删除绑定设备
      */

+ 30 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasPatrolEventServiceImpl.java

@@ -2,8 +2,15 @@ package com.usky.sas.service.impl;
 
 import com.usky.common.mybatis.core.AbstractCrudService;
 import com.usky.sas.domain.SasPatrolEvent;
+import com.usky.sas.enums.SystemTypeCodeEnum;
 import com.usky.sas.mapper.SasPatrolEventMapper;
+import com.usky.sas.service.SasMapService;
 import com.usky.sas.service.SasPatrolEventService;
+import com.usky.sas.service.vo.MapSaveRequest;
+import com.usky.sas.service.vo.MapTreeItem;
+import com.usky.sas.service.vo.MapInfoVo;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 /**
@@ -11,4 +18,27 @@ import org.springframework.stereotype.Service;
  */
 @Service
 public class SasPatrolEventServiceImpl extends AbstractCrudService<SasPatrolEventMapper, SasPatrolEvent> implements SasPatrolEventService {
+
+    @Autowired
+    private SasMapService sasMapService;
+
+    @Override
+    public String addMap(MapSaveRequest request) {
+        request.setType(SystemTypeCodeEnum.patrol.getCode());
+        return sasMapService.create(request);
+    }
+
+    @Override
+    public List<MapTreeItem> getMapTree() {
+        return sasMapService.getMapTreeByType(SystemTypeCodeEnum.patrol.getCode());
+    }
+
+    @Override
+    public MapInfoVo getMapInfo(String mapId) {
+        MapInfoVo vo = sasMapService.getMapInfo(mapId);
+        if (vo == null || vo.getType() == null || vo.getType() != SystemTypeCodeEnum.patrol.getCode()) {
+            return null;
+        }
+        return vo;
+    }
 }

+ 30 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasUsbEventServiceImpl.java

@@ -2,8 +2,15 @@ package com.usky.sas.service.impl;
 
 import com.usky.common.mybatis.core.AbstractCrudService;
 import com.usky.sas.domain.SasUsbEvent;
+import com.usky.sas.enums.SystemTypeCodeEnum;
 import com.usky.sas.mapper.SasUsbEventMapper;
+import com.usky.sas.service.SasMapService;
 import com.usky.sas.service.SasUsbEventService;
+import com.usky.sas.service.vo.MapSaveRequest;
+import com.usky.sas.service.vo.MapTreeItem;
+import com.usky.sas.service.vo.MapInfoVo;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 /**
@@ -11,4 +18,27 @@ import org.springframework.stereotype.Service;
  */
 @Service
 public class SasUsbEventServiceImpl extends AbstractCrudService<SasUsbEventMapper, SasUsbEvent> implements SasUsbEventService {
+
+    @Autowired
+    private SasMapService sasMapService;
+
+    @Override
+    public String addMap(MapSaveRequest request) {
+        request.setType(SystemTypeCodeEnum.usbalarm.getCode());
+        return sasMapService.create(request);
+    }
+
+    @Override
+    public List<MapTreeItem> getMapTree() {
+        return sasMapService.getMapTreeByType(SystemTypeCodeEnum.usbalarm.getCode());
+    }
+
+    @Override
+    public MapInfoVo getMapInfo(String mapId) {
+        MapInfoVo vo = sasMapService.getMapInfo(mapId);
+        if (vo == null || vo.getType() == null || vo.getType() != SystemTypeCodeEnum.usbalarm.getCode()) {
+            return null;
+        }
+        return vo;
+    }
 }

+ 1 - 1
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/DeviceBatchAddRequest.java

@@ -14,7 +14,7 @@ public class DeviceBatchAddRequest {
     /** 设备类型(必填,对应 SystemTypeCodeEnum.code) */
     private Integer deviceType;
 
-    /** 设备 IP(必填) */
+    /** 设备 IP(可选) */
     private String ipAddr;
 
     /** 设备端口(必填) */

+ 1 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/DeviceConfigSaveRequest.java

@@ -13,6 +13,7 @@ public class DeviceConfigSaveRequest {
 
     private Integer deviceType;
 
+    /** 设备 IP(可选) */
     private String ipAddr;
 
     private Integer port;

+ 2 - 2
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/DeviceImportTemplateVO.java

@@ -19,8 +19,8 @@ public class DeviceImportTemplateVO {
     @Excel(name = "设备编号(必填)")
     private String deviceId;
 
-    /** 设备 IP(必填) */
-    @Excel(name = "设备IP(必填)")
+    /** 设备 IP(可选) */
+    @Excel(name = "设备IP(可选)")
     private String ipAddr;
 
     /** 设备端口(必填) */

+ 68 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/MapInfoVo.java

@@ -0,0 +1,68 @@
+package com.usky.sas.service.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 地图详细信息(含背景图完整 URL、设备点位及设备信息、点位图标 URL)
+ */
+@Data
+public class MapInfoVo {
+
+    private String id;
+    private String name;
+    private Integer type;
+    private String remark;
+    private String parentId;
+    private Double width;
+    private Double height;
+    private Boolean isMask;
+    private String backImgId;
+    private LocalDateTime createTime;
+    private LocalDateTime updateTime;
+
+    /** 背景图完整访问 URL(protocol + host + port + pic.url/path) */
+    private String backImgUrl;
+
+    /** 地图下绑定的设备点位列表 */
+    private List<MapDeviceInfoVo> deviceList;
+
+    @Data
+    public static class MapDeviceInfoVo {
+        private String id;
+        private String deviceId;
+        private String mapId;
+        private String imgId;
+        private String type;
+        private BigDecimal x;
+        private BigDecimal y;
+        private Double width;
+        private Double height;
+        private Double angle;
+        private String text;
+        private LocalDateTime createTime;
+        private LocalDateTime updateTime;
+
+        /** 点位图标完整访问 URL */
+        private String imgUrl;
+
+        /** 绑定的设备详情(含设备类型名称) */
+        private DeviceInfoVo deviceInfo;
+    }
+
+    @Data
+    public static class DeviceInfoVo {
+        private String id;
+        private String deviceId;
+        private Integer channel;
+        /** 设备类型名称(如:视频安防监控) */
+        private String deviceType;
+        private String ipAddr;
+        private Integer port;
+        private String address;
+        private String note;
+    }
+}