Просмотр исходного кода

pms 组态图 图元绑定设备点位参数接口

zhangcl 10 часов назад
Родитель
Сommit
3cc61305b5
28 измененных файлов с 1604 добавлено и 0 удалено
  1. 4 0
      yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java
  2. 109 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeController.java
  3. 51 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/vo/IotWebtopoDeviceSvgnodePageReqVO.java
  4. 59 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/vo/IotWebtopoDeviceSvgnodeRespVO.java
  5. 40 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/vo/IotWebtopoDeviceSvgnodeSaveReqVO.java
  6. 177 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/IotWebtopoProjectController.java
  7. 29 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoDevicePointParamsRespVO.java
  8. 35 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoDeviceRespVO.java
  9. 48 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoProjectPageReqVO.java
  10. 60 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoProjectRespVO.java
  11. 44 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoProjectSaveReqVO.java
  12. 93 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/IotWebtopoProjectDeviceController.java
  13. 39 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/vo/IotWebtopoProjectDevicePageReqVO.java
  14. 43 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/vo/IotWebtopoProjectDeviceRespVO.java
  15. 28 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/vo/IotWebtopoProjectDeviceSaveReqVO.java
  16. 3 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotDeviceRespVO.java
  17. 66 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeDO.java
  18. 62 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotwebtopoproject/IotWebtopoProjectDO.java
  19. 50 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotwebtopoprojectdevice/IotWebtopoProjectDeviceDO.java
  20. 33 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeMapper.java
  21. 32 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotwebtopoproject/IotWebtopoProjectMapper.java
  22. 29 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotwebtopoprojectdevice/IotWebtopoProjectDeviceMapper.java
  23. 55 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeService.java
  24. 112 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeServiceImpl.java
  25. 55 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoproject/IotWebtopoProjectService.java
  26. 122 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoproject/IotWebtopoProjectServiceImpl.java
  27. 55 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoprojectdevice/IotWebtopoProjectDeviceService.java
  28. 71 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoprojectdevice/IotWebtopoProjectDeviceServiceImpl.java

+ 4 - 0
yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java

@@ -109,4 +109,8 @@ public interface ErrorCodeConstant{
     ErrorCode IOT_OPERATION_MEETING_DETAIL_NOT_EXISTS = new ErrorCode(282, "生产运营会明细不存在");
     ErrorCode IOT_OPERATION_MEETING_ATTRS_NOT_EXISTS = new ErrorCode(284, "专业公司工作量扩展属性不存在");
     ErrorCode IOT_DEVICE_MAX_RUN_LOG_NOT_EXISTS = new ErrorCode(285, "设备运行数据记录最大值不存在");
+    ErrorCode IOT_WEBTOPO_PROJECT_NOT_EXISTS = new ErrorCode(286, "组态项目列不存在");
+    ErrorCode IOT_WEBTOPO_DEVICE_SVGNODE_NOT_EXISTS = new ErrorCode(287, "组态-svg与设备绑定不存在");
+    ErrorCode IOT_WEBTOPO_PROJECT_DEVICE_NOT_EXISTS = new ErrorCode(288, "组态项目关联设备不存在");
+    ErrorCode IOT_WEBTOPO_DEVICE_SVGNODE_EXISTS = new ErrorCode(287, "组态-svg与设备绑定已经存在");
 }

+ 109 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeController.java

@@ -0,0 +1,109 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode;
+
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodePageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodeRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodeSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopodevicesvgnode.IotWebtopoDeviceSvgnodeDO;
+import cn.iocoder.yudao.module.pms.service.iotwebtopodevicesvgnode.IotWebtopoDeviceSvgnodeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 组态-svg与设备绑定")
+@RestController
+@RequestMapping("/pms/iot-webtopo-device-svgnode")
+@Validated
+public class IotWebtopoDeviceSvgnodeController {
+
+    @Resource
+    private IotWebtopoDeviceSvgnodeService iotWebtopoDeviceSvgnodeService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建组态-svg与设备绑定")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-device-svgnode:create')")
+    public CommonResult<Long> createIotWebtopoDeviceSvgnode(@Valid @RequestBody IotWebtopoDeviceSvgnodeSaveReqVO createReqVO) {
+        return success(iotWebtopoDeviceSvgnodeService.createIotWebtopoDeviceSvgnode(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新组态-svg与设备绑定")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-device-svgnode:update')")
+    public CommonResult<Boolean> updateIotWebtopoDeviceSvgnode(@Valid @RequestBody IotWebtopoDeviceSvgnodeSaveReqVO updateReqVO) {
+        iotWebtopoDeviceSvgnodeService.updateIotWebtopoDeviceSvgnode(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除组态-svg与设备绑定")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-device-svgnode:delete')")
+    public CommonResult<Boolean> deleteIotWebtopoDeviceSvgnode(@RequestParam("id") Long id) {
+        iotWebtopoDeviceSvgnodeService.deleteIotWebtopoDeviceSvgnode(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得组态-svg与设备绑定")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-device-svgnode:query')")
+    public CommonResult<IotWebtopoDeviceSvgnodeRespVO> getIotWebtopoDeviceSvgnode(@RequestParam("id") Long id) {
+        IotWebtopoDeviceSvgnodeDO iotWebtopoDeviceSvgnode = iotWebtopoDeviceSvgnodeService.getIotWebtopoDeviceSvgnode(id);
+        return success(BeanUtils.toBean(iotWebtopoDeviceSvgnode, IotWebtopoDeviceSvgnodeRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得组态-svg与设备绑定分页")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-device-svgnode:query')")
+    public CommonResult<PageResult<IotWebtopoDeviceSvgnodeRespVO>> getIotWebtopoDeviceSvgnodePage(@Valid IotWebtopoDeviceSvgnodePageReqVO pageReqVO) {
+        PageResult<IotWebtopoDeviceSvgnodeDO> pageResult = iotWebtopoDeviceSvgnodeService.getIotWebtopoDeviceSvgnodePage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, IotWebtopoDeviceSvgnodeRespVO.class));
+    }
+
+    @GetMapping("/deviceSvgNodes")
+    @Operation(summary = "获得组态-svg与设备绑定列表")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-device-svgnode:query')")
+    public CommonResult<List<IotWebtopoDeviceSvgnodeRespVO>> deviceSvgNodes(@Valid IotWebtopoDeviceSvgnodePageReqVO pageReqVO) {
+        List<IotWebtopoDeviceSvgnodeRespVO> resultDeviceSvgNodes = new ArrayList<>();
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        PageResult<IotWebtopoDeviceSvgnodeDO> pageResult = iotWebtopoDeviceSvgnodeService.getIotWebtopoDeviceSvgnodePage(pageReqVO);
+        if (ObjUtil.isNotEmpty(pageResult)) {
+            List<IotWebtopoDeviceSvgnodeDO> deviceSvgNodes = pageResult.getList();
+            return success(BeanUtils.toBean(deviceSvgNodes, IotWebtopoDeviceSvgnodeRespVO.class));
+        }
+        return success(resultDeviceSvgNodes);
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出组态-svg与设备绑定 Excel")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-device-svgnode:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportIotWebtopoDeviceSvgnodeExcel(@Valid IotWebtopoDeviceSvgnodePageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<IotWebtopoDeviceSvgnodeDO> list = iotWebtopoDeviceSvgnodeService.getIotWebtopoDeviceSvgnodePage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "组态-svg与设备绑定.xls", "数据", IotWebtopoDeviceSvgnodeRespVO.class,
+                        BeanUtils.toBean(list, IotWebtopoDeviceSvgnodeRespVO.class));
+    }
+
+}

+ 51 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/vo/IotWebtopoDeviceSvgnodePageReqVO.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 组态-svg与设备绑定分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotWebtopoDeviceSvgnodePageReqVO extends PageParam {
+
+    @Schema(description = "部门id", example = "28516")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "28700")
+    private Long projectId;
+
+    @Schema(description = "设备id", example = "10537")
+    private Long deviceId;
+
+    @Schema(description = "节点id", example = "3464")
+    private String svgNodeId;
+
+    @Schema(description = "节点属性")
+    private String svgNodeProp;
+
+    @Schema(description = "设备属性")
+    private String deviceProp;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "你猜")
+    private String remark;
+
+    @Schema(description = "状态", example = "1")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 59 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/vo/IotWebtopoDeviceSvgnodeRespVO.java

@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 组态-svg与设备绑定 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotWebtopoDeviceSvgnodeRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "2878")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "部门id", example = "28516")
+    @ExcelProperty("部门id")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "28700")
+    @ExcelProperty("项目id")
+    private Long projectId;
+
+    @Schema(description = "设备id", example = "10537")
+    @ExcelProperty("设备id")
+    private Long deviceId;
+
+    @Schema(description = "节点id", example = "3464")
+    @ExcelProperty("节点id")
+    private String svgNodeId;
+
+    @Schema(description = "节点属性")
+    @ExcelProperty("节点属性")
+    private String svgNodeProp;
+
+    @Schema(description = "设备属性")
+    @ExcelProperty("设备属性")
+    private String deviceProp;
+
+    @Schema(description = "排序值")
+    @ExcelProperty("排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "你猜")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "状态", example = "1")
+    @ExcelProperty("状态")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 40 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopodevicesvgnode/vo/IotWebtopoDeviceSvgnodeSaveReqVO.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 组态-svg与设备绑定新增/修改 Request VO")
+@Data
+public class IotWebtopoDeviceSvgnodeSaveReqVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "2878")
+    private Long id;
+
+    @Schema(description = "部门id", example = "28516")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "28700")
+    private Long projectId;
+
+    @Schema(description = "设备id", example = "10537")
+    private Long deviceId;
+
+    @Schema(description = "节点id", example = "3464")
+    private String svgNodeId;
+
+    @Schema(description = "节点属性")
+    private String svgNodeProp;
+
+    @Schema(description = "设备属性")
+    private String deviceProp;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "你猜")
+    private String remark;
+
+    @Schema(description = "状态", example = "1")
+    private Integer status;
+
+}

+ 177 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/IotWebtopoProjectController.java

@@ -0,0 +1,177 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.pms.ThingsModelDTO;
+import cn.iocoder.yudao.module.pms.controller.admin.TableDataInfo;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo.*;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDevicePageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoproject.IotWebtopoProjectDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoprojectdevice.IotWebtopoProjectDeviceDO;
+import cn.iocoder.yudao.module.pms.service.IotDeviceService;
+import cn.iocoder.yudao.module.pms.service.iotwebtopoproject.IotWebtopoProjectService;
+import cn.iocoder.yudao.module.pms.service.iotwebtopoprojectdevice.IotWebtopoProjectDeviceService;
+import com.alibaba.fastjson.JSON;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.client.RestTemplate;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 组态项目列")
+@RestController
+@RequestMapping("/pms/iot-webtopo-project")
+@Validated
+public class IotWebtopoProjectController {
+
+    @Resource
+    private IotWebtopoProjectService iotWebtopoProjectService;
+
+    @Resource
+    private IotWebtopoProjectDeviceService iotWebtopoProjectDeviceService;
+
+    @Resource
+    private IotDeviceService iotDeviceService;
+
+    @Value("${yanfan.url}")
+    private String yanfanUrl;
+
+    @Resource
+    private RestTemplate restTemplate;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建组态项目列")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project:create')")
+    public CommonResult<Long> createIotWebtopoProject(@Valid @RequestBody IotWebtopoProjectSaveReqVO createReqVO) {
+        return success(iotWebtopoProjectService.createIotWebtopoProject(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新组态项目列")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project:update')")
+    public CommonResult<Boolean> updateIotWebtopoProject(@Valid @RequestBody IotWebtopoProjectSaveReqVO updateReqVO) {
+        iotWebtopoProjectService.updateIotWebtopoProject(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除组态项目列")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project:delete')")
+    public CommonResult<Boolean> deleteIotWebtopoProject(@RequestParam("id") Long id) {
+        iotWebtopoProjectService.deleteIotWebtopoProject(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得组态项目详情")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project:query')")
+    public CommonResult<IotWebtopoProjectRespVO> getIotWebtopoProject(@RequestParam("id") Long id) {
+        IotWebtopoProjectDO iotWebtopoProject = iotWebtopoProjectService.getIotWebtopoProject(id);
+        return success(buildWebtopProject(iotWebtopoProject));
+    }
+
+    /**
+     * 查询对应的 组态项目信息
+     * @param project
+     * @return
+     */
+    private IotWebtopoProjectRespVO buildWebtopProject(IotWebtopoProjectDO project) {
+        if (ObjUtil.isEmpty(project)) {
+            return new IotWebtopoProjectRespVO();
+        }
+        IotWebtopoProjectRespVO projectVO = BeanUtils.toBean(project, IotWebtopoProjectRespVO.class);
+        // 查询组态项目对应的设备列表
+        IotWebtopoProjectDevicePageReqVO pageReqVO = new IotWebtopoProjectDevicePageReqVO();
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        pageReqVO.setProjectId(project.getId());
+        PageResult<IotWebtopoProjectDeviceDO> pageDevices = iotWebtopoProjectDeviceService.getIotWebtopoProjectDevicePage(pageReqVO);
+        if (ObjUtil.isNotEmpty(pageDevices)) {
+            List<IotWebtopoProjectDeviceDO> projectDevices = pageDevices.getList();
+            List<IotWebtopoDeviceRespVO> devices = new ArrayList<>();
+            Set<Long> deviceIds = new HashSet<>();
+            if (CollUtil.isNotEmpty(projectDevices)) {
+                projectDevices.forEach(pd -> {
+                    deviceIds.add(pd.getDeviceId());
+                });
+                // 批量查询所有设备详情
+                if (CollUtil.isNotEmpty(deviceIds)) {
+                    // todo 查询IOT平台获取每个设备的所有 点位参数 列表
+                    Map<Long, IotDeviceRespVO> devicePair = iotDeviceService.getDeviceMap(new ArrayList<>(deviceIds));
+                    if (CollUtil.isNotEmpty(devicePair)) {
+                        devicePair.forEach((deviceId, device) -> {
+                            // 查询包含 yanfan 数采设备id 的设备
+                            Long yfDeviceId = device.getYfDeviceId();
+                            List<IotWebtopoDevicePointParamsRespVO> params = new ArrayList<>();
+                            if (ObjUtil.isNotEmpty(yfDeviceId)) {
+                                TableDataInfo tableDataInfo = restTemplate.getForObject(yanfanUrl + "/prod-api/iot/device/listThingsModel?deviceId=" + yfDeviceId + "&pageNum=1&pageSize=200", TableDataInfo.class);
+                                if (ObjUtil.isNotEmpty(tableDataInfo)) {
+                                    List<ThingsModelDTO> thingsModel = JSON.parseArray(JSON.toJSONString(tableDataInfo.getRows()), ThingsModelDTO.class);
+                                    if (CollUtil.isNotEmpty(thingsModel)) {
+                                        thingsModel.forEach(model -> {
+                                            IotWebtopoDevicePointParamsRespVO tempParam = new IotWebtopoDevicePointParamsRespVO();
+                                            tempParam.setParamCode(model.getIdentifier());
+                                            tempParam.setParamName(model.getModelName());
+                                            tempParam.setParamUnit(model.getUnit());
+                                            params.add(tempParam);
+                                        });
+                                    }
+                                }
+                            }
+                            IotWebtopoDeviceRespVO tempDevice = new IotWebtopoDeviceRespVO();
+                            tempDevice.setId(device.getId());
+                            tempDevice.setDeviceName(device.getDeviceName());
+                            tempDevice.setDeviceCode(device.getDeviceCode());
+                            tempDevice.setPointParams(params);
+                            devices.add(tempDevice);
+                        });
+                        projectVO.setLinkedDevices(devices);
+                    }
+                }
+            }
+        }
+        return projectVO;
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得组态项目列分页")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project:query')")
+    public CommonResult<PageResult<IotWebtopoProjectRespVO>> getIotWebtopoProjectPage(@Valid IotWebtopoProjectPageReqVO pageReqVO) {
+        PageResult<IotWebtopoProjectDO> pageResult = iotWebtopoProjectService.getIotWebtopoProjectPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, IotWebtopoProjectRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出组态项目列 Excel")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportIotWebtopoProjectExcel(@Valid IotWebtopoProjectPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<IotWebtopoProjectDO> list = iotWebtopoProjectService.getIotWebtopoProjectPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "组态项目列.xls", "数据", IotWebtopoProjectRespVO.class,
+                        BeanUtils.toBean(list, IotWebtopoProjectRespVO.class));
+    }
+
+}

+ 29 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoDevicePointParamsRespVO.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 设备数采点位参数 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotWebtopoDevicePointParamsRespVO {
+
+    @Schema(description = "点位名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("点位名称")
+    private String paramName;
+
+    @Schema(description = "点位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
+    @ExcelProperty("点位编码")
+    private String paramCode;
+
+    @Schema(description = "点位参数值", requiredMode = Schema.RequiredMode.REQUIRED, example = "8581")
+    private String paramValue;
+
+    @Schema(description = "点位参数值 单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "H")
+    @ExcelProperty("点位参数值 单位")
+    private String paramUnit;
+
+
+}

+ 35 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoDeviceRespVO.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 设备台账 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotWebtopoDeviceRespVO {
+
+    @Schema(description = "设备id 主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "6797")
+    @ExcelProperty("设备id 主键id")
+    private Long id;
+
+    @Schema(description = "资产编码", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("设备编码")
+    private String deviceCode;
+
+    @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "空压机")
+    @ExcelProperty("设备名称")
+    private String deviceName;
+
+    @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "sg")
+    @ExcelProperty("设备状态")
+    private String deviceStatus;
+
+    @Schema(description = "设备点位参数列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
+    @ExcelProperty("设备点位参数列表")
+    private List<IotWebtopoDevicePointParamsRespVO> pointParams;
+
+}

+ 48 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoProjectPageReqVO.java

@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 组态项目列分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotWebtopoProjectPageReqVO extends PageParam {
+
+    @Schema(description = "部门id", example = "15434")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "14584")
+    private Long projectId;
+
+    @Schema(description = "项目名称", example = "赵六")
+    private String projectName;
+
+    @Schema(description = "缩略图")
+    private String thumbnail;
+
+    @Schema(description = "数据模型")
+    private String dataModel;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态", example = "2")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 60 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoProjectRespVO.java

@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo;
+
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 组态项目列 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotWebtopoProjectRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23657")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "部门id", example = "15434")
+    @ExcelProperty("部门id")
+    private Long deptId;
+
+    @Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14584")
+    @ExcelProperty("项目id")
+    private Long projectId;
+
+    @Schema(description = "项目名称", example = "赵六")
+    @ExcelProperty("项目名称")
+    private String projectName;
+
+    @Schema(description = "缩略图")
+    @ExcelProperty("缩略图")
+    private String thumbnail;
+
+    @Schema(description = "数据模型")
+    @ExcelProperty("数据模型")
+    private String dataModel;
+
+    @Schema(description = "排序值")
+    @ExcelProperty("排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "状态", example = "2")
+    @ExcelProperty("状态")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "设备列表", example = "2")
+    @ExcelProperty("设备列表")
+    private List<IotWebtopoDeviceRespVO> linkedDevices;
+}

+ 44 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoproject/vo/IotWebtopoProjectSaveReqVO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 组态项目列新增/修改 Request VO")
+@Data
+public class IotWebtopoProjectSaveReqVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23657")
+    private Long id;
+
+    @Schema(description = "部门id", example = "15434")
+    private Long deptId;
+
+    @Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14584")
+    private Long projectId;
+
+    @Schema(description = "项目名称", example = "赵六")
+    private String projectName;
+
+    @Schema(description = "缩略图")
+    private String thumbnail;
+
+    @Schema(description = "数据模型")
+    private String dataModel;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态", example = "2")
+    private Integer status;
+
+    /**
+     * 扩展字段
+     */
+    @Schema(description = "已经绑定的设备id列表", example = "2,3")
+    private List<Long> linkedDeviceIds;
+}

+ 93 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/IotWebtopoProjectDeviceController.java

@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDevicePageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDeviceRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDeviceSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoprojectdevice.IotWebtopoProjectDeviceDO;
+import cn.iocoder.yudao.module.pms.service.iotwebtopoprojectdevice.IotWebtopoProjectDeviceService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 组态项目关联设备")
+@RestController
+@RequestMapping("/pms/iot-webtopo-project-device")
+@Validated
+public class IotWebtopoProjectDeviceController {
+
+    @Resource
+    private IotWebtopoProjectDeviceService iotWebtopoProjectDeviceService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建组态项目关联设备")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project-device:create')")
+    public CommonResult<Long> createIotWebtopoProjectDevice(@Valid @RequestBody IotWebtopoProjectDeviceSaveReqVO createReqVO) {
+        return success(iotWebtopoProjectDeviceService.createIotWebtopoProjectDevice(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新组态项目关联设备")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project-device:update')")
+    public CommonResult<Boolean> updateIotWebtopoProjectDevice(@Valid @RequestBody IotWebtopoProjectDeviceSaveReqVO updateReqVO) {
+        iotWebtopoProjectDeviceService.updateIotWebtopoProjectDevice(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除组态项目关联设备")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project-device:delete')")
+    public CommonResult<Boolean> deleteIotWebtopoProjectDevice(@RequestParam("id") Long id) {
+        iotWebtopoProjectDeviceService.deleteIotWebtopoProjectDevice(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得组态项目关联设备")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project-device:query')")
+    public CommonResult<IotWebtopoProjectDeviceRespVO> getIotWebtopoProjectDevice(@RequestParam("id") Long id) {
+        IotWebtopoProjectDeviceDO iotWebtopoProjectDevice = iotWebtopoProjectDeviceService.getIotWebtopoProjectDevice(id);
+        return success(BeanUtils.toBean(iotWebtopoProjectDevice, IotWebtopoProjectDeviceRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得组态项目关联设备分页")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project-device:query')")
+    public CommonResult<PageResult<IotWebtopoProjectDeviceRespVO>> getIotWebtopoProjectDevicePage(@Valid IotWebtopoProjectDevicePageReqVO pageReqVO) {
+        PageResult<IotWebtopoProjectDeviceDO> pageResult = iotWebtopoProjectDeviceService.getIotWebtopoProjectDevicePage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, IotWebtopoProjectDeviceRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出组态项目关联设备 Excel")
+    @PreAuthorize("@ss.hasPermission('pms:iot-webtopo-project-device:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportIotWebtopoProjectDeviceExcel(@Valid IotWebtopoProjectDevicePageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<IotWebtopoProjectDeviceDO> list = iotWebtopoProjectDeviceService.getIotWebtopoProjectDevicePage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "组态项目关联设备.xls", "数据", IotWebtopoProjectDeviceRespVO.class,
+                        BeanUtils.toBean(list, IotWebtopoProjectDeviceRespVO.class));
+    }
+
+}

+ 39 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/vo/IotWebtopoProjectDevicePageReqVO.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 组态项目关联设备分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotWebtopoProjectDevicePageReqVO extends PageParam {
+
+    @Schema(description = "部门id", example = "26451")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "4299")
+    private Long projectId;
+
+    @Schema(description = "设备id", example = "8042")
+    private Long deviceId;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态", example = "1")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 43 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/vo/IotWebtopoProjectDeviceRespVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 组态项目关联设备 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotWebtopoProjectDeviceRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20359")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "部门id", example = "26451")
+    @ExcelProperty("部门id")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "4299")
+    @ExcelProperty("项目id")
+    private Long projectId;
+
+    @Schema(description = "设备id", example = "8042")
+    @ExcelProperty("设备id")
+    private Long deviceId;
+
+    @Schema(description = "备注", example = "随便")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "状态", example = "1")
+    @ExcelProperty("状态")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 28 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotwebtopoprojectdevice/vo/IotWebtopoProjectDeviceSaveReqVO.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 组态项目关联设备新增/修改 Request VO")
+@Data
+public class IotWebtopoProjectDeviceSaveReqVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20359")
+    private Long id;
+
+    @Schema(description = "部门id", example = "26451")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "4299")
+    private Long projectId;
+
+    @Schema(description = "设备id", example = "8042")
+    private Long deviceId;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态", example = "1")
+    private Integer status;
+
+}

+ 3 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotDeviceRespVO.java

@@ -248,6 +248,9 @@ public class IotDeviceRespVO {
     @Schema(description = "保养/维修项关联的设备bom物料列表")
     private List<IotDeviceMaterialRespVO> deviceBomMaterials;
 
+    @Schema(description = "yanfan设备id")
+    private Long yfDeviceId;
+
     @Schema(description = "编码分类")
     private String yfClass;
 

+ 66 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeDO.java

@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopodevicesvgnode;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * 组态-svg与设备绑定 DO
+ *
+ * @author ruiqi
+ */
+@TableName("rq_iot_webtopo_device_svgnode")
+@KeySequence("rq_iot_webtopo_device_svgnode_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotWebtopoDeviceSvgnodeDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 部门id
+     */
+    private Long deptId;
+    /**
+     * 项目id
+     */
+    private Long projectId;
+    /**
+     * 设备id
+     */
+    private Long deviceId;
+    /**
+     * 节点id
+     */
+    private String svgNodeId;
+    /**
+     * 节点属性
+     */
+    private String svgNodeProp;
+    /**
+     * 设备属性
+     */
+    private String deviceProp;
+    /**
+     * 排序值
+     */
+    private Integer sort;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 状态
+     */
+    private Integer status;
+
+}

+ 62 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotwebtopoproject/IotWebtopoProjectDO.java

@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoproject;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * 组态项目列 DO
+ *
+ * @author ruiqi
+ */
+@TableName("rq_iot_webtopo_project")
+@KeySequence("rq_iot_webtopo_project_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotWebtopoProjectDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 部门id
+     */
+    private Long deptId;
+    /**
+     * 项目id
+     */
+    private Long projectId;
+    /**
+     * 项目名称
+     */
+    private String projectName;
+    /**
+     * 缩略图
+     */
+    private String thumbnail;
+    /**
+     * 数据模型
+     */
+    private String dataModel;
+    /**
+     * 排序值
+     */
+    private Integer sort;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 状态
+     */
+    private Integer status;
+
+}

+ 50 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotwebtopoprojectdevice/IotWebtopoProjectDeviceDO.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoprojectdevice;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * 组态项目关联设备 DO
+ *
+ * @author ruiqi
+ */
+@TableName("rq_iot_webtopo_project_device")
+@KeySequence("rq_iot_webtopo_project_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotWebtopoProjectDeviceDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 部门id
+     */
+    private Long deptId;
+    /**
+     * 项目id
+     */
+    private Long projectId;
+    /**
+     * 设备id
+     */
+    private Long deviceId;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 状态
+     */
+    private Integer status;
+
+}

+ 33 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeMapper.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.pms.dal.mysql.iotwebtopodevicesvgnode;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodePageReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopodevicesvgnode.IotWebtopoDeviceSvgnodeDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 组态-svg与设备绑定 Mapper
+ *
+ * @author ruiqi
+ */
+@Mapper
+public interface IotWebtopoDeviceSvgnodeMapper extends BaseMapperX<IotWebtopoDeviceSvgnodeDO> {
+
+    default PageResult<IotWebtopoDeviceSvgnodeDO> selectPage(IotWebtopoDeviceSvgnodePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<IotWebtopoDeviceSvgnodeDO>()
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getProjectId, reqVO.getProjectId())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getDeviceId, reqVO.getDeviceId())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getSvgNodeId, reqVO.getSvgNodeId())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getSvgNodeProp, reqVO.getSvgNodeProp())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getDeviceProp, reqVO.getDeviceProp())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getSort, reqVO.getSort())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(IotWebtopoDeviceSvgnodeDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(IotWebtopoDeviceSvgnodeDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(IotWebtopoDeviceSvgnodeDO::getId));
+    }
+
+}

+ 32 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotwebtopoproject/IotWebtopoProjectMapper.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.pms.dal.mysql.iotwebtopoproject;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo.IotWebtopoProjectPageReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoproject.IotWebtopoProjectDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 组态项目列 Mapper
+ *
+ * @author ruiqi
+ */
+@Mapper
+public interface IotWebtopoProjectMapper extends BaseMapperX<IotWebtopoProjectDO> {
+
+    default PageResult<IotWebtopoProjectDO> selectPage(IotWebtopoProjectPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<IotWebtopoProjectDO>()
+                .eqIfPresent(IotWebtopoProjectDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(IotWebtopoProjectDO::getProjectId, reqVO.getProjectId())
+                .likeIfPresent(IotWebtopoProjectDO::getProjectName, reqVO.getProjectName())
+                .eqIfPresent(IotWebtopoProjectDO::getThumbnail, reqVO.getThumbnail())
+                .eqIfPresent(IotWebtopoProjectDO::getDataModel, reqVO.getDataModel())
+                .eqIfPresent(IotWebtopoProjectDO::getSort, reqVO.getSort())
+                .eqIfPresent(IotWebtopoProjectDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(IotWebtopoProjectDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(IotWebtopoProjectDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(IotWebtopoProjectDO::getId));
+    }
+
+}

+ 29 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotwebtopoprojectdevice/IotWebtopoProjectDeviceMapper.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.pms.dal.mysql.iotwebtopoprojectdevice;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDevicePageReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoprojectdevice.IotWebtopoProjectDeviceDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 组态项目关联设备 Mapper
+ *
+ * @author ruiqi
+ */
+@Mapper
+public interface IotWebtopoProjectDeviceMapper extends BaseMapperX<IotWebtopoProjectDeviceDO> {
+
+    default PageResult<IotWebtopoProjectDeviceDO> selectPage(IotWebtopoProjectDevicePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<IotWebtopoProjectDeviceDO>()
+                .eqIfPresent(IotWebtopoProjectDeviceDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(IotWebtopoProjectDeviceDO::getProjectId, reqVO.getProjectId())
+                .eqIfPresent(IotWebtopoProjectDeviceDO::getDeviceId, reqVO.getDeviceId())
+                .eqIfPresent(IotWebtopoProjectDeviceDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(IotWebtopoProjectDeviceDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(IotWebtopoProjectDeviceDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(IotWebtopoProjectDeviceDO::getId));
+    }
+
+}

+ 55 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.pms.service.iotwebtopodevicesvgnode;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodePageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodeSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopodevicesvgnode.IotWebtopoDeviceSvgnodeDO;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 组态-svg与设备绑定 Service 接口
+ *
+ * @author ruiqi
+ */
+public interface IotWebtopoDeviceSvgnodeService {
+
+    /**
+     * 创建组态-svg与设备绑定
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createIotWebtopoDeviceSvgnode(@Valid IotWebtopoDeviceSvgnodeSaveReqVO createReqVO);
+
+    /**
+     * 更新组态-svg与设备绑定
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateIotWebtopoDeviceSvgnode(@Valid IotWebtopoDeviceSvgnodeSaveReqVO updateReqVO);
+
+    /**
+     * 删除组态-svg与设备绑定
+     *
+     * @param id 编号
+     */
+    void deleteIotWebtopoDeviceSvgnode(Long id);
+
+    /**
+     * 获得组态-svg与设备绑定
+     *
+     * @param id 编号
+     * @return 组态-svg与设备绑定
+     */
+    IotWebtopoDeviceSvgnodeDO getIotWebtopoDeviceSvgnode(Long id);
+
+    /**
+     * 获得组态-svg与设备绑定分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 组态-svg与设备绑定分页
+     */
+    PageResult<IotWebtopoDeviceSvgnodeDO> getIotWebtopoDeviceSvgnodePage(IotWebtopoDeviceSvgnodePageReqVO pageReqVO);
+}

+ 112 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopodevicesvgnode/IotWebtopoDeviceSvgnodeServiceImpl.java

@@ -0,0 +1,112 @@
+package cn.iocoder.yudao.module.pms.service.iotwebtopodevicesvgnode;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodePageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopodevicesvgnode.vo.IotWebtopoDeviceSvgnodeSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopodevicesvgnode.IotWebtopoDeviceSvgnodeDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotwebtopodevicesvgnode.IotWebtopoDeviceSvgnodeMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_WEBTOPO_DEVICE_SVGNODE_EXISTS;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_WEBTOPO_DEVICE_SVGNODE_NOT_EXISTS;
+
+/**
+ * 组态-svg与设备绑定 Service 实现类
+ *
+ * @author ruiqi
+ */
+@Service
+@Validated
+public class IotWebtopoDeviceSvgnodeServiceImpl implements IotWebtopoDeviceSvgnodeService {
+
+    @Resource
+    private IotWebtopoDeviceSvgnodeMapper iotWebtopoDeviceSvgnodeMapper;
+
+    @Override
+    public Long createIotWebtopoDeviceSvgnode(IotWebtopoDeviceSvgnodeSaveReqVO createReqVO) {
+        if (ObjUtil.isEmpty(createReqVO)) {
+            throw exception(IOT_WEBTOPO_DEVICE_SVGNODE_NOT_EXISTS);
+        }
+        // deviceId-svgNodeId-svgNodeProp 唯一标识
+        // 查询是否已经存在 3个属性的联合唯一键值
+        IotWebtopoDeviceSvgnodePageReqVO reqVO = new IotWebtopoDeviceSvgnodePageReqVO();
+        reqVO.setDeviceId(createReqVO.getDeviceId());
+        reqVO.setSvgNodeId(createReqVO.getSvgNodeId());
+        reqVO.setSvgNodeProp(createReqVO.getSvgNodeProp());
+        reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        PageResult<IotWebtopoDeviceSvgnodeDO> pageResult = iotWebtopoDeviceSvgnodeMapper.selectPage(reqVO);
+        if (ObjUtil.isNotEmpty(pageResult)) {
+            List<IotWebtopoDeviceSvgnodeDO> deviceSvgNodes = pageResult.getList();
+            if (CollUtil.isNotEmpty(deviceSvgNodes)) {
+                throw exception(IOT_WEBTOPO_DEVICE_SVGNODE_EXISTS);
+            }
+        }
+        // 插入
+        IotWebtopoDeviceSvgnodeDO iotWebtopoDeviceSvgnode = BeanUtils.toBean(createReqVO, IotWebtopoDeviceSvgnodeDO.class);
+        iotWebtopoDeviceSvgnodeMapper.insert(iotWebtopoDeviceSvgnode);
+        // 返回
+        return iotWebtopoDeviceSvgnode.getId();
+    }
+
+    @Override
+    public void updateIotWebtopoDeviceSvgnode(IotWebtopoDeviceSvgnodeSaveReqVO updateReqVO) {
+        // 校验存在
+        validateIotWebtopoDeviceSvgnodeExists(updateReqVO.getId());
+        // deviceId-svgNodeId-svgNodeProp 唯一标识
+        // 查询是否已经存在 3个属性的联合唯一键值
+        IotWebtopoDeviceSvgnodePageReqVO reqVO = new IotWebtopoDeviceSvgnodePageReqVO();
+        reqVO.setDeviceId(updateReqVO.getDeviceId());
+        reqVO.setSvgNodeId(updateReqVO.getSvgNodeId());
+        reqVO.setSvgNodeProp(updateReqVO.getSvgNodeProp());
+        reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        PageResult<IotWebtopoDeviceSvgnodeDO> pageResult = iotWebtopoDeviceSvgnodeMapper.selectPage(reqVO);
+        if (ObjUtil.isNotEmpty(pageResult)) {
+            List<IotWebtopoDeviceSvgnodeDO> deviceSvgNodes = pageResult.getList();
+            if (CollUtil.isNotEmpty(deviceSvgNodes)) {
+                deviceSvgNodes.forEach(node -> {
+                    if (!node.getId().equals(updateReqVO.getId())) {
+                        throw exception(IOT_WEBTOPO_DEVICE_SVGNODE_EXISTS);
+                    }
+                });
+            }
+        }
+        // 更新
+        IotWebtopoDeviceSvgnodeDO updateObj = BeanUtils.toBean(updateReqVO, IotWebtopoDeviceSvgnodeDO.class);
+        iotWebtopoDeviceSvgnodeMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteIotWebtopoDeviceSvgnode(Long id) {
+        // 校验存在
+        validateIotWebtopoDeviceSvgnodeExists(id);
+        // 删除
+        iotWebtopoDeviceSvgnodeMapper.deleteById(id);
+    }
+
+    private void validateIotWebtopoDeviceSvgnodeExists(Long id) {
+        if (iotWebtopoDeviceSvgnodeMapper.selectById(id) == null) {
+            throw exception(IOT_WEBTOPO_DEVICE_SVGNODE_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public IotWebtopoDeviceSvgnodeDO getIotWebtopoDeviceSvgnode(Long id) {
+        return iotWebtopoDeviceSvgnodeMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<IotWebtopoDeviceSvgnodeDO> getIotWebtopoDeviceSvgnodePage(IotWebtopoDeviceSvgnodePageReqVO pageReqVO) {
+        return iotWebtopoDeviceSvgnodeMapper.selectPage(pageReqVO);
+    }
+}

+ 55 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoproject/IotWebtopoProjectService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.pms.service.iotwebtopoproject;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo.IotWebtopoProjectPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo.IotWebtopoProjectSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoproject.IotWebtopoProjectDO;
+
+import javax.validation.Valid;
+
+/**
+ * 组态项目列 Service 接口
+ *
+ * @author ruiqi
+ */
+public interface IotWebtopoProjectService {
+
+    /**
+     * 创建组态项目列
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createIotWebtopoProject(@Valid IotWebtopoProjectSaveReqVO createReqVO);
+
+    /**
+     * 更新组态项目列
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateIotWebtopoProject(@Valid IotWebtopoProjectSaveReqVO updateReqVO);
+
+    /**
+     * 删除组态项目列
+     *
+     * @param id 编号
+     */
+    void deleteIotWebtopoProject(Long id);
+
+    /**
+     * 获得组态项目列
+     *
+     * @param id 编号
+     * @return 组态项目列
+     */
+    IotWebtopoProjectDO getIotWebtopoProject(Long id);
+
+    /**
+     * 获得组态项目列分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 组态项目列分页
+     */
+    PageResult<IotWebtopoProjectDO> getIotWebtopoProjectPage(IotWebtopoProjectPageReqVO pageReqVO);
+
+}

+ 122 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoproject/IotWebtopoProjectServiceImpl.java

@@ -0,0 +1,122 @@
+package cn.iocoder.yudao.module.pms.service.iotwebtopoproject;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo.IotWebtopoProjectPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoproject.vo.IotWebtopoProjectSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoproject.IotWebtopoProjectDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoprojectdevice.IotWebtopoProjectDeviceDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotwebtopoproject.IotWebtopoProjectMapper;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotwebtopoprojectdevice.IotWebtopoProjectDeviceMapper;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
+import com.google.common.collect.ImmutableMap;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_WEBTOPO_PROJECT_NOT_EXISTS;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.DEPT_NOT_FOUND;
+
+/**
+ * 组态项目列 Service 实现类
+ *
+ * @author ruiqi
+ */
+@Service
+@Validated
+public class IotWebtopoProjectServiceImpl implements IotWebtopoProjectService {
+
+    @Resource
+    private IotWebtopoProjectMapper iotWebtopoProjectMapper;
+
+    @Resource
+    private IotWebtopoProjectDeviceMapper iotWebtopoProjectDeviceMapper;
+
+    @Override
+    public Long createIotWebtopoProject(IotWebtopoProjectSaveReqVO createReqVO) {
+        // 插入
+        // 如果没有传 deptId 获取当前登录人的部门id
+        if (ObjUtil.isEmpty(createReqVO.getDeptId())) {
+            // 查询当前登录人所属公司
+            Long loginUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
+            createReqVO.setDeptId(loginUserDeptId);
+        }
+        IotWebtopoProjectDO iotWebtopoProject = BeanUtils.toBean(createReqVO, IotWebtopoProjectDO.class);
+        iotWebtopoProjectMapper.insert(iotWebtopoProject);
+        // 添加关联的设备信息
+        List<Long> deviceIds = createReqVO.getLinkedDeviceIds();
+        if (CollUtil.isNotEmpty(deviceIds)) {
+            List<IotWebtopoProjectDeviceDO> linkedDevices = new ArrayList<>();
+            deviceIds.forEach(deviceId -> {
+                IotWebtopoProjectDeviceDO tempDevice = new IotWebtopoProjectDeviceDO();
+                tempDevice.setProjectId(createReqVO.getId());
+                tempDevice.setDeviceId(deviceId);
+                linkedDevices.add(tempDevice);
+            });
+            if (CollUtil.isNotEmpty(linkedDevices)) {
+                boolean flag = iotWebtopoProjectDeviceMapper.insertBatch(linkedDevices);
+            }
+        }
+        // 返回
+        return iotWebtopoProject.getId();
+    }
+
+    @Override
+    public void updateIotWebtopoProject(IotWebtopoProjectSaveReqVO updateReqVO) {
+        // 校验存在
+        validateIotWebtopoProjectExists(updateReqVO.getId());
+        // 更新
+        IotWebtopoProjectDO updateObj = BeanUtils.toBean(updateReqVO, IotWebtopoProjectDO.class);
+        iotWebtopoProjectMapper.updateById(updateObj);
+        // 更新组态项目已经绑定的设备列表
+        List<Long> deviceIds = updateReqVO.getLinkedDeviceIds();
+        if (CollUtil.isNotEmpty(deviceIds)) {
+            // 先删除再新增
+            int count = iotWebtopoProjectDeviceMapper.deleteByMap(ImmutableMap.of(
+                    "project_id", updateObj.getId()
+            ));
+            List<IotWebtopoProjectDeviceDO> linkedDevices = new ArrayList<>();
+            deviceIds.forEach(deviceId -> {
+                IotWebtopoProjectDeviceDO tempDevice = new IotWebtopoProjectDeviceDO();
+                tempDevice.setProjectId(updateReqVO.getId());
+                tempDevice.setDeviceId(deviceId);
+                linkedDevices.add(tempDevice);
+            });
+            if (CollUtil.isNotEmpty(linkedDevices)) {
+                boolean flag = iotWebtopoProjectDeviceMapper.insertBatch(linkedDevices);
+            }
+        }
+    }
+
+    @Override
+    public void deleteIotWebtopoProject(Long id) {
+        // 校验存在
+        validateIotWebtopoProjectExists(id);
+        // 删除
+        iotWebtopoProjectMapper.deleteById(id);
+    }
+
+    private void validateIotWebtopoProjectExists(Long id) {
+        if (iotWebtopoProjectMapper.selectById(id) == null) {
+            throw exception(IOT_WEBTOPO_PROJECT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public IotWebtopoProjectDO getIotWebtopoProject(Long id) {
+        return iotWebtopoProjectMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<IotWebtopoProjectDO> getIotWebtopoProjectPage(IotWebtopoProjectPageReqVO pageReqVO) {
+        return iotWebtopoProjectMapper.selectPage(pageReqVO);
+    }
+
+}

+ 55 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoprojectdevice/IotWebtopoProjectDeviceService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.pms.service.iotwebtopoprojectdevice;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDevicePageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDeviceSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoprojectdevice.IotWebtopoProjectDeviceDO;
+
+import javax.validation.Valid;
+
+/**
+ * 组态项目关联设备 Service 接口
+ *
+ * @author ruiqi
+ */
+public interface IotWebtopoProjectDeviceService {
+
+    /**
+     * 创建组态项目关联设备
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createIotWebtopoProjectDevice(@Valid IotWebtopoProjectDeviceSaveReqVO createReqVO);
+
+    /**
+     * 更新组态项目关联设备
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateIotWebtopoProjectDevice(@Valid IotWebtopoProjectDeviceSaveReqVO updateReqVO);
+
+    /**
+     * 删除组态项目关联设备
+     *
+     * @param id 编号
+     */
+    void deleteIotWebtopoProjectDevice(Long id);
+
+    /**
+     * 获得组态项目关联设备
+     *
+     * @param id 编号
+     * @return 组态项目关联设备
+     */
+    IotWebtopoProjectDeviceDO getIotWebtopoProjectDevice(Long id);
+
+    /**
+     * 获得组态项目关联设备分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 组态项目关联设备分页
+     */
+    PageResult<IotWebtopoProjectDeviceDO> getIotWebtopoProjectDevicePage(IotWebtopoProjectDevicePageReqVO pageReqVO);
+
+}

+ 71 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotwebtopoprojectdevice/IotWebtopoProjectDeviceServiceImpl.java

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.pms.service.iotwebtopoprojectdevice;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDevicePageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotwebtopoprojectdevice.vo.IotWebtopoProjectDeviceSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotwebtopoprojectdevice.IotWebtopoProjectDeviceDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotwebtopoprojectdevice.IotWebtopoProjectDeviceMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_WEBTOPO_PROJECT_DEVICE_NOT_EXISTS;
+
+/**
+ * 组态项目关联设备 Service 实现类
+ *
+ * @author ruiqi
+ */
+@Service
+@Validated
+public class IotWebtopoProjectDeviceServiceImpl implements IotWebtopoProjectDeviceService {
+
+    @Resource
+    private IotWebtopoProjectDeviceMapper iotWebtopoProjectDeviceMapper;
+
+    @Override
+    public Long createIotWebtopoProjectDevice(IotWebtopoProjectDeviceSaveReqVO createReqVO) {
+        // 插入
+        IotWebtopoProjectDeviceDO iotWebtopoProjectDevice = BeanUtils.toBean(createReqVO, IotWebtopoProjectDeviceDO.class);
+        iotWebtopoProjectDeviceMapper.insert(iotWebtopoProjectDevice);
+        // 返回
+        return iotWebtopoProjectDevice.getId();
+    }
+
+    @Override
+    public void updateIotWebtopoProjectDevice(IotWebtopoProjectDeviceSaveReqVO updateReqVO) {
+        // 校验存在
+        validateIotWebtopoProjectDeviceExists(updateReqVO.getId());
+        // 更新
+        IotWebtopoProjectDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotWebtopoProjectDeviceDO.class);
+        iotWebtopoProjectDeviceMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteIotWebtopoProjectDevice(Long id) {
+        // 校验存在
+        validateIotWebtopoProjectDeviceExists(id);
+        // 删除
+        iotWebtopoProjectDeviceMapper.deleteById(id);
+    }
+
+    private void validateIotWebtopoProjectDeviceExists(Long id) {
+        if (iotWebtopoProjectDeviceMapper.selectById(id) == null) {
+            throw exception(IOT_WEBTOPO_PROJECT_DEVICE_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public IotWebtopoProjectDeviceDO getIotWebtopoProjectDevice(Long id) {
+        return iotWebtopoProjectDeviceMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<IotWebtopoProjectDeviceDO> getIotWebtopoProjectDevicePage(IotWebtopoProjectDevicePageReqVO pageReqVO) {
+        return iotWebtopoProjectDeviceMapper.selectPage(pageReqVO);
+    }
+
+}