Bladeren bron

init v1.0.0

linhuili 3 jaren geleden
bovenliggende
commit
132c17d4bd
100 gewijzigde bestanden met toevoegingen van 4879 en 0 verwijderingen
  1. 9 0
      dmp-business/README.md
  2. 9 0
      dmp-business/dc-digital-version/README.md
  3. 30 0
      dmp-business/dc-digital-version/pom.xml
  4. 24 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/constant/VersionOperator.java
  5. 23 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/constant/VersionOperatorLevel.java
  6. 26 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/constant/VersionState.java
  7. 51 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/controller/VersionDefineController.java
  8. 20 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/dao/ObjectInfoHistoryMapper.java
  9. 20 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/dao/ObjectTypeHistoryMapper.java
  10. 12 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/dao/VersionDefineMapper.java
  11. 14 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectInfo.java
  12. 19 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectInfoHistory.java
  13. 14 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectType.java
  14. 19 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectTypeHistory.java
  15. 37 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/VersionDefine.java
  16. 44 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/IObjectInfoHistoryService.java
  17. 45 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/IObjectTypeHistoryService.java
  18. 31 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/IVersionDefineService.java
  19. 62 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/impl/ObjectInfoHistoryServiceImpl.java
  20. 67 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/impl/ObjectTypeHistoryServiceImpl.java
  21. 138 0
      dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/impl/VersionDefineServiceImpl.java
  22. 11 0
      dmp-business/dc-digital-version/src/main/resources/bootstrap.yml
  23. 0 0
      dmp-business/dc-digital-version/src/main/resources/db.init/data.sql
  24. 41 0
      dmp-business/dc-digital-version/src/main/resources/db.init/schema.sql
  25. 15 0
      dmp-business/dc-digital-version/src/main/resources/mapper/ObjectInfoHistoryMapper.xml
  26. 13 0
      dmp-business/dc-digital-version/src/main/resources/mapper/ObjectTypeHistoryMapper.xml
  27. 9 0
      dmp-business/dc-digital/README.md
  28. 38 0
      dmp-business/dc-digital/pom.xml
  29. 25 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalDataCategory.java
  30. 32 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalDataType.java
  31. 27 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalMessageConstant.java
  32. 32 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalObjectType.java
  33. 33 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalObjectTypeShort.java
  34. 120 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/utils/DigitalCommonUtils.java
  35. 47 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/utils/DigitalMessageHelper.java
  36. 113 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/utils/QueryCriteriaHelper.java
  37. 60 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/GraphDefineController.java
  38. 93 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/ObjectInfoController.java
  39. 88 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/ObjectTypeController.java
  40. 64 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/RelationDefineController.java
  41. 12 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/GraphDefineMapper.java
  42. 12 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/ObjectInfoMapper.java
  43. 12 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/ObjectTypeMapper.java
  44. 12 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/RelationDefineMapper.java
  45. 50 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IGraphDefineService.java
  46. 79 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IObjectInfoService.java
  47. 74 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IObjectTypeService.java
  48. 50 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IRelationDefineService.java
  49. 55 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/GraphDefineServiceImpl.java
  50. 188 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/ObjectInfoServiceImpl.java
  51. 197 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/ObjectTypeServiceImpl.java
  52. 55 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/RelationDefineServiceImpl.java
  53. 41 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/config/DigitalRabbitConfig.java
  54. 88 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/controller/ObjectDigitalController.java
  55. 88 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/controller/ObjectRelationController.java
  56. 12 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/dao/ObjectDigitalMapper.java
  57. 12 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/dao/ObjectRelationMapper.java
  58. 46 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/entity/ObjectDigital.java
  59. 35 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/entity/ObjectRelation.java
  60. 79 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/handler/ProjectMessageHandler.java
  61. 163 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/handler/ProjectMessageVO.java
  62. 57 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/IObjectDigitalService.java
  63. 50 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/IObjectRelationService.java
  64. 158 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/impl/ObjectDigitalServiceImpl.java
  65. 54 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/impl/ObjectRelationServiceImpl.java
  66. 19 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/EnumVO.java
  67. 41 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/ParserResult.java
  68. 108 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/RegionVO.java
  69. 21 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/IInfoDataParser.java
  70. 57 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/InfoDataFactory.java
  71. 150 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AbstractInfoDataParser.java
  72. 36 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AttachmentInfoParser.java
  73. 34 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/BooleanInfoParser.java
  74. 142 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DateInfoParser.java
  75. 14 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DoubleInfoParser.java
  76. 53 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/EnumInfoParser.java
  77. 14 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/IntegerInfoParser.java
  78. 72 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/NumberInfoParser.java
  79. 51 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/StringInfoParser.java
  80. 21 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeObjectInfo.java
  81. 22 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeObjectType.java
  82. 21 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeProject.java
  83. 22 0
      dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeSchema.java
  84. 11 0
      dmp-business/dc-digital/src/main/resources/bootstrap.yml
  85. 0 0
      dmp-business/dc-digital/src/main/resources/db.init/data.sql
  86. 66 0
      dmp-business/dc-digital/src/main/resources/db.init/migrate.sql
  87. 152 0
      dmp-business/dc-digital/src/main/resources/db.init/schema.sql
  88. 5 0
      dmp-business/dc-digital/src/main/resources/mapper/DictDataMapper.xml
  89. 121 0
      dmp-business/dc-digital/src/test/java/com/persagy/dc/define/test/ObjectTypeDefineControllerTest.java
  90. 9 0
      dmp-business/dmp-knowledge/README.md
  91. 34 0
      dmp-business/dmp-knowledge/pom.xml
  92. 63 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/controller/DictDataController.java
  93. 63 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/controller/DictTypeController.java
  94. 13 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/dao/DictDataMapper.java
  95. 13 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/dao/DictTypeMapper.java
  96. 103 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/entity/DictData.java
  97. 32 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/entity/DictType.java
  98. 21 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/service/DictDataService.java
  99. 21 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/service/DictTypeService.java
  100. 0 0
      dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/service/impl/DictDataServiceImpl.java

+ 9 - 0
dmp-business/README.md

@@ -0,0 +1,9 @@
+数据中心 - 业务服务
+============ 
+
+说明
+---------------
+
+最新变化
+---------------
+

+ 9 - 0
dmp-business/dc-digital-version/README.md

@@ -0,0 +1,9 @@
+数据字典编辑工具
+============ 
+
+说明
+---------------
+
+最新变化
+---------------
+

+ 30 - 0
dmp-business/dc-digital-version/pom.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>dc-business</artifactId>
+        <groupId>com.persagy</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>dc-digital-version</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!-- 配置中心(包含注册中心) -->
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>integrated-config-client</artifactId>
+        </dependency>
+        <!-- 项目启动 -->
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-mybatis</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 24 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/constant/VersionOperator.java

@@ -0,0 +1,24 @@
+package com.persagy.dc.dictionary.constant;
+
+import lombok.Getter;
+
+/**
+ * 版本操作
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Getter
+public enum VersionOperator {
+    /** 版本操作 */
+    CREATE("CREATE", "新增"),
+    UPDATE("UPDATE", "修改"),
+    DELETE("DELETE", "删除");
+
+    private String index;
+    private String name;
+
+    VersionOperator(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 23 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/constant/VersionOperatorLevel.java

@@ -0,0 +1,23 @@
+package com.persagy.dc.dictionary.constant;
+
+import lombok.Getter;
+
+/**
+ * 操作等级
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Getter
+public enum VersionOperatorLevel {
+    /** 操作等级 */
+    NORMAL(0, "普通"),
+    MAJOR(1, "重大");
+
+    private Integer index;
+    private String name;
+
+    VersionOperatorLevel(Integer index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 26 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/constant/VersionState.java

@@ -0,0 +1,26 @@
+package com.persagy.dc.dictionary.constant;
+
+import lombok.Getter;
+
+/**
+ * 版本状态
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Getter
+public enum VersionState {
+    /** 版本状态 */
+    CANCELED("0", "已取消"),
+    TO_CONFIRM("1", "待确认"),
+    TO_PUBLISH("2", "待发布"),
+    PUBLISHING("3", "发布中"),
+    FINISHED("4", "已完成");
+
+    private String index;
+    private String name;
+
+    VersionState(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 51 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/controller/VersionDefineController.java

@@ -0,0 +1,51 @@
+package com.persagy.dc.dictionary.controller;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.dictionary.entity.VersionDefine;
+import com.persagy.dc.dictionary.service.IVersionDefineService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+/**
+ * 版本定义Controller
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@RestController
+@RequestMapping("/rwdedit/version")
+public class VersionDefineController {
+
+    @Autowired
+    private IVersionDefineService service;
+
+    @PostMapping("/create")
+    public CommonResult<VersionDefine> create(@RequestBody VersionDefine define) {
+        if(StrUtil.isBlank(define.getVersion())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        define = service.insertVersion(define);
+        return ResultHelper.single(define);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<VersionDefine> update(@RequestBody VersionDefine define) {
+        if(StrUtil.isBlank(define.getVersion())) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        define = service.updateVersion(define);
+        return ResultHelper.single(define);
+    }
+
+    @PostMapping("/delete")
+    public CommonResult delete(@RequestBody String id) {
+        service.deleteVersion(id);
+        return ResultHelper.success();
+    }
+}

+ 20 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/dao/ObjectInfoHistoryMapper.java

@@ -0,0 +1,20 @@
+package com.persagy.dc.dictionary.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.dictionary.entity.ObjectInfoHistory;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 信息点历史dao
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+public interface ObjectInfoHistoryMapper extends BaseMapper<ObjectInfoHistory> {
+
+    /**
+     * 按版本复制
+     * @param srcVersion 源版本
+     * @param version 复制后版本
+     */
+    void copyByVersion(@Param("srcVersion")String srcVersion, @Param("version")String version);
+}

+ 20 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/dao/ObjectTypeHistoryMapper.java

@@ -0,0 +1,20 @@
+package com.persagy.dc.dictionary.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.dictionary.entity.ObjectTypeHistory;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 对象类型历史dao
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+public interface ObjectTypeHistoryMapper extends BaseMapper<ObjectTypeHistory> {
+
+    /**
+     * 按版本复制
+     * @param srcVersion 源版本
+     * @param version 复制后版本
+     */
+    void copyByVersion(@Param("srcVersion")String srcVersion, @Param("version")String version);
+}

+ 12 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/dao/VersionDefineMapper.java

@@ -0,0 +1,12 @@
+package com.persagy.dc.dictionary.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.dictionary.entity.VersionDefine;
+
+/**
+ * 版本定义dao
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+public interface VersionDefineMapper extends BaseMapper<VersionDefine> {
+}

+ 14 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectInfo.java

@@ -0,0 +1,14 @@
+package com.persagy.dc.dictionary.entity;
+
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+
+/**
+ * 对象信息点
+ * 应该是在RWD的SDK中,但SDK现在没有,所以暂时先在此定义一个
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Data
+public class ObjectInfo extends AuditableEntity {
+}

+ 19 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectInfoHistory.java

@@ -0,0 +1,19 @@
+package com.persagy.dc.dictionary.entity;
+
+import lombok.Data;
+
+/**
+ * 信息点 历史记录
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Data
+public class ObjectInfoHistory extends ObjectInfo{
+
+    /** 版本号 */
+    private String version;
+    /** 操作:CREATE,UPDATE,DELETE */
+    private String operator;
+    /** 操作等级:0-普通,1-重大 */
+    private Integer operatorLevel;
+}

+ 14 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectType.java

@@ -0,0 +1,14 @@
+package com.persagy.dc.dictionary.entity;
+
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+
+/**
+ * 对象类型
+ * 应该是在RWD的SDK中,但SDK现在没有,所以暂时先在此定义一个
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Data
+public class ObjectType extends AuditableEntity {
+}

+ 19 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/ObjectTypeHistory.java

@@ -0,0 +1,19 @@
+package com.persagy.dc.dictionary.entity;
+
+import lombok.Data;
+
+/**
+ * 对象类型 历史记录
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Data
+public class ObjectTypeHistory extends ObjectType{
+
+    /** 版本号 */
+    private String version;
+    /** 操作:CREATE,UPDATE,DELETE */
+    private String operator;
+    /** 操作等级:0-普通,1-重大 */
+    private Integer operatorLevel;
+}

+ 37 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/entity/VersionDefine.java

@@ -0,0 +1,37 @@
+package com.persagy.dc.dictionary.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.lang.PsDateTime;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+
+/**
+ * 版本定义
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Data
+@TableName("rwdedit_version")
+public class VersionDefine extends AuditableEntity {
+
+    /** 版本号 */
+    private String version;
+    /** 版本状态:@see VersionState */
+    private String state;
+    /** 最新标识 */
+    private Boolean lastFlag;
+    /** 上一版本号 */
+    private String lastVersion;
+    /** 显示顺序 */
+    private Integer showOrder;
+    /** 确认人 */
+    private String confirmUser;
+    /** 确认时间 */
+    private PsDateTime confirmTime;
+    /** 发布人 */
+    private String publishUser;
+    /** 发布时间 */
+    private PsDateTime publishTime;
+    /** 完成时间 */
+    private PsDateTime finishTime;
+}

+ 44 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/IObjectInfoHistoryService.java

@@ -0,0 +1,44 @@
+package com.persagy.dc.dictionary.service;
+
+import com.persagy.dc.dictionary.entity.ObjectInfoHistory;
+
+/**
+ * 对象信息点 服务
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+public interface IObjectInfoHistoryService {
+
+    /**
+     * 新增
+     * @param history
+     * @return
+     */
+    ObjectInfoHistory insert(ObjectInfoHistory history);
+
+    /**
+     * 按版本复制
+     * @param srcVersion 源版本
+     * @param version 复制后版本
+     */
+    void copyByVersion(String srcVersion, String version);
+
+    /**
+     * 修改
+     * @param history
+     * @return
+     */
+    ObjectInfoHistory update(ObjectInfoHistory history);
+
+    /**
+     * 删除
+     * @param id
+     */
+    void delete(String id);
+
+    /**
+     * 版本删除前校验
+     * @param version
+     */
+    void validateOnVersionDelete(String version);
+}

+ 45 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/IObjectTypeHistoryService.java

@@ -0,0 +1,45 @@
+package com.persagy.dc.dictionary.service;
+
+import com.persagy.dc.dictionary.entity.ObjectTypeHistory;
+
+/**
+ * 对象类型 服务
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+public interface IObjectTypeHistoryService {
+
+    /**
+     * 新增
+     * @param history
+     * @return
+     */
+    ObjectTypeHistory insert(ObjectTypeHistory history);
+
+    /**
+     * 按版本复制
+     * @param srcVersion 源版本
+     * @param version 复制后版本
+     */
+    void copyByVersion(String srcVersion, String version);
+
+    /**
+     * 修改
+     * @param history
+     * @return
+     */
+    ObjectTypeHistory update(ObjectTypeHistory history);
+
+    /**
+     * 删除
+     * @param id
+     */
+    void delete(String id);
+
+    /**
+     * 版本删除前校验
+     * @param version
+     */
+    void validateOnVersionDelete(String version);
+
+}

+ 31 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/IVersionDefineService.java

@@ -0,0 +1,31 @@
+package com.persagy.dc.dictionary.service;
+
+import com.persagy.dc.dictionary.entity.VersionDefine;
+
+/**
+ * 版本定义接口
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+public interface IVersionDefineService {
+
+    /**
+     * 创建版本
+     * @param vo
+     * @return
+     */
+    VersionDefine insertVersion(VersionDefine vo);
+
+    /**
+     * 修改版本
+     * @param vo
+     * @return
+     */
+    VersionDefine updateVersion(VersionDefine vo);
+
+    /**
+     * 删除版本
+     * @param id
+     */
+    void deleteVersion(String id);
+}

+ 62 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/impl/ObjectInfoHistoryServiceImpl.java

@@ -0,0 +1,62 @@
+package com.persagy.dc.dictionary.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.dictionary.dao.ObjectInfoHistoryMapper;
+import com.persagy.dc.dictionary.entity.ObjectInfoHistory;
+import com.persagy.dc.dictionary.service.IObjectInfoHistoryService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+
+/**
+ * 信息点历史 实现类
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class ObjectInfoHistoryServiceImpl implements IObjectInfoHistoryService {
+
+    @Resource
+    private ObjectInfoHistoryMapper dao;
+
+    @Override
+    public ObjectInfoHistory insert(ObjectInfoHistory history) {
+        dao.insert(history);
+        return history;
+    }
+
+    @Override
+    public void copyByVersion(String srcVersion, String version) {
+        dao.copyByVersion(srcVersion, version);
+    }
+
+    @Override
+    public ObjectInfoHistory update(ObjectInfoHistory history) {
+        dao.updateById(history);
+        return history;
+    }
+
+    @Override
+    public void delete(String id) {
+        ObjectInfoHistory vo = dao.selectById(id);
+        vo.setValid(ValidEnum.FALSE.getType());
+        dao.updateById(vo);
+    }
+
+    @Override
+    public void validateOnVersionDelete(String version) {
+        // 查询
+        LambdaQueryWrapper<ObjectInfoHistory> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.in(ObjectInfoHistory::getVersion, version);
+        queryWrapper.eq(ObjectInfoHistory::getValid, ValidEnum.TRUE.getType());
+        queryWrapper.isNotNull(ObjectInfoHistory::getOperator);
+        Integer count = dao.selectCount(queryWrapper);
+        if(count != null && count > 0) {
+            throw new BusinessException("该版本有信息点变更记录不可直接删除!");
+        }
+    }
+}

+ 67 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/impl/ObjectTypeHistoryServiceImpl.java

@@ -0,0 +1,67 @@
+package com.persagy.dc.dictionary.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.dictionary.dao.ObjectTypeHistoryMapper;
+import com.persagy.dc.dictionary.entity.ObjectTypeHistory;
+import com.persagy.dc.dictionary.service.IObjectTypeHistoryService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+
+/**
+ * 对象类型历史 实现类
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class ObjectTypeHistoryServiceImpl implements IObjectTypeHistoryService {
+
+    @Resource
+    private ObjectTypeHistoryMapper dao;
+
+    @Override
+    public ObjectTypeHistory insert(ObjectTypeHistory history) {
+        dao.insert(history);
+        return history;
+    }
+
+    @Override
+    public void copyByVersion(String srcVersion, String version) {
+        /**
+         * TODO 目前是以编辑工具中数据为主体操作。应调整为从数据字典中读取当前数据
+         * 这样可以避免非编辑工具触发的数据字典编辑场景,产生的数据不一致
+         * 同时也可以通过调整数据字典服务源来支持为其他数据字典服务提供编辑服务
+         **/
+        dao.copyByVersion(srcVersion, version);
+    }
+
+    @Override
+    public ObjectTypeHistory update(ObjectTypeHistory history) {
+        dao.updateById(history);
+        return history;
+    }
+
+    @Override
+    public void delete(String id) {
+        ObjectTypeHistory vo = dao.selectById(id);
+        vo.setValid(ValidEnum.FALSE.getType());
+        dao.updateById(vo);
+    }
+
+    @Override
+    public void validateOnVersionDelete(String version) {
+        // 查询
+        LambdaQueryWrapper<ObjectTypeHistory> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.in(ObjectTypeHistory::getVersion, version);
+        queryWrapper.eq(ObjectTypeHistory::getValid, ValidEnum.TRUE.getType());
+        queryWrapper.isNotNull(ObjectTypeHistory::getOperator);
+        Integer count = dao.selectCount(queryWrapper);
+        if(count != null && count > 0) {
+            throw new BusinessException("该版本有对象类型变更记录不可直接删除!");
+        }
+    }
+}

+ 138 - 0
dmp-business/dc-digital-version/src/main/java/com/persagy/dc/dictionary/service/impl/VersionDefineServiceImpl.java

@@ -0,0 +1,138 @@
+package com.persagy.dc.dictionary.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.dictionary.constant.VersionState;
+import com.persagy.dc.dictionary.dao.VersionDefineMapper;
+import com.persagy.dc.dictionary.entity.VersionDefine;
+import com.persagy.dc.dictionary.service.IObjectInfoHistoryService;
+import com.persagy.dc.dictionary.service.IObjectTypeHistoryService;
+import com.persagy.dc.dictionary.service.IVersionDefineService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 版本定义实现类
+ * @author Charlie Yu
+ * @date 2021-06-23
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class VersionDefineServiceImpl implements IVersionDefineService {
+
+    @Resource
+    private VersionDefineMapper dao;
+    @Autowired
+    private IObjectTypeHistoryService typeHistoryService;
+    @Autowired
+    private IObjectInfoHistoryService infoHistoryService;
+
+    @Override
+    public VersionDefine insertVersion(VersionDefine vo) {
+        validate(vo);
+        // 查询最新版本
+        VersionDefine lastVersion = queryLastVersion();
+        if(lastVersion != null) {
+            vo.setLastVersion(lastVersion.getVersion());
+            vo.setShowOrder(lastVersion.getShowOrder() + 1);
+            // 修改原最新版本标识
+            lastVersion.setLastFlag(false);
+            dao.updateById(lastVersion);
+            // 生成此版本数据字典
+            typeHistoryService.copyByVersion(lastVersion.getVersion(), vo.getVersion());
+            infoHistoryService.copyByVersion(lastVersion.getVersion(), vo.getVersion());
+        } else {
+            vo.setShowOrder(1);
+        }
+        // 默认值
+        vo.setState(VersionState.TO_CONFIRM.getIndex());
+        vo.setLastFlag(true);
+        dao.insert(vo);
+        return vo;
+    }
+
+    /**
+     * 查询最新版本
+     * @return
+     */
+    private VersionDefine queryLastVersion() {
+        LambdaQueryWrapper<VersionDefine> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(VersionDefine::getValid, ValidEnum.TRUE.getType());
+        queryWrapper.eq(VersionDefine::getLastFlag, true);
+        return dao.selectOne(queryWrapper);
+    }
+
+    /**
+     * 保存校验
+     * @param vo
+     */
+    private void validate(VersionDefine vo) {
+        // 新增校验
+        if(StrUtil.isBlank(vo.getId())) {
+            if(hasFlowingVersion()) {
+                throw new BusinessException("存在未发布完成版本,不可重复创建!");
+            }
+        }
+        // 重名校验
+        LambdaQueryWrapper<VersionDefine> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(VersionDefine::getValid, ValidEnum.TRUE.getType());
+        queryWrapper.eq(VersionDefine::getVersion, vo.getVersion());
+        if(StrUtil.isNotBlank(vo.getId())) {
+            queryWrapper.ne(VersionDefine::getId, vo.getId());
+        }
+        Integer count = dao.selectCount(queryWrapper);
+        if(count != null && count >0) {
+            throw new BusinessException("版本编号已存在!");
+        }
+    }
+
+    /**
+     * 是否存在流程中版本
+     * 流程中:待确认、待发布、发布中
+     * @return
+     */
+    private boolean hasFlowingVersion() {
+        // 流程中的状态
+        List<String> flowingState = Arrays.asList(VersionState.TO_CONFIRM.getIndex(),
+                VersionState.TO_PUBLISH.getIndex(), VersionState.PUBLISHING.getIndex());
+        // 查询
+        LambdaQueryWrapper<VersionDefine> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.in(VersionDefine::getState, flowingState);
+        queryWrapper.eq(VersionDefine::getValid, ValidEnum.TRUE.getType());
+        Integer count = dao.selectCount(queryWrapper);
+        return count != null && count > 0;
+    }
+
+    @Override
+    public VersionDefine updateVersion(VersionDefine vo) {
+        validate(vo);
+        dao.updateById(vo);
+        return vo;
+    }
+
+    @Override
+    public void deleteVersion(String id) {
+        VersionDefine vo = dao.selectById(id);
+        if(VersionState.TO_CONFIRM.getIndex() != vo.getState()) {
+            throw new BusinessException("版本不是待确认状态,不允许删除!");
+        }
+        // 版本中存在维护记录时,不允许删除
+        typeHistoryService.validateOnVersionDelete(vo.getVersion());
+        infoHistoryService.validateOnVersionDelete(vo.getVersion());
+        // 恢复上一版本的最新标识
+        if(StrUtil.isNotBlank(vo.getLastVersion())) {
+            VersionDefine lastVersion = dao.selectById(vo.getLastVersion());
+            lastVersion.setLastFlag(true);
+            dao.updateById(lastVersion);
+        }
+        vo.setValid(ValidEnum.FALSE.getType());
+        dao.updateById(vo);
+    }
+}

+ 11 - 0
dmp-business/dc-digital-version/src/main/resources/bootstrap.yml

@@ -0,0 +1,11 @@
+server:
+  port: 9001
+spring:
+  application:
+    # 应用名称
+    name: dc-digital-version
+
+config:
+  file:
+    absolute:
+      path: ${CONFIG_FILE_PATH:D:\SpringCloud}

+ 0 - 0
dmp-business/dc-digital-version/src/main/resources/db.init/data.sql


+ 41 - 0
dmp-business/dc-digital-version/src/main/resources/db.init/schema.sql

@@ -0,0 +1,41 @@
+-- ----------------------------
+-- Table structure for dic_dt_type
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `dic_dt_data` (
+`id` varchar(80) NOT NULL,
+`dict_type_id` varchar(80) NOT NULL COMMENT '字典类型ID',
+`parent_id` varchar(80) DEFAULT NULL COMMENT '父节点',
+`type` varchar(80) NOT NULL COMMENT '字典类型',
+`code` varchar(200) NOT NULL COMMENT '字典数据编码',
+`label` varchar(200) NOT NULL COMMENT '字典数据标签',
+`status` int(11) NOT NULL COMMENT '状态',
+`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+`create_user` varchar(40) DEFAULT NULL COMMENT '创建用户',
+`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+`update_user` varchar(40) DEFAULT NULL COMMENT '更新用户',
+`remark` varchar(200) DEFAULT NULL,
+`order_num` int(11) DEFAULT NULL,
+PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='字典数据';
+
+-- ----------------------------
+-- Table structure for dic_dt_data
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS  `dic_dt_data` (
+`id` varchar(80) NOT NULL,
+`dict_type_id` varchar(80) NOT NULL COMMENT '字典类型ID',
+`parent_id` varchar(80) DEFAULT NULL COMMENT '父节点',
+`type` varchar(80) NOT NULL COMMENT '字典类型',
+`code` varchar(200) NOT NULL COMMENT '字典数据编码',
+`label` varchar(200) NOT NULL COMMENT '字典数据标签',
+`status` int(11) NOT NULL COMMENT '状态',
+`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+`create_user` varchar(40) DEFAULT NULL COMMENT '创建用户',
+`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+`update_user` varchar(40) DEFAULT NULL COMMENT '更新用户',
+`remark` varchar(200) DEFAULT NULL,
+`order_num` int(11) DEFAULT NULL,
+PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='字典数据';
+
+

+ 15 - 0
dmp-business/dc-digital-version/src/main/resources/mapper/ObjectInfoHistoryMapper.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.persagy.dc.dictionary.dao.ObjectInfoHistoryMapper">
+
+    <insert id="copyByVersion">
+        insert into rwd_object_info_his(id,group_code,project_id,code,orig_code,name,alias_code,alias_name,
+            class_code,category,type,first_tag,second_tag,priority,input_mode,unit,data_type,orig_data_type,
+            is_multiple,is_region,formatter,data_source,note,sub_flag,weak_point,is_used,version,operator,operator_level)
+        select id,group_code,project_id,code,orig_code,name,alias_code,alias_name,
+            class_code,category,type,first_tag,second_tag,priority,input_mode,unit,data_type,orig_data_type,
+            is_multiple,is_region,formatter,data_source,note,sub_flag,weak_point,is_used,#{version},null,null
+        from rwd_object_info_his
+        where version = #{srcVersion}
+    </insert>
+</mapper>

+ 13 - 0
dmp-business/dc-digital-version/src/main/resources/mapper/ObjectTypeHistoryMapper.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.persagy.dc.dictionary.dao.ObjectTypeHistoryMapper">
+
+    <insert id="copyByVersion">
+        insert into rwd_object_type_his(id,group_code,obj_type,name,alias_code,alias_name,
+            type,project_id,major_code,system_code,equipment_code,parent_code,is_used,version,operator,operator_level)
+        select id,group_code,obj_type,name,alias_code,alias_name,type,project_id,major_code,system_code,
+            equipment_code,parent_code,is_used,#{version},null,null
+        from rwd_object_type_his
+        where version = #{srcVersion}
+    </insert>
+</mapper>

+ 9 - 0
dmp-business/dc-digital/README.md

@@ -0,0 +1,9 @@
+数据孪生服务
+============ 
+
+说明
+---------------
+
+最新变化
+---------------
+

+ 38 - 0
dmp-business/dc-digital/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>dc-business</artifactId>
+        <groupId>com.persagy</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>dc-digital</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!-- 配置中心(包含注册中心) -->
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>integrated-config-client</artifactId>
+        </dependency>
+        <!-- 项目启动 -->
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-mybatis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-amqp-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-digital-starter</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 25 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalDataCategory.java

@@ -0,0 +1,25 @@
+package com.persagy.dc.basic.constant;
+
+import lombok.Getter;
+
+/**
+ * 数据分类
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Getter
+public enum DigitalDataCategory {
+    /** 数据类型 */
+    STATIC("STATIC", "静态量"),
+    PULSE("PULSE", "脉冲量"),
+    GRADATION("GRADATION", "阶段量"),
+    SEQUENTIAL("SEQUENTIAL", "时序量");
+
+    private String index;
+    private String name;
+
+    DigitalDataCategory(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 32 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalDataType.java

@@ -0,0 +1,32 @@
+package com.persagy.dc.basic.constant;
+
+import lombok.Getter;
+
+/**
+ * 数据类型
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Getter
+public enum DigitalDataType {
+    /** 数据类型 */
+    INTEGER("INTEGER", "整数"),
+    DOUBLE("DOUBLE", "数值"),
+    BOOLEAN("BOOLEAN", "布尔"),
+    STRING("STRING", "字符"),
+    DATETIME("DATETIME", "日期"),
+    ENUM("ENUM", "枚举"),
+    MENUM("MENUM", "多选枚举"),
+    ATTACHMENT("ATTACHMENT", "附件"),
+    PIC("PIC", "图片"),
+    OBJECT("OBJECT", "对象"),
+    REFENUM("REFENUM", "参照枚举");
+
+    private String index;
+    private String name;
+
+    DigitalDataType(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 27 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalMessageConstant.java

@@ -0,0 +1,27 @@
+package com.persagy.dc.basic.constant;
+
+/**
+ * 消息相关常量
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface DigitalMessageConstant {
+
+    /** 消息-exchange */
+    String MESSAGE_EXCHANGE = "exchange-digital";
+    /** 消息-路由Key */
+    String MESSAGE_ROUTING = "routing-digital-change";
+
+    /** 新增前 */
+    String OPERATE_BEFORE_INSERT = "BeforeInsert";
+    /** 修改前 */
+    String OPERATE_BEFORE_UPDATE = "BeforeUpdate";
+    /** 删除前 */
+    String OPERATE_BEFORE_DELETE = "BeforeDelete";
+    /** 新增后 */
+    String OPERATE_AFTER_INSERT = "AfterInsert";
+    /** 修改后 */
+    String OPERATE_AFTER_UPDATE = "AfterUpdate";
+    /** 删除后 */
+    String OPERATE_AFTER_DELETE = "AfterDelete";
+}

+ 32 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalObjectType.java

@@ -0,0 +1,32 @@
+package com.persagy.dc.basic.constant;
+
+import lombok.Getter;
+
+/**
+ * 对象类型
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Getter
+public enum DigitalObjectType {
+    /** 对象类型 */
+    PROJECT("project", "项目"),
+    BUILDING("building", "楼"),
+    FLOOR("floor", "楼层"),
+    SPACE("space", "空间"),
+    SYSTEM("system", "系统"),
+    EQUIPMENT("equipment", "设备"),
+    SHAFT("shaft", "竖井"),
+    COMPONENT("component", "部件"),
+    VIRTUAL("virtual", "虚拟对象"),
+    TOOL("tool", "工具"),
+    MATERIAL("material", "耗材");
+
+    private String index;
+    private String name;
+
+    DigitalObjectType(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 33 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/constant/DigitalObjectTypeShort.java

@@ -0,0 +1,33 @@
+package com.persagy.dc.basic.constant;
+
+import lombok.Getter;
+
+/**
+ * 对象类型简写
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Getter
+public enum DigitalObjectTypeShort {
+
+    /** 对象类型简写 */
+    PROJECT("Pj", "项目"),
+    BUILDING("Bd", "楼"),
+    FLOOR("Fl", "楼层"),
+    SPACE("Sp", "空间"),
+    SYSTEM("Sy", "系统"),
+    EQUIPMENT("Eq", "设备"),
+    SHAFT("Sh", "竖井"),
+    COMPONENT("Ec", "部件"),
+    VIRTUAL("Vo", "虚拟对象"),
+    TOOL("To", "工具"),
+    MATERIAL("Ma", "耗材");
+
+    private String index;
+    private String name;
+
+    DigitalObjectTypeShort(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 120 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/utils/DigitalCommonUtils.java

@@ -0,0 +1,120 @@
+package com.persagy.dc.basic.utils;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.persagy.dc.basic.constant.DigitalObjectType;
+import com.persagy.dc.basic.constant.DigitalObjectTypeShort;
+import com.persagy.dc.common.constant.CommonConstant;
+import com.persagy.dc.common.context.AppContext;
+import com.persagy.dc.common.model.entity.BaseEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 数据孪生通用工具
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public class DigitalCommonUtils {
+
+    /**
+     * 确认项目范围条件
+     * @param wrapper 查询条件
+     */
+    public static <T extends BaseEntity> void ensureProjectCriteria(QueryWrapper<T> wrapper) {
+        List<String> inSql = new ArrayList<>();
+        // 0-平台级数据
+        inSql.add(CommonConstant.DEFAULT_ID);
+        // groupCode-集团级数据
+        if(StrUtil.isNotBlank(AppContext.getContext().getGroupCode())) {
+            inSql.add(AppContext.getContext().getGroupCode());
+        }
+        // projectId-项目级数据
+        if(StrUtil.isNotBlank(AppContext.getContext().getProjectId())) {
+            inSql.add(AppContext.getContext().getProjectId());
+        }
+        wrapper.in(StrUtil.toUnderlineCase(AppContext.PROJECT_ID), inSql);
+    }
+
+    /**
+     * 确认项目范围条件
+     * @param wrapper 查询条件
+     */
+    public static <T extends BaseEntity> void ensureProjectCriteria(QueryWrapper<T> wrapper, String projectId) {
+        List<String> inSql = new ArrayList<>();
+        // 0-平台级数据
+        inSql.add(CommonConstant.DEFAULT_ID);
+        // groupCode-集团级数据
+        if(!CommonConstant.DEFAULT_ID.equalsIgnoreCase(projectId)) {
+            inSql.add(AppContext.getContext().getGroupCode());
+        }
+        if(StrUtil.isNotBlank(projectId)) {
+            inSql.add(projectId);
+        }
+        wrapper.in(StrUtil.toUnderlineCase(AppContext.PROJECT_ID), inSql);
+    }
+
+    /**
+     * 获取数据范围ID
+     * @return 0-平台级数据,groupCode-集团级数据,projectId-项目级数据
+     */
+    public static String getProjectId() {
+        // projectId-项目级数据
+        if(StrUtil.isNotBlank(AppContext.getContext().getProjectId())) {
+            return AppContext.getContext().getProjectId();
+        } else if(StrUtil.isNotBlank(AppContext.getContext().getGroupCode())) {
+            // groupCode-集团级数据
+            return AppContext.getContext().getGroupCode();
+        } else {
+            return CommonConstant.DEFAULT_ID;
+        }
+    }
+
+    /**
+     * 生成对象主键
+     * @param projectId 项目ID
+     * @param category 对象类型
+     * @return 两位prefix + 无前缀projectId + simpleUUID
+     */
+    public static String fetchObjectId(String projectId, String category) {
+        if (DigitalObjectType.PROJECT.getIndex().equalsIgnoreCase(category)) {
+            return projectId;
+        }
+        String prefix = getIdPrefix(category);
+        if(StrUtil.isBlank(prefix)) {
+            return IdUtil.simpleUUID();
+        }
+        return prefix + projectId.substring(2) + IdUtil.simpleUUID();
+    }
+
+    /**
+     * 根据对象类型获取Id前缀
+     * @param category 对象类型
+     * @return 两位的前缀 - 空字符串表示无效的对象类型
+     */
+    private static String getIdPrefix(String category) {
+        if(DigitalObjectType.PROJECT.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.PROJECT.getIndex();
+        } else if (DigitalObjectType.BUILDING.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.BUILDING.getIndex();
+        } else if (DigitalObjectType.FLOOR.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.FLOOR.getIndex();
+        } else if (DigitalObjectType.SPACE.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.SPACE.getIndex();
+        } else if (DigitalObjectType.SYSTEM.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.SYSTEM.getIndex();
+        } else if (DigitalObjectType.EQUIPMENT.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.EQUIPMENT.getIndex();
+        } else if (DigitalObjectType.SHAFT.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.SHAFT.getIndex();
+        } else if (DigitalObjectType.COMPONENT.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.COMPONENT.getIndex();
+        } else if (DigitalObjectType.VIRTUAL.getIndex().equalsIgnoreCase(category)) {
+            return DigitalObjectTypeShort.VIRTUAL.getIndex();
+        } else {
+            return "";
+        }
+    }
+}

+ 47 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/utils/DigitalMessageHelper.java

@@ -0,0 +1,47 @@
+package com.persagy.dc.basic.utils;
+
+import cn.hutool.json.JSONUtil;
+import com.persagy.dc.amqp.handler.RabbitMessageSender;
+import com.persagy.dc.basic.constant.DigitalMessageConstant;
+import com.persagy.dc.basic.model.DigitalManageMessage;
+import com.persagy.dc.common.model.entity.BaseEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 数据孪生消息发送助手
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Component
+public class DigitalMessageHelper {
+
+    @Autowired
+    private RabbitMessageSender messageSender;
+
+    /**
+     * 发送消息
+     * @param operator 操作类型
+     * @param oldVO 原数据
+     * @param newVO 现数据
+     * @param syncFlag 同步消息标识
+     */
+    public void sendMessage(String operator, BaseEntity oldVO, BaseEntity newVO, boolean syncFlag) {
+        DigitalManageMessage message = new DigitalManageMessage();
+        message.setOperatorType(operator);
+        message.setOperatorObj(newVO.getClass().getSimpleName());
+        message.setOldObj(oldVO);
+        message.setNewObj(newVO);
+        // 同步消息
+        if(syncFlag) {
+            messageSender.sendAndReceive(DigitalMessageConstant.MESSAGE_EXCHANGE,
+                    DigitalMessageConstant.MESSAGE_ROUTING,
+                    JSONUtil.toJsonStr(message));
+        } else {
+            // 异步消息
+            messageSender.send(DigitalMessageConstant.MESSAGE_EXCHANGE,
+                    DigitalMessageConstant.MESSAGE_ROUTING,
+                    JSONUtil.toJsonStr(message));
+        }
+    }
+}

+ 113 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/basic/utils/QueryCriteriaHelper.java

@@ -0,0 +1,113 @@
+package com.persagy.dc.basic.utils;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.dc.basic.model.QueryCriteria;
+import com.persagy.dc.common.model.entity.BaseEntity;
+
+import java.util.Iterator;
+
+/**
+ * 查询条件 助手
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public class QueryCriteriaHelper {
+
+    /**
+     * 转换为Page分页信息
+     * @param criteria
+     * @return
+     */
+    public static Page toPage(QueryCriteria criteria) {
+        if(criteria == null) {
+            criteria = new QueryCriteria();
+        }
+        // 当前页默认为1
+        if(criteria.getPage() == null || criteria.getPage() < 1) {
+            criteria.setPage(1L);
+        }
+        // 没有每页行数表示不分页
+        if(criteria.getSize() == null || criteria.getSize() < 1) {
+            criteria.setSize(-1L);
+        }
+        Page pageInfo = new Page();
+        pageInfo.setCurrent(criteria.getPage());
+        pageInfo.setSize(criteria.getSize());
+        pageInfo.setOrders(criteria.getOrders());
+        pageInfo.setSearchCount(!criteria.isWithoutCount());
+        return pageInfo;
+    }
+
+    /**
+     * 转换为查询条件
+     * @param wrapper
+     */
+    public static <T extends BaseEntity> void toWrapper(QueryWrapper<T> wrapper, QueryCriteria criteria) {
+        if(criteria == null || criteria.getCriteria() == null || criteria.getCriteria().isEmpty(null)) {
+            return;
+        }
+        Iterator<String> fields = criteria.getCriteria().fieldNames();
+        // 按字段循环
+        while(fields.hasNext()) {
+            String field = fields.next();
+            JsonNode fieldValue = criteria.getCriteria().get(field);
+            String dbField = StrUtil.toUnderlineCase(field);
+            // 值节点
+            if(fieldValue.isValueNode()) {
+                wrapper.eq(dbField, JsonNodeUtils.getNodeValue(fieldValue));
+                continue;
+            }
+            // 数组
+            if(fieldValue.isArray()) {
+                wrapper.in(dbField, JsonNodeUtils.getListValue(fieldValue));
+                continue;
+            }
+            // 对象
+            if(fieldValue.isObject()) {
+                Iterator<String> valueOperators = fieldValue.fieldNames();
+                while(valueOperators.hasNext()) {
+                    String valueOperator = valueOperators.next();
+                    JsonNode operatorValue = fieldValue.get(valueOperator);
+                    addCondition(wrapper, dbField, valueOperator,operatorValue);
+                }
+            }
+        }
+    }
+
+    /**
+     * 按条件类型添加查询条件
+     * @param wrapper
+     * @param field
+     * @param operator
+     * @param valueNode
+     */
+    private static <T extends BaseEntity> void addCondition(QueryWrapper<T> wrapper, String field, String operator, JsonNode valueNode) {
+        if("$ne".equalsIgnoreCase(operator)) {
+            wrapper.ne(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if("$gt".equalsIgnoreCase(operator)) {
+            wrapper.gt(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if("$gte".equalsIgnoreCase(operator)) {
+            wrapper.ge(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if("$lt".equalsIgnoreCase(operator)) {
+            wrapper.lt(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if("$lte".equalsIgnoreCase(operator)) {
+            wrapper.le(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if("$in".equalsIgnoreCase(operator)) {
+            wrapper.in(field, JsonNodeUtils.getListValue(valueNode));
+        } else if("$like".equalsIgnoreCase(operator)) {
+            wrapper.like(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if("$notLike".equalsIgnoreCase(operator)) {
+            wrapper.notLike(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if("$null".equalsIgnoreCase(operator)) {
+            boolean nullFlag = valueNode.booleanValue();
+            if(nullFlag) {
+                wrapper.isNull(field);
+            } else {
+                wrapper.isNotNull(field);
+            }
+        }
+    }
+}

+ 60 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/GraphDefineController.java

@@ -0,0 +1,60 @@
+package com.persagy.dc.define.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.model.QueryCriteria;
+import com.persagy.dc.basic.utils.QueryCriteriaHelper;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.model.response.PageList;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.define.entity.GraphDefine;
+import com.persagy.dc.define.service.IGraphDefineService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+/**
+ * 对象类型 Controller
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@RestController
+@RequestMapping("/define/graph")
+public class GraphDefineController {
+
+    @Autowired
+    private IGraphDefineService service;
+
+    @PostMapping("query")
+    public CommonResult<PageList<GraphDefine>> query(@RequestBody QueryCriteria criteria) {
+        if(criteria == null) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        QueryWrapper<GraphDefine> wrapper = new QueryWrapper<>();
+        // 转换查询条件
+        QueryCriteriaHelper.toWrapper(wrapper, criteria);
+        Page page = service.queryByCondition(QueryCriteriaHelper.toPage(criteria), wrapper);
+        return ResultHelper.multi(page.getRecords(), page.getTotal());
+    }
+
+    @PostMapping("/create")
+    public CommonResult<GraphDefine> create(@RequestBody GraphDefine vo){
+        vo = service.insert(vo);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<GraphDefine> update(@RequestBody GraphDefine vo){
+        vo = service.update(vo);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/delete")
+    public void delete(@RequestBody String id){
+        service.delete(id);
+    }
+}

+ 93 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/ObjectInfoController.java

@@ -0,0 +1,93 @@
+package com.persagy.dc.define.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.model.QueryCriteria;
+import com.persagy.dc.basic.utils.DigitalCommonUtils;
+import com.persagy.dc.basic.utils.QueryCriteriaHelper;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.model.response.PageList;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+import com.persagy.dc.define.service.IObjectInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 对象类型 Controller
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@RestController
+@RequestMapping("/define/info")
+public class ObjectInfoController {
+
+    @Autowired
+    private IObjectInfoService service;
+
+    @PostMapping("query")
+    public CommonResult<PageList<ObjectInfoDefine>> query(@RequestBody QueryCriteria criteria) {
+        if(criteria == null) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        QueryWrapper<ObjectInfoDefine> wrapper = new QueryWrapper<>();
+        // 添加所属项目条件
+        DigitalCommonUtils.ensureProjectCriteria(wrapper);
+        // 转换查询条件
+        QueryCriteriaHelper.toWrapper(wrapper, criteria);
+        Page page = QueryCriteriaHelper.toPage(criteria);
+        // 没有排序条件时,按默认条件排序
+        if(CollUtil.isEmpty(page.getOrders())) {
+            wrapper.orderByAsc("show_order");
+        }
+        page = service.queryByCondition(page, wrapper);
+        return ResultHelper.multi(page.getRecords(), page.getTotal());
+    }
+
+    @PostMapping("/create")
+    public CommonResult<ObjectInfoDefine> create(@Valid @RequestBody ObjectInfoDefine vo){
+        List<ObjectInfoDefine> voList = CollUtil.newArrayList(vo);
+        service.insert(voList);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/createBatch")
+    public CommonResult<PageList<ObjectInfoDefine>> createBatch(@Valid @RequestBody List<ObjectInfoDefine> voList){
+        voList = service.insert(voList);
+        return ResultHelper.multi(voList);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<ObjectInfoDefine> update(@Valid @RequestBody ObjectInfoDefine vo){
+        List<ObjectInfoDefine> voList = CollUtil.newArrayList(vo);
+        service.update(voList);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/updateBatch")
+    public CommonResult<PageList<ObjectInfoDefine>> updateBatch(@Valid @RequestBody List<ObjectInfoDefine> voList){
+        voList = service.update(voList);
+        return ResultHelper.multi(voList);
+    }
+
+    @PostMapping("/delete")
+    public CommonResult delete(@RequestBody String id){
+        service.delete(CollUtil.newArrayList(id));
+        return ResultHelper.success();
+    }
+
+    @PostMapping("/deleteBatch")
+    public CommonResult deleteBatch(@RequestBody List<String> id){
+        service.delete(id);
+        return ResultHelper.success();
+    }
+}

+ 88 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/ObjectTypeController.java

@@ -0,0 +1,88 @@
+package com.persagy.dc.define.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.model.QueryCriteria;
+import com.persagy.dc.basic.utils.DigitalCommonUtils;
+import com.persagy.dc.basic.utils.QueryCriteriaHelper;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.model.response.PageList;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.define.entity.ObjectTypeDefine;
+import com.persagy.dc.define.service.IObjectTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 对象类型 Controller
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@RestController
+@RequestMapping("/define/type")
+public class ObjectTypeController {
+
+    @Autowired
+    private IObjectTypeService service;
+
+    @PostMapping("query")
+    public CommonResult<PageList<ObjectTypeDefine>> query(@RequestBody QueryCriteria criteria) {
+        if(criteria == null) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        QueryWrapper<ObjectTypeDefine> wrapper = new QueryWrapper<>();
+        // 添加所属项目条件
+        DigitalCommonUtils.ensureProjectCriteria(wrapper);
+        // 转换查询条件
+        QueryCriteriaHelper.toWrapper(wrapper, criteria);
+        Page page = service.queryByCondition(QueryCriteriaHelper.toPage(criteria), wrapper);
+        return ResultHelper.multi(page.getRecords(), page.getTotal());
+    }
+
+    @PostMapping("/create")
+	public CommonResult<ObjectTypeDefine> create(@Valid @RequestBody ObjectTypeDefine vo){
+        List<ObjectTypeDefine> voList = CollUtil.newArrayList(vo);
+        service.insert(voList);
+		return ResultHelper.single(vo);
+	}
+
+    @PostMapping("/createBatch")
+    public CommonResult<PageList<ObjectTypeDefine>> createBatch(@Valid @RequestBody List<ObjectTypeDefine> voList){
+        voList = service.insert(voList);
+        return ResultHelper.multi(voList);
+    }
+
+	@PostMapping("/update")
+	public CommonResult<ObjectTypeDefine> update(@Valid @RequestBody ObjectTypeDefine vo){
+        List<ObjectTypeDefine> voList = CollUtil.newArrayList(vo);
+        service.update(voList);
+		return ResultHelper.single(vo);
+	}
+
+    @PostMapping("/updateBatch")
+    public CommonResult<PageList<ObjectTypeDefine>> updateBatch(@Valid @RequestBody List<ObjectTypeDefine> voList){
+        voList = service.update(voList);
+        return ResultHelper.multi(voList);
+    }
+
+	@PostMapping("/delete")
+	public CommonResult delete(@RequestBody String id){
+        service.delete(CollUtil.newArrayList(id));
+        return ResultHelper.success();
+	}
+
+    @PostMapping("/deleteBatch")
+    public CommonResult deleteBatch(@RequestBody List<String> id){
+        service.delete(id);
+        return ResultHelper.success();
+    }
+}

+ 64 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/controller/RelationDefineController.java

@@ -0,0 +1,64 @@
+package com.persagy.dc.define.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.model.QueryCriteria;
+import com.persagy.dc.basic.utils.DigitalCommonUtils;
+import com.persagy.dc.basic.utils.QueryCriteriaHelper;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.model.response.PageList;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.define.entity.ObjectTypeDefine;
+import com.persagy.dc.define.entity.RelationDefine;
+import com.persagy.dc.define.service.IRelationDefineService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+/**
+ * 对象类型 Controller
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@RestController
+@RequestMapping("/define/relation")
+public class RelationDefineController {
+
+    @Autowired
+    private IRelationDefineService service;
+
+    @PostMapping("query")
+    public CommonResult<PageList<ObjectTypeDefine>> query(@RequestBody QueryCriteria criteria) {
+        if(criteria == null) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        QueryWrapper<RelationDefine> wrapper = new QueryWrapper<>();
+        // 添加所属项目条件
+        DigitalCommonUtils.ensureProjectCriteria(wrapper);
+        // 转换查询条件
+        QueryCriteriaHelper.toWrapper(wrapper, criteria);
+        Page page = service.queryByCondition(QueryCriteriaHelper.toPage(criteria), wrapper);
+        return ResultHelper.multi(page.getRecords(), page.getTotal());
+    }
+
+    @PostMapping("/create")
+    public CommonResult<RelationDefine> create(@RequestBody RelationDefine vo){
+        vo = service.insert(vo);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<RelationDefine> update(@RequestBody RelationDefine vo){
+        vo = service.update(vo);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/delete")
+    public void delete(@RequestBody String id){
+        service.delete(id);
+    }
+}

+ 12 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/GraphDefineMapper.java

@@ -0,0 +1,12 @@
+package com.persagy.dc.define.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.define.entity.GraphDefine;
+
+/**
+ * 图定义 DAO
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface GraphDefineMapper extends BaseMapper<GraphDefine> {
+}

+ 12 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/ObjectInfoMapper.java

@@ -0,0 +1,12 @@
+package com.persagy.dc.define.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+
+/**
+ * 信息点 DAO
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface ObjectInfoMapper extends BaseMapper<ObjectInfoDefine> {
+}

+ 12 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/ObjectTypeMapper.java

@@ -0,0 +1,12 @@
+package com.persagy.dc.define.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.define.entity.ObjectTypeDefine;
+
+/**
+ * 对象类型 DAO
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface ObjectTypeMapper extends BaseMapper<ObjectTypeDefine> {
+}

+ 12 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/dao/RelationDefineMapper.java

@@ -0,0 +1,12 @@
+package com.persagy.dc.define.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.define.entity.RelationDefine;
+
+/**
+ * 关系定义 DAO
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface RelationDefineMapper extends BaseMapper<RelationDefine> {
+}

+ 50 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IGraphDefineService.java

@@ -0,0 +1,50 @@
+package com.persagy.dc.define.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.define.entity.GraphDefine;
+
+import java.util.List;
+
+/**
+ * 图定义 接口
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface IGraphDefineService {
+
+    /**
+     * 按条件查询
+     * @param queryWrapper 查询条件
+     * @return 列表
+     */
+    List<GraphDefine> queryByCondition(Wrapper<GraphDefine> queryWrapper);
+
+    /**
+     * 按条件查询
+     * @param page 分页条件
+     * @param queryWrapper 查询条件
+     * @return 分页结果
+     */
+    Page queryByCondition(Page page, Wrapper<GraphDefine> queryWrapper);
+
+    /**
+     * 新增
+     * @param vo 待新增数据
+     * @return 新增后数据
+     */
+    GraphDefine insert(GraphDefine vo);
+
+    /**
+     * 修改
+     * @param vo 待修改数据
+     * @return 修改后数据
+     */
+    GraphDefine update(GraphDefine vo);
+
+    /**
+     * 删除
+     * @param id 主键
+     */
+    void delete(String id);
+}

+ 79 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IObjectInfoService.java

@@ -0,0 +1,79 @@
+package com.persagy.dc.define.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 信息点 接口
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface IObjectInfoService {
+
+    /**
+     * 通过主键查询
+     * @param id
+     * @return
+     */
+    ObjectInfoDefine load(String id);
+
+    /**
+     * 通过多主键查询
+     * @param idList
+     * @return
+     */
+    List<ObjectInfoDefine> queryByIds(List<String> idList);
+
+    /**
+     * 通过对象类型编码查询
+     * @param typeCode
+     * @return
+     */
+    List<ObjectInfoDefine> queryByType(String typeCode);
+
+    /**
+     * 通过多对象类型编码查询
+     * @param typeCodeList
+     * @return Map<typeCode, Map<InfoCode, ObjectInfo>>
+     */
+    Map<String, Map<String, ObjectInfoDefine>> queryByTypes(List<String> typeCodeList);
+
+    /**
+     * 按条件查询
+     * @param queryWrapper 查询条件
+     * @return 列表
+     */
+    List<ObjectInfoDefine> queryByCondition(Wrapper<ObjectInfoDefine> queryWrapper);
+
+    /**
+     * 按条件查询
+     * @param page 分页条件
+     * @param queryWrapper 查询条件
+     * @return 分页结果
+     */
+    Page queryByCondition(Page page, Wrapper<ObjectInfoDefine> queryWrapper);
+
+    /**
+     * 新增
+     * @param voList 待新增数据
+     * @return 新增后数据
+     */
+    List<ObjectInfoDefine> insert(List<ObjectInfoDefine> voList);
+
+    /**
+     * 修改
+     * @param voList 待修改数据
+     * @return 修改后数据
+     */
+    List<ObjectInfoDefine> update(List<ObjectInfoDefine> voList);
+
+    /**
+     * 删除
+     * @param idList 主键
+     */
+    void delete(List<String> idList);
+}

+ 74 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IObjectTypeService.java

@@ -0,0 +1,74 @@
+package com.persagy.dc.define.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.define.entity.ObjectTypeDefine;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 对象类型 接口
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface IObjectTypeService {
+
+    /**
+     * 查询Map
+     * @return <code, name>
+     */
+    Map<String, String> queryCodeNameMap();
+
+    /**
+     * 按项目、应用查询 - 支持订阅
+     * @param projectId 项目ID
+     * @param appId 应用ID
+     * @return 列表结果
+     */
+    List<ObjectTypeDefine> queryByProjectAndApp(String projectId, String appId);
+
+    /**
+     * 按项目、应用查询 - 支持订阅
+     * @param page 分页条件
+     * @param projectId 项目ID
+     * @param appId 应用ID
+     * @return 分页结果
+     */
+    Page queryByProjectAndApp(Page page, String projectId, String appId);
+
+    /**
+     * 按条件查询
+     * @param queryWrapper 查询条件
+     * @return 列表
+     */
+    List<ObjectTypeDefine> queryByCondition(Wrapper<ObjectTypeDefine> queryWrapper);
+
+    /**
+     * 按条件查询
+     * @param page 分页条件
+     * @param queryWrapper 查询条件
+     * @return 分页结果
+     */
+    Page queryByCondition(Page page, Wrapper<ObjectTypeDefine> queryWrapper);
+
+    /**
+     * 新增
+     * @param voList 待新增数据
+     * @return 新增后数据
+     */
+    List<ObjectTypeDefine> insert(List<ObjectTypeDefine> voList);
+
+    /**
+     * 修改
+     * @param voList 待修改数据
+     * @return 修改后数据
+     */
+    List<ObjectTypeDefine> update(List<ObjectTypeDefine> voList);
+
+    /**
+     * 删除
+     * @param idList 主键
+     */
+    void delete(List<String> idList);
+}

+ 50 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/IRelationDefineService.java

@@ -0,0 +1,50 @@
+package com.persagy.dc.define.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.define.entity.RelationDefine;
+
+import java.util.List;
+
+/**
+ * 关系定义 接口
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+public interface IRelationDefineService {
+
+    /**
+     * 按条件查询
+     * @param queryWrapper 查询条件
+     * @return 列表
+     */
+    List<RelationDefine> queryByCondition(Wrapper<RelationDefine> queryWrapper);
+
+    /**
+     * 按条件查询
+     * @param page 分页条件
+     * @param queryWrapper 查询条件
+     * @return 分页结果
+     */
+    Page queryByCondition(Page page, Wrapper<RelationDefine> queryWrapper);
+
+    /**
+     * 新增
+     * @param vo 待新增数据
+     * @return 新增后数据
+     */
+    RelationDefine insert(RelationDefine vo);
+
+    /**
+     * 修改
+     * @param vo 待修改数据
+     * @return 修改后数据
+     */
+    RelationDefine update(RelationDefine vo);
+
+    /**
+     * 删除
+     * @param id 主键
+     */
+    void delete(String id);
+}

+ 55 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/GraphDefineServiceImpl.java

@@ -0,0 +1,55 @@
+package com.persagy.dc.define.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.define.dao.GraphDefineMapper;
+import com.persagy.dc.define.entity.GraphDefine;
+import com.persagy.dc.define.service.IGraphDefineService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 图定义 实现类
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class GraphDefineServiceImpl implements IGraphDefineService {
+
+    @Resource
+    private GraphDefineMapper dao;
+
+    @Override
+    public List<GraphDefine> queryByCondition(Wrapper<GraphDefine> queryWrapper) {
+        return dao.selectList(queryWrapper);
+    }
+
+    @Override
+    public Page queryByCondition(Page page, Wrapper<GraphDefine> queryWrapper) {
+        return dao.selectPage(page, queryWrapper);
+    }
+
+    @Override
+    public GraphDefine insert(GraphDefine vo) {
+        dao.insert(vo);
+        return vo;
+    }
+
+    @Override
+    public GraphDefine update(GraphDefine vo) {
+        dao.updateById(vo);
+        return vo;
+    }
+
+    @Override
+    public void delete(String id) {
+        GraphDefine vo = dao.selectById(id);
+        vo.setValid(ValidEnum.FALSE.getType());
+        dao.updateById(vo);
+    }
+}

+ 188 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/ObjectInfoServiceImpl.java

@@ -0,0 +1,188 @@
+package com.persagy.dc.define.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.text.StrFormatter;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.constant.DigitalMessageConstant;
+import com.persagy.dc.basic.utils.DigitalMessageHelper;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.entity.BaseEntity;
+import com.persagy.dc.define.dao.ObjectInfoMapper;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+import com.persagy.dc.define.service.IObjectInfoService;
+import com.persagy.dc.parser.service.InfoDataFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 信息点 实现类
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class ObjectInfoServiceImpl implements IObjectInfoService {
+
+    @Resource
+    private ObjectInfoMapper dao;
+    @Autowired
+    private DigitalMessageHelper messageSender;
+
+    @Override
+    public ObjectInfoDefine load(String id) {
+        return dao.selectById(id);
+    }
+
+    @Override
+    public List<ObjectInfoDefine> queryByIds(List<String> idList) {
+        return dao.selectBatchIds(idList);
+    }
+
+    @Override
+    public List<ObjectInfoDefine> queryByType(String typeCode) {
+        LambdaQueryWrapper<ObjectInfoDefine> wrapper = new LambdaQueryWrapper();
+        wrapper.eq(ObjectInfoDefine::getClassCode, typeCode);
+        wrapper.eq(ObjectInfoDefine::getValid, ValidEnum.TRUE.getType());
+        wrapper.orderByAsc(ObjectInfoDefine::getShowOrder);
+        return queryByCondition(wrapper);
+    }
+
+    @Override
+    public Map<String, Map<String, ObjectInfoDefine>> queryByTypes(List<String> typeCodeList) {
+        LambdaQueryWrapper<ObjectInfoDefine> wrapper = new LambdaQueryWrapper();
+        wrapper.in(ObjectInfoDefine::getClassCode, typeCodeList);
+        wrapper.eq(ObjectInfoDefine::getValid, ValidEnum.TRUE.getType());
+        wrapper.orderByAsc(ObjectInfoDefine::getShowOrder);
+        List<ObjectInfoDefine> infoList = queryByCondition(wrapper);
+        if(CollUtil.isEmpty(infoList)) {
+            return null;
+        }
+        return infoList.stream().collect(Collectors.groupingBy(ObjectInfoDefine::getClassCode, Collectors.toMap(ObjectInfoDefine::getCode, p->p, (v1, v2) -> v1)));
+    }
+
+    @Override
+    public List<ObjectInfoDefine> queryByCondition(Wrapper<ObjectInfoDefine> queryWrapper) {
+        return dao.selectList(queryWrapper);
+    }
+
+    @Override
+    public Page queryByCondition(Page page, Wrapper<ObjectInfoDefine> queryWrapper) {
+        return dao.selectPage(page, queryWrapper);
+    }
+
+    @Override
+    public List<ObjectInfoDefine> insert(List<ObjectInfoDefine> voList) {
+        if(CollUtil.isEmpty(voList)) {
+            return null;
+        }
+        validateOnSave(voList, false);
+        voList.forEach(vo -> {
+            // 新增前消息 - 暂不提供同步消息
+///            messageSender.sendMessage(DigitalMessageConstant.OPERATE_BEFORE_INSERT, null, vo, true);
+            // 新增
+            dao.insert(vo);
+            // 新增后消息
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_INSERT, null, vo, false);
+        });
+        return voList;
+    }
+
+    @Override
+    public List<ObjectInfoDefine> update(List<ObjectInfoDefine> voList) {
+        if(CollUtil.isEmpty(voList)) {
+            return null;
+        }
+        validateOnSave(voList, true);
+        List<String> idList = CollUtil.getFieldValues(voList, BaseEntity.PROP_ID, String.class);
+        List<ObjectInfoDefine> dbList = dao.selectBatchIds(idList);
+        Map<String, ObjectInfoDefine> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
+        voList.forEach(vo -> {
+            ObjectInfoDefine dbVO = MapUtil.get(dbMap, vo.getId(), ObjectInfoDefine.class);
+            // 容错处理
+            if(dbVO == null) {
+                return;
+            }
+            // 修改前消息 - 暂不提供同步消息
+///            messageSender.sendMessage(DigitalMessageConstant.OPERATE_BEFORE_UPDATE, dbVO, vo, true);
+            // 修改
+            dao.updateById(vo);
+            // 修改后消息
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_UPDATE, dbVO, vo, false);
+        });
+        return voList;
+    }
+
+    /**
+     * 保存校验
+     * 编码全局唯一
+     * @param voList
+     * @param isUpdate
+     */
+    private void validateOnSave(List<ObjectInfoDefine> voList, boolean isUpdate) {
+        Set<String> codeSet = new HashSet<>();
+        List<String> idList = new ArrayList<>();
+        for(ObjectInfoDefine vo:voList) {
+            // 编码重复
+            if(!codeSet.add(vo.getCode())) {
+                throw new BusinessException(StrFormatter.format("存在重复编码{},不允许保存!", vo.getCode()));
+            }
+            // 校验器校验
+            InfoDataFactory.parse(vo, null);
+            // 修改时,收集待排除的主键
+            if(isUpdate) {
+                idList.add(vo.getId());
+            }
+        }
+        // 查询条件
+        LambdaQueryWrapper<ObjectInfoDefine> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.select(ObjectInfoDefine::getCode);
+        queryWrapper.in(ObjectInfoDefine::getValid, ValidEnum.TRUE.getType());
+        queryWrapper.in(ObjectInfoDefine::getCode, codeSet);
+        if(isUpdate) {
+            queryWrapper.notIn(ObjectInfoDefine::getId, idList);
+        }
+        // 查询重复的编码
+        List<ObjectInfoDefine> dbList = dao.selectList(queryWrapper);
+        if(CollUtil.isEmpty(dbList)) {
+            return;
+        }
+        List<String> codes = CollUtil.getFieldValues(voList, "code", String.class);
+        throw new BusinessException(StrFormatter.format("存在重复编码{},不允许保存!", codes));
+    }
+
+    @Override
+    public void delete(List<String> idList) {
+        if(CollUtil.isEmpty(idList)) {
+            return;
+        }
+        List<ObjectInfoDefine> dbList = dao.selectBatchIds(idList);
+        Map<String, ObjectInfoDefine> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
+        idList.forEach(id -> {
+            ObjectInfoDefine dbVO = MapUtil.get(dbMap, id, ObjectInfoDefine.class);
+            // 容错处理
+            if(dbVO == null) {
+                return;
+            }
+            // 删除前消息 - 暂不提供同步消息
+///            messageSender.sendMessage(DigitalMessageConstant.OPERATE_BEFORE_DELETE, null, dbVO, true);
+            // 删除
+            ObjectInfoDefine vo = new ObjectInfoDefine();
+            vo.setId(id);
+            vo.setValid(ValidEnum.FALSE.getType());
+            dao.updateById(vo);
+            // 删除后消息
+            dbVO.setValid(ValidEnum.FALSE.getType());
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_DELETE, null, dbVO, false);
+        });
+    }
+}

+ 197 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/ObjectTypeServiceImpl.java

@@ -0,0 +1,197 @@
+package com.persagy.dc.define.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.text.StrFormatter;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.constant.DigitalMessageConstant;
+import com.persagy.dc.basic.utils.DigitalCommonUtils;
+import com.persagy.dc.basic.utils.DigitalMessageHelper;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.entity.BaseEntity;
+import com.persagy.dc.define.dao.ObjectTypeMapper;
+import com.persagy.dc.define.entity.ObjectTypeDefine;
+import com.persagy.dc.define.service.IObjectTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+/**
+ * 对象类型 实现类
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+@CacheConfig(cacheNames = {"dt_object_type"})
+public class ObjectTypeServiceImpl implements IObjectTypeService {
+
+    @Resource
+    private ObjectTypeMapper dao;
+    @Autowired
+    private DigitalMessageHelper messageSender;
+
+    @Override
+    @Cacheable(key = "targetClass + methodName + #p0 + #p1")
+    public List<ObjectTypeDefine> queryByProjectAndApp(String projectId, String appId) {
+        // TODO 指定条件查询使用Redis
+        QueryWrapper<ObjectTypeDefine> wrapper = new QueryWrapper<>();
+        DigitalCommonUtils.ensureProjectCriteria(wrapper, projectId);
+        if(StrUtil.isNotBlank(appId)) {
+            // TODO 根据应用ID关联订阅条件
+
+        }
+        return queryByCondition(wrapper);
+    }
+
+    @Override
+    @Cacheable(key = "targetClass + methodName")
+    public Map<String, String> queryCodeNameMap() {
+        LambdaQueryWrapper<ObjectTypeDefine> wrapper = new LambdaQueryWrapper<>();
+        wrapper.select(ObjectTypeDefine::getId, ObjectTypeDefine::getCode, ObjectTypeDefine::getName);
+        wrapper.eq(ObjectTypeDefine::getValid, ValidEnum.TRUE.getType());
+        List<ObjectTypeDefine> voList = queryByCondition(wrapper);
+        return CollUtil.fieldValueAsMap(voList, "code", "name");
+    }
+
+    @Override
+    public Page queryByProjectAndApp(Page page, String projectId, String appId) {
+        // TODO 分页查询使用ES
+        QueryWrapper<ObjectTypeDefine> wrapper = new QueryWrapper<>();
+        DigitalCommonUtils.ensureProjectCriteria(wrapper, projectId);
+        if(StrUtil.isNotBlank(appId)) {
+            // TODO 根据应用ID关联订阅条件
+
+        }
+        return queryByCondition(page, wrapper);
+    }
+
+    @Override
+    public List<ObjectTypeDefine> queryByCondition(Wrapper<ObjectTypeDefine> queryWrapper) {
+        return dao.selectList(queryWrapper);
+    }
+
+    @Override
+    public Page queryByCondition(Page page, Wrapper<ObjectTypeDefine> queryWrapper) {
+        return dao.selectPage(page, queryWrapper);
+    }
+
+    @Override
+    @CacheEvict(allEntries = true)
+    public List<ObjectTypeDefine> insert(List<ObjectTypeDefine> voList) {
+        if(CollUtil.isEmpty(voList)) {
+            return null;
+        }
+        validateOnSave(voList, false);
+        voList.forEach(vo -> {
+            // 新增前消息 - 暂不提供同步消息
+///            messageSender.sendMessage(DigitalMessageConstant.OPERATE_BEFORE_INSERT, null, vo, true);
+            // 新增
+            dao.insert(vo);
+            // 新增后消息
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_INSERT, null, vo, false);
+        });
+        return voList;
+    }
+
+    @Override
+    @CacheEvict(allEntries = true)
+    public List<ObjectTypeDefine> update(List<ObjectTypeDefine> voList) {
+        if(CollUtil.isEmpty(voList)) {
+            return null;
+        }
+        validateOnSave(voList, true);
+        List<String> idList = CollUtil.getFieldValues(voList, BaseEntity.PROP_ID, String.class);
+        List<ObjectTypeDefine> dbList = dao.selectBatchIds(idList);
+        Map<String, ObjectTypeDefine> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
+        voList.forEach(vo -> {
+            ObjectTypeDefine dbVO = MapUtil.get(dbMap, vo.getId(), ObjectTypeDefine.class);
+            // 容错处理
+            if(dbVO == null) {
+                return;
+            }
+            // 修改前消息 - 暂不提供同步消息
+///            messageSender.sendMessage(DigitalMessageConstant.OPERATE_BEFORE_UPDATE, dbVO, vo, true);
+            // 修改
+            dao.updateById(vo);
+            // 修改后消息
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_UPDATE, dbVO, vo, false);
+        });
+        return voList;
+    }
+
+    /**
+     * 保存校验
+     * 编码全局唯一
+     * @param voList
+     * @param isUpdate
+     */
+    private void validateOnSave(List<ObjectTypeDefine> voList, boolean isUpdate) {
+        Set<String> codeSet = new HashSet<>();
+        List<String> idList = new ArrayList<>();
+        for(ObjectTypeDefine vo:voList) {
+            // 编码重复
+            if(!codeSet.add(vo.getCode())) {
+                throw new BusinessException(StrFormatter.format("存在重复编码{},不允许保存!", vo.getCode()));
+            }
+            // 修改时,收集待排除的主键
+            if(isUpdate) {
+                idList.add(vo.getId());
+            }
+        }
+        // 查询条件
+        LambdaQueryWrapper<ObjectTypeDefine> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.select(ObjectTypeDefine::getCode);
+        queryWrapper.in(ObjectTypeDefine::getValid, ValidEnum.TRUE.getType());
+        queryWrapper.in(ObjectTypeDefine::getCode, codeSet);
+        if(isUpdate) {
+            queryWrapper.notIn(ObjectTypeDefine::getId, idList);
+        }
+        // 查询重复的编码
+        List<ObjectTypeDefine> dbList = dao.selectList(queryWrapper);
+        if(CollUtil.isEmpty(dbList)) {
+            return;
+        }
+        List<String> codes = CollUtil.getFieldValues(voList, "code", String.class);
+        throw new BusinessException(StrFormatter.format("存在重复编码{},不允许保存!", codes));
+    }
+
+    @Override
+    @CacheEvict(allEntries = true)
+    public void delete(List<String> idList) {
+        if(CollUtil.isEmpty(idList)) {
+            return;
+        }
+        List<ObjectTypeDefine> dbList = dao.selectBatchIds(idList);
+        Map<String, ObjectTypeDefine> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
+        idList.forEach(id -> {
+            ObjectTypeDefine dbVO = MapUtil.get(dbMap, id, ObjectTypeDefine.class);
+            // 容错处理
+            if(dbVO == null) {
+                return;
+            }
+            // 删除前消息 - 暂不提供同步消息
+///            messageSender.sendMessage(DigitalMessageConstant.OPERATE_BEFORE_DELETE, null, dbVO, true);
+            // 删除
+            ObjectTypeDefine vo = new ObjectTypeDefine();
+            vo.setId(id);
+            vo.setValid(ValidEnum.FALSE.getType());
+            dao.updateById(vo);
+            // 删除后消息
+            dbVO.setValid(ValidEnum.FALSE.getType());
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_DELETE, null, dbVO, false);
+        });
+    }
+}

+ 55 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/define/service/impl/RelationDefineServiceImpl.java

@@ -0,0 +1,55 @@
+package com.persagy.dc.define.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.define.dao.RelationDefineMapper;
+import com.persagy.dc.define.entity.RelationDefine;
+import com.persagy.dc.define.service.IRelationDefineService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 关系定义 实现类
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class RelationDefineServiceImpl implements IRelationDefineService {
+
+    @Resource
+    private RelationDefineMapper dao;
+
+    @Override
+    public List<RelationDefine> queryByCondition(Wrapper<RelationDefine> queryWrapper) {
+        return dao.selectList(queryWrapper);
+    }
+
+    @Override
+    public Page queryByCondition(Page page, Wrapper<RelationDefine> queryWrapper) {
+        return dao.selectPage(page, queryWrapper);
+    }
+
+    @Override
+    public RelationDefine insert(RelationDefine vo) {
+        dao.insert(vo);
+        return vo;
+    }
+
+    @Override
+    public RelationDefine update(RelationDefine vo) {
+        dao.updateById(vo);
+        return vo;
+    }
+
+    @Override
+    public void delete(String id) {
+        RelationDefine vo = dao.selectById(id);
+        vo.setValid(ValidEnum.FALSE.getType());
+        dao.updateById(vo);
+    }
+}

+ 41 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/config/DigitalRabbitConfig.java

@@ -0,0 +1,41 @@
+package com.persagy.dc.digital.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.Queue;
+import org.springframework.amqp.core.TopicExchange;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 项目变更消息配置
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Slf4j
+@Configuration
+public class DigitalRabbitConfig {
+
+    /** 项目消息 - Exchange */
+    public static final String PROJECT_EXCHANGE = "saas.common.topic";
+    /** 项目消息 - Queue */
+    public static final String PROJECT_QUEUE = "bdtp.project.saas.queue";
+    /** 项目消息 - RoutingKey */
+    public static final String PROJECT_ROUTING_KEY = "saas.common.bdtp.project";
+
+    @Bean
+    public TopicExchange projectExchange() {
+        return new TopicExchange(PROJECT_EXCHANGE);
+    }
+
+    @Bean
+    public Queue projectQueue(){
+        return new Queue(PROJECT_QUEUE);
+    }
+
+    @Bean
+    public Binding projectBinding() {
+        return BindingBuilder.bind(projectQueue()).to(projectExchange()).with(PROJECT_ROUTING_KEY);
+    }
+}

+ 88 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/controller/ObjectDigitalController.java

@@ -0,0 +1,88 @@
+package com.persagy.dc.digital.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.model.QueryCriteria;
+import com.persagy.dc.basic.utils.DigitalCommonUtils;
+import com.persagy.dc.basic.utils.QueryCriteriaHelper;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.model.response.PageList;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.digital.entity.ObjectDigital;
+import com.persagy.dc.digital.service.IObjectDigitalService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 对象数据 Controller
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+@RestController
+@RequestMapping("/object/digital")
+public class ObjectDigitalController {
+
+    @Autowired
+    private IObjectDigitalService service;
+
+    @PostMapping("query")
+    public CommonResult<PageList<ObjectDigital>> query(@RequestBody QueryCriteria criteria) {
+        if(criteria == null) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        QueryWrapper<ObjectDigital> wrapper = new QueryWrapper<>();
+        // 添加所属项目条件
+        DigitalCommonUtils.ensureProjectCriteria(wrapper);
+        // 转换查询条件
+        QueryCriteriaHelper.toWrapper(wrapper, criteria);
+        Page page = service.queryByCondition(QueryCriteriaHelper.toPage(criteria), wrapper);
+        return ResultHelper.multi(page.getRecords(), page.getTotal());
+    }
+
+    @PostMapping("/create")
+    public CommonResult<ObjectDigital> create(@Valid @RequestBody ObjectDigital vo){
+        List<ObjectDigital> voList = CollUtil.newArrayList(vo);
+        service.insert(voList);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/createBatch")
+    public CommonResult<PageList<ObjectDigital>> createBatch(@Valid @RequestBody List<ObjectDigital> voList){
+        voList = service.insert(voList);
+        return ResultHelper.multi(voList);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<ObjectDigital> update(@Valid @RequestBody ObjectDigital vo){
+        List<ObjectDigital> voList = CollUtil.newArrayList(vo);
+        service.update(voList);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/updateBatch")
+    public CommonResult<PageList<ObjectDigital>> updateBatch(@Valid @RequestBody List<ObjectDigital> voList){
+        voList = service.update(voList);
+        return ResultHelper.multi(voList);
+    }
+
+    @PostMapping("/delete")
+    public CommonResult delete(@RequestBody String id){
+        service.delete(CollUtil.newArrayList(id));
+        return ResultHelper.success();
+    }
+
+    @PostMapping("/deleteBatch")
+    public CommonResult deleteBatch(@RequestBody List<String> id){
+        service.delete(id);
+        return ResultHelper.success();
+    }
+}

+ 88 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/controller/ObjectRelationController.java

@@ -0,0 +1,88 @@
+package com.persagy.dc.digital.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.model.QueryCriteria;
+import com.persagy.dc.basic.utils.DigitalCommonUtils;
+import com.persagy.dc.basic.utils.QueryCriteriaHelper;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.model.response.PageList;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.digital.entity.ObjectRelation;
+import com.persagy.dc.digital.service.IObjectRelationService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 关系数据 Controller
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+@RestController
+@RequestMapping("/object/relation")
+public class ObjectRelationController {
+
+    @Autowired
+    private IObjectRelationService service;
+
+    @PostMapping("query")
+    public CommonResult<PageList<ObjectRelation>> query(@RequestBody QueryCriteria criteria) {
+        if(criteria == null) {
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        QueryWrapper<ObjectRelation> wrapper = new QueryWrapper<>();
+        // 添加所属项目条件
+        DigitalCommonUtils.ensureProjectCriteria(wrapper);
+        // 转换查询条件
+        QueryCriteriaHelper.toWrapper(wrapper, criteria);
+        Page page = service.queryByCondition(QueryCriteriaHelper.toPage(criteria), wrapper);
+        return ResultHelper.multi(page.getRecords(), page.getTotal());
+    }
+
+    @PostMapping("/create")
+    public CommonResult<ObjectRelation> create(@Valid @RequestBody ObjectRelation vo){
+        List<ObjectRelation> voList = CollUtil.newArrayList(vo);
+        service.insert(voList);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/createBatch")
+    public CommonResult<PageList<ObjectRelation>> createBatch(@Valid @RequestBody List<ObjectRelation> voList){
+        voList = service.insert(voList);
+        return ResultHelper.multi(voList);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<ObjectRelation> update(@Valid @RequestBody ObjectRelation vo){
+        List<ObjectRelation> voList = CollUtil.newArrayList(vo);
+        service.update(voList);
+        return ResultHelper.single(vo);
+    }
+
+    @PostMapping("/updateBatch")
+    public CommonResult<PageList<ObjectRelation>> updateBatch(@Valid @RequestBody List<ObjectRelation> voList){
+        voList = service.update(voList);
+        return ResultHelper.multi(voList);
+    }
+
+    @PostMapping("/delete")
+    public CommonResult delete(@RequestBody String id){
+        service.delete(CollUtil.newArrayList(id));
+        return ResultHelper.success();
+    }
+
+    @PostMapping("/deleteBatch")
+    public CommonResult deleteBatch(@RequestBody List<String> id){
+        service.delete(id);
+        return ResultHelper.success();
+    }
+}

+ 12 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/dao/ObjectDigitalMapper.java

@@ -0,0 +1,12 @@
+package com.persagy.dc.digital.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.digital.entity.ObjectDigital;
+
+/**
+ * 对象数据 DAO
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+public interface ObjectDigitalMapper extends BaseMapper<ObjectDigital> {
+}

+ 12 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/dao/ObjectRelationMapper.java

@@ -0,0 +1,12 @@
+package com.persagy.dc.digital.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.digital.entity.ObjectRelation;
+
+/**
+ * 关系数据 DAO
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+public interface ObjectRelationMapper extends BaseMapper<ObjectRelation> {
+}

+ 46 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/entity/ObjectDigital.java

@@ -0,0 +1,46 @@
+package com.persagy.dc.digital.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * 对象数据
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName(value = "dt_object")
+public class ObjectDigital extends AuditableEntity {
+    /** 项目ID */
+    private String projectId;
+    /** 名称 */
+    private String name;
+    /** 本地编码 */
+    private String localId;
+    /** 本地名称 */
+    private String localName;
+    /** 对象分类 */
+    private String objType;
+    /** 类型编码 */
+    private String classCode;
+    /** 组标识 */
+    private Integer grouping;
+    /** 边类型编码 */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private ObjectNode infos;
+    /** 虚点清单 */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<String> virtualCodes;
+    /** 创建应用 */
+    private String createApp;
+    /** 最后修改应用 */
+    private String updateApp;
+}

+ 35 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/entity/ObjectRelation.java

@@ -0,0 +1,35 @@
+package com.persagy.dc.digital.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 对象数据
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("dt_relation")
+public class ObjectRelation extends AuditableEntity {
+    /** 项目ID */
+    private String projectId;
+    /** 图例ID */
+    private String graphId;
+    /** 图例编码 */
+    private String graphCode;
+    /** 关系编码 */
+    private String relCode;
+    /** 关系值 */
+    private String relValue;
+    /** 来源对象 */
+    private String objFrom;
+    /** 目标对象 */
+    private String objTo;
+    /** 创建应用 */
+    private String createApp;
+    /** 最后修改应用 */
+    private String updateApp;
+}

+ 79 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/handler/ProjectMessageHandler.java

@@ -0,0 +1,79 @@
+package com.persagy.dc.digital.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.persagy.dc.amqp.handler.AbstractRabbitHandlerTemplate;
+import com.persagy.dc.common.constant.CommonConstant;
+import com.persagy.dc.common.context.AppContext;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.digital.config.DigitalRabbitConfig;
+import com.persagy.dc.digital.entity.ObjectDigital;
+import com.persagy.dc.digital.service.IObjectDigitalService;
+import com.persagy.dc.mybatis.helper.DynamicDataSourceHelper;
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * 项目消息消费
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Slf4j
+@Component
+@RabbitListener(queues = DigitalRabbitConfig.PROJECT_QUEUE)
+public class ProjectMessageHandler extends AbstractRabbitHandlerTemplate {
+
+    @Autowired
+    private ObjectMapper objectMapper;
+    @Autowired
+    private IObjectDigitalService digitalService;
+
+    /**
+     * 消费
+     * @param message 消息体字符串
+     * @param channel 通道对象
+     * @param vo     消息对象
+     */
+    @Override
+    protected void handler(String message, Channel channel, Message vo) {
+        try {
+            ProjectMessageVO msgVO = objectMapper.readValue(message, ProjectMessageVO.class);
+            initContextInfo(msgVO);
+            ObjectDigital project = msgVO.toObjectDigital();
+            // 幂等处理 - 检查是否已经存在
+            ObjectDigital dbVO = digitalService.load(project.getId());
+            if(dbVO == null) {
+                digitalService.insert(CollUtil.newArrayList(project));
+            } else {
+                digitalService.update(CollUtil.newArrayList(project));
+            }
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            throw new BusinessException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 初始化上下文,切换数据源
+     * @param vo
+     */
+    private void initContextInfo(ProjectMessageVO vo) {
+        AppContext.getContext().setGroupCode(vo.getGroupCode());
+        AppContext.getContext().setProjectId(vo.getProjectId());
+        AppContext.getContext().setAppId("BOSS");
+        String userId = vo.getUpdateUser();
+        // 无用户时,默认为默认系统用户
+        if(StrUtil.isBlank(userId)) {
+            userId = CommonConstant.DEFAULT_ID;
+        }
+        AppContext.getContext().setAccountId(userId);
+        DynamicDataSourceHelper.loadDataSource();
+    }
+}

+ 163 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/handler/ProjectMessageVO.java

@@ -0,0 +1,163 @@
+package com.persagy.dc.digital.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dc.common.context.AppContext;
+import com.persagy.dc.common.lang.PsDateTime;
+import com.persagy.dc.digital.entity.ObjectDigital;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * 项目消息对象
+ * {
+ *   "id":"PR1395270128588939265", //项目主键Id
+ *   "groupCode":"ICBC",           //集团编码
+ *   "projectId":"Pj8765863329",   //项目ID
+ *   "projectLocalId":"8765863329",//项目本地编码
+ *   "areaId":"AR1381523632282435585",//区域ID
+ *   "projectName":"项目名称",       //项目名称
+ *   "provinceCode":"",             //项目所在省份
+ *   "cityCode":"",                 //项目所在市
+ *   "zoneCode":"",                 //项目所在区
+ *   "location":"天府大道219号",      //项目详细地址
+ *   "openTime":1623985811012,       //开业时间
+ *   "createTime":1623985811012,     //创建时间
+ *   "updateTime":1623985811012,     //更新时间
+ *   "updateUser":"AC1372371635352403969",//最后修改人ID
+ *   "remark":"备注",                 //备注
+ *   "valid":1,                      //有效状态,0-无效,1-有效
+ *   "projectFun":"E100",            //项目功能
+ *   "projectWeather":"20",          //项目天气
+ *   "projectImage":["图4.jpg","图6.jpg"],//项目图片,set集合
+ *   "longitude":11.002,             //项目经度
+ *   "latitude":22.99,               //项目纬度
+ *   "manageZone":"高新区",            //集团管理分区
+ *   "type":"create"                //通知类型,create-创建,update-修改
+ * }
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Data
+public class ProjectMessageVO {
+
+    /** 项目主键Id */
+    private String id;
+    /** 集团编码 */
+    private String groupCode;
+    /** 项目ID */
+    private String projectId;
+    /** 项目本地编码 */
+    private String projectLocalId;
+    /** 区域ID */
+    private String areaId;
+    /** 项目名称 */
+    private String projectName;
+    /** 项目所在省份 */
+    private String provinceCode;
+    /** 项目所在市 */
+    private String cityCode;
+    /** 项目所在区 */
+    private String zoneCode;
+    /** 项目详细地址 */
+    private String location;
+    /** 开业时间 */
+    private PsDateTime openTime;
+    /** 创建时间 */
+    private PsDateTime createTime;
+    /** 更新时间 */
+    private PsDateTime updateTime;
+    /** 最后修改人ID */
+    private String updateUser;
+    /** 备注 */
+    private String remark;
+    /** 有效状态,0-无效,1-有效 */
+    private Integer valid;
+    /** 项目功能 */
+    private String projectFun;
+    /** 项目天气 */
+    private String projectWeather;
+    /** 项目图片,set集合 */
+    private Set<String> projectImage;
+    /** 项目经度 */
+    private BigDecimal longitude;
+    /** 项目纬度 */
+    private BigDecimal latitude;
+    /** 集团管理分区 */
+    private String manageZone;
+    /** 通知类型,create-创建,update-修改 */
+    private String type;
+
+    /**
+     * 转换为对象
+     * @return
+     */
+    public ObjectDigital toObjectDigital() {
+        ObjectDigital project = new ObjectDigital();
+        project.setId(projectId);
+        project.setProjectId(projectId);
+        project.setName(projectName);
+        project.setLocalId(projectLocalId);
+        project.setObjType("project");
+        project.setClassCode("project");
+        project.setGrouping(1);
+        project.setVirtualCodes(Collections.emptyList());
+        project.setValid(valid);
+        if("create".equalsIgnoreCase(type)) {
+            project.setCreateApp(AppContext.getContext().getAppId());
+        } else {
+            project.setUpdateApp(AppContext.getContext().getAppId());
+        }
+        project.setInfos(toObjectInfos());
+        return project;
+    }
+
+    /**
+     * 构建infos
+     * @return
+     */
+    public ObjectNode toObjectInfos() {
+        // 构建infos - 为空不写入
+        ObjectNode infos = JsonNodeFactory.instance.objectNode();
+        if(StrUtil.isNotBlank(provinceCode)) {
+            infos.put("province", provinceCode);
+        }
+        if(StrUtil.isNotBlank(cityCode)) {
+            infos.put("city", cityCode);
+        }
+        if(StrUtil.isNotBlank(zoneCode)) {
+            infos.put("urbanZone", zoneCode);
+        }
+        if(longitude != null) {
+            infos.put("longitude", longitude);
+        }
+        if(latitude != null) {
+            infos.put("latitude", latitude);
+        }
+        if(StrUtil.isNotBlank(location)) {
+            infos.put("address", location);
+        }
+        if(openTime != null) {
+            infos.put("businessOpeningTime", openTime.toString("yyyyMMdd"));
+        }
+        if(StrUtil.isNotBlank(projectFun)) {
+            infos.put("projFuncType", projectFun);
+        }
+        if(StrUtil.isNotBlank(projectWeather)) {
+            infos.put("climateZone", projectWeather);
+        }
+        if(StrUtil.isNotBlank(manageZone)) {
+            infos.put("groupManageZone", manageZone);
+        }
+        // 添加图片
+        if(CollUtil.isNotEmpty(projectImage)) {
+            projectImage.forEach(p -> infos.withArray("projPic").addPOJO(p));
+        }
+        return infos;
+    }
+}

+ 57 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/IObjectDigitalService.java

@@ -0,0 +1,57 @@
+package com.persagy.dc.digital.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.digital.entity.ObjectDigital;
+
+import java.util.List;
+
+/**
+ * 对象数据 接口
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+public interface IObjectDigitalService {
+
+    /**
+     * 通过ID查询
+     * @param id 主键
+     * @return
+     */
+    ObjectDigital load(String id);
+
+    /**
+     * 按条件查询
+     * @param queryWrapper 查询条件
+     * @return 列表
+     */
+    List<ObjectDigital> queryByCondition(Wrapper<ObjectDigital> queryWrapper);
+
+    /**
+     * 按条件查询
+     * @param page 分页条件
+     * @param queryWrapper 查询条件
+     * @return 分页结果
+     */
+    Page queryByCondition(Page page, Wrapper<ObjectDigital> queryWrapper);
+
+    /**
+     * 新增
+     * @param voList 待新增数据
+     * @return 新增后数据
+     */
+    List<ObjectDigital> insert(List<ObjectDigital> voList);
+
+    /**
+     * 修改
+     * @param voList 待修改数据
+     * @return 修改后数据
+     */
+    List<ObjectDigital> update(List<ObjectDigital> voList);
+
+    /**
+     * 删除
+     * @param idList 主键
+     */
+    void delete(List<String> idList);
+}

+ 50 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/IObjectRelationService.java

@@ -0,0 +1,50 @@
+package com.persagy.dc.digital.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.digital.entity.ObjectRelation;
+
+import java.util.List;
+
+/**
+ * 关系数据 接口
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+public interface IObjectRelationService {
+
+    /**
+     * 按条件查询
+     * @param queryWrapper 查询条件
+     * @return 列表
+     */
+    List<ObjectRelation> queryByCondition(Wrapper<ObjectRelation> queryWrapper);
+
+    /**
+     * 按条件查询
+     * @param page 分页条件
+     * @param queryWrapper 查询条件
+     * @return 分页结果
+     */
+    Page queryByCondition(Page page, Wrapper<ObjectRelation> queryWrapper);
+
+    /**
+     * 新增
+     * @param voList 待新增数据
+     * @return 新增后数据
+     */
+    List<ObjectRelation> insert(List<ObjectRelation> voList);
+
+    /**
+     * 修改
+     * @param voList 待修改数据
+     * @return 修改后数据
+     */
+    List<ObjectRelation> update(List<ObjectRelation> voList);
+
+    /**
+     * 删除
+     * @param idList 主键
+     */
+    void delete(List<String> idList);
+}

+ 158 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/impl/ObjectDigitalServiceImpl.java

@@ -0,0 +1,158 @@
+package com.persagy.dc.digital.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.map.MapUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dc.basic.constant.DigitalMessageConstant;
+import com.persagy.dc.basic.utils.DigitalCommonUtils;
+import com.persagy.dc.basic.utils.DigitalMessageHelper;
+import com.persagy.dc.common.constant.ValidEnum;
+import com.persagy.dc.common.model.entity.BaseEntity;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+import com.persagy.dc.define.service.IObjectInfoService;
+import com.persagy.dc.digital.dao.ObjectDigitalMapper;
+import com.persagy.dc.digital.entity.ObjectDigital;
+import com.persagy.dc.digital.service.IObjectDigitalService;
+import com.persagy.dc.parser.service.InfoDataFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 对象数据 实现类
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class ObjectDigitalServiceImpl implements IObjectDigitalService {
+
+    @Resource
+    private ObjectDigitalMapper dao;
+    @Autowired
+    private DigitalMessageHelper messageSender;
+    @Autowired
+    private IObjectInfoService infoService;
+
+    @Override
+    public ObjectDigital load(String id) {
+        return dao.selectById(id);
+    }
+
+    @Override
+    public List<ObjectDigital> queryByCondition(Wrapper<ObjectDigital> queryWrapper) {
+        return dao.selectList(queryWrapper);
+    }
+
+    @Override
+    public Page queryByCondition(Page page, Wrapper<ObjectDigital> queryWrapper) {
+        return dao.selectPage(page, queryWrapper);
+    }
+
+    @Override
+    public List<ObjectDigital> insert(List<ObjectDigital> voList) {
+        if(CollUtil.isEmpty(voList)) {
+            return null;
+        }
+        validateOnSave(voList, false);
+        voList.forEach(vo -> {
+            // 生成ID
+            vo.setId(DigitalCommonUtils.fetchObjectId(vo.getProjectId(), vo.getObjType()));
+            // 新增
+            dao.insert(vo);
+            // 新增后消息
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_INSERT, null, vo, false);
+        });
+        return voList;
+    }
+
+    @Override
+    public List<ObjectDigital> update(List<ObjectDigital> voList) {
+        if(CollUtil.isEmpty(voList)) {
+            return null;
+        }
+        validateOnSave(voList, true);
+        List<String> idList = CollUtil.getFieldValues(voList, BaseEntity.PROP_ID, String.class);
+        List<ObjectDigital> dbList = dao.selectBatchIds(idList);
+        Map<String, ObjectDigital> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
+        voList.forEach(vo -> {
+            ObjectDigital dbVO = MapUtil.get(dbMap, vo.getId(), ObjectDigital.class);
+            // 容错处理
+            if(dbVO == null) {
+                return;
+            }
+            // 修改
+            dao.updateById(vo);
+            // 修改后消息
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_UPDATE, dbVO, vo, false);
+        });
+        return voList;
+    }
+
+    /**
+     * 保存校验
+     * 编码全局唯一
+     * @param voList
+     * @param isUpdate
+     */
+    private void validateOnSave(List<ObjectDigital> voList, boolean isUpdate) {
+        validateInfoCode(voList);
+    }
+
+    /**
+     * 信息点值校验
+     * @param voList
+     */
+    private void validateInfoCode(List<ObjectDigital> voList) {
+        // 查询信息点定义
+        List<String> typeCodeList = CollUtil.getFieldValues(voList, "classCode", String.class);
+        Map<String, Map<String, ObjectInfoDefine>> allInfoMap = infoService.queryByTypes(typeCodeList);
+        // 信息点校验器
+        for(ObjectDigital vo:voList) {
+            Map<String, ObjectInfoDefine> infoMap = allInfoMap.get(vo.getClassCode());
+            if(MapUtil.isEmpty(infoMap)) {
+                continue;
+            }
+            // 信息点值对象
+            ObjectNode infos = vo.getInfos();
+            // 按信息点定义循环校验
+            for(String infoCode:infoMap.keySet()) {
+                if(!infos.has(infoCode)) {
+                    continue;
+                }
+                InfoDataFactory.parse(infoMap.get(infoCode), infos.get(infoCode));
+            }
+        }
+    }
+
+    @Override
+    public void delete(List<String> idList) {
+        if(CollUtil.isEmpty(idList)) {
+            return;
+        }
+        List<ObjectDigital> dbList = dao.selectBatchIds(idList);
+        Map<String, ObjectDigital> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
+        idList.forEach(id -> {
+            ObjectDigital dbVO = MapUtil.get(dbMap, id, ObjectDigital.class);
+            // 容错处理
+            if(dbVO == null) {
+                return;
+            }
+            // 删除
+            ObjectDigital vo = new ObjectDigital();
+            vo.setId(id);
+            vo.setValid(ValidEnum.FALSE.getType());
+            dao.updateById(vo);
+            // 删除后消息
+            dbVO.setValid(ValidEnum.FALSE.getType());
+            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_DELETE, null, dbVO, false);
+        });
+    }
+}

+ 54 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/digital/service/impl/ObjectRelationServiceImpl.java

@@ -0,0 +1,54 @@
+package com.persagy.dc.digital.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.dc.basic.utils.DigitalMessageHelper;
+import com.persagy.dc.digital.dao.ObjectRelationMapper;
+import com.persagy.dc.digital.entity.ObjectRelation;
+import com.persagy.dc.digital.service.IObjectRelationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 关系数据 实现类
+ * @author Charlie Yu
+ * @date 2021-07-08
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class ObjectRelationServiceImpl implements IObjectRelationService {
+
+    @Resource
+    private ObjectRelationMapper dao;
+    @Autowired
+    private DigitalMessageHelper messageSender;
+
+    @Override
+    public List<ObjectRelation> queryByCondition(Wrapper<ObjectRelation> queryWrapper) {
+        return dao.selectList(queryWrapper);
+    }
+
+    @Override
+    public Page queryByCondition(Page page, Wrapper<ObjectRelation> queryWrapper) {
+        return dao.selectPage(page, queryWrapper);
+    }
+
+    @Override
+    public List<ObjectRelation> insert(List<ObjectRelation> voList) {
+        return null;
+    }
+
+    @Override
+    public List<ObjectRelation> update(List<ObjectRelation> voList) {
+        return null;
+    }
+
+    @Override
+    public void delete(List<String> idList) {
+
+    }
+}

+ 19 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/EnumVO.java

@@ -0,0 +1,19 @@
+package com.persagy.dc.parser.entity;
+
+import lombok.Data;
+
+/**
+ * 枚举数据
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Data
+public class EnumVO {
+
+    /** 编码 */
+    private String code;
+    /** 名称 */
+    private String name;
+    /** 上级编码 */
+    private String parentCode;
+}

+ 41 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/ParserResult.java

@@ -0,0 +1,41 @@
+package com.persagy.dc.parser.entity;
+
+import cn.hutool.core.util.BooleanUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+import lombok.Data;
+
+/**
+ * 信息点 处理结果
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Data
+public class ParserResult {
+
+    /** 信息点定义 */
+    private ObjectInfoDefine infoDefine;
+    /** 信息点值 */
+    private JsonNode valueInfo;
+
+    public ParserResult(ObjectInfoDefine infoDefine, JsonNode valueInfo) {
+        this.infoDefine = infoDefine;
+        this.valueInfo = valueInfo;
+    }
+
+    /**
+     * 是否复选
+     * @return
+     */
+    public boolean isMulti() {
+        return BooleanUtil.isTrue(infoDefine.getMultipleFlag());
+    }
+
+    /**
+     * 是否区间
+     * @return
+     */
+    public boolean isRegion() {
+        return BooleanUtil.isTrue(infoDefine.getRegionFlag());
+    }
+}

+ 108 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/RegionVO.java

@@ -0,0 +1,108 @@
+package com.persagy.dc.parser.entity;
+
+import cn.hutool.core.collection.CollUtil;
+import com.fasterxml.jackson.annotation.JsonAlias;
+import com.persagy.dc.common.model.data.RegionValue;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 区间数据
+ * @param <T> 数据泛型
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Data
+public class RegionVO<T extends Comparable> {
+
+    /** 大于 */
+    @JsonAlias(value = "$gt")
+    public T great;
+    /** 大于等于 */
+    @JsonAlias(value = "$gte")
+    public T greatEqual;
+    /** 小于 */
+    @JsonAlias(value = "$lt")
+    public T less;
+    /** 小于等于 */
+    @JsonAlias(value = "$lte")
+    public T lessEqual;
+
+    public RegionVO() {
+    }
+
+    public RegionVO(T great, T greatEqual, T less, T lessEqual) {
+        this.great = great;
+        this.greatEqual = greatEqual;
+        this.less = less;
+        this.lessEqual = lessEqual;
+    }
+
+    /**
+     * 是否为空
+     * @return
+     */
+    public boolean isEmpty() {
+        return great == null && greatEqual == null && less == null && lessEqual == null;
+    }
+
+    /**
+     * 转换为RegionValue
+     * @return
+     */
+    public RegionValue<T> toRegionValue() {
+        RegionValue region = new RegionValue();
+        // 区间开始赋值
+        if(great != null) {
+            if(greatEqual == null || great.compareTo(greatEqual) >= 0) {
+                region.setStart(great);
+                region.setContainStart(false);
+            } else {
+                region.setStart(greatEqual);
+                region.setContainStart(true);
+            }
+        } else {
+            // 只有大于等于
+            if(greatEqual != null) {
+                region.setStart(greatEqual);
+                region.setContainStart(true);
+            }
+        }
+        // 区间结束赋值
+        if(less != null) {
+            if(lessEqual == null || less.compareTo(lessEqual) <= 0) {
+                region.setEnd(less);
+                region.setContainEnd(false);
+            } else {
+                region.setEnd(lessEqual);
+                region.setContainEnd(true);
+            }
+        } else {
+            // 只有小于等于
+            if(lessEqual != null) {
+                region.setEnd(lessEqual);
+                region.setContainEnd(true);
+            }
+        }
+        return region;
+    }
+
+    /**
+     * 转换为RegionValue
+     * @param values
+     * @param <T>
+     * @return
+     */
+    public static <T extends Comparable> List<RegionValue<T>> toRegionValueList(List<RegionVO<T>> values) {
+        if(CollUtil.isEmpty(values)) {
+            return null;
+        }
+        List<RegionValue<T>> regionList = new ArrayList<>();
+        for(RegionVO<T> value:values) {
+            regionList.add(value.toRegionValue());
+        }
+        return regionList;
+    }
+}

+ 21 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/IInfoDataParser.java

@@ -0,0 +1,21 @@
+package com.persagy.dc.parser.service;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+import com.persagy.dc.parser.entity.ParserResult;
+
+/**
+ * 信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public interface IInfoDataParser {
+
+    /**
+     * 处理信息点
+     * @param infoDefine 信息点 定义信息
+     * @param valueInfo 信息点 值信息
+     * @return ParserResult
+     */
+    ParserResult parse(ObjectInfoDefine infoDefine, JsonNode valueInfo);
+}

+ 57 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/InfoDataFactory.java

@@ -0,0 +1,57 @@
+package com.persagy.dc.parser.service;
+
+import cn.hutool.core.map.MapUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.dc.basic.constant.DigitalDataType;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+import com.persagy.dc.parser.entity.ParserResult;
+import com.persagy.dc.parser.service.impl.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 信息点 处理工厂
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class InfoDataFactory {
+
+    /** 信息点处理器Map<DataType, Parser> */
+    private static Map<String, IInfoDataParser> parserMap = new HashMap<>(16);
+
+    /**
+     * 处理信息点
+     * @param infoDefine 信息点 定义信息
+     * @param valueInfo 信息点 值信息
+     * @return ParserResult
+     */
+    public static ParserResult parse(ObjectInfoDefine infoDefine, JsonNode valueInfo) {
+        IInfoDataParser parser = getParser(infoDefine.getDataType());
+        return parser.parse(infoDefine, valueInfo);
+    }
+
+    /**
+     * 根据数据类型获取信息点处理器
+     * @param dataType 数据类型
+     * @return
+     */
+    private static IInfoDataParser getParser(String dataType) {
+        // 懒加载
+        if(MapUtil.isEmpty(parserMap)) {
+            parserMap.put(DigitalDataType.ATTACHMENT.getIndex(), new AttachmentInfoParser());
+            parserMap.put(DigitalDataType.BOOLEAN.getIndex(), new BooleanInfoParser());
+            parserMap.put(DigitalDataType.DATETIME.getIndex(), new DateInfoParser());
+            parserMap.put(DigitalDataType.DOUBLE.getIndex(), new DoubleInfoParser());
+            parserMap.put(DigitalDataType.ENUM.getIndex(), new EnumInfoParser());
+            parserMap.put(DigitalDataType.INTEGER.getIndex(), new IntegerInfoParser());
+            parserMap.put(DigitalDataType.STRING.getIndex(), new StringInfoParser());
+        }
+        // 校验类型传值
+        if(!parserMap.containsKey(dataType)) {
+            throw new BusinessException("找不到对应数据类型的处理器!");
+        }
+        return parserMap.get(dataType);
+    }
+}

+ 150 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AbstractInfoDataParser.java

@@ -0,0 +1,150 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.persagy.dc.basic.constant.DigitalDataCategory;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.helper.SpringHelper;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.define.entity.ObjectInfoDefine;
+import com.persagy.dc.parser.entity.ParserResult;
+import com.persagy.dc.parser.entity.RegionVO;
+import com.persagy.dc.parser.service.IInfoDataParser;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 信息点 抽象处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Slf4j
+public abstract class AbstractInfoDataParser implements IInfoDataParser {
+
+    private static ObjectMapper objectMapper;
+
+    /**
+     * 接口实现
+     * @param infoDefine 信息点 定义信息
+     * @param valueInfo 信息点 值信息
+     * @return
+     */
+    @Override
+    public ParserResult parse(ObjectInfoDefine infoDefine, JsonNode valueInfo) {
+        ParserResult result = new ParserResult(infoDefine, valueInfo);
+        try {
+            // 校验信息点定义
+            validateDefine(result);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            throw new BusinessException(StrUtil.format("信息点[{}]定义有误,数据源格式有误!", result.getInfoDefine().getCode()));
+        }
+        // 空值、非静态信息点不需要值校验
+        if(valueInfo == null ||
+                JsonNodeType.NULL == valueInfo.getNodeType() ||
+                DigitalDataCategory.STATIC.getIndex().equalsIgnoreCase(infoDefine.getCategory())) {
+            return result;
+        }
+        try {
+            // 值校验
+            validateValue(result);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            throw new BusinessException(StrUtil.format("信息点[{}]数据格式有误!", result.getInfoDefine().getCode()));
+        }
+        return result;
+    }
+
+    /**
+     * 信息点定义校验
+     * @param result 校验参数
+     * @throws IOException json转换异常
+     */
+    protected abstract void validateDefine(ParserResult result) throws IOException;
+
+    /**
+     * 信息点值校验
+     * @param result 校验参数
+     * @throws IOException json转换异常
+     */
+    protected abstract void validateValue(ParserResult result) throws IOException;
+
+    /**
+     * 获取数据
+     * @param value
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    protected <T> T formatValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        return getObjectMapper().readValue(value.toString(), clazz);
+    }
+
+    /**
+     * 获取数据
+     * @param value
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    protected <T> List<T> formatListValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(ArrayList.class, clazz);
+        return getObjectMapper().readValue(value.toString(), javaType);
+    }
+
+    /**
+     * 获取数据
+     * @param value json
+     * @param clazz 泛型类
+     * @param <T>
+     * @return RegionValue
+     */
+    protected <T extends Comparable> RegionValue<T> formatRegionValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(RegionVO.class, clazz);
+        RegionVO<T> region = getObjectMapper().readValue(value.toString(), javaType);
+        return region == null ? null:region.toRegionValue();
+    }
+
+    /**
+     * 获取数据
+     * @param value
+     * @param clazz 泛型类
+     * @param <T>
+     * @return List<RegionValue<T>>
+     */
+    protected <T extends Comparable> List<RegionValue<T>> formatRegionListValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(RegionVO.class, clazz);
+        javaType = getObjectMapper().getTypeFactory().constructParametricType(List.class, javaType);
+        List<RegionVO<T>> regionList = getObjectMapper().readValue(value.toString(), javaType);
+        return RegionVO.toRegionValueList(regionList);
+    }
+
+    /**
+     * 获取ObjectMapper
+     * @return
+     */
+    protected ObjectMapper getObjectMapper() {
+        if(objectMapper == null) {
+            objectMapper = SpringHelper.getBean(ObjectMapper.class);
+        }
+        return objectMapper;
+    }
+}

+ 36 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AttachmentInfoParser.java

@@ -0,0 +1,36 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 附件信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class AttachmentInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected void validateDefine(ParserResult result) {
+        // 不支持区间格式
+        if(result.isRegion()) {
+            throw new BusinessException(StrUtil.format("信息点[{}]定义有误,Attachment类型不允许定义区间!", result.getInfoDefine().getCode()));
+        }
+    }
+
+    @Override
+    protected void validateValue(ParserResult result) throws IOException{
+        // 复数
+        if(result.isMulti()) {
+            List<ObjectNode> valueList = formatListValue(result.getValueInfo(), ObjectNode.class);
+        } else {
+            // 单数
+            ObjectNode value = formatValue(result.getValueInfo(), ObjectNode.class);
+        }
+    }
+}

+ 34 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/BooleanInfoParser.java

@@ -0,0 +1,34 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+
+/**
+ * 布尔信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class BooleanInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected void validateDefine(ParserResult result) {
+        // 不支持区间格式
+        if(result.isRegion()) {
+            throw new BusinessException(StrUtil.format("信息点[{}]定义有误,Boolean类型不允许定义区间!", result.getInfoDefine().getCode()));
+        }
+    }
+
+    @Override
+    protected void validateValue(ParserResult result) throws IOException {
+        // 复数
+        if(result.isMulti()) {
+            formatListValue(result.getValueInfo(), Boolean.class);
+        } else {
+            // 单数
+            formatValue(result.getValueInfo(), Boolean.class);
+        }
+    }
+}

+ 142 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DateInfoParser.java

@@ -0,0 +1,142 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.common.utils.RegionUtil;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 日期信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class DateInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected void validateDefine(ParserResult result) throws IOException {
+        // 格式默认为yyyyMMddHHmmss
+        if(StrUtil.isBlank(result.getInfoDefine().getFormatter())) {
+            result.getInfoDefine().setFormatter("yyyyMMddHHmmss");
+        }
+        String formatter = result.getInfoDefine().getFormatter();
+        // 数据源 - 应为区间列表格式
+        List<RegionValue<String>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), String.class);
+        // 区间格式校验
+        if(!matchRegionDataFormat(formatter, dataSource)) {
+            throw new BusinessException(StrUtil.format("信息点[{}]定义有误,数据源格式有误!", result.getInfoDefine().getCode()));
+        }
+    }
+
+    @Override
+    protected void validateValue(ParserResult result) throws IOException {
+        String formatter = result.getInfoDefine().getFormatter();
+        // 数据源定义信息
+        List<RegionValue<String>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), String.class);
+        // 复数
+        if(result.isMulti()) {
+            // 复数区间
+            if(result.isRegion()) {
+                List<RegionValue<String>> valueList = formatRegionListValue(result.getValueInfo(), String.class);
+                // 区间格式校验
+                if (!matchRegionDataFormat(formatter, valueList)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据格式有误!", result.getInfoDefine().getCode()));
+                }
+                // 区间范围校验
+                if (!RegionUtil.allContains(dataSource, valueList)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            } else {
+                // 复数非区间
+                List<String> valueList = formatListValue(result.getValueInfo(), String.class);
+                // 区间格式校验
+                if (!matchDataFormat(formatter, valueList)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据格式有误!", result.getInfoDefine().getCode()));
+                }
+                // 区间范围校验
+                if (!RegionUtil.allContain(dataSource, valueList)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            }
+        } else {
+            // 单数区间
+            if(result.isRegion()) {
+                RegionValue<String> value = formatRegionValue(result.getValueInfo(), String.class);
+                // 日期格式校验
+                if (!matchRegionDataFormat(formatter, CollUtil.newArrayList(value))) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据格式有误!", result.getInfoDefine().getCode()));
+                }
+                // 区间范围校验
+                if (!RegionUtil.anyContains(dataSource, value)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            } else {
+                // 单数非区间
+                String value = formatValue(result.getValueInfo(), String.class);
+                // 日期格式校验
+                if (!matchDataFormat(formatter, value)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据格式有误!", result.getInfoDefine().getCode()));
+                }
+                // 区间范围校验
+                if (!RegionUtil.anyContain(dataSource, value)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            }
+        }
+    }
+
+    /**
+     * 是否为指定格式日期区间
+     * @param formatter 格式
+     * @param regions 区间
+     * @return
+     */
+    private boolean matchRegionDataFormat(String formatter, List<RegionValue<String>> regions) {
+        if(CollUtil.isEmpty(regions) || StrUtil.isBlank(formatter)) {
+            return true;
+        }
+        for(RegionValue<String> region:regions) {
+            // 如果都匹配,则继续判断
+            if(matchDataFormat(formatter, region.getStart()) && matchDataFormat(formatter, region.getEnd())) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否为指定格式日期
+     * @param formatter 格式
+     * @param valueList 日期字符串
+     * @return
+     */
+    private boolean matchDataFormat(String formatter, List<String> valueList) {
+        if(CollUtil.isEmpty(valueList) || StrUtil.isBlank(formatter)) {
+            return true;
+        }
+        for(String value:valueList) {
+            // 如果匹配,则继续判断
+            if(matchDataFormat(formatter, value)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否为指定格式日期
+     * @param formatter 格式
+     * @param value 日期字符串
+     * @return
+     */
+    private boolean matchDataFormat(String formatter, String value) {
+        // 日期可以任意匹配,因此只可判断长度是否一致
+        return StrUtil.isBlank(formatter) || StrUtil.isBlank(value) || formatter.length() == value.length();
+    }
+}

+ 14 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DoubleInfoParser.java

@@ -0,0 +1,14 @@
+package com.persagy.dc.parser.service.impl;
+
+/**
+ * 数值信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class DoubleInfoParser extends NumberInfoParser<Double> {
+
+    @Override
+    protected Class<Double> getClassType() {
+        return Double.class;
+    }
+}

+ 53 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/EnumInfoParser.java

@@ -0,0 +1,53 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.parser.entity.EnumVO;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 枚举信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class EnumInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected void validateDefine(ParserResult result) throws IOException {
+        // 字符串类型不支持区间格式
+        if(result.isRegion()) {
+            throw new BusinessException(StrUtil.format("信息点[{}]定义有误,ENUM类型不允许定义区间!", result.getInfoDefine().getCode()));
+        }
+        // 数据源 - 应为区间列表格式
+        formatListValue(result.getInfoDefine().getDataSource(), EnumVO.class);
+    }
+
+    @Override
+    protected void validateValue(ParserResult result) throws IOException {
+        // 数据源定义信息
+        List<EnumVO> dataSource = formatListValue(result.getInfoDefine().getDataSource(), EnumVO.class);
+        Set<String> codeSet = new HashSet<>();
+        for(EnumVO enumVO:dataSource) {
+            codeSet.add(enumVO.getCode());
+        }
+        // 复数
+        if(result.isMulti()) {
+            List<String> valueList = formatListValue(result.getValueInfo(), String.class);
+            if(!CollUtil.containsAll(codeSet, valueList)) {
+                throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+            }
+        } else {
+            // 单数
+            String value = formatValue(result.getValueInfo(), String.class);
+            if(!codeSet.contains(value)) {
+                throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+            }
+        }
+    }
+}

+ 14 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/IntegerInfoParser.java

@@ -0,0 +1,14 @@
+package com.persagy.dc.parser.service.impl;
+
+/**
+ * 整数信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class IntegerInfoParser extends NumberInfoParser<Integer> {
+
+    @Override
+    protected Class<Integer> getClassType() {
+        return Integer.class;
+    }
+}

+ 72 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/NumberInfoParser.java

@@ -0,0 +1,72 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.common.utils.RegionUtil;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 数值信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class NumberInfoParser <T extends Comparable> extends AbstractInfoDataParser {
+
+    @Override
+    protected void validateDefine(ParserResult result) throws IOException {
+        // 数据源 - 应为区间列表格式
+        formatRegionListValue(result.getInfoDefine().getDataSource(), getClassType());
+    }
+
+    @Override
+    protected void validateValue(ParserResult result) throws IOException {
+        // 数据源定义信息
+        List<RegionValue<T>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), getClassType());
+        // 复数
+        if(result.isMulti()) {
+            // 复数区间
+            if(result.isRegion()) {
+                List<RegionValue<T>> valueList = formatRegionListValue(result.getValueInfo(), getClassType());
+                // 区间范围校验
+                if (!RegionUtil.allContains(dataSource, valueList)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            } else {
+                // 复数非区间
+                List<T> valueList = formatListValue(result.getValueInfo(), getClassType());
+                // 区间范围校验
+                if (!RegionUtil.allContain(dataSource, valueList)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            }
+        } else {
+            // 单数区间
+            if(result.isRegion()) {
+                RegionValue<T> value = formatRegionValue(result.getValueInfo(), getClassType());
+                // 区间范围校验
+                if (!RegionUtil.anyContains(dataSource, value)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            } else {
+                // 单数非区间
+                T value = formatValue(result.getValueInfo(), getClassType());
+                // 区间范围校验
+                if (!RegionUtil.anyContain(dataSource, value)) {
+                    throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+                }
+            }
+        }
+    }
+
+    /**
+     * 泛型类
+     * @return
+     */
+    protected Class<T> getClassType() {
+        return null;
+    }
+}

+ 51 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/StringInfoParser.java

@@ -0,0 +1,51 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.common.utils.RegionUtil;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 字符串信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class StringInfoParser extends AbstractInfoDataParser{
+
+    @Override
+    protected void validateDefine(ParserResult result) throws IOException {
+        // 字符串类型不支持区间格式
+        if(result.isRegion()) {
+            throw new BusinessException(StrUtil.format("信息点[{}]定义有误,STRING类型不允许定义区间!", result.getInfoDefine().getCode()));
+        }
+        // 数据源 - 应为区间列表格式
+        formatRegionListValue(result.getInfoDefine().getDataSource(), Integer.class);
+    }
+
+    @Override
+    protected void validateValue(ParserResult result) throws IOException {
+        // 数据源定义信息
+        List<RegionValue<Integer>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), Integer.class);
+        // 复数
+        if(result.isMulti()) {
+            List<String> valueList = formatListValue(result.getValueInfo(), String.class);
+            // 字符串长度校验
+            List<Integer> lengthList = valueList.stream().map(String::length).collect(Collectors.toList());
+            if(!RegionUtil.allContain(dataSource, lengthList)) {
+                throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+            }
+        } else {
+            // 单数
+            String value = formatValue(result.getValueInfo(), String.class);
+            // 字符串长度校验
+            if(!RegionUtil.anyContain(dataSource, value.length())) {
+                throw new BusinessException(StrUtil.format("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode()));
+            }
+        }
+    }
+}

+ 21 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeObjectInfo.java

@@ -0,0 +1,21 @@
+package com.persagy.dc.subscribe.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 订阅信息点范围
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("dt_subscribe_info")
+public class SubscribeObjectInfo extends AuditableEntity {
+    /** 方案ID */
+    private String schemaId;
+    /** 信息点ID */
+    private String infoId;
+}

+ 22 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeObjectType.java

@@ -0,0 +1,22 @@
+package com.persagy.dc.subscribe.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 订阅类型范围
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("dt_subscribe_type")
+public class SubscribeObjectType extends AuditableEntity {
+
+    /** 方案ID */
+    private String schemaId;
+    /** 对象类型ID */
+    private String typeId;
+}

+ 21 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeProject.java

@@ -0,0 +1,21 @@
+package com.persagy.dc.subscribe.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 订阅项目范围
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("dt_subscribe_project")
+public class SubscribeProject extends AuditableEntity {
+    /** 方案ID */
+    private String schemaId;
+    /** 项目ID */
+    private String projectId;
+}

+ 22 - 0
dmp-business/dc-digital/src/main/java/com/persagy/dc/subscribe/entity/SubscribeSchema.java

@@ -0,0 +1,22 @@
+package com.persagy.dc.subscribe.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 订阅方案
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("dt_subscribe_schema")
+public class SubscribeSchema extends AuditableEntity {
+
+    /** 方案名称 */
+    private String name;
+    /** 备注 */
+    private String remark;
+}

+ 11 - 0
dmp-business/dc-digital/src/main/resources/bootstrap.yml

@@ -0,0 +1,11 @@
+server:
+  port: 8832
+spring:
+  application:
+    # 应用名称
+    name: dc-digital
+
+config:
+  file:
+    absolute:
+      path: ${CONFIG_FILE_PATH:D:\SpringCloud}

+ 0 - 0
dmp-business/dc-digital/src/main/resources/db.init/data.sql


+ 66 - 0
dmp-business/dc-digital/src/main/resources/db.init/migrate.sql

@@ -0,0 +1,66 @@
+-- 数据迁移
+-- 对象类型定义表,仅同步了标准表,集团表太多
+replace into `dc_dic`.`dt_define_type`(`id`,`code`,`name`,`alias_code`,
+  `alias_name`,`obj_type`,`group_code`,`project_id`,`major_code`,
+  `system_code`,`equipment_code`,`parent_code`,`version`,`creator`,
+  `creation_time`,`modifier`,`modified_time`,`valid`)
+SELECT `id`,`code`,`name`,`alias_code`,
+  `alias_name`,`obj_type`,`group_code`,`project_id`,`major_code`,
+  `system_code`,`equipment_code`,`parent_code`,null,'0',
+  date_format(now(), '%Y%m%d%h%i%s'),null,null,1
+FROM `dmp_rwd`.`rwd_def_class`;
+
+-- 信息点,仅同步了标准表,集团表太多
+replace into `dc_dic`.`dt_define_info`(`id`,`code`,`name`,`alias_code`,
+  `alias_name`,`class_code`,`group_code`,`project_id`,`category`,
+  `first_tag`,`second_tag`,`priority`,`input_mode`,`unit`,`data_type`,
+  `multiple_flag`,`region_flag`,`formatter`,`data_source`,`remark`,
+  `sub_flag`,`weak_point`,`show_order`,`version`,
+  `creator`,`creation_time`,`modifier`,`modified_time`,`valid`)
+SELECT `id`,`code`,`name`,`alias_code`,
+  `alias_name`,`class_code`,`group_code`,`project_id`,`category`,
+  `first_tag`,`second_tag`,`priority`,`input_mode`,`unit`,`data_type`,
+  `is_multiple`,`is_region`,`formater`,`data_source`,`note`,
+  `sub_flag`,`weak_point`,null,null,
+  '0',date_format(now(), '%Y%m%d%h%i%s'),null,null,1
+FROM `dmp_rwd`.`rwd_def_funcid`;
+
+-- 图类型定义
+replace into `dc_dic`.`dt_define_graph`(`id`,`code`,`name`,`first_category`,
+  `second_category`,`remark`,`object_types`,
+  `creator`,`creation_time`,`modifier`,`modified_time`,`valid`)
+SELECT `id`,`code`,`name`,`first_category`,
+  `second_category`,`category_remark`,`object_types`,
+  '0',date_format(now(), '%Y%m%d%h%i%s'),null,null,1
+FROM `dmp_rwd`.`rwd_def_graph`;
+
+-- 关系定义
+replace into `dc_dic`.`dt_define_rel`(`id`,`code`,`name`,`graph_code`,
+  `directional`,`attribute`,`target_objs`,`remark`,
+  `creator`,`creation_time`,`modifier`,`modified_time`,`valid`)
+SELECT `id`,`code`,`name`,`graph_code`,
+  `directional`,`attribute`,`target_objs`,`remark`,
+  '0',date_format(now(), '%Y%m%d%h%i%s'),null,null,1
+FROM `dmp_rwd`.`rwd_def_rel`;
+
+-- 对象
+replace into `dc_dic`.`dt_object`(`id`,`name`,`local_id`,
+  `local_name`,`group_code`,`project_id`,`obj_type`,`class_code`,
+  `grouping`,`infos`,`virtual_codes`,`create_app`,`update_app`,
+  `creator`,`creation_time`,`modifier`,`modified_time`,`valid`)
+SELECT `id`,`name`,`local_id`,
+  `local_name`,`group_code`,`project_id`,`obj_type`,`class_code`,
+  `grouping`,`infos`,`virtual_info_codes`,`create_app`,`update_app`,
+  '0',date_format(now(), '%Y%m%d%h%i%s'),null,null,1
+FROM `dmp_rwd`.`rwd_object`;
+
+-- 关系
+replace into `dc_dic`.`dt_relation`(`id`,`graph_id`,`graph_code`,
+  `rel_code`,`rel_value`,`group_code`,`project_id`,`obj_from`,`obj_to`,
+  `create_app`,`update_app`,
+  `creator`,`creation_time`,`modifier`,`modified_time`,`valid`)
+SELECT `id`,`graph_id`,`graph_code`,
+  `rel_code`,`rel_value`,`group_code`,`project_id`,`obj_from`,`obj_to`,
+  `create_app`,`update_app`,
+  '0',date_format(now(), '%Y%m%d%h%i%s'),null,null,1
+FROM `dmp_rwd`.`rwd_relation`;

+ 152 - 0
dmp-business/dc-digital/src/main/resources/db.init/schema.sql

@@ -0,0 +1,152 @@
+CREATE TABLE IF NOT EXISTS `dt_define_type` (
+  `id` varchar(40) NOT NULL COMMENT '主键',
+  `code` varchar(60) NOT NULL COMMENT '编码-全局唯一',
+  `name` varchar(200) NOT NULL COMMENT '名称',
+  `alias_code` varchar(60) NOT NULL COMMENT '别名编码, 集团下唯一 ',
+  `alias_name` varchar(200) NOT NULL COMMENT '别名名称',
+  `obj_type` varchar(40) DEFAULT NULL COMMENT '大类型:项目建筑楼层空间系统设备竖井',
+  `group_code` varchar(40) NOT NULL DEFAULT '0' COMMENT '集团编码',
+  `project_id` varchar(40) NOT NULL DEFAULT '0' COMMENT '项目id',
+  `major_code` varchar(60) DEFAULT NULL COMMENT '专业编码, 上级类型是系统or设备时该字段有值',
+  `system_code` varchar(60) DEFAULT NULL COMMENT '系统编码,上级类型是设备时该字段有值,值为系统类型的code',
+  `equipment_code` varchar(60) DEFAULT NULL COMMENT '设备编码,上级类型是部件时该字段有值,值为设备类型的code',
+  `parent_code` varchar(60) DEFAULT NULL COMMENT '上级类型code,默认为"0"',
+  `version` varchar(40) DEFAULT NULL COMMENT '最后修改版本',
+  `creator` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+  `modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
+  `modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+  `valid` tinyint DEFAULT NULL COMMENT '合法标识',
+  `ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_code` (`code`) USING BTREE,
+  KEY `idx_alias_code` (`alias_code`) USING BTREE,
+  KEY `idx_parent_code` (`parent_code`) USING BTREE,
+  KEY `idx_major_code` (`major_code`) USING BTREE,
+  KEY `idx_code_1` (`group_code`,`project_id`,`code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='对象类型定义';
+
+CREATE TABLE IF NOT EXISTS `dt_define_info` (
+  `id` varchar(40) NOT NULL,
+  `code` varchar(60) NOT NULL COMMENT '信息点编码,同类型下唯一,标准驼峰格式',
+  `name` varchar(200) DEFAULT NULL COMMENT '信息点名称',
+  `alias_code` varchar(60) DEFAULT NULL COMMENT '别名编码',
+  `alias_name` varchar(200) DEFAULT NULL COMMENT '别名名称',
+  `class_code` varchar(60) DEFAULT NULL COMMENT '类型编码',
+  `group_code` varchar(40) NOT NULL DEFAULT '0' COMMENT '集团编码',
+  `project_id` varchar(40) NOT NULL DEFAULT '0' COMMENT '项目id',
+  `category` varchar(40) DEFAULT NULL COMMENT '信息点分类:静态,脉冲,阶段,时序',
+  `first_tag` varchar(40) DEFAULT NULL COMMENT '一级标签',
+  `second_tag` varchar(40) DEFAULT NULL COMMENT '二级标签',
+  `priority` varchar(10) DEFAULT NULL COMMENT '优先级',
+  `input_mode` varchar(40) DEFAULT NULL COMMENT '输入方式',
+  `unit` varchar(40) DEFAULT NULL COMMENT '单位',
+  `data_type` varchar(40) DEFAULT NULL COMMENT '数据类型',
+  `multiple_flag` int(11) DEFAULT NULL COMMENT '是否复数',
+  `region_flag` int(11) DEFAULT NULL COMMENT '是否区间',
+  `formatter` varchar(40) DEFAULT NULL COMMENT '数据格式',
+  `data_source` json DEFAULT NULL COMMENT '数据源取值范围/枚举值清单等,根据dataType有不同的内容',
+  `remark` text COMMENT '备注',
+  `sub_flag` int(11) DEFAULT NULL COMMENT '子分类标记:是否可以按此信息点进行子分类替换,同一类型下目前只支持一个子分类信息点',
+  `weak_point` int(11) DEFAULT NULL COMMENT '虚点',
+  `show_order` int(11) DEFAULT NULL COMMENT '显示顺序',
+  `version` varchar(40) DEFAULT NULL COMMENT '最后修改版本',
+  `creator` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+  `modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
+  `modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+  `valid` tinyint DEFAULT NULL COMMENT '合法标识',
+  `ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_class_1` (`class_code`,`code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='信息点定义表';
+
+CREATE TABLE IF NOT EXISTS `dt_define_graph` (
+  `id` varchar(40) NOT NULL,
+  `code` varchar(60) DEFAULT NULL COMMENT '编码',
+  `name` varchar(200) DEFAULT NULL COMMENT '名称',
+  `first_category` varchar(40) DEFAULT NULL COMMENT '一级分类',
+  `second_category` varchar(40) DEFAULT NULL COMMENT '二级分类',
+  `remark` varchar(255) DEFAULT NULL COMMENT '分类说明',
+  `object_types` varchar(255) DEFAULT NULL COMMENT '关系两侧对象类别',
+  `creator` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+  `modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
+  `modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+  `valid` tinyint DEFAULT NULL COMMENT '合法标识',
+  `ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_code` (`code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='图类型表';
+
+CREATE TABLE IF NOT EXISTS `dt_define_rel` (
+  `id` varchar(40) NOT NULL,
+  `code` varchar(60) DEFAULT NULL COMMENT '编码',
+  `name` varchar(200) DEFAULT NULL COMMENT '名称',
+  `graph_code` varchar(60) DEFAULT NULL COMMENT '图编码',
+  `directional` int(11) DEFAULT NULL COMMENT '边方向性',
+  `attribute` varchar(255) DEFAULT NULL COMMENT '边属性',
+  `target_objs` varchar(255) DEFAULT NULL COMMENT '主要连接对象',
+  `remark` varchar(45) DEFAULT NULL,
+  `creator` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+  `modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
+  `modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+  `valid` tinyint DEFAULT NULL COMMENT '合法标识',
+  `ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_code` (`code`) USING BTREE,
+  KEY `idx_graph_code` (`graph_code`,`code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='边类型表';
+
+CREATE TABLE IF NOT EXISTS `dt_object` (
+  `id` varchar(100) NOT NULL,
+  `name` varchar(100) DEFAULT NULL COMMENT '对象名称',
+  `local_id` varchar(100) DEFAULT NULL COMMENT '对象本地编码',
+  `local_name` varchar(100) DEFAULT NULL COMMENT '对象本地名称',
+  `group_code` varchar(40) DEFAULT NULL COMMENT '集团编码',
+  `project_id` varchar(40) NOT NULL COMMENT '项目id',
+  `obj_type` varchar(40) NOT NULL COMMENT '对象分类',
+  `class_code` varchar(60) NOT NULL COMMENT '对象类型编码',
+  `grouping` int(11) NOT NULL DEFAULT '1' COMMENT '1单个对象,2对象组',
+  `infos` json DEFAULT NULL COMMENT '边类型编码',
+  `virtual_codes` json DEFAULT NULL COMMENT '虚点清单',
+  `create_app` varchar(40) DEFAULT NULL COMMENT '创建应用',
+  `update_app` varchar(40) DEFAULT NULL COMMENT '最后更新应用',
+  `creator` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+  `modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
+  `modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+  `valid` tinyint DEFAULT NULL COMMENT '合法标识',
+  `ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_project_1` (`project_id`,`class_code`,`creation_time`) USING BTREE,
+  KEY `idx_project_2` (`project_id`,`creation_time`) USING BTREE,
+  KEY `idx_project_3` (`project_id`,`modified_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='对象实例表';
+
+CREATE TABLE IF NOT EXISTS `dt_relation` (
+  `id` varchar(40) NOT NULL,
+  `group_code` varchar(40) DEFAULT NULL,
+  `project_id` varchar(40) NOT NULL,
+  `graph_id` varchar(40) DEFAULT NULL COMMENT '图主键',
+  `graph_code` varchar(60) DEFAULT NULL COMMENT '图编码',
+  `rel_code` varchar(60) DEFAULT NULL COMMENT '关系编码',
+  `rel_value` varchar(45) DEFAULT NULL COMMENT '关系值',
+  `obj_from` varchar(40) DEFAULT NULL COMMENT '来源对象',
+  `obj_to` varchar(40) DEFAULT NULL COMMENT '目标对象',
+  `create_app` varchar(40) DEFAULT NULL COMMENT '创建应用',
+  `update_app` varchar(40) DEFAULT NULL COMMENT '最后更新应用',
+  `creator` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `creation_time` char(14) NULL DEFAULT NULL COMMENT '创建时间',
+  `modifier` varchar(32) DEFAULT NULL COMMENT '最后修改人',
+  `modified_time` char(14) NULL DEFAULT NULL COMMENT '最后修改时间',
+  `valid` tinyint DEFAULT NULL COMMENT '合法标识',
+  `ts` timestamp default current_timestamp on update current_timestamp NOT NULL COMMENT '乐观锁',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_graph_code` (`graph_code`) USING BTREE,
+  KEY `idx_1` (`project_id`,`graph_code`,`rel_code`,`obj_from`,`obj_to`) USING BTREE,
+  KEY `idx_2` (`project_id`,`graph_id`,`rel_code`,`obj_from`,`obj_to`) USING BTREE,
+  KEY `idx_3` (`project_id`,`graph_code`,`rel_code`,`obj_to`) USING BTREE,
+  KEY `idx_4` (`project_id`,`graph_id`,`rel_code`,`obj_to`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='关系实例表';

+ 5 - 0
dmp-business/dc-digital/src/main/resources/mapper/DictDataMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.persagy.dc.dic.dao.DictDataMapper">
+
+</mapper>

+ 121 - 0
dmp-business/dc-digital/src/test/java/com/persagy/dc/define/test/ObjectTypeDefineControllerTest.java

@@ -0,0 +1,121 @@
+package com.persagy.dc.define.test;
+
+import com.persagy.dc.common.constant.ResponseCode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.context.WebApplicationContext;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureMockMvc
+public class ObjectTypeDefineControllerTest {
+
+    @Autowired
+    private WebApplicationContext context;
+    private MockMvc mvc;
+
+    @Before
+    public void setup() {
+        mvc = MockMvcBuilders.webAppContextSetup(context).build();
+    }
+
+    /**
+     * head参数
+     * @return
+     */
+    private MultiValueMap<String, String> getHeadParam() {
+        MultiValueMap<String, String> param = new LinkedMultiValueMap<>();
+        param.add("groupCode", "WD");
+        param.add("projectId", null);
+        param.add("appId", "BDTP");
+        param.add("userId", "0");
+        return param;
+    }
+
+    @Test
+    public void query() throws Exception {
+        String body = "{\n" +
+                "    \"criteria\": {\n" +
+                "        \"objType\":{\n" +
+                "            \"$like\":\"comp\"\n" +
+                "        }\n" +
+                "    }\n" +
+                "}";
+        mvc.perform(MockMvcRequestBuilders.post("/define/type/query")
+                .params(getHeadParam())
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(body))
+                .andExpect(MockMvcResultMatchers.status().isOk())
+                .andExpect(MockMvcResultMatchers.jsonPath("$.respCode").value(ResponseCode.A00000.getCode()));
+    }
+
+    @Test
+    public void create() throws Exception {
+        String body = "{\n" +
+                "    \"code\": \"TEXT-TTTTTTTT\",\n" +
+                "    \"name\": \"基础桩\",\n" +
+                "    \"aliasCode\": \"CFCSFDPL\",\n" +
+                "    \"aliasName\": \"基础桩\",\n" +
+                "    \"objType\": \"component\",\n" +
+                "    \"projectId\": \"0\",\n" +
+                "    \"majorCode\": \"CF\",\n" +
+                "    \"systemCode\": \"CFCS\",\n" +
+                "    \"equipmentCode\": \"CFCSFD\",\n" +
+                "    \"parentCode\": \"component\",\n" +
+                "    \"version\": null\n" +
+                "}";
+        mvc.perform(MockMvcRequestBuilders.post("/define/type/create")
+                .params(getHeadParam())
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(body))
+                .andExpect(MockMvcResultMatchers.status().isOk())
+                .andExpect(MockMvcResultMatchers.jsonPath("$.respCode").value(ResponseCode.A00000.getCode()));
+    }
+
+    @Test
+    public void update() throws Exception {
+        String body = "{\n" +
+                "    \"id\": \"1413018374673371138\",\n" +
+                "    \"code\": \"TEXT-TTTTTTTT\",\n" +
+                "    \"name\": \"基础桩\",\n" +
+                "    \"aliasCode\": \"CFCSFDPL\",\n" +
+                "    \"aliasName\": \"基础桩\",\n" +
+                "    \"objType\": \"component\",\n" +
+                "    \"projectId\": \"0\",\n" +
+                "    \"majorCode\": \"CF\",\n" +
+                "    \"systemCode\": \"CFCS\",\n" +
+                "    \"equipmentCode\": \"CFCSFD\",\n" +
+                "    \"parentCode\": \"component\",\n" +
+                "    \"version\": null\n" +
+                "}";
+        mvc.perform(MockMvcRequestBuilders.post("/define/type/update")
+                .params(getHeadParam())
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(body))
+                .andExpect(MockMvcResultMatchers.status().isOk())
+                .andExpect(MockMvcResultMatchers.jsonPath("$.respCode").value(ResponseCode.A00000.getCode()));
+    }
+
+    @Test
+    public void delete() throws Exception {
+        String body = "1413018374673371138";
+        mvc.perform(MockMvcRequestBuilders.post("/define/type/delete")
+                .params(getHeadParam())
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(body))
+                .andExpect(MockMvcResultMatchers.status().isOk())
+                .andExpect(MockMvcResultMatchers.jsonPath("$.respCode").value(ResponseCode.A00000.getCode()));
+    }
+}

+ 9 - 0
dmp-business/dmp-knowledge/README.md

@@ -0,0 +1,9 @@
+知识库服务
+============ 
+
+说明
+---------------
+
+最新变化
+---------------
+

+ 34 - 0
dmp-business/dmp-knowledge/pom.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>dc-business</artifactId>
+        <groupId>com.persagy</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>dc-knowledge</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!-- 配置中心(包含注册中心) -->
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>integrated-config-client</artifactId>
+        </dependency>
+        <!-- 项目启动 -->
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-mybatis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>dc-common</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 63 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/controller/DictDataController.java

@@ -0,0 +1,63 @@
+package com.persagy.dc.dic.controller;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.model.response.PageList;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.dic.entity.DictData;
+import com.persagy.dc.dic.service.DictDataService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import java.util.List;
+
+/**
+ * 字典数据
+ * @author:linhuili
+ * @date:2021/6/10
+ */
+@RestController
+@RequestMapping(value = "/dic/data/")
+public class DictDataController {
+
+    @Autowired
+    private DictDataService DictDataService;
+
+    @PostMapping("/create")
+    public CommonResult<DictData> create(@RequestBody DictData DictData) {
+        if(StrUtil.isBlank(DictData.getDictTypeId())){
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        DictData content = DictDataService.create(DictData);
+        return ResultHelper.single(content);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<DictData> update(@RequestBody DictData DictData) {
+        if(StrUtil.isBlank(DictData.getDictTypeId())|| StrUtil.isBlank(DictData.getId()) ){
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        DictData content = DictDataService.update(DictData);
+        return ResultHelper.single(content);
+    }
+
+    @PostMapping("/delete")
+    public CommonResult<DictData> delete(@RequestBody DictData DictData) {
+        if(StrUtil.isBlank(DictData.getDictTypeId()) || StrUtil.isBlank(DictData.getId()) ){
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        DictData content = DictDataService.delete(DictData);
+        return ResultHelper.single(content);
+    }
+
+    @PostMapping("/query")
+    public CommonResult<PageList<DictData>> query(@RequestBody DictData DictData) {
+        List<DictData> content = DictDataService.query(DictData);
+        return ResultHelper.multi(content);
+    }
+}

+ 63 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/controller/DictTypeController.java

@@ -0,0 +1,63 @@
+package com.persagy.dc.dic.controller;
+
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.constant.ResponseCode;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.common.model.response.CommonResult;
+import com.persagy.dc.common.utils.ResultHelper;
+import com.persagy.dc.dic.entity.DictType;
+import com.persagy.dc.dic.service.DictTypeService;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 字典类型
+ * @author:linhuili
+ * @date:2021/6/10
+ */
+@RestController
+@RequestMapping(value = "/dic/type/")
+public class DictTypeController {
+
+    @Autowired
+    private DictTypeService dictTypeService;
+
+    @PostMapping("/create")
+    public CommonResult<DictType> create(@RequestBody DictType dictType) {
+        if(StrUtil.isBlank(dictType.getGroupCode())){
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        DictType content = dictTypeService.create(dictType);
+        return ResultHelper.single(content);
+    }
+
+    @PostMapping("/update")
+    public CommonResult<DictType> update(@RequestBody DictType dictType) {
+        if(StrUtil.isBlank(dictType.getGroupCode())|| StrUtil.isBlank(dictType.getId()) ){
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        DictType content = dictTypeService.update(dictType);
+        return ResultHelper.single(content);
+    }
+
+    @PostMapping("/delete")
+    public CommonResult<DictType> delete(@RequestBody DictType dictType) {
+        if(StrUtil.isBlank(dictType.getGroupCode()) || StrUtil.isBlank(dictType.getId()) ){
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        DictType content = dictTypeService.delete(dictType);
+        return ResultHelper.single(content);
+    }
+
+    @PostMapping("/query")
+    public CommonResult<List<DictType>> query(@RequestBody DictType dictType) {
+        if(StrUtil.isBlank(dictType.getGroupCode())){
+            throw new BusinessException(ResponseCode.A0400.getCode(), ResponseCode.A0400.getDesc());
+        }
+        List<DictType> content = dictTypeService.query(dictType);
+        return ResultHelper.single(content);
+    }
+}

+ 13 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/dao/DictDataMapper.java

@@ -0,0 +1,13 @@
+package com.persagy.dc.dic.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.dic.entity.DictData;
+
+/**
+ * 字典数据
+ * @author:linhuili
+ * @date:2021/6/10
+ */
+public interface DictDataMapper extends BaseMapper<DictData> {
+
+}

+ 13 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/dao/DictTypeMapper.java

@@ -0,0 +1,13 @@
+package com.persagy.dc.dic.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.dc.dic.entity.DictType;
+
+/**
+ * 字典类型
+ * @author:linhuili
+ * @date:2021/6/10
+ */
+public interface DictTypeMapper extends BaseMapper<DictType> {
+
+}

+ 103 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/entity/DictData.java

@@ -0,0 +1,103 @@
+package com.persagy.dc.dic.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.lang.PsDateTime;
+import lombok.*;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 字典数据
+ * @author linhuili
+ * @since 2021/06/10
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("dic_dt_data")
+public class DictData implements Serializable {
+	private static final long serialVersionUID = 1469402428094643376L;
+
+	/**
+	 * 主键ID
+	 */
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	private String id;
+
+	/**
+	 * 字典类型ID
+	 */
+	@TableId(value = "dict_type_id")
+	private String dictTypeId;
+
+	/**
+	 * 父节点
+	 */
+	@TableId(value = "parent_id")
+	private String parentCode;
+
+	/**
+	 * 字典类型
+	 */
+	@TableId(value = "type")
+	private String type;
+
+	/**
+	 * 字典数据编码
+	 */
+	@TableId(value = "code")
+	private String code;
+
+	/**
+	 * 字典数据标签
+	 */
+	@TableId(value = "label")
+	private String label;
+
+	/**
+	 * 状态 0:停用,1:正常
+	 */
+	@TableId(value = "status")
+	private String status;
+
+	/**
+	 *  创建时间
+	 */
+	@TableId(value = "create_time")
+	private PsDateTime createTime;
+
+	/**
+	 *  创建用户
+	 */
+	@TableId(value = "create_user")
+	private String createUser;
+
+	/**
+	 *  更新时间
+	 */
+	@TableId(value = "update_time")
+	private PsDateTime updateTime;
+
+	/**
+	 *  更新用户
+	 */
+	@TableId(value = "update_user")
+	private String updateUser;
+
+	/**
+	 *  备注
+	 */
+	@TableId(value = "remark")
+	private String remark;
+
+	/**
+	 *  排序字段
+	 */
+	@TableId(value = "order_num")
+	private Integer orderNum;
+	
+
+}

+ 32 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/entity/DictType.java

@@ -0,0 +1,32 @@
+package com.persagy.dc.dic.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.persagy.dc.common.model.entity.AuditableEntity;
+import lombok.Data;
+
+/**
+ * 字典类型
+ * @author linhuili
+ * @since 2021/06/10
+ */
+@Data
+@TableName("dic_dt_type")
+public class DictType extends AuditableEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 集团编码 */
+    private String groupCode;
+
+    /** 字典类型 */
+    private String type;
+
+    /** 字典类型名称 */
+    private String name;
+
+    /** 描述 */
+    private String description;
+
+    /** 备注 */
+    private String remark;
+}

+ 21 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/service/DictDataService.java

@@ -0,0 +1,21 @@
+package com.persagy.dc.dic.service;
+
+import com.persagy.dc.dic.entity.DictData;
+
+import java.util.List;
+
+/**
+ * 字典数据
+ * @author:linhuili
+ * @date:2021/6/10
+ */
+public interface DictDataService {
+
+    DictData create(DictData dictData);
+
+    DictData update(DictData dictData);
+
+    DictData delete(DictData dictData);
+
+    List<DictData> query(DictData dictData);
+}

+ 21 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/service/DictTypeService.java

@@ -0,0 +1,21 @@
+package com.persagy.dc.dic.service;
+
+import com.persagy.dc.dic.entity.DictType;
+
+import java.util.List;
+
+/**
+ * 字典类型
+ * @author:linhuili
+ * @date:2021/6/10
+ */
+public interface DictTypeService {
+
+    DictType create(DictType dictType);
+
+    DictType update(DictType dictType);
+
+    DictType delete(DictType dictType);
+
+    List<DictType> query(DictType dictType);
+}

+ 0 - 0
dmp-business/dmp-knowledge/src/main/java/com/persagy/dc/dic/service/impl/DictDataServiceImpl.java


Some files were not shown because too many files changed in this diff