Browse Source

Merge branch 'develop' of http://39.106.8.246:3003/BDTP/digital-twin into develop

lijie 3 years ago
parent
commit
fbb41ba9fc
24 changed files with 1264 additions and 252 deletions
  1. 0 0
      dmp-business/dmp-dic/src/main/resources/mapper/HistoryIotService.xml
  2. 29 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/basic/constant/IotUrlConstant.java
  3. 23 12
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/basic/utils/DigitalMessageHelper.java
  4. 24 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/basic/utils/MeterUtils.java
  5. 7 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/define/service/IObjectTypeService.java
  6. 10 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/define/service/impl/ObjectTypeServiceImpl.java
  7. 7 136
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/controller/ObjectDigitalController.java
  8. 6 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/entity/ObjectDigital.java
  9. 11 1
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/service/IObjectDigitalService.java
  10. 97 7
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/service/impl/ObjectDigitalServiceImpl.java
  11. 197 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/utils/ObjectDigitalCriteriaHelper.java
  12. 111 5
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/controller/IotController.java
  13. 4 1
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/model/history/InfoCodeModel.java
  14. 5 3
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/CurrentDataService.java
  15. 17 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/HistoryIotService.java
  16. 27 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/SettingIotService.java
  17. 0 68
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/CurrentDataServiceImpl.java
  18. 173 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/CurrentIotServiceImpl.java
  19. 167 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/HistoryIotServiceImpl.java
  20. 203 0
      dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/SettingIotServiceImpl.java
  21. 2 2
      dmp-business/dmp-rwd/src/main/resources/mapper/DigitalMigrateMapper.xml
  22. 63 0
      dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/model/QueryOperator.java
  23. 8 4
      dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/utils/JsonNodeUtils.java
  24. 73 13
      dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/utils/QueryCriteriaHelper.java

dmp-business/dmp-dic/src/main/resources/mapper/DictDataMapper.xml → dmp-business/dmp-dic/src/main/resources/mapper/HistoryIotService.xml


+ 29 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/basic/constant/IotUrlConstant.java

@@ -0,0 +1,29 @@
+package com.persagy.dmp.rwd.basic.constant;
+
+/**
+ * iot请求常量
+ * @author:linhuili
+ * @date:2021/8/12
+ */
+public class IotUrlConstant {
+
+    /**
+     * 查询实时数据
+     */
+    public static String QUERY_CUCCRENT_DATA = "/presentreportbatch_post";
+
+    /**
+     * 查询历史数据/分精度数据
+     */
+    public static String QUERY_HISTORY_DATA = "/fjd_query_batch_post";
+
+    /**
+     * 动态信息点绑定
+     */
+    public static String POINT_SET_DATA = "/pointsetbatch_post";
+
+    /**
+     * 查询指令执行结果
+     */
+    public static String QUERY_POINT_SET_DATA = "/pointsetresultbatch_post";
+}

+ 23 - 12
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/basic/utils/DigitalMessageHelper.java

@@ -1,10 +1,13 @@
 package com.persagy.dmp.rwd.basic.utils;
 
-import cn.hutool.json.JSONUtil;
-import com.persagy.dmp.common.model.entity.BaseEntity;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.persagy.dmp.amqp.handler.RabbitMessageSender;
-import com.persagy.dmp.rwd.basic.constant.DigitalMessageConstant;
 import com.persagy.dmp.basic.model.DigitalManageMessage;
+import com.persagy.dmp.common.exception.BusinessException;
+import com.persagy.dmp.common.model.entity.BaseEntity;
+import com.persagy.dmp.rwd.basic.constant.DigitalMessageConstant;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -14,10 +17,13 @@ import org.springframework.stereotype.Component;
  * @date 2021-06-25
  */
 @Component
+@Slf4j
 public class DigitalMessageHelper {
 
     @Autowired
     private RabbitMessageSender messageSender;
+    @Autowired
+    private ObjectMapper objectMapper;
 
     /**
      * 发送消息
@@ -33,15 +39,20 @@ public class DigitalMessageHelper {
         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));
+        try {
+            if(syncFlag) {
+                messageSender.sendAndReceive(DigitalMessageConstant.MESSAGE_EXCHANGE,
+                        DigitalMessageConstant.MESSAGE_ROUTING,
+                        objectMapper.writeValueAsString(message));
+            } else {
+                // 异步消息
+                    messageSender.send(DigitalMessageConstant.MESSAGE_EXCHANGE,
+                            DigitalMessageConstant.MESSAGE_ROUTING,
+                            objectMapper.writeValueAsString(message));
+            }
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+            throw new BusinessException("消息格式有误!");
         }
     }
 }

+ 24 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/basic/utils/MeterUtils.java

@@ -0,0 +1,24 @@
+package com.persagy.dmp.rwd.basic.utils;
+
+/**
+ * 表号功能号校验工具类
+ * @author:linhuili
+ * @date:2021/8/12
+ */
+public class MeterUtils {
+
+	/**
+	 * 表号功能号格式匹配
+	 * @param infoCodeValue
+	 * @return
+	 */
+	public static boolean matchFormat(String infoCodeValue){
+		// 判断信息点的值是不是表号-功能号格式
+		// 包含中划线且中划线不在开头结尾
+		int idx = infoCodeValue.indexOf("-");
+		if (idx < 1 || idx == infoCodeValue.length() - 1) {
+			return false;
+		}
+		return true;
+	}
+}

+ 7 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/define/service/IObjectTypeService.java

@@ -71,4 +71,11 @@ public interface IObjectTypeService {
      * @param idList 主键
      */
     void delete(List<String> idList);
+
+
+    /**
+     * 查询对象类型Map
+     * @return <code, name>
+     */
+    Map<String, String> queryObjTypeMap();
 }

+ 10 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/define/service/impl/ObjectTypeServiceImpl.java

@@ -67,6 +67,16 @@ public class ObjectTypeServiceImpl implements IObjectTypeService {
     }
 
     @Override
+    @Cacheable(key = "targetClass + methodName")
+    public Map<String, String> queryObjTypeMap() {
+        LambdaQueryWrapper<ObjectTypeDefine> wrapper = new LambdaQueryWrapper<>();
+        wrapper.select(ObjectTypeDefine::getId, ObjectTypeDefine::getCode, ObjectTypeDefine::getObjType);
+        wrapper.eq(ObjectTypeDefine::getValid, ValidEnum.TRUE.getType());
+        List<ObjectTypeDefine> voList = queryByCondition(wrapper);
+        return CollUtil.fieldValueAsMap(voList, "code", "objType");
+    }
+
+    @Override
     public Page queryByProjectAndApp(Page page, String projectId, String appId) {
         // TODO 分页查询使用ES
         QueryWrapper<ObjectTypeDefine> wrapper = new QueryWrapper<>();

+ 7 - 136
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/controller/ObjectDigitalController.java

@@ -1,11 +1,8 @@
 package com.persagy.dmp.rwd.digital.controller;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ReflectUtil;
-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.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.persagy.dmp.basic.model.QueryCriteria;
@@ -14,13 +11,13 @@ import com.persagy.dmp.basic.utils.QueryCriteriaHelper;
 import com.persagy.dmp.common.constant.CommonConstant;
 import com.persagy.dmp.common.constant.ResponseCode;
 import com.persagy.dmp.common.exception.BusinessException;
-import com.persagy.dmp.common.model.entity.BaseEntity;
 import com.persagy.dmp.common.model.response.CommonResult;
 import com.persagy.dmp.common.utils.ParamCheckUtil;
 import com.persagy.dmp.common.utils.ResultHelper;
 import com.persagy.dmp.mybatis.utils.ConditionUtil;
 import com.persagy.dmp.rwd.digital.entity.ObjectDigital;
 import com.persagy.dmp.rwd.digital.service.IObjectDigitalService;
+import com.persagy.dmp.rwd.digital.utils.ObjectDigitalCriteriaHelper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -28,9 +25,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
 /**
  * 对象数据 Controller
@@ -56,145 +51,21 @@ public class ObjectDigitalController{
         // 添加所属项目条件
         ConditionUtil.ensureProjectCriteria(wrapper);
         // 处理扩展条件
-        ensureExtraCond(wrapper, criteria.getCriteria());
+        ObjectDigitalCriteriaHelper.ensureExtraCond(criteria.getCriteria());
         // 转换查询条件
         QueryCriteriaHelper.toWrapper(wrapper, criteria);
         Page page = service.queryByCondition(QueryCriteriaHelper.toPage(criteria), wrapper);
         // 处理扩展属性
-        List<ObjectNode> records = JsonNodeUtils.toListNode(page.getRecords(), "infos", criteria.getWithColumns());
+        List<ObjectNode> records = JsonNodeUtils.toListNode(page.getRecords(), ObjectDigital.EXTRA_COLUMN, criteria.getWithColumns());
         return ResultHelper.multi(records, page.getTotal());
     }
 
-    /**
-     * 拼接扩展条件
-     * @param wrapper
-     * @param criteria
-     */
-    private void ensureExtraCond(QueryWrapper<ObjectDigital> wrapper, ObjectNode criteria) {
-        ensureSearchCond(wrapper, criteria);
-        ensureRelationCond(wrapper, criteria);
-        ensureJsonCond(wrapper, criteria);
-    }
-
-    /**
-     * 拼接json条件
-     * @param wrapper
-     * @param criteria
-     */
-    private void ensureJsonCond(QueryWrapper<ObjectDigital> wrapper, ObjectNode criteria) {
-        Set<String> fieldSet = ReflectUtil.getFieldMap(ObjectDigital.class).keySet();
-        Iterator<String> fieldNames = criteria.fieldNames();
-        while (fieldNames.hasNext()) {
-            String infoCode = fieldNames.next();
-            // 基础属性不用处理
-            if(fieldSet.contains(infoCode)) {
-                continue;
-            }
-            JsonNode value = criteria.get(infoCode);
-            if(value == null || value.isNull()) {
-                continue;
-            }
-            // 如果值是对象
-            if(value.isObject()) {
-                // 包含
-                if (value.has("$contains")) {
-                    JsonNode valueNode = value.get("$contains");
-                    String valueStr = valueNode.isTextual() ? value.asText():value.toString();
-                    wrapper.eq(StrUtil.format("json_contains({}, {}, '$.{}')", "infos", valueStr, infoCode), 1);
-                } else if (value.has("$notcontains")) {
-                    // 不包含
-                    JsonNode valueNode = value.get("$notcontains");
-                    String valueStr = valueNode.isTextual() ? value.asText():value.toString();
-                    wrapper.eq(StrUtil.format("json_contains({}, {}, '$.{}')", "infos", valueStr, infoCode), 0);
-                }
-            } else if(value.isTextual()) {
-                wrapper.eq(StrUtil.format("json_unquote(json_extract({}, '$.{}'))", "infos", infoCode), value.asText());
-            } else if(value.isInt()) {
-                wrapper.eq(StrUtil.format("ifnull(json_extract({}, '$.{}'), -9999)", "infos", infoCode), value.asInt());
-            } else if(value.isDouble()) {
-                wrapper.eq(StrUtil.format("ifnull(json_extract({}, '$.{}'), -9999.99)", "infos", infoCode), value.asDouble());
-            }
-            // 处理完成后删除
-            fieldNames.remove();
-        }
-    }
-
-    /**
-     * 拼接$search条件
-     * @param wrapper
-     * @param criteria
-     */
-    private void ensureSearchCond(QueryWrapper<ObjectDigital> wrapper, ObjectNode criteria) {
-        if(criteria == null || criteria.isNull()) {
-            return;
-        }
-        // 处理relationFrom
-        JsonNode search = criteria.get("$search");
-        if(search != null && search.isTextual()) {
-            String searchValue = search.asText();
-            wrapper.isNotNull(StrUtil.format("json_search({0}, 'one', {1})", "infos", searchValue));
-            // 处理完成后删除
-            criteria.remove("$search");
-        }
-    }
-
-    /**
-     * 处理关系条件
-     * @param wrapper
-     * @param criteria
-     */
-    private void ensureRelationCond(QueryWrapper<ObjectDigital> wrapper, ObjectNode criteria) {
-        if(criteria == null || criteria.isNull()) {
-            return;
-        }
-        // 处理relationFrom
-        JsonNode relationFrom = criteria.get("relationFrom");
-        if(relationFrom != null && relationFrom.isObject() && relationFrom.size() > 0) {
-            StringBuilder inSql = new StringBuilder("(select obj_from from dt_relation where 1=1 ");
-            addWhereCond(relationFrom, inSql, "graphId");
-            addWhereCond(relationFrom, inSql, "graphCode");
-            addWhereCond(relationFrom, inSql, "relCode");
-            addWhereCond(relationFrom, inSql, "objTo");
-            inSql.append(")");
-            wrapper.inSql(BaseEntity.PROP_ID, inSql.toString());
-            // 处理完成后删除
-            criteria.remove("relationFrom");
-        }
-        // 处理relationTo
-        JsonNode relationTo = criteria.get("relationTo");
-        if(relationTo != null && relationTo.isObject() && relationTo.size() > 0) {
-            StringBuilder inSql = new StringBuilder("(select obj_to from dt_relation where 1=1 ");
-            addWhereCond(relationTo, inSql, "graphId");
-            addWhereCond(relationTo, inSql, "graphCode");
-            addWhereCond(relationTo, inSql, "relCode");
-            addWhereCond(relationTo, inSql, "objFrom");
-            inSql.append(")");
-            wrapper.inSql(BaseEntity.PROP_ID, inSql.toString());
-            // 处理完成后删除
-            criteria.remove("relationTo");
-        }
-    }
-
-    /**
-     * 添加where条件
-     * @param node json对象
-     * @param inSql in条件
-     * @param field 属性名
-     */
-    private void addWhereCond(JsonNode node, StringBuilder inSql, String field) {
-        String value = (String) JsonNodeUtils.getNodeValue(node.get(field));
-        if(StrUtil.isNotEmpty(value)) {
-            String column = StrUtil.toUnderlineCase(field);
-            inSql.append("and " + column + " = '" + value + "' ");
-        }
-    }
-
     @PostMapping("/createOne")
     public CommonResult<ObjectDigital> create(@Valid @RequestBody ObjectNode node){
         //基础参数校验
         ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
 
-        ObjectDigital vo = JsonNodeUtils.toEntity(node, ObjectDigital.class, "infos");
+        ObjectDigital vo = JsonNodeUtils.toEntity(node, ObjectDigital.class, ObjectDigital.EXTRA_COLUMN);
         List<ObjectDigital> voList = CollUtil.newArrayList(vo);
         service.insert(voList);
         return ResultHelper.single(vo);
@@ -205,7 +76,7 @@ public class ObjectDigitalController{
         //基础参数校验
         ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
 
-        List<ObjectDigital> voList = JsonNodeUtils.toEntity(array, ObjectDigital.class, "infos");
+        List<ObjectDigital> voList = JsonNodeUtils.toEntity(array, ObjectDigital.class, ObjectDigital.EXTRA_COLUMN);
         voList = service.insert(voList);
         return ResultHelper.multi(voList);
     }
@@ -215,7 +86,7 @@ public class ObjectDigitalController{
         //基础参数校验
         ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
 
-        ObjectDigital vo = JsonNodeUtils.toEntity(node, ObjectDigital.class, "infos");
+        ObjectDigital vo = JsonNodeUtils.toEntity(node, ObjectDigital.class, ObjectDigital.EXTRA_COLUMN);
         List<ObjectDigital> voList = CollUtil.newArrayList(vo);
         service.update(voList);
         return ResultHelper.single(vo);
@@ -226,7 +97,7 @@ public class ObjectDigitalController{
         //基础参数校验
         ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
 
-        List<ObjectDigital> voList = JsonNodeUtils.toEntity(array, ObjectDigital.class, "infos");
+        List<ObjectDigital> voList = JsonNodeUtils.toEntity(array, ObjectDigital.class, ObjectDigital.EXTRA_COLUMN);
         voList = service.update(voList);
         return ResultHelper.multi(voList);
     }

+ 6 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/entity/ObjectDigital.java

@@ -19,6 +19,10 @@ import java.util.List;
 @EqualsAndHashCode(callSuper = true)
 @TableName(value = "dt_object",autoResultMap = true)
 public class ObjectDigital extends AuditableEntity {
+
+    /** 扩展属性列 */
+    public static final String EXTRA_COLUMN = "infos";
+
     /** 项目ID */
     private String projectId;
     /** 名称 */
@@ -31,6 +35,8 @@ public class ObjectDigital extends AuditableEntity {
     private String objType;
     /** 类型编码 */
     private String classCode;
+    /** 集团编码 */
+    private String groupCode;
     /** 组标识 */
     private Integer grouping;
     /** 边类型编码 */

+ 11 - 1
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/service/IObjectDigitalService.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.persagy.dmp.rwd.digital.entity.ObjectDigital;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 对象数据 接口
@@ -53,5 +54,14 @@ public interface IObjectDigitalService {
      * 删除
      * @param idList 主键
      */
-    void delete(List<String> idList);
+    void delete(List<String> idList) ;
+
+    /**
+     * 查询虚拟信息点
+     * @param projectId
+     * @param groupCode
+     * @param ids
+     * @return
+     */
+    Map<String, List<String>>  queryVirtualCodeMap(String projectId, String groupCode, List<String> ids);
 }

+ 97 - 7
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/service/impl/ObjectDigitalServiceImpl.java

@@ -6,11 +6,14 @@ import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ReflectUtil;
 import com.alibaba.fastjson.JSONArray;
 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.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.common.context.AppContext;
+import com.persagy.dmp.define.entity.ObjectTypeDefine;
 import com.persagy.dmp.rwd.basic.constant.DigitalMessageConstant;
 import com.persagy.dmp.rwd.basic.utils.DigitalCommonUtils;
 import com.persagy.dmp.rwd.basic.utils.DigitalMessageHelper;
@@ -18,6 +21,7 @@ import com.persagy.dmp.rwd.define.service.IObjectInfoService;
 import com.persagy.dmp.common.constant.ValidEnum;
 import com.persagy.dmp.common.model.entity.BaseEntity;
 import com.persagy.dmp.define.entity.ObjectInfoDefine;
+import com.persagy.dmp.rwd.define.service.IObjectTypeService;
 import com.persagy.dmp.rwd.digital.dao.ObjectDigitalMapper;
 import com.persagy.dmp.rwd.digital.entity.ObjectDigital;
 import com.persagy.dmp.rwd.digital.service.IObjectDigitalService;
@@ -45,6 +49,8 @@ public class ObjectDigitalServiceImpl implements IObjectDigitalService {
     private DigitalMessageHelper messageSender;
     @Autowired
     private IObjectInfoService infoService;
+    @Autowired
+    private IObjectTypeService typeService;
 
     @Override
     public ObjectDigital load(String id) {
@@ -67,9 +73,18 @@ public class ObjectDigitalServiceImpl implements IObjectDigitalService {
             return null;
         }
         validateOnSave(voList, false);
+        //获取对象类型
+        Map<String, String> typeMap = typeService.queryObjTypeMap();
         voList.forEach(vo -> {
             // 生成ID
             vo.setId(DigitalCommonUtils.fetchObjectId(vo.getProjectId(), vo.getObjType()));
+            //设置项目id
+            vo.setProjectId(AppContext.getContext().getProjectId());
+            //设置集团编码
+            vo.setGroupCode(AppContext.getContext().getGroupCode());
+            //设置对象类型-objType
+            vo.setObjType(typeMap.get(vo.getClassCode()));
+            vo.setValid(ValidEnum.TRUE.getType());
             // 新增
             dao.insert(vo);
             // 新增后消息
@@ -80,22 +95,24 @@ public class ObjectDigitalServiceImpl implements IObjectDigitalService {
 
 
     @Override
-    public List<ObjectDigital> update(List<ObjectDigital> voList) {
+    public List<ObjectDigital> update(List<ObjectDigital> voList){
         if(CollUtil.isEmpty(voList)) {
             return null;
         }
         //获取$remove字段
         Map<String, Object> removeMap = getRemoveInfo(voList);
-
-        //信息点校验
-        Map<String, Map<String, ObjectInfoDefine>> allInfoMap = validateOnSave(voList, true);
-
         //获取基础属性
         Set<String> fieldSet = ReflectUtil.getFieldMap(ObjectDigital.class).keySet();
-
+        //查询数据库中存在的数据
         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);
+
+        //填充classCode
+        fillClassCodeForUpdate(voList,dbMap);
+        //信息点校验
+        Map<String, Map<String, ObjectInfoDefine>> allInfoMap = validateOnSave(voList, true);
+
         voList.forEach(vo -> {
             ObjectDigital dbVO = MapUtil.get(dbMap, vo.getId(), ObjectDigital.class);
             // 容错处理
@@ -135,12 +152,26 @@ public class ObjectDigitalServiceImpl implements IObjectDigitalService {
      * @param voList
      */
     private Map<String, Map<String, ObjectInfoDefine>> validateInfoCode(List<ObjectDigital> voList) {
-        // 查询信息点定义
+        //获取该信息点当前classCode
         List<String> typeCodeList = CollUtil.getFieldValues(voList, "classCode", String.class);
+
+        //查询通用类型:equipment,building,floor,space等
+        Map<String, String> objTypeMap = typeService.queryObjTypeMap();
+        queryParentClassCode(typeCodeList,objTypeMap);
+
+        // 查询信息点定义
         Map<String, Map<String, ObjectInfoDefine>> allInfoMap = infoService.queryByTypes(typeCodeList);
         // 信息点校验器
         for(ObjectDigital vo:voList) {
             Map<String, ObjectInfoDefine> infoMap = allInfoMap.get(vo.getClassCode());
+            String objType = objTypeMap.get(vo.getClassCode());
+            //设置通用信息点
+            if(!objType.equals(vo.getClassCode())){
+                Map<String, ObjectInfoDefine> commonInfoDefineMap = allInfoMap.get(objType);
+                if(commonInfoDefineMap!=null || commonInfoDefineMap.size()>0){
+                    infoMap.putAll(commonInfoDefineMap);
+                }
+            }
             if(MapUtil.isEmpty(infoMap)) {
                 continue;
             }
@@ -184,6 +215,29 @@ public class ObjectDigitalServiceImpl implements IObjectDigitalService {
     }
 
     /**
+     * 查询对应的通用类型
+     * @param typeCodeList
+     */
+    private void  queryParentClassCode(List<String> typeCodeList,Map<String, String> objTypeMap){
+        if(typeCodeList == null || typeCodeList.size()<=0){
+            return ;
+        }
+        //查询classCode对应点objType
+        List<String> parentCodes = new ArrayList<>();
+        for (String classCode : typeCodeList) {
+            String objType = objTypeMap.get(classCode);
+            if(StringUtils.isEmpty(objType) || "0".equals(objType) || parentCodes.contains(objType)){
+                return ;
+            }
+            parentCodes.add(objType);
+        }
+
+        if(parentCodes!=null && parentCodes.size()>0){
+            typeCodeList.addAll(parentCodes);
+        }
+        return ;
+    }
+    /**
      * 数据合并
      * @param dbVO 源数据
      * @param vo 目标数据
@@ -291,4 +345,40 @@ public class ObjectDigitalServiceImpl implements IObjectDigitalService {
             messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_DELETE, null, dbVO, false);
         });
     }
+
+    /**
+     * 修改时填充classCode
+     * @param voList
+     * @param dbMap
+     */
+    private void fillClassCodeForUpdate(List<ObjectDigital> voList,Map<String, ObjectDigital> dbMap){
+        if(voList == null || voList.size()<=0){
+            return;
+        }
+        for (ObjectDigital digital : voList) {
+            ObjectDigital dbDigital = dbMap.get(digital.getId());
+            if(dbDigital!=null){
+                digital.setClassCode(dbDigital.getClassCode());
+            }
+        }
+    }
+
+
+    /**
+     * 查询虚拟信息点
+     * @param projectId
+     * @param groupCode
+     * @param ids
+     * @return
+     */
+    public Map<String, List<String>> queryVirtualCodeMap(String projectId,String groupCode,List<String> ids) {
+        LambdaQueryWrapper<ObjectDigital> wrapper = new LambdaQueryWrapper<>();
+        wrapper.select(ObjectDigital::getId, ObjectDigital::getVirtualCodes);
+        wrapper.eq(ObjectDigital::getProjectId,projectId);
+        wrapper.eq(ObjectDigital::getGroupCode,groupCode);
+        wrapper.in(ObjectDigital::getId,ids);
+        wrapper.eq(ObjectDigital::getValid, ValidEnum.TRUE.getType());
+        List<ObjectDigital> objectDigitals = queryByCondition(wrapper);
+        return CollUtil.fieldValueAsMap(objectDigitals, "id", "virtual_codes");
+    }
 }

+ 197 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/digital/utils/ObjectDigitalCriteriaHelper.java

@@ -0,0 +1,197 @@
+package com.persagy.dmp.rwd.digital.utils;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ReflectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.basic.model.QueryOperator;
+import com.persagy.dmp.basic.utils.JsonNodeUtils;
+import com.persagy.dmp.common.model.entity.BaseEntity;
+import com.persagy.dmp.rwd.digital.entity.ObjectDigital;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 对象 查询条件 助手
+ * 增加对对象专属条件的处理
+ * @author Charlie Yu
+ * @date 2021-08-16
+ */
+public class ObjectDigitalCriteriaHelper {
+
+    /** 对象类字段集 */
+    private static final Set<String> DIGITAL_FIELDS = ReflectUtil.getFieldMap(ObjectDigital.class).keySet();
+
+    /**
+     * 拼接扩展条件
+     * 暂用#JSON#表示是json条件,不处理驼峰
+     * @param criteria
+     */
+    public static void ensureExtraCond(ObjectNode criteria) {
+        ensureSearchCond(criteria);
+        ensureRelationCond(criteria);
+        ensureJsonCond(criteria);
+    }
+
+    /**
+     * 拼接json条件
+     * @param criteria
+     */
+    private static void ensureJsonCond(ObjectNode criteria) {
+        Iterator<String> fieldNames = criteria.fieldNames();
+        Map<String, JsonNode> valueMap = new HashMap<>();
+        while (fieldNames.hasNext()) {
+            String infoCode = fieldNames.next();
+            // 基础属性不用处理
+            if(DIGITAL_FIELDS.contains(infoCode)) {
+                continue;
+            }
+            JsonNode value = criteria.get(infoCode);
+            if(value == null || value.isNull()) {
+                continue;
+            }
+            // 如果是or条件
+            if(QueryOperator.OR.getIndex().equalsIgnoreCase(infoCode)) {
+                processOrCond(value);
+                continue;
+            }
+            // 如果值是对象
+            if(value.isObject()) {
+                // 包含
+                if (value.has(QueryOperator.CONTAINS.getIndex())) {
+                    JsonNode valueNode = value.get(QueryOperator.CONTAINS.getIndex());
+                    String valueStr = valueNode.isTextual() ? value.asText():value.toString();
+                    String key = StrUtil.format("#JSON#json_contains({}, {}, '$.{}')", ObjectDigital.EXTRA_COLUMN, valueStr, infoCode);
+                    valueMap.put(key, criteria.numberNode(1));
+                } else if (value.has(QueryOperator.NOT_CONTAINS.getIndex())) {
+                    // 不包含
+                    JsonNode valueNode = value.get(QueryOperator.NOT_CONTAINS.getIndex());
+                    String valueStr = valueNode.isTextual() ? value.asText():value.toString();
+                    String key = StrUtil.format("#JSON#json_contains({}, {}, '$.{}')", ObjectDigital.EXTRA_COLUMN, valueStr, infoCode);
+                    valueMap.put(key, criteria.numberNode(0));
+                }
+            } else if(value.isTextual()) {
+                String key = StrUtil.format("#JSON#json_unquote(json_extract({}, '$.{}'))", ObjectDigital.EXTRA_COLUMN, infoCode);
+                valueMap.put(key, value);
+            } else if(value.isInt()) {
+                String key = StrUtil.format("#JSON#ifnull(json_extract({}, '$.{}'), -9999)", ObjectDigital.EXTRA_COLUMN, infoCode);
+                valueMap.put(key, value);
+            } else if(value.isDouble()) {
+                String key = StrUtil.format("#JSON#ifnull(json_extract({}, '$.{}'), -9999.99)", ObjectDigital.EXTRA_COLUMN, infoCode);
+                valueMap.put(key, value);
+            }
+            // 处理完成后删除
+            fieldNames.remove();
+        }
+        // 将valueMap写入criteria中
+        if(MapUtil.isEmpty(valueMap)) {
+            return;
+        }
+        for(String key:valueMap.keySet()) {
+            criteria.set(key, valueMap.get(key));
+        }
+    }
+
+    /**
+     * 处理or条件
+     * @param node
+     */
+    private static void processOrCond(JsonNode node) {
+        if(node == null || node.isNull()) {
+            return;
+        }
+        // 如果是数组 - 递归继续处理即可
+        if(node.isArray()) {
+            Iterator<JsonNode> elements = node.elements();
+            while (elements.hasNext()) {
+                // 递归继续处理
+                JsonNode objNode = elements.next();
+                processOrCond(objNode);
+            }
+            return;
+        }
+        // 如果是对象,则转换条件
+        if(node.isObject()) {
+            // 对象 递归从头开始处理
+            ObjectNode obj = (ObjectNode) node;
+            ensureExtraCond(obj);
+            return;
+        }
+    }
+
+    /**
+     * 拼接$search条件
+     * @param criteria
+     */
+    private static void ensureSearchCond(ObjectNode criteria) {
+        if(criteria == null || criteria.isNull()) {
+            return;
+        }
+        // 处理search
+        JsonNode search = criteria.get(QueryOperator.SEARCH.getIndex());
+        if(search != null && search.isTextual()) {
+            String searchValue = search.asText();
+            String key = StrUtil.format("#JSON#json_search({0}, 'one', {1})", ObjectDigital.EXTRA_COLUMN, searchValue);
+            ObjectNode searchObj = criteria.putObject(key);
+            searchObj.put(QueryOperator.NULL.getIndex(), false);
+            // 处理完成后删除
+            criteria.remove(QueryOperator.SEARCH.getIndex());
+        }
+    }
+
+    /**
+     * 处理关系条件
+     * @param criteria
+     */
+    private static void ensureRelationCond(ObjectNode criteria) {
+        if(criteria == null || criteria.isNull()) {
+            return;
+        }
+        // 处理relationFrom
+        JsonNode relationFrom = criteria.get(QueryOperator.RELATION_FROM.getIndex());
+        if(relationFrom != null && relationFrom.isObject() && relationFrom.size() > 0) {
+            StringBuilder inSql = new StringBuilder("(select obj_from from dt_relation where 1=1 ");
+            addWhereCond(relationFrom, inSql, "graphId");
+            addWhereCond(relationFrom, inSql, "graphCode");
+            addWhereCond(relationFrom, inSql, "relCode");
+            addWhereCond(relationFrom, inSql, "objTo");
+            inSql.append(")");
+            ObjectNode inObj = criteria.putObject(BaseEntity.PROP_ID);
+            inObj.put(QueryOperator.IN_SQL.getIndex(), inSql.toString());
+            // 处理完成后删除
+            criteria.remove(QueryOperator.RELATION_FROM.getIndex());
+        }
+        // 处理relationTo
+        JsonNode relationTo = criteria.get(QueryOperator.RELATION_TO.getIndex());
+        if(relationTo != null && relationTo.isObject() && relationTo.size() > 0) {
+            StringBuilder inSql = new StringBuilder("(select obj_to from dt_relation where 1=1 ");
+            addWhereCond(relationTo, inSql, "graphId");
+            addWhereCond(relationTo, inSql, "graphCode");
+            addWhereCond(relationTo, inSql, "relCode");
+            addWhereCond(relationTo, inSql, "objFrom");
+            inSql.append(")");
+            ObjectNode inObj = criteria.putObject(BaseEntity.PROP_ID);
+            inObj.put(QueryOperator.IN_SQL.getIndex(), inSql.toString());
+            // 处理完成后删除
+            criteria.remove(QueryOperator.RELATION_TO.getIndex());
+        }
+    }
+
+    /**
+     * 添加where条件
+     * @param node json对象
+     * @param inSql in条件
+     * @param field 属性名
+     */
+    private static void addWhereCond(JsonNode node, StringBuilder inSql, String field) {
+        String value = (String) JsonNodeUtils.getNodeValue(node.get(field));
+        if(StrUtil.isNotEmpty(value)) {
+            String column = StrUtil.toUnderlineCase(field);
+            inSql.append("and " + column + " = '" + value + "' ");
+        }
+    }
+}

+ 111 - 5
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/controller/IotController.java

@@ -1,18 +1,24 @@
 package com.persagy.dmp.rwd.iot.controller;
-
-
 import com.persagy.dmp.common.constant.CommonConstant;
+import com.persagy.dmp.common.constant.ResponseCode;
+import com.persagy.dmp.common.exception.BusinessException;
 import com.persagy.dmp.common.model.response.CommonResult;
 import com.persagy.dmp.common.utils.ParamCheckUtil;
 import com.persagy.dmp.common.utils.ResultHelper;
 import com.persagy.dmp.rwd.iot.model.CurrentDataModel;
-import com.persagy.dmp.rwd.iot.service.CurrentDataService;
+import com.persagy.dmp.rwd.iot.model.SettingDataModel;
+import com.persagy.dmp.rwd.iot.model.history.InfoCodeModel;
+import com.persagy.dmp.rwd.iot.model.history.RequestModel;
+import com.persagy.dmp.rwd.iot.service.CurrentIotService;
+import com.persagy.dmp.rwd.iot.service.HistoryIotService;
+import com.persagy.dmp.rwd.iot.service.SettingIotService;
 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.ArrayList;
 import java.util.List;
 
 /**
@@ -25,13 +31,113 @@ import java.util.List;
 public class IotController {
 
 	@Autowired
-	private CurrentDataService currentDataService;
+	private CurrentIotService currentDataService;
+
+	@Autowired
+	private HistoryIotService historyDataService;
 
+	@Autowired
+	private SettingIotService settingDataService;
+
+	/**
+	 * 查询对象绑点信息点的实时数据
+	 * @param param
+	 * @return
+	 * @throws Exception
+	 */
 	@PostMapping("/data/current")
-	public CommonResult<List<CurrentDataModel>> current(@RequestBody List<CurrentDataModel> param) {
+	@Deprecated
+	public CommonResult<List<CurrentDataModel>> current(@RequestBody List<CurrentDataModel> param) throws Exception {
 		//基础参数校验
 		ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
+		//查询实时数据
 		List<CurrentDataModel> currentData = currentDataService.getCurrentData(param);
+		if(currentData == null || currentData.size()<=0){
+			return ResultHelper.multi(new ArrayList<>(),0);
+		}
 		return ResultHelper.multi(currentData,currentData.size());
 	}
+
+
+	/**
+	 * 查询历史数据/分精度数据
+	 * @param request
+	 * @return
+	 */
+	@PostMapping("/data/history")
+	public CommonResult<List<InfoCodeModel>> history(@RequestBody RequestModel request) throws Exception{
+		//基础参数校验
+		ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
+		checkHistoryRequest(request);
+        //查询历史数据/分精度数据
+		List<InfoCodeModel> historyData = historyDataService.getHistoryData(request);
+
+		if(historyData == null || historyData.size()<=0){
+			return ResultHelper.multi(new ArrayList<>(),0);
+		}
+		return ResultHelper.multi(historyData,historyData.size());
+	}
+
+	/**
+	 * 发送控制指令/设定动态参数
+	 * @param param
+	 * @return
+	 */
+	@PostMapping("/funcid/setting")
+	public CommonResult<List<SettingDataModel>> setting(@RequestBody List<SettingDataModel> param) {
+		//基础参数校验
+		ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
+		//发送控制指令/设定动态参数
+		List<SettingDataModel> settingData = settingDataService.settingDataService(param);
+
+		if(settingData == null || settingData.size()<=0){
+			return ResultHelper.multi(new ArrayList<>(),0);
+		}
+		return ResultHelper.multi(settingData,settingData.size());
+	}
+
+
+	/**
+	 * 查询指令执行结果
+	 * @param param
+	 * @return
+	 */
+	@PostMapping("/funcid/settingQuery")
+	public CommonResult<List<SettingDataModel>> settingQuery(@RequestBody List<String> param) {
+		//基础参数校验
+		ParamCheckUtil.checkParam(CommonConstant.QUERY_GROUPCODE,CommonConstant.QUERY_PROJECTID);
+		//发送控制指令/设定动态参数
+		List<SettingDataModel> settingData = settingDataService.settingQuery(param);
+
+		if(settingData == null || settingData.size()<=0){
+			return ResultHelper.multi(new ArrayList<>(),0);
+		}
+		return ResultHelper.multi(settingData,settingData.size());
+	}
+
+	/**
+	 * 查询历史数据请求参数校验
+	 * @param request
+	 */
+	private void checkHistoryRequest(RequestModel request) {
+		String startTime = request.getStartTime();
+		if (startTime == null) {
+			throw new BusinessException(ResponseCode.A0400.getCode(), "startTime is required");
+		}
+		String endTime = request.getEndTime();
+		if (endTime == null) {
+			throw new BusinessException(ResponseCode.A0400.getCode(), "endTime is required");
+		}
+		String period = request.getPeriod();
+		if (period == null) {
+			throw new BusinessException(ResponseCode.A0400.getCode(), "period is required");
+		}
+		List<InfoCodeModel> params = request.getParams();
+		if (params == null || params.size() == 0) {
+			throw new BusinessException(ResponseCode.A0400.getCode(), "params is required");
+		}
+	}
+
+
+
 }

+ 4 - 1
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/model/history/InfoCodeModel.java

@@ -1,5 +1,6 @@
 package com.persagy.dmp.rwd.iot.model.history;
 
+import com.alibaba.fastjson.JSONArray;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import lombok.Getter;
 import lombok.Setter;
@@ -15,5 +16,7 @@ public class InfoCodeModel {
 	private String status;
 	private String error;
 
-	private ArrayNode data;
+	private JSONArray data;
+
+
 }

+ 5 - 3
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/CurrentDataService.java

@@ -5,12 +5,14 @@ import com.persagy.dmp.rwd.iot.model.CurrentDataModel;
 
 import java.util.List;
 
-public interface CurrentDataService {
+public interface CurrentIotService {
 
     /**
-     * 查询实时数据
+     * 查询对象绑点信息点的实时数据
      * @param param
      * @return
      */
-    List<CurrentDataModel> getCurrentData(List<CurrentDataModel> param);
+    List<CurrentDataModel> getCurrentData(List<CurrentDataModel> param) throws Exception;
+
+
 }

+ 17 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/HistoryIotService.java

@@ -0,0 +1,17 @@
+package com.persagy.dmp.rwd.iot.service;
+
+import com.persagy.dmp.rwd.iot.model.CurrentDataModel;
+import com.persagy.dmp.rwd.iot.model.history.InfoCodeModel;
+import com.persagy.dmp.rwd.iot.model.history.RequestModel;
+
+import java.util.List;
+
+public interface HistoryIotService {
+
+    /**
+     * 查询对象绑点信息点的实时数据
+     * @param request
+     * @return
+     */
+    List<InfoCodeModel> getHistoryData(RequestModel request) throws Exception;
+}

+ 27 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/SettingIotService.java

@@ -0,0 +1,27 @@
+package com.persagy.dmp.rwd.iot.service;
+
+import com.persagy.dmp.common.model.response.CommonResult;
+import com.persagy.dmp.rwd.iot.model.SettingDataModel;
+import com.persagy.dmp.rwd.iot.model.history.InfoCodeModel;
+import com.persagy.dmp.rwd.iot.model.history.RequestModel;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.List;
+
+public interface SettingIotService {
+
+    /**
+     * 发送控制指令/设定动态参数
+     * @param param
+     * @return
+     */
+    List<SettingDataModel> settingDataService(List<SettingDataModel> param);
+
+
+    /**
+     * 查询指令执行结果
+     * @param param
+     * @return
+     */
+    List<SettingDataModel> settingQuery(@RequestBody List<String> param);
+}

+ 0 - 68
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/CurrentDataServiceImpl.java

@@ -1,68 +0,0 @@
-package com.persagy.dmp.rwd.iot.service.impl;
-
-import com.persagy.dmp.common.context.AppContext;
-import com.persagy.dmp.rwd.iot.model.CurrentDataModel;
-import com.persagy.dmp.rwd.iot.service.CurrentDataService;
-import lombok.Getter;
-import lombok.Setter;
-import org.springframework.stereotype.Service;
-
-import java.util.*;
-
-/**
- * iot-查询实时数据
- * @author:linhuili
- * @date:2021/8/11
- */
-@Service
-public class CurrentDataServiceImpl implements CurrentDataService {
-
-    /**
-     * 查询实时数据
-     * @param param
-     * @return
-     */
-    @Override
-    public List<CurrentDataModel> getCurrentData(List<CurrentDataModel> param) {
-        if(param == null || param.size()<=0){
-            return new ArrayList<>();
-        }
-
-        String groupCode = AppContext.getContext().getGroupCode();
-        String projectId = AppContext.getContext().getProjectId();
-
-        //查询对象绑点信息点的实时数据
-        List<PointParam> parameters = new LinkedList<>();
-        for (CurrentDataModel model : param) {
-            if (model.getObjectId() == null) {
-                model.setError("对象id不可为空");
-                continue;
-            }
-            String infoCode = model.getInfoCode();
-            if (infoCode == null) {
-                model.setError("信息点编码不可为空");
-                continue;
-            }
-
-            //表号功能号校验
-           // String infoCodeValue = getInfoCodeValue(groupCode, projectId, model.getObjectId(), infoCode);
-            parameters.add(new PointParam(model.getMeter(), model.getFunction()));
-        }
-        return null;
-    }
-
-    /**
-     * 信息点参数定义
-     */
-    @Getter
-    @Setter
-    public static class PointParam {
-        String meter;
-        String funcid;
-
-        public PointParam(String meter, String function) {
-            this.meter = meter;
-            this.funcid = function;
-        }
-    }
-}

+ 173 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/CurrentIotServiceImpl.java

@@ -0,0 +1,173 @@
+package com.persagy.dmp.rwd.iot.service.impl;
+
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.basic.model.QueryCriteria;
+import com.persagy.dmp.basic.utils.QueryCriteriaHelper;
+import com.persagy.dmp.common.context.AppContext;
+import com.persagy.dmp.mybatis.utils.ConditionUtil;
+import com.persagy.dmp.rwd.basic.constant.IotUrlConstant;
+import com.persagy.dmp.rwd.basic.utils.MeterUtils;
+import com.persagy.dmp.rwd.digital.entity.ObjectDigital;
+import com.persagy.dmp.rwd.digital.service.IObjectDigitalService;
+import com.persagy.dmp.rwd.iot.model.CurrentDataModel;
+import com.persagy.dmp.rwd.iot.service.CurrentIotService;
+import lombok.Getter;
+import lombok.Setter;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+
+
+/**
+ * iot-查询实时数据
+ * @author:linhuili
+ * @date:2021/8/11
+ */
+@Service
+public class CurrentIotServiceImpl implements CurrentIotService {
+
+    @Autowired
+    private IObjectDigitalService objectDigitalService;
+
+    @Value("${persagy.iot.data.server}")
+    private String iotDataServer;
+
+
+    /**
+     * 查询对象绑点信息点的实时数据
+     * @param param
+     * @return
+     */
+    @Override
+    public List<CurrentDataModel> getCurrentData(List<CurrentDataModel> param) throws Exception{
+        if(param == null || param.size()<=0){
+            return new ArrayList<>();
+        }
+        //表号功能号校验
+        List<PointParam> parameters = verifyMeterAndFunction(param);
+        if (parameters.size() == 0) {
+            return param;
+        }
+
+        //查询实时数据
+        String url = iotDataServer + IotUrlConstant.QUERY_CUCCRENT_DATA;
+        JSONObject requestBody = new JSONObject();
+        requestBody.put("building", AppContext.getContext().getProjectId().substring(2));
+        requestBody.put("points", parameters);
+        String response = HttpUtil.post(url, requestBody.toString(), 3000);
+        JSONObject result = JSONObject.parseObject(response);
+        if(result == null){
+            return param;
+        }
+        JSONArray points = result.getJSONArray("points");
+        //绑定表号功能号
+        for (Object object : points) {
+            JSONObject item = (JSONObject) object;
+            String meter = item.getString("meter");
+            String funcid = item.getString("funcid");
+            for (CurrentDataModel model : param) {
+                if (meter.equals(model.getMeter()) && funcid.equals(model.getFunction())) {
+                    model.setData(item.get("data"));
+                    model.setTime(item.getString("receivetime"));
+                }
+            }
+        }
+        return param;
+    }
+
+
+    /**
+     * 校验表号功能号
+     * @param param
+     */
+    private List<PointParam> verifyMeterAndFunction(List<CurrentDataModel> param){
+        List<PointParam> parameters = new LinkedList<>();
+        for (CurrentDataModel model : param) {
+            if (model.getObjectId() == null) {
+                model.setError("对象id不可为空");
+                continue;
+            }
+            String infoCode = model.getInfoCode();
+            if (infoCode == null) {
+                model.setError("信息点编码不可为空");
+                continue;
+            }
+            //校验表号功能号是否存在
+            String infoCodeValue = getInfoCodeValue(model.getObjectId(), infoCode);
+            if(StringUtils.isEmpty(infoCodeValue)){
+                model.setError("value of infoCode[" + model.getObjectId() + ":" + infoCode + "] is null");
+                continue;
+            }
+            // 判断信息点的值是不是表号-功能号格式
+            model.setInfoValue(infoCodeValue);
+            if (!MeterUtils.matchFormat(infoCodeValue)) {
+                model.setError("value of infoCode[" + model.getObjectId() + ":" + infoCode + "][ " + infoCodeValue + "] 不是正确的表号功能号");
+                continue;
+            }
+            parameters.add(new PointParam(model.getMeter(), model.getFunction()));
+        }
+        return parameters;
+    }
+
+
+    /**
+     * 查询信息点值
+     * @param objectId
+     * @param infoCode
+     * @return
+     * @throws Exception
+     */
+    public String getInfoCodeValue(String objectId,String infoCode){
+        //查询条件封装
+        QueryCriteria queryCriteria = new QueryCriteria();
+        ObjectNode criteria = JsonNodeFactory.instance.objectNode();
+        criteria.put("id",objectId);
+        criteria.put("valid",1);
+        queryCriteria.setCriteria(criteria);
+
+        //查询object对象
+        QueryWrapper<ObjectDigital> wrapper = new QueryWrapper<>();
+        // 添加所属项目条件
+        ConditionUtil.ensureProjectCriteria(wrapper);
+        // 转换查询条件
+        QueryCriteriaHelper.toWrapper(wrapper,queryCriteria);
+        List<ObjectDigital> data = objectDigitalService.queryByCondition(wrapper);
+
+        if(data == null || data.size()<=0){
+            return null;
+        }
+        if("classCode".equals(infoCode)){
+            return data.get(0).getClassCode();
+        }
+        ObjectNode jsonNodes = data.get(0).getInfos();
+        if(jsonNodes.has(infoCode)){
+            return jsonNodes.get(infoCode).textValue();
+        }
+        return null;
+    }
+
+    /**
+     * 信息点参数定义
+     */
+    @Getter
+    @Setter
+    public static class PointParam {
+        String meter;
+        String funcid;
+
+        public PointParam(String meter, String function) {
+            this.meter = meter;
+            this.funcid = function;
+        }
+    }
+}
+

+ 167 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/HistoryIotServiceImpl.java

@@ -0,0 +1,167 @@
+package com.persagy.dmp.rwd.iot.service.impl;
+
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.common.context.AppContext;
+import com.persagy.dmp.rwd.basic.constant.IotUrlConstant;
+import com.persagy.dmp.rwd.basic.utils.MeterUtils;
+import com.persagy.dmp.rwd.iot.model.history.InfoCodeModel;
+import com.persagy.dmp.rwd.iot.model.history.RequestModel;
+import com.persagy.dmp.rwd.iot.service.HistoryIotService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * iot-查询历史数据/分精度数据
+ * @author:linhuili
+ * @date:2021/8/11
+ */
+@Service
+public class HistoryIotServiceImpl implements HistoryIotService {
+
+    @Autowired
+    private CurrentIotServiceImpl currentDataService;
+
+    @Value("${persagy.iot.data.server}")
+    private String iotDataServer;
+    /**
+     * 查询历史数据/分精度数据
+     * @param request
+     * @return
+     * @throws Exception
+     */
+    @Override
+    public List<InfoCodeModel> getHistoryData(RequestModel request) throws Exception {
+        List<InfoCodeModel> params = request.getParams();
+        //信息点校验
+        ArrayNode pointList = JsonNodeFactory.instance.arrayNode();
+        for (InfoCodeModel param : params) {
+            param.setStatus("success");
+            checkParam(param, pointList);
+        }
+        if (pointList.size() == 0) {
+            return params;
+        }
+
+        //转换为iot请求参数
+        ObjectNode requestNode = JsonNodeFactory.instance.objectNode();
+        requestNode.put("building", AppContext.getContext().getProjectId().substring(2));
+        for (JsonNode jsonNode : pointList) {
+            ObjectNode item = (ObjectNode) jsonNode;
+            item.put("time_period", request.getPeriod());
+            item.put("time_from", request.getStartTime());
+            item.put("time_to", request.getEndTime());
+        }
+        requestNode.set("points", pointList);
+
+        //查询对象绑点信息点的历史数据
+        String url = iotDataServer + IotUrlConstant.QUERY_HISTORY_DATA;
+        String response = HttpUtil.post(url, requestNode.toString(), 30000);
+        JSONObject object = JSONObject.parseObject(response);
+        if(object == null){
+            return params;
+        }
+        JSONArray points = object.getJSONArray("points");
+        handleIotHisQueryReuslt(params,points);
+
+        return params;
+    }
+
+
+    /**
+     * iot历史数据查询结果封装
+     * @param params
+     * @param points
+     */
+    private void handleIotHisQueryReuslt(List<InfoCodeModel> params ,JSONArray points){
+        if(points == null || points.size()<=0){
+            return;
+        }
+        for (Object point : points) {
+            JSONObject meterItem = (JSONObject) point;
+            String meter = meterItem.getString("meter");
+            String function = meterItem.getString("funcid") + "";
+            for (InfoCodeModel param : params) {
+                if (!(meter + "-" + function).equals(param.getMeter() + "-" + param.getFunction())) {
+                    continue;
+                }
+
+                JSONArray data = new JSONArray();
+                JSONArray datas = meterItem.getJSONArray("datas");
+                if (datas != null && datas.size() > 0) {
+                    for (Object jsonNode : datas) {
+                        JSONObject dataItem = (JSONObject) jsonNode;
+                        JSONObject item = new JSONObject();
+                        item.put("time", dataItem.getString("data_time"));
+                        item.put("data", dataItem.getString("data_value"));
+                        data.add(item);
+                    }
+                }
+                param.setData(data);
+            }
+        }
+    }
+
+
+    /**
+     * 信息点校验
+     * @param param
+     * @param pointList
+     * @throws Exception
+     */
+    private void checkParam(InfoCodeModel param, ArrayNode pointList) throws Exception {
+        String objectId = param.getObjectId();
+        if (objectId == null) {
+            param.setStatus("error");
+            param.setError("objectId is not required");
+            return;
+        }
+        String infoCode = param.getInfoCode();
+        if (infoCode == null) {
+            param.setStatus("error");
+            param.setError("infoCode is not required");
+            return;
+        }
+        String classCode = currentDataService.getInfoCodeValue(objectId, "classCode");
+        if (classCode == null) {
+            param.setStatus("error");
+            param.setError("对象不存在或已失效");
+            return;
+        }
+
+        String infoCodeValue = currentDataService.getInfoCodeValue(objectId, infoCode);
+        if (infoCodeValue == null) {
+            param.setStatus("error");
+            param.setError("value of infoCode[" + objectId + ":" + infoCode + "] is null");
+            return;
+        }
+        // 判断信息点的值是不是表号-功能号格式
+        if (!MeterUtils.matchFormat(infoCodeValue)) {
+            param.setStatus("error");
+            param.setError("value of infoCode[" + objectId + ":" + infoCode + "][ " + infoCodeValue + "] 不是正确的表号功能号");
+            return;
+        }
+
+        int idx = infoCodeValue.lastIndexOf("-");
+        if (idx == -1) {
+
+        } else {
+            String meter = infoCodeValue.substring(0, idx);
+            String function = infoCodeValue.substring(idx + 1);
+            param.setMeter(meter);
+            param.setFunction(function);
+            ObjectNode point = pointList.addObject();
+            point.put("meter", meter);
+            point.put("funcid", Long.parseLong(function));
+        }
+    }
+
+}

+ 203 - 0
dmp-business/dmp-rwd/src/main/java/com/persagy/dmp/rwd/iot/service/impl/SettingIotServiceImpl.java

@@ -0,0 +1,203 @@
+package com.persagy.dmp.rwd.iot.service.impl;
+
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.common.context.AppContext;
+import com.persagy.dmp.rwd.basic.constant.IotUrlConstant;
+import com.persagy.dmp.rwd.basic.utils.MeterUtils;
+import com.persagy.dmp.rwd.digital.service.IObjectDigitalService;
+import com.persagy.dmp.rwd.iot.model.SettingDataModel;
+import com.persagy.dmp.rwd.iot.service.SettingIotService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * iot-动态参数设定/查询
+ * @author:linhuili
+ * @date:2021/8/11
+ */
+@Service
+public class SettingIotServiceImpl implements SettingIotService {
+
+    @Autowired
+    private CurrentIotServiceImpl currentDataService;
+
+    @Autowired
+    private IObjectDigitalService iObjectDigitalService;
+
+    @Value("${persagy.iot.data.server}")
+    private String iotDataServer;
+
+    /**
+     * 发送控制指令/设定动态参数
+     * @param param
+     * @return
+     */
+    @Override
+    public List<SettingDataModel> settingDataService(List<SettingDataModel> param) {
+        //设定动态参数
+        ArrayNode pointValueList = JsonNodeFactory.instance.arrayNode();
+        settingParam(param,pointValueList);
+
+        //绑定动态参数
+        String projectLocalId = AppContext.getContext().getProjectId().substring(2);
+        ObjectNode requestNode = JsonNodeFactory.instance.objectNode();
+        requestNode.put("building", projectLocalId);
+        requestNode.set("points", pointValueList);
+
+        String url = iotDataServer + IotUrlConstant.POINT_SET_DATA;
+        String response = HttpUtil.post(url, requestNode.toString(), 30000);
+        JSONObject object = JSONObject.parseObject(response);
+        if(object == null){
+            return param;
+        }
+
+        //返回结果封装
+        JSONArray points = object.getJSONArray("points");
+        for (Object node : points) {
+            JSONObject item = (JSONObject) node;
+            String meter = item.getString("meter");
+            String funcid = item.getString("funcid")+"";
+            for (SettingDataModel model : param) {
+                if (model.getMeter().equals(meter) && model.getFunction().equals(funcid)) {
+                    // 楼号-表号-功能号-时间作为唯一标识
+                    String exeCode = projectLocalId + ":" + meter + ":" + funcid + ":" + item.getString("receivetime");
+                    model.setExeCode(exeCode);
+                }
+            }
+        }
+        return param;
+    }
+
+    /**
+     * 动态参数设置
+     * @param param
+     * @param pointValueList
+     */
+    private void settingParam(List<SettingDataModel> param,ArrayNode pointValueList){
+        //查询虚拟信息点
+        Map<String, List<String>> virtualCodeMap = getVirtualCodeMap(param);
+
+        Map<String, Set<String>> virtualPointCache = new HashMap<>();
+        for (SettingDataModel model : param) {
+            model.setStatus("success");
+
+            //查询信息点值
+            String objectId = model.getObjectId();
+            String infoCode = model.getInfoCode();
+            String infoCodeValue = currentDataService.getInfoCodeValue(objectId, infoCode);
+
+            //信息点校验
+            if (infoCodeValue == null) {
+                model.setStatus("error");
+                model.setError("value of infoCode[" + objectId + ":" + infoCode + "] is null");
+                continue;
+            }
+
+            // 判断信息点的值是不是表号-功能号格式
+            if (!MeterUtils.matchFormat(infoCodeValue)) {
+                model.setStatus("error");
+                model.setError("value of infoCode[" + objectId + ":" + infoCode + "][ " + infoCodeValue + "] 不是正确的表号功能号");
+                continue;
+            }
+
+            //设置表号功能号
+            int idx = infoCodeValue.lastIndexOf("-");
+            String meter = infoCodeValue.substring(0, idx);
+            String function = infoCodeValue.substring(idx + 1);
+            model.setMeter(meter);
+            model.setFunction(function);
+            ObjectNode point = pointValueList.addObject();
+            point.put("meter", meter);
+            point.put("funcid", Long.parseLong(function));
+            point.put("data", model.getValue()); // TODO 要细分类型
+
+            //设置虚拟信息点
+            if (!virtualPointCache.containsKey(objectId)) {
+                List<String> virtualCode = virtualCodeMap.get(objectId);
+                if (virtualCode != null && virtualCode.size() > 0) {
+                    virtualPointCache.put(objectId, new HashSet<>(virtualCode));
+                } else {
+                    virtualPointCache.put(objectId, Collections.emptySet());
+                }
+            }
+            Set<String> virtualPointList = virtualPointCache.get(objectId);
+            point.put("virtual", virtualPointList.contains(infoCode));
+        }
+    }
+
+    /**
+     * 获取对象信息点虚拟信息点
+     * @param param
+     * @return
+     */
+    private Map<String, List<String>> getVirtualCodeMap(List<SettingDataModel> param){
+        List<String> ids = param.stream().map(SettingDataModel::getObjectId).collect(Collectors.toList());
+        String projectId = AppContext.getContext().getProjectId();
+        String groupCode = AppContext.getContext().getGroupCode();
+        Map<String, List<String>> map = iObjectDigitalService.queryVirtualCodeMap(projectId, groupCode, ids);
+        return map;
+    }
+
+    /**
+     * 查询指令执行结果
+     * @param param
+     * @return
+     */
+    @Override
+    public List<SettingDataModel> settingQuery(List<String> param) {
+        if (param == null || param.size() == 0) {
+            return null;
+        }
+
+        //设置查询参数
+        String projectLocalId = AppContext.getContext().getProjectId().substring(2);
+        ObjectNode requestNode = JsonNodeFactory.instance.objectNode();
+        requestNode.put("building", projectLocalId);
+        ArrayNode points = requestNode.putArray("points");
+        for (String str : param) {
+            ObjectNode point = points.addObject();
+            String[] split = str.split(":");
+            point.put("meter", split[1]);
+            point.put("funcid", Integer.parseInt(split[2]));
+            point.put("receivetime", split[3]);
+        }
+
+        //查询动态参数
+        String url = iotDataServer + IotUrlConstant.QUERY_POINT_SET_DATA;
+        String response = HttpUtil.post(url, requestNode.toString(), 30000);
+        JSONObject object = JSONObject.parseObject(response);
+        if(object == null){
+            return null;
+        }
+
+        //控制指令执行结果封装
+        JSONArray responseData = object.getJSONArray("points");
+        List<SettingDataModel> list = new LinkedList<>();
+        for (Object datum : responseData) {
+            JSONObject item = (JSONObject) datum;
+            //表号
+            String meter = item.getString("meter");
+            //功能号
+            String function = item.getString("funcid") + "";
+            //执行指令
+            String receivetime = item.getString("receivetime");
+            String exeCode = projectLocalId + ":" + meter + ":" + function + ":" + receivetime;
+            SettingDataModel model = new SettingDataModel();
+            model.setExeCode(exeCode);
+            //指令执行结果
+            model.setExeResult(item.getString("status"));
+            list.add(model);
+        }
+        return list;
+    }
+}

+ 2 - 2
dmp-business/dmp-rwd/src/main/resources/mapper/DigitalMigrateMapper.xml

@@ -54,7 +54,7 @@
         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
+          '0',date_format(now(), '%Y%m%d%h%i%s'),null,null,`valid`
         FROM `${schema}`.`rwd_object_${groupCode}_${projectId}`
     </insert>
     <insert id="migrateRelation">
@@ -65,7 +65,7 @@
         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
+          '0',date_format(now(), '%Y%m%d%h%i%s'),null,null,`status`
         FROM `${schema}`.`rwd_relation_${groupCode}_${projectId}`
     </insert>
 

+ 63 - 0
dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/model/QueryOperator.java

@@ -0,0 +1,63 @@
+package com.persagy.dmp.basic.model;
+
+import lombok.Getter;
+
+/**
+ * 查询条件
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Getter
+public enum QueryOperator {
+
+    /** 查询条件 */
+    NE("$ne", "不等于"),
+    GT("$gt", "大于"),
+    GTE("$gte", "大于等于"),
+    LT("$lt", "小于"),
+    LTE("$lte", "小于等于"),
+    IN("$in", "等于"),
+    LIKE("$like", "包含"),
+    NOT_LIKE("$notLike", "不包含"),
+    NULL("$null", "空"),
+
+    CONTAINS("$contains", "包含"),
+    NOT_CONTAINS("$notcontains", "不包含"),
+    SEARCH("$search", "匹配"),
+    RELATION_FROM("relationFrom", "关系来源"),
+    RELATION_TO("relationTo", "关系目标"),
+
+    /** 暂不使用 */
+    SQL("$sql", "SQL"),
+    /** 20210816 支持relation条件 */
+    IN_SQL("$inSql", "IN_SQL"),
+    /** 20210816 支持or条件 */
+    AND("$and", "且"),
+    OR("$or", "或"),
+    /** 20210816 支持数据中心左、右like条件 */
+    LIKE_LEFT("$likeLeft", "左包含"),
+    LIKE_RIGHT("$likeRight", "右包含");
+
+    private String index;
+    private String name;
+
+    QueryOperator(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+
+    /**
+     * 通过Index查找
+     * @param index
+     * @return
+     */
+    public static QueryOperator findByIndex(String index) {
+        QueryOperator[] values = QueryOperator.values();
+        for(QueryOperator value:values) {
+            if(value.getIndex().equalsIgnoreCase(index)) {
+                return value;
+            }
+        }
+        return null;
+    }
+}

+ 8 - 4
dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/utils/JsonNodeUtils.java

@@ -2,6 +2,7 @@ package com.persagy.dmp.basic.utils;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ReflectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -10,7 +11,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.persagy.dmp.common.constant.ResponseCode;
 import com.persagy.dmp.common.exception.BusinessException;
 import com.persagy.dmp.common.helper.SpringHelper;
-import com.persagy.dmp.common.model.entity.BaseEntity;
 
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -30,7 +30,7 @@ public class JsonNodeUtils {
      * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
      * @return Json对象
      */
-    public static ObjectNode toObjectNode(BaseEntity vo, String extraColumn, Set<String> extraColumns) {
+    public static ObjectNode toObjectNode(Object vo, String extraColumn, Set<String> extraColumns) {
         if(vo == null) {
             return null;
         }
@@ -54,7 +54,7 @@ public class JsonNodeUtils {
      * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
      * @return Json对象
      */
-    public static List<ObjectNode> toListNode(List<BaseEntity> voList, String extraColumn, Set<String> extraColumns) {
+    public static List<ObjectNode> toListNode(List<Object> voList, String extraColumn, Set<String> extraColumns) {
         if(CollUtil.isEmpty(voList)) {
             return null;
         }
@@ -82,7 +82,7 @@ public class JsonNodeUtils {
      * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
      * @return Json对象
      */
-    public static ArrayNode toArrayNode(List<BaseEntity> voList, String extraColumn, Set<String> extraColumns) {
+    public static ArrayNode toArrayNode(List<Object> voList, String extraColumn, Set<String> extraColumns) {
         if(CollUtil.isEmpty(voList)) {
             return null;
         }
@@ -109,6 +109,10 @@ public class JsonNodeUtils {
      * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
      */
     private static void ensureExtras(ObjectNode node, String extraColumn, Set<String> extraColumns) {
+        // 没有扩展列不用处理
+        if(StrUtil.isBlank(extraColumn)) {
+            return;
+        }
         JsonNode extraNode = node.get(extraColumn);
         // 如果扩展列的值为空或不是对象,直接返回
         if(extraNode == null || extraNode.isNull() || !extraNode.isObject()) {

+ 73 - 13
dmp-comp/dmp-digital-starter/src/main/java/com/persagy/dmp/basic/utils/QueryCriteriaHelper.java

@@ -4,7 +4,9 @@ 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.fasterxml.jackson.databind.node.ObjectNode;
 import com.persagy.dmp.basic.model.QueryCriteria;
+import com.persagy.dmp.basic.model.QueryOperator;
 import com.persagy.dmp.common.model.entity.BaseEntity;
 
 import java.util.Iterator;
@@ -46,15 +48,38 @@ public class QueryCriteriaHelper {
      * @param wrapper
      */
     public static <T extends BaseEntity> void toWrapper(QueryWrapper<T> wrapper, QueryCriteria criteria) {
-        if(criteria == null || criteria.getCriteria() == null || criteria.getCriteria().isEmpty(null)) {
+        if(criteria == null) {
             return;
         }
-        Iterator<String> fields = criteria.getCriteria().fieldNames();
+        toWrapper(wrapper, criteria.getCriteria());
+    }
+
+    /**
+     * 转换为查询条件
+     * @param wrapper
+     */
+    public static <T extends BaseEntity> void toWrapper(QueryWrapper<T> wrapper, ObjectNode criteria) {
+        if(criteria == null || criteria.isEmpty(null)) {
+            return;
+        }
+        Iterator<String> fields = criteria.fieldNames();
         // 按字段循环
         while(fields.hasNext()) {
             String field = fields.next();
-            JsonNode fieldValue = criteria.getCriteria().get(field);
-            String dbField = StrUtil.toUnderlineCase(field);
+            JsonNode fieldValue = criteria.get(field);
+            // #JSON#开关的不转驼峰
+            String dbField = StrUtil.startWith(field, "#JSON#")?field.substring(6):StrUtil.toUnderlineCase(field);
+            // 20210813增加ADM传sql特殊处理 - 不公开到接口文档中
+            if("$sql".equalsIgnoreCase(field)) {
+                wrapper.apply((String)JsonNodeUtils.getNodeValue(fieldValue));
+                continue;
+            }
+            // 20210816增加or条件支持
+            if(QueryOperator.OR.getIndex().equalsIgnoreCase(field)) {
+                // 内部重新创建QueryWrapper
+                wrapper.or(orWrapper -> addOrCondition(orWrapper, fieldValue));
+                continue;
+            }
             // 值节点
             if(fieldValue.isValueNode()) {
                 wrapper.eq(dbField, JsonNodeUtils.getNodeValue(fieldValue));
@@ -78,6 +103,35 @@ public class QueryCriteriaHelper {
     }
 
     /**
+     * 添加or条件
+     * @param wrapper
+     * @param node
+     * @param <T>
+     */
+    private static <T extends BaseEntity> void addOrCondition(QueryWrapper<T> wrapper, JsonNode node) {
+        if(node == null || node.isNull()) {
+            return;
+        }
+        // 如果是数组 - 递归继续处理即可
+        if(node.isArray()) {
+            Iterator<JsonNode> elements = node.elements();
+            while (elements.hasNext()) {
+                // 递归继续处理
+                JsonNode objNode = elements.next();
+                addOrCondition(wrapper, objNode);
+            }
+            return;
+        }
+        // 如果是对象,则转换条件
+        if(node.isObject()) {
+            // 对象 递归处理
+            ObjectNode obj = (ObjectNode) node;
+            toWrapper(wrapper, obj);
+            return;
+        }
+    }
+
+    /**
      * 按条件类型添加查询条件
      * @param wrapper
      * @param field
@@ -85,23 +139,29 @@ public class QueryCriteriaHelper {
      * @param valueNode
      */
     private static <T extends BaseEntity> void addCondition(QueryWrapper<T> wrapper, String field, String operator, JsonNode valueNode) {
-        if("$ne".equalsIgnoreCase(operator)) {
+        if(QueryOperator.NE.getIndex().equalsIgnoreCase(operator)) {
             wrapper.ne(field, JsonNodeUtils.getNodeValue(valueNode));
-        } else if("$gt".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.GT.getIndex().equalsIgnoreCase(operator)) {
             wrapper.gt(field, JsonNodeUtils.getNodeValue(valueNode));
-        } else if("$gte".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.GTE.getIndex().equalsIgnoreCase(operator)) {
             wrapper.ge(field, JsonNodeUtils.getNodeValue(valueNode));
-        } else if("$lt".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.LT.getIndex().equalsIgnoreCase(operator)) {
             wrapper.lt(field, JsonNodeUtils.getNodeValue(valueNode));
-        } else if("$lte".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.LTE.getIndex().equalsIgnoreCase(operator)) {
             wrapper.le(field, JsonNodeUtils.getNodeValue(valueNode));
-        } else if("$in".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.IN.getIndex().equalsIgnoreCase(operator)) {
             wrapper.in(field, JsonNodeUtils.getListValue(valueNode));
-        } else if("$like".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.IN_SQL.getIndex().equalsIgnoreCase(operator)) {
+            wrapper.inSql(field, (String) JsonNodeUtils.getNodeValue(valueNode));
+        } else if(QueryOperator.LIKE.getIndex().equalsIgnoreCase(operator)) {
             wrapper.like(field, JsonNodeUtils.getNodeValue(valueNode));
-        } else if("$notLike".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.LIKE_LEFT.getIndex().equalsIgnoreCase(operator)) {
+            wrapper.likeLeft(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if(QueryOperator.LIKE_RIGHT.getIndex().equalsIgnoreCase(operator)) {
+            wrapper.likeRight(field, JsonNodeUtils.getNodeValue(valueNode));
+        } else if(QueryOperator.NOT_LIKE.getIndex().equalsIgnoreCase(operator)) {
             wrapper.notLike(field, JsonNodeUtils.getNodeValue(valueNode));
-        } else if("$null".equalsIgnoreCase(operator)) {
+        } else if(QueryOperator.NULL.getIndex().equalsIgnoreCase(operator)) {
             boolean nullFlag = valueNode.booleanValue();
             if(nullFlag) {
                 wrapper.isNull(field);