Commit bc9115b519c9cd85be3bd54d9da730bfd19778ca

Authored by xp.Huang
1 parent 7d980b63

fix: 场景联动、数据流转、规则链转换脚本加上规则链筛选

Showing 41 changed files with 568 additions and 160 deletions
... ... @@ -64,10 +64,15 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
64 64 import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage;
65 65 import org.thingsboard.server.common.data.rule.RuleChainType;
66 66 import org.thingsboard.server.common.data.script.ScriptLanguage;
  67 +import org.thingsboard.server.common.data.yunteng.core.exception.TkDataValidationException;
  68 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  69 +import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO;
67 70 import org.thingsboard.server.common.msg.TbMsg;
68 71 import org.thingsboard.server.common.msg.TbMsgDataType;
69 72 import org.thingsboard.server.common.msg.TbMsgMetaData;
70 73 import org.thingsboard.server.dao.event.EventService;
  74 +import org.thingsboard.server.dao.yunteng.service.ConvertConfigService;
  75 +import org.thingsboard.server.dao.yunteng.service.TkDeviceProfileService;
71 76 import org.thingsboard.server.queue.util.TbCoreComponent;
72 77 import org.thingsboard.server.service.rule.TbRuleChainService;
73 78 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
... ... @@ -152,6 +157,12 @@ public class RuleChainController extends BaseController {
152 157 @Autowired(required = false)
153 158 private ActorSystemContext actorContext;
154 159
  160 + @Autowired
  161 + private TkDeviceProfileService tkDeviceProfileService;
  162 +
  163 + @Autowired
  164 + private ConvertConfigService convertConfigService;
  165 +
155 166 @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}")
156 167 private boolean debugPerTenantEnabled;
157 168
... ... @@ -325,7 +336,15 @@ public class RuleChainController extends BaseController {
325 336 checkParameter(RULE_CHAIN_ID, strRuleChainId);
326 337 RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
327 338 RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.DELETE);
  339 + //判断规则链是否被产品在使用 thingskit
  340 + String tenantId = getCurrentUser().getCurrentTenantId();
  341 + List<String> deviceProfileNames = tkDeviceProfileService.checkRuleChainIdUsedByDeviceProfiles(tenantId,ruleChainId.getId());
  342 + if(null !=deviceProfileNames && !deviceProfileNames.isEmpty()){
  343 + throw new TkDataValidationException(String.format(ErrorMessage.RULE_CHAIN_USED_BY_DEVICE_PROFILE.getMessage(),deviceProfileNames.get(0)));
  344 + }
328 345 tbRuleChainService.delete(ruleChain, getCurrentUser());
  346 + //删除规则链转换脚本
  347 + convertConfigService.deleteConvertConfigByRuleChainId(tenantId, ruleChainId.getId().toString(),0);
329 348 }
330 349
331 350 @ApiOperation(value = "Get latest input message (getLatestRuleNodeDebugInput)",
... ...
... ... @@ -9,6 +9,8 @@ import io.swagger.annotations.ApiOperation;
9 9 import io.swagger.annotations.ApiParam;
10 10 import java.util.*;
11 11 import java.util.concurrent.ConcurrentMap;
  12 +import java.util.stream.Collectors;
  13 +
12 14 import lombok.RequiredArgsConstructor;
13 15 import org.springframework.beans.factory.annotation.Autowired;
14 16 import org.springframework.beans.factory.annotation.Value;
... ... @@ -20,10 +22,9 @@ import org.thingsboard.common.util.JacksonUtil;
20 22 import org.thingsboard.server.actors.ActorSystemContext;
21 23 import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
22 24 import org.thingsboard.server.common.data.StringUtils;
23   -import org.thingsboard.server.common.data.audit.ActionType;
24 25 import org.thingsboard.server.common.data.exception.ThingsboardException;
  26 +import org.thingsboard.server.common.data.id.RuleChainId;
25 27 import org.thingsboard.server.common.data.id.TenantId;
26   -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
27 28 import org.thingsboard.server.common.data.rule.*;
28 29 import org.thingsboard.server.common.data.yunteng.common.DeleteGroup;
29 30 import org.thingsboard.server.common.data.yunteng.common.UpdateGroup;
... ... @@ -34,12 +35,12 @@ import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO;
34 35 import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertConfigDTO;
35 36 import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertConfigReqDTO;
36 37 import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertReqDTO;
  38 +import org.thingsboard.server.common.data.yunteng.dto.scene.SceneLinkageDTO;
37 39 import org.thingsboard.server.common.data.yunteng.enums.OrderTypeEnum;
38 40 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
39 41 import org.thingsboard.server.controller.BaseController;
40 42 import org.thingsboard.server.dao.yunteng.service.ConvertConfigService;
41 43 import org.thingsboard.server.dao.yunteng.service.SceneLinkageService;
42   -import org.thingsboard.server.dao.yunteng.service.TkRuleChainService;
43 44 import org.thingsboard.server.queue.util.TbCoreComponent;
44 45 import org.thingsboard.server.service.rule.TbRuleChainService;
45 46 import org.thingsboard.server.service.security.permission.Operation;
... ... @@ -51,7 +52,6 @@ import org.thingsboard.server.service.security.permission.Operation;
51 52 @Api(tags = {"数据流转控制器"})
52 53 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
53 54 public class TkConvertDataToController extends BaseController {
54   - private final TkRuleChainService tkRuleChainService;
55 55 private final ConvertConfigService convertConfigService;
56 56 private final SceneLinkageService sceneLinkageService;
57 57
... ... @@ -75,7 +75,8 @@ public class TkConvertDataToController extends BaseController {
75 75 @RequestParam(value = ORDER_FILED, required = false) String orderBy,
76 76 @RequestParam(value = "startTime", required = false) Long startTime,
77 77 @RequestParam(value = "endTime", required = false) Long endTime,
78   - @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType)
  78 + @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType,
  79 + @RequestParam(value = "ruleChainId",required = false) String ruleChainId)
79 80 throws ThingsboardException {
80 81
81 82 HashMap<String, Object> queryMap = new HashMap<>();
... ... @@ -85,6 +86,7 @@ public class TkConvertDataToController extends BaseController {
85 86 queryMap.put("nodeType", nodeType);
86 87 queryMap.put("name", name);
87 88 queryMap.put("status", status);
  89 + queryMap.put("ruleChainId",ruleChainId);
88 90 checkTimeAndPut(queryMap, startTime, endTime);
89 91 if (orderType != null) {
90 92 queryMap.put(ORDER_TYPE, orderType.name());
... ... @@ -156,8 +158,8 @@ public class TkConvertDataToController extends BaseController {
156 158 }
157 159
158 160 @PostMapping("update/config")
159   - @ApiOperation("启用或禁用配置")
160   - public RuleChainMetaData updateConfig(
  161 + @ApiOperation("启用或禁用数据流转")
  162 + public ResponseEntity<Boolean> updateConfig(
161 163 @Validated(UpdateGroup.class) @RequestBody ConvertConfigReqDTO convertConfigReqDTO)
162 164 throws Exception {
163 165 if (convertConfigService.checkConvertConfigStatusExist(
... ... @@ -171,47 +173,53 @@ public class TkConvertDataToController extends BaseController {
171 173 List<RuleNode> nodes =
172 174 convertConfigService.getRuleNodesByConvertConfigIds(
173 175 ids, null, FastIotConstants.CONVERT_DATA);
174   - RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
175 176 if (null != nodes && nodes.size() > 0) {
176   - ruleChainMetaData = saveRuleChain(nodes, status, FastIotConstants.CONVERT_DATA,null);
  177 + classificationSaveRuleChain(nodes,status,FastIotConstants.CONVERT_DATA,null);
177 178 }
178   - convertConfigService.updateConvertStatusByIds(
179   - ids, status, getCurrentUser().getCurrentTenantId());
180   - return ruleChainMetaData;
  179 + return ResponseEntity.ok(convertConfigService.updateConvertStatusByIds(
  180 + ids, status, getCurrentUser().getCurrentTenantId()));
181 181 }
182 182
183 183 @PostMapping("update/js")
184 184 @ApiOperation("启用或禁用转换脚本")
185   - public RuleChainMetaData updateJs(
  185 + public ResponseEntity<Boolean> updateJs(
186 186 @Validated(UpdateGroup.class) @RequestBody ConvertReqDTO convertJSReqDTO)
187 187 throws Exception {
188 188 int status = convertJSReqDTO.getStatus();
  189 + ConvertConfigDTO checkConfig = convertConfigService.findConvertConfigDTOById(getCurrentUser().getCurrentTenantId(),
  190 + convertJSReqDTO.getId());
  191 + if(null == checkConfig){
  192 + throw new TkDataValidationException(ErrorMessage.NOT_BELONG_CURRENT_CUSTOMER.getMessage());
  193 + }
189 194 if (status == FastIotConstants.StateValue.ENABLE
190   - && convertConfigService.checkConvertJSStatusEnable(getCurrentUser().getCurrentTenantId())) {
  195 + && convertConfigService.checkConvertJSStatusEnable(getCurrentUser().getCurrentTenantId(),checkConfig.getRuleChainId())) {
191 196 throw new TkDataValidationException(ErrorMessage.CONVERT_JS_IS_ALONE.getMessage());
192 197 }
193 198 List<String> ids = new ArrayList<>();
194   - ids.add(convertJSReqDTO.getId());
  199 + ids.add(checkConfig.getId());
195 200 List<RuleNode> nodes =
196 201 convertConfigService.getRuleNodesByConvertConfigIds(
197 202 ids, null, FastIotConstants.JAVA_SCRIPT);
198   -
199   - RuleChainMetaData ruleChainMetaData =
200   - saveRuleChain(nodes, status, FastIotConstants.JAVA_SCRIPT,null);
201   - convertConfigService.updateConvertStatusByIds(
202   - ids, status, getCurrentUser().getCurrentTenantId());
203   - return ruleChainMetaData;
  203 + RuleChainId ruleChainId = StringUtils.isEmpty(checkConfig.getRuleChainId())?null:new RuleChainId(UUID.fromString(checkConfig.getRuleChainId()));
  204 + saveRuleChain(ruleChainId,nodes, status, FastIotConstants.JAVA_SCRIPT,null);
  205 + return ResponseEntity.ok(
  206 + convertConfigService.updateConvertStatusByIds(
  207 + ids, status, getCurrentUser().getCurrentTenantId()));
204 208 }
205 209
206 210 @PostMapping("update/scene")
207 211 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
208 212 @ApiOperation("启用或禁用场景联动")
209   - public RuleChainMetaData updateScene(
  213 + public ResponseEntity<Boolean> updateScene(
210 214 @Validated(UpdateGroup.class) @RequestBody ConvertReqDTO convertReqDTO)
211 215 throws Exception {
212   - int status = -1;
213   - String sceneId = convertReqDTO.getId();
214 216 String currentTenant = getCurrentUser().getCurrentTenantId();
  217 + SceneLinkageDTO querySceneLink = sceneLinkageService.selectById(currentTenant, convertReqDTO.getId());
  218 + if(null == querySceneLink){
  219 + throw new TkDataValidationException(ErrorMessage.NOT_BELONG_CURRENT_TENANT.getMessage());
  220 + }
  221 + int status = -1;
  222 + String sceneId = querySceneLink.getId();
215 223 Integer sceneStatus = convertReqDTO.getStatus();
216 224 JsonNode configuration =
217 225 sceneLinkageService.getRuleNodeConfig(
... ... @@ -255,9 +263,10 @@ public class TkConvertDataToController extends BaseController {
255 263 objectNode.remove(otherKey);
256 264 scene.setConfiguration(objectNode);
257 265 }
258   - RuleChainMetaData result = saveRuleChain(ruleNodes, status, FastIotConstants.SCENE_REACT,nodeConnectionName);
  266 + RuleChainId ruleChainId = StringUtils.isEmpty(querySceneLink.getRuleChainId())?null:new RuleChainId(UUID.fromString(querySceneLink.getRuleChainId()));
  267 + saveRuleChain(ruleChainId,ruleNodes, status, FastIotConstants.SCENE_REACT,nodeConnectionName);
259 268 sceneLinkageService.updateSceneStatus(sceneId, sceneStatus, currentTenant);
260   - return result;
  269 + return ResponseEntity.ok(true);
261 270 }
262 271
263 272 /**
... ... @@ -265,33 +274,17 @@ public class TkConvertDataToController extends BaseController {
265 274 *
266 275 * @param nodes 规则节点
267 276 * @param status 0禁用 1启用
  277 + * @param nodeType
  278 + * @param nodeConnectionName
268 279 * @return 规则节点数据
269 280 */
270   - private RuleChainMetaData saveRuleChain(List<RuleNode> nodes, Integer status, Integer nodeType,
  281 + private void saveRuleChain(RuleChainId ruleChainId,List<RuleNode> nodes, Integer status, Integer nodeType,
271 282 String nodeConnectionName)
272 283 throws Exception {
273   - boolean needSaveRuleNode;
274 284 TenantId tenantId = getTenantId();
275   - // 1. GET DEFAULT RULE CHAIN
276   - RuleChain ruleChain = tkRuleChainService.getRootTenantRuleChain(getTenantId());
277   - // 2. GET RULE CHAIN METADATA
278   - RuleChainMetaData ruleChainMetaData =
279   - ruleChainService.loadRuleChainMetaData(getTenantId(), ruleChain.getId());
280   - // 3. SETUP CONNECTION AND ADD OR DELETE RULE NODE
281   - if (status == FastIotConstants.MagicNumber.ZERO) {
282   - needSaveRuleNode =
283   - convertConfigService.deleteRuleNode(
284   - nodes, ruleChainMetaData, nodeType, getCurrentUser().getCurrentTenantId());
285   - } else {
286   - convertConfigService.addRuleNode(
287   - nodes, ruleChainMetaData, nodeType, getCurrentUser().getCurrentTenantId());
288   - //添加节点连接信息
289   - addConnectionInfo(nodeConnectionName,nodeType,ruleChainMetaData);
290   - needSaveRuleNode = true;
291   - }
292   - // 4. SAVE METADATA
293   - RuleChainMetaData savedRuleChainMetaData = null;
294   - if (needSaveRuleNode) {
  285 + RuleChain ruleChain;
  286 + RuleChainMetaData savedRuleChainMetaData = convertConfigService.getTenantRuleChainMetaData(tenantId,ruleChainId,nodes,status,nodeType,nodeConnectionName);
  287 + if (null !=savedRuleChainMetaData && savedRuleChainMetaData.isNeedSaveRuleNode()) {
295 288 if (debugPerTenantEnabled) {
296 289 ConcurrentMap<TenantId, DebugTbRateLimits> debugPerTenantLimits =
297 290 actorContext.getDebugPerTenantLimits();
... ... @@ -300,42 +293,32 @@ public class TkConvertDataToController extends BaseController {
300 293 debugPerTenantLimits.remove(tenantId, debugTbRateLimits);
301 294 }
302 295 }
303   - ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE);
304   - savedRuleChainMetaData = tbRuleChainService.saveRuleChainMetaData(tenantId, ruleChain, ruleChainMetaData, true, getCurrentUser());
  296 + ruleChain = checkRuleChain(savedRuleChainMetaData.getRuleChainId(), Operation.WRITE);
  297 + tbRuleChainService.saveRuleChainMetaData(tenantId, ruleChain, savedRuleChainMetaData, true, getCurrentUser());
305 298 }
306   - return savedRuleChainMetaData;
307 299 }
308 300
309   - private ResponseEntity<Boolean> delete(DeleteDTO deleteDTO, Integer nodeType)
310   - throws Exception {
  301 + private ResponseEntity<Boolean> delete(DeleteDTO deleteDTO, Integer nodeType){
311 302 List<RuleNode> nodes =
312 303 convertConfigService.getRuleNodesByConvertConfigIds(
313 304 new ArrayList<>(deleteDTO.getIds()), FastIotConstants.StateValue.ENABLE, nodeType);
314   - if (nodes != null && nodes.size() > FastIotConstants.MagicNumber.ZERO) {
315   - saveRuleChain(nodes, 0, nodeType,null);
316   - }
  305 + classificationSaveRuleChain(nodes,0,nodeType,null);
317 306 return ResponseEntity.ok(convertConfigService.deleteConvertConfig(deleteDTO, nodeType));
318 307 }
319   - private void addConnectionInfo(String nodeConnectionName,Integer nodeType,RuleChainMetaData ruleChainMetaData){
320   - if(null != nodeConnectionName && nodeType == FastIotConstants.SCENE_REACT){
321   - int i = 0;
322   - //查找事件节点下标
323   - int formIndex = 0;
324   - int toIndex = 0;
325   - for(RuleNode ruleNode : ruleChainMetaData.getNodes()){
326   - if(ruleNode.getType().equals(nodeConnectionName)){
327   - formIndex = i;
328   - }
329   - if(ruleNode.getType().equals(FastIotConstants.TkNodeClassName.GET_ORIGINATOR_FIELDS_NODE)){
330   - toIndex = i;
331   - }
332   - i++;
  308 +
  309 + private void classificationSaveRuleChain(List<RuleNode> nodes,Integer saveStatus,Integer nodeType,String nodeConnectionName){
  310 + if (nodes != null && nodes.size() > FastIotConstants.MagicNumber.ZERO) {
  311 + //将规则节点按规则链分类
  312 + Map<RuleChainId,List<RuleNode>> classification = nodes.stream().collect(Collectors.groupingBy(RuleNode::getRuleChainId));
  313 + if(classification !=null && !classification.isEmpty()){
  314 + classification.keySet().forEach(key->{
  315 + try {
  316 + saveRuleChain(key,nodes, saveStatus, nodeType,nodeConnectionName);
  317 + } catch (Exception e) {
  318 + throw new RuntimeException(e);
  319 + }
  320 + });
333 321 }
334   - NodeConnectionInfo newConnectionInfo = new NodeConnectionInfo();
335   - newConnectionInfo.setFromIndex(formIndex);
336   - newConnectionInfo.setToIndex(toIndex);
337   - newConnectionInfo.setType("SUCCESS");
338   - ruleChainMetaData.getConnections().add(newConnectionInfo);
339 322 }
340 323 }
341 324 }
... ...
... ... @@ -106,16 +106,16 @@ public class TkDeviceProfileController extends BaseController {
106 106 }
107 107
108 108 @GetMapping("/me/list")
109   - @ApiOperation("选项列表")
110   - @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{})")
  109 + @ApiOperation("产品列表")
  110 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
111 111 public ResponseEntity listDeviceProfile(
112 112 @ApiParam(value = "设备类型") @RequestParam(value = "deviceType", required = false)
113   - DeviceTypeEnum deviceType,DeviceTransportType transportType,Boolean isSceneLinkage)
  113 + DeviceTypeEnum deviceType,DeviceTransportType transportType,Boolean isSceneLinkage,String ruleChainId)
114 114 throws ThingsboardException {
115 115 List<DeviceProfileDTO> results;
116 116 TenantId tenantId = getCurrentUser().getTenantId();
117 117 if (getCurrentUser().isTenantAdmin()) {
118   - results = tkDeviceProfileService.findDeviceProfile(tenantId, null,deviceType,transportType,isSceneLinkage);
  118 + results = tkDeviceProfileService.findDeviceProfile(tenantId, null,deviceType,transportType,isSceneLinkage,ruleChainId);
119 119 } else {
120 120 List<TkDeviceProfileEntity> listEntity =
121 121 tkDeviceProfileService.findCustomerDeviceProfiles(
... ...
... ... @@ -94,7 +94,8 @@ public class TkSceneLinkageController extends BaseController {
94 94 @RequestParam(value = "name", required = false) String name,
95 95 @RequestParam(value = "status", required = false) Integer status,
96 96 @RequestParam(value = "organizationId", required = false) String organizationId,
97   - @RequestParam(value = "triggers", required = false) List<TriggerDTO> triggers)
  97 + @RequestParam(value = "triggers", required = false) List<TriggerDTO> triggers,
  98 + @RequestParam(value = "ruleChainId",required = false) String ruleChainId)
98 99 throws ThingsboardException {
99 100 HashMap<String, Object> queryMap = new HashMap<>();
100 101 queryMap.put(PAGE_SIZE, pageSize);
... ... @@ -103,6 +104,7 @@ public class TkSceneLinkageController extends BaseController {
103 104 queryMap.put("status", status);
104 105 queryMap.put("organizationId", organizationId);
105 106 queryMap.put("triggers", triggers);
  107 + queryMap.put("ruleChainId",ruleChainId);
106 108 queryMap.put("currentUser",getCurrentUser().getCurrentUserId());
107 109 //如果是普通租户在最外层默认放入组织id
108 110 if(getCurrentUser().isPtCommonTenant()){
... ...
... ... @@ -238,7 +238,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
238 238 if (TkEdgeProcessorFactory.isTkProcessorExist(type.getEntityType())) {
239 239 TkEdgeProcessorFactory.getTkProcessor(type.getEntityType()).processEntityNotification(tenantId, edgeNotificationMsg);
240 240 } else {
241   - log.error("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type);
  241 + log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type);
242 242 }
243 243 } catch (Exception e) {
244 244 callBackFailure(tenantId, edgeNotificationMsg, callback, e);
... ...
... ... @@ -69,6 +69,9 @@ public class RpcCommandTask {
69 69 if (null != tkTaskCenterDTO) {
70 70 TargetTypeEnum targetType = tkTaskCenterDTO.getTargetType();
71 71 TargetContentDTO targetContent = tkTaskCenterDTO.getExecuteTarget();
  72 + if(null == targetContent){
  73 + return;
  74 + }
72 75 JsonNode cmdJsonNode = tkTaskCenterDTO.getExecuteContent().getPushContent();
73 76 SecurityUser securityUser = new SecurityUser();
74 77 String taskCenterId = tkTaskCenterDTO.getId();
... ...
... ... @@ -45,6 +45,9 @@ public class RuleChainMetaData {
45 45 @ApiModelProperty(position = 5, required = true, value = "List of JSON objects that represent connections between rule nodes and other rule chains.")
46 46 private List<RuleChainConnectionInfo> ruleChainConnections;
47 47
  48 + //thingskit
  49 + private boolean needSaveRuleNode;
  50 +
48 51 public void addConnectionInfo(int fromIndex, int toIndex, String type) {
49 52 NodeConnectionInfo connectionInfo = new NodeConnectionInfo();
50 53 connectionInfo.setFromIndex(fromIndex);
... ...
... ... @@ -43,7 +43,7 @@ public enum ErrorMessage {
43 43 DEVICE_NOT_EXISTENCE_IN_TENANT(400021,"当前租户下不存在该设备"),
44 44 DEVICE_RELATION_IS_ABSENT(400022,"设备关联关系已不存在"),
45 45 DATA_IS_DELETED(400023,"数据已经删除"),
46   - CONVERT_JS_IS_ALONE(400024,"转换脚本只能启用一个"),
  46 + CONVERT_JS_IS_ALONE(400024,"同一个规则链转换脚本只能启用一个"),
47 47 PHONE_OR_EMAIL_HAS_REGISTER(400025,"手机或邮箱已被使用"),
48 48 CONTACT_ALREADY_ASSOCIATED(400026,"当前联系人已与告警配置【%s】关联"),
49 49 MSG_CODE_NOT_MATCHED(400027,"验证码不正确"),
... ... @@ -142,6 +142,10 @@ public enum ErrorMessage {
142 142 CUSTOMER_USER_UPDATE_ERROR(400117,"已分配设备给该客户,请取消分配后重试"),
143 143 SCRIPT_EVAL_FAILED(400118,"租户【%s】启动脚本【%s】失败,失败原因【%s】"),
144 144 SCENE_REACT_IS_EDGE(400119,"场景联动来自于边端请勿操作"),
  145 + RULE_CHAIN_USED_BY_DEVICE_PROFILE(400120,"该规则链正在被【%s】产品使用,不能被删除!!"),
  146 + NODE_NAME_ALREADY_EXISTS(400121,"同类型的节点名称已被使用"),
  147 + CHOICE_DEVICE_PROFILE_RULE_CHAIN_IS_USED_FOR_CONVERT(400122,"选中的产品【%s】正在被数据流转【%s】使用,不能更换规则链!!"),
  148 + CHOICE_DEVICE_PROFILE_RULE_CHAIN_IS_USED_FOR_SCENE(400123,"选中的产品【%s】正在被场景联动【%s】使用,不能更换规则链!!"),
145 149 HAVE_NO_PERMISSION(500002,"没有修改权限"),
146 150 NOT_ALLOED_ISOLATED_IN_MONOLITH(500003,"【monolith】模式下,不能选择【isolated】类型的租户配置");
147 151
... ...
... ... @@ -25,6 +25,12 @@ public class ConvertConfigDTO extends TenantDTO {
25 25 @NotNull(message = "配置参数不能为空或者空字符串")
26 26 private JsonNode configuration;
27 27
  28 + @ApiModelProperty(value = "规则链ID")
  29 + private String ruleChainId;
  30 +
  31 + @ApiModelProperty(value = "规则链名称")
  32 + private String ruleChainName;
  33 +
28 34 @ApiModelProperty(value = "附加信息")
29 35 private JsonNode additionalInfo;
30 36
... ...
... ... @@ -49,6 +49,9 @@ public class DoActionDTO extends TenantDTO {
49 49 @ApiModelProperty(value = "场景联动id")
50 50 private String sceneLinkageId;
51 51
  52 + @ApiModelProperty(value = "场景联动名称")
  53 + private String sceneLinkageName;
  54 +
52 55 @ApiModelProperty(value = "输出目标为告警才进行配置")
53 56 private String alarmProfileId;
54 57 }
... ...
... ... @@ -38,4 +38,7 @@ public class DoConditionDTO extends TenantDTO {
38 38 @ApiModelProperty(value = "场景联动id")
39 39 private String sceneLinkageId;
40 40
  41 + @ApiModelProperty(value = "场景联动名称")
  42 + private String sceneLinkageName;
  43 +
41 44 }
... ...
... ... @@ -44,4 +44,13 @@ public class SceneLinkageDTO extends TenantDTO implements HasName {
44 44
45 45 @ApiModelProperty(value = "创建用户")
46 46 private String creatorName;
  47 +
  48 + @NotEmpty(
  49 + message = "规则链ID不能为空或者空字符串",
  50 + groups = {AddGroup.class})
  51 + @ApiModelProperty(value = "规则链ID", required = true)
  52 + private String ruleChainId;
  53 +
  54 + @ApiModelProperty(value = "规则链名称")
  55 + private String ruleChainName;
47 56 }
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.scene;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.io.Serializable;
  6 +import java.util.List;
  7 +
  8 +@Data
  9 +public class SceneLinkageDeviceProfileDTO implements Serializable {
  10 + private String sceneId;
  11 + private String sceneName;
  12 + private List<String> deviceProfileIds;
  13 +
  14 + public SceneLinkageDeviceProfileDTO(String sceneId, String sceneName, List<String> deviceProfileIds) {
  15 + this.sceneId = sceneId;
  16 + this.sceneName = sceneName;
  17 + this.deviceProfileIds = deviceProfileIds;
  18 + }
  19 +}
... ...
... ... @@ -43,6 +43,9 @@ public class TriggerDTO extends TenantDTO {
43 43 @ApiModelProperty(value = "场景联动id")
44 44 private String sceneLinkageId;
45 45
  46 + @ApiModelProperty(value = "场景联动名称")
  47 + private String sceneLinkageName;
  48 +
46 49 public AlarmRule getTriggerCondition() {
47 50 return JacksonUtil.convertValue(triggerCondition,AlarmRule.class);
48 51 }
... ...
... ... @@ -197,7 +197,7 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
197 197 publishEvictEvent(new TenantEvictEvent(savedTenant.getId(), create));
198 198 eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedTenant.getId()).entityId(savedTenant.getId()).created(create).build());
199 199 if (tenant.getId() == null) {
200   - DeviceProfile deviceProfile = deviceProfileService.createDefaultDeviceProfile(savedTenant.getId());
  200 + deviceProfileService.createDefaultDeviceProfile(savedTenant.getId());
201 201 assetProfileService.createDefaultAssetProfile(savedTenant.getId());
202 202 //Thingskit function
203 203 deviceProfileService.createDeviceProfile(savedTenant.getId(),"默认MQTT网关设备", DeviceTypeEnum.GATEWAY);
... ...
... ... @@ -18,6 +18,7 @@ public class ConvertConfig extends TenantBaseEntity {
18 18 private String name;
19 19 private String type;
20 20
  21 + private String ruleChainId;
21 22 @TableField(typeHandler = EnumTypeHandler.class)
22 23 private DatasourceTypeEnum datasourceType;
23 24
... ...
... ... @@ -21,4 +21,6 @@ public class TkSceneLinkageEntity extends TenantBaseEntity {
21 21 private String description;
22 22
23 23 private String organizationId;
  24 +
  25 + private String ruleChainId;
24 26 }
... ...
... ... @@ -11,6 +11,8 @@ import org.apache.commons.lang3.StringUtils;
11 11 import org.springframework.stereotype.Service;
12 12 import org.springframework.transaction.annotation.Transactional;
13 13 import org.thingsboard.common.util.JacksonUtil;
  14 +import org.thingsboard.server.common.data.id.RuleChainId;
  15 +import org.thingsboard.server.common.data.id.TenantId;
14 16 import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
15 17 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
16 18 import org.thingsboard.server.common.data.rule.RuleNode;
... ... @@ -22,54 +24,36 @@ import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertConfigDTO;
22 24 import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO;
23 25 import org.thingsboard.server.common.data.yunteng.enums.DatasourceTypeEnum;
24 26 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
  27 +import org.thingsboard.server.dao.rule.RuleChainService;
25 28 import org.thingsboard.server.dao.yunteng.ConvertConfig;
26 29 import org.thingsboard.server.dao.yunteng.mapper.ConvertConfigMapper;
27 30 import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
28 31 import org.thingsboard.server.dao.yunteng.service.ConvertConfigService;
29 32
30   -import java.time.LocalDateTime;
31 33 import java.util.*;
32 34 import java.util.concurrent.ConcurrentHashMap;
33 35 import java.util.concurrent.atomic.AtomicInteger;
  36 +import java.util.stream.Collectors;
34 37
35 38 @Slf4j
36 39 @Service
37 40 @RequiredArgsConstructor
38 41 public class TkConvertConfigServiceImpl
39   - extends AbstractBaseService<ConvertConfigMapper, ConvertConfig>
40   - implements ConvertConfigService {
  42 + extends AbstractBaseService<ConvertConfigMapper, ConvertConfig>
  43 + implements ConvertConfigService {
41 44 private final String connectionType = "Success";
42 45 private final String originatorType =
43   - "org.thingsboard.rule.engine.metadata.TbGetOriginatorFieldsNode";
  46 + "org.thingsboard.rule.engine.metadata.TbGetOriginatorFieldsNode";
44 47 private final String sceneOriginatorName = "scene@thingskit";
45 48 private final String scriptType = "org.thingsboard.rule.engine.transform.TbTransformMsgNode";
46 49 private final String filterScriptType = "org.thingsboard.rule.engine.filter.TbJsFilterNode";
47 50 private final String convertNodeName = "dataConvert@thingskit";
  51 + private final RuleChainService ruleChainService;
48 52
49 53 @Override
50 54 public TkPageData<ConvertConfigDTO> page(String tenantId, Map<String, Object> queryMap) {
51   - LocalDateTime startTime = (LocalDateTime) queryMap.get("startTime");
52   - LocalDateTime endTime = (LocalDateTime) queryMap.get("endTime");
53   - IPage<ConvertConfig> iPage =
54   - baseMapper.selectPage(
55   - getPage(queryMap, FastIotConstants.DefaultOrder.CREATE_TIME, false),
56   - new LambdaQueryWrapper<ConvertConfig>()
57   - .eq(ConvertConfig::getTenantId, tenantId)
58   - .eq(
59   - null != queryMap.get("status"),
60   - ConvertConfig::getStatus,
61   - queryMap.get("status"))
62   - .eq(ConvertConfig::getNodeType, queryMap.get("nodeType"))
63   - .and(
64   - null != startTime && null != endTime,
65   - qr ->
66   - qr.ge(ConvertConfig::getCreateTime, startTime)
67   - .le(ConvertConfig::getCreateTime, endTime))
68   - .like(
69   - null != queryMap.get("name"),
70   - ConvertConfig::getName,
71   - String.valueOf(queryMap.get("name")))
72   - );
  55 + IPage<ConvertConfigDTO> iPage = baseMapper.getConvertPage(
  56 + getPage(queryMap, FastIotConstants.DefaultOrder.CREATE_TIME, false),tenantId,queryMap);
73 57 return getPageData(iPage, ConvertConfigDTO.class);
74 58 }
75 59
... ... @@ -77,6 +61,8 @@ public class TkConvertConfigServiceImpl
77 61 @Transactional
78 62 public ConvertConfigDTO createOrUpdate(ConvertConfigDTO convertConfig) {
79 63 ConvertConfig config = convertConfig.getEntity(ConvertConfig.class);
  64 + //设置规则链ID
  65 + config.setRuleChainId(getRuleChainId(convertConfig));
80 66 config.setDatasourceContent(
81 67 JacksonUtil.convertValue(convertConfig.getDatasourceContent(), JsonNode.class));
82 68 if (StringUtils.isNotEmpty(convertConfig.getId())) {
... ... @@ -92,10 +78,9 @@ public class TkConvertConfigServiceImpl
92 78 if (!checkConfig.getName().equals(config.getName())) {
93 79 // Check Name
94 80 boolean result =
95   - checkConvertConfigNameExist(
96   - convertConfig.getId(), config.getName(), config.getType(), config.getTenantId());
  81 + checkConvertConfigNameExist(null, config.getName(), config.getType(), config.getTenantId());
97 82 if (result) {
98   - throw new TkDataValidationException(ErrorMessage.NAME_ALREADY_EXISTS.getMessage());
  83 + throw new TkDataValidationException(ErrorMessage.NODE_NAME_ALREADY_EXISTS.getMessage());
99 84 }
100 85 }
101 86 // 修改不改状态
... ... @@ -107,7 +92,7 @@ public class TkConvertConfigServiceImpl
107 92 checkConvertConfigNameExist(
108 93 null, config.getName(), config.getType(), config.getTenantId());
109 94 if (result) {
110   - throw new TkDataValidationException(ErrorMessage.NAME_ALREADY_EXISTS.getMessage());
  95 + throw new TkDataValidationException(ErrorMessage.NODE_NAME_ALREADY_EXISTS.getMessage());
111 96 }
112 97 // DEFAULT DISABLE
113 98 config.setStatus(FastIotConstants.StateValue.DISABLE);
... ... @@ -143,12 +128,13 @@ public class TkConvertConfigServiceImpl
143 128
144 129 @Override
145 130 public ConvertConfigDTO findConvertConfigDTOByName(
146   - String tenantId, String name, Integer nodeType) {
  131 + String tenantId, String name,String type, Integer nodeType) {
147 132 ConvertConfig convertConfig =
148 133 baseMapper.selectOne(
149 134 new LambdaQueryWrapper<ConvertConfig>()
150 135 .eq(ConvertConfig::getTenantId, tenantId)
151 136 .eq(ConvertConfig::getName, name)
  137 + .eq(ConvertConfig::getType,type)
152 138 .eq(ConvertConfig::getNodeType, nodeType));
153 139 return null != convertConfig ? convertConfig.getDTO(ConvertConfigDTO.class) : null;
154 140 }
... ... @@ -173,7 +159,12 @@ public class TkConvertConfigServiceImpl
173 159 ruleNode.setType(convertConfig.getType());
174 160 ruleNode.setConfiguration(convertConfig.getConfiguration());
175 161 ruleNode.setAdditionalInfo(convertConfig.getAdditionalInfo());
176   -
  162 + if (StringUtils.isNotEmpty(convertConfig.getRuleChainId())) {
  163 + ruleNode.setRuleChainId(
  164 + new RuleChainId(UUID.fromString(convertConfig.getRuleChainId())));
  165 + } else {
  166 + ruleNode.setRuleChainId(ruleChainService.getRootTenantRuleChain(new TenantId(UUID.fromString(convertConfig.getTenantId()))).getId());
  167 + }
177 168 ruleNodes.add(ruleNode);
178 169 });
179 170 return ruleNodes;
... ... @@ -204,15 +195,16 @@ public class TkConvertConfigServiceImpl
204 195 }
205 196
206 197 @Override
207   - public boolean checkConvertJSStatusEnable(String tenantId) {
  198 + public boolean checkConvertJSStatusEnable(String tenantId,String ruleChainId) {
208 199 return baseMapper
209 200 .selectList(
210   - new LambdaQueryWrapper<ConvertConfig>()
211   - .eq(ConvertConfig::getTenantId, tenantId)
212   - .eq(ConvertConfig::getStatus, FastIotConstants.StateValue.ENABLE)
213   - .eq(ConvertConfig::getNodeType, FastIotConstants.JAVA_SCRIPT))
  201 + new LambdaQueryWrapper<ConvertConfig>()
  202 + .eq(ConvertConfig::getTenantId, tenantId)
  203 + .eq(ConvertConfig::getStatus, FastIotConstants.StateValue.ENABLE)
  204 + .eq(ConvertConfig::getNodeType, FastIotConstants.JAVA_SCRIPT)
  205 + .eq(ConvertConfig::getRuleChainId,ruleChainId))
214 206 .size()
215   - > FastIotConstants.MagicNumber.ZERO;
  207 + > FastIotConstants.MagicNumber.ZERO;
216 208 }
217 209 /**
218 210 * 删除规则节点
... ... @@ -254,6 +246,41 @@ public class TkConvertConfigServiceImpl
254 246 }
255 247 }
256 248
  249 + @Override
  250 + public RuleChainMetaData getTenantRuleChainMetaData(TenantId tenantId, RuleChainId ruleChainId,List<RuleNode> nodes,
  251 + int status,int nodeType,String nodeConnectionName) {
  252 + boolean needSaveRuleNode = true;
  253 + RuleChainMetaData ruleChainMetaData =
  254 + ruleChainService.loadRuleChainMetaData(tenantId, ruleChainId);
  255 + if (status == FastIotConstants.MagicNumber.ZERO) {
  256 + needSaveRuleNode = deleteRuleNode(nodes, ruleChainMetaData, nodeType, tenantId.getId().toString());
  257 + } else {
  258 + addRuleNode(nodes, ruleChainMetaData, nodeType, tenantId.getId().toString());
  259 + //添加节点连接信息
  260 + addConnectionInfo(nodeConnectionName,nodeType,ruleChainMetaData);
  261 + }
  262 + ruleChainMetaData.setNeedSaveRuleNode(needSaveRuleNode);
  263 + return ruleChainMetaData;
  264 + }
  265 +
  266 + @Override
  267 + public boolean deleteConvertConfigByRuleChainId(String tenantId, String ruleChainId, Integer nodeType) {
  268 + nodeType = null == nodeType?0:nodeType;
  269 + return baseMapper.delete(new LambdaQueryWrapper<ConvertConfig>().eq(ConvertConfig::getTenantId,tenantId).
  270 + eq(ConvertConfig::getRuleChainId,ruleChainId).eq(ConvertConfig::getNodeType,nodeType)) > FastIotConstants.MagicNumber.ZERO;
  271 + }
  272 +
  273 + @Override
  274 + public List<ConvertConfigDTO> getConvertConfigUsedByRuleChainIds(String tenantId, List<String> ruleChainIds,Integer nodeType) {
  275 + List<ConvertConfig> convertConfigs = baseMapper.selectList(new LambdaQueryWrapper<ConvertConfig>().
  276 + eq(ConvertConfig::getTenantId,tenantId).eq(null != nodeType,ConvertConfig::getNodeType,nodeType)
  277 + .in(ConvertConfig::getRuleChainId,ruleChainIds));
  278 + if(null != convertConfigs && !convertConfigs.isEmpty()){
  279 + return convertConfigs.stream().map(entity->entity.getDTO(ConvertConfigDTO.class)).collect(Collectors.toList());
  280 + }
  281 + return null;
  282 + }
  283 +
257 284 private boolean deleteConvertJS(List<RuleNode> nodes, RuleChainMetaData ruleChainMetaData) {
258 285 boolean needDelete = false;
259 286 // 1. Get firstNodeIndex
... ... @@ -329,7 +356,7 @@ public class TkConvertConfigServiceImpl
329 356 // 判断数据源是产品、设备、全部
330 357 ConvertConfigDTO convertConfigDTO =
331 358 findConvertConfigDTOByName(
332   - tenantId, deleteRuleNode.getName(), FastIotConstants.CONVERT_DATA.intValue());
  359 + tenantId, deleteRuleNode.getName(),deleteRuleNode.getType(), FastIotConstants.CONVERT_DATA.intValue());
333 360 boolean haveFilterNode = false;
334 361 String filterNodeName = null;
335 362 String filterType = null;
... ... @@ -522,7 +549,7 @@ public class TkConvertConfigServiceImpl
522 549 // estimate datasource type
523 550 ConvertConfigDTO convertConfigDTO =
524 551 findConvertConfigDTOByName(
525   - tenantId, ruleNode.getName(), FastIotConstants.CONVERT_DATA.intValue());
  552 + tenantId, ruleNode.getName(),ruleNode.getType(), FastIotConstants.CONVERT_DATA.intValue());
526 553 if (null != convertConfigDTO
527 554 && null != convertConfigDTO.getDatasourceType()
528 555 && !Objects.equals(convertConfigDTO.getDatasourceType(), DatasourceTypeEnum.ALL)) {
... ... @@ -849,4 +876,33 @@ public class TkConvertConfigServiceImpl
849 876 objectNode.put("layoutY", layoutY + randomNum);
850 877 return objectNode;
851 878 }
  879 +
  880 + private String getRuleChainId(ConvertConfigDTO convertConfig){
  881 + //通过nodeType区分是转换脚本(0)、数据流转(1)
  882 + return StringUtils.isNotEmpty(convertConfig.getRuleChainId()) ? convertConfig.getRuleChainId():
  883 + ruleChainService.getRootTenantRuleChain(new TenantId(UUID.fromString(convertConfig.getTenantId()))).getId().toString();
  884 + }
  885 +
  886 + private void addConnectionInfo(String nodeConnectionName,Integer nodeType,RuleChainMetaData ruleChainMetaData){
  887 + if(null != nodeConnectionName && nodeType == FastIotConstants.SCENE_REACT){
  888 + int i = 0;
  889 + //查找事件节点下标
  890 + int formIndex = 0;
  891 + int toIndex = 0;
  892 + for(RuleNode ruleNode : ruleChainMetaData.getNodes()){
  893 + if(ruleNode.getType().equals(nodeConnectionName)){
  894 + formIndex = i;
  895 + }
  896 + if(ruleNode.getType().equals(FastIotConstants.TkNodeClassName.GET_ORIGINATOR_FIELDS_NODE)){
  897 + toIndex = i;
  898 + }
  899 + i++;
  900 + }
  901 + NodeConnectionInfo newConnectionInfo = new NodeConnectionInfo();
  902 + newConnectionInfo.setFromIndex(formIndex);
  903 + newConnectionInfo.setToIndex(toIndex);
  904 + newConnectionInfo.setType("SUCCESS");
  905 + ruleChainMetaData.getConnections().add(newConnectionInfo);
  906 + }
  907 + }
852 908 }
... ...
... ... @@ -15,33 +15,30 @@ import org.thingsboard.server.common.data.device.profile.*;
15 15 import org.thingsboard.server.common.data.id.*;
16 16 import org.thingsboard.server.common.data.rule.RuleChain;
17 17 import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
18   -import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
19 18 import org.thingsboard.server.common.data.yunteng.constant.QueryConstant;
20 19 import org.thingsboard.server.common.data.yunteng.core.exception.TkDataValidationException;
21 20 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
22 21 import org.thingsboard.server.common.data.yunteng.dto.*;
  22 +import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertConfigDTO;
  23 +import org.thingsboard.server.common.data.yunteng.dto.scene.SceneLinkageDeviceProfileDTO;
23 24 import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
24   -import org.thingsboard.server.common.data.yunteng.enums.FunctionTypeEnum;
25 25 import org.thingsboard.server.common.data.yunteng.enums.TcpAuthTypeEnum;
26 26 import org.thingsboard.server.common.data.yunteng.enums.TransportTypeEnum;
27   -import org.thingsboard.server.common.data.yunteng.id.TkThingsModelId;
28 27 import org.thingsboard.server.common.data.yunteng.utils.CopyUtils;
29 28 import org.thingsboard.server.common.data.yunteng.utils.DateTimeUtils;
30 29 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
31 30 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
32 31 import org.thingsboard.server.dao.rule.RuleChainService;
33 32 import org.thingsboard.server.dao.yunteng.entities.*;
34   -import org.thingsboard.server.dao.yunteng.event.TkEdgeSyncService;
35 33 import org.thingsboard.server.dao.yunteng.mapper.DeviceMapper;
36   -import org.thingsboard.server.dao.yunteng.mapper.ThingsModelMapper;
37 34 import org.thingsboard.server.dao.yunteng.mapper.TkDeviceProfileCategoryMapper;
38 35 import org.thingsboard.server.dao.yunteng.mapper.TkDeviceProfileMapper;
39   -import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
40 36 import org.thingsboard.server.dao.yunteng.service.AbstractTbBaseService;
  37 +import org.thingsboard.server.dao.yunteng.service.ConvertConfigService;
  38 +import org.thingsboard.server.dao.yunteng.service.SceneLinkageService;
41 39 import org.thingsboard.server.dao.yunteng.service.TkDeviceProfileService;
42 40
43 41 import java.time.LocalDateTime;
44   -import java.time.ZoneOffset;
45 42 import java.util.*;
46 43 import java.util.stream.Collectors;
47 44
... ... @@ -58,6 +55,10 @@ public class TkDeviceProfileServiceImpl
58 55
59 56 private final RuleChainService ruleChainService;
60 57
  58 + private final ConvertConfigService convertConfigService;
  59 +
  60 + private final SceneLinkageService sceneLinkageService;
  61 +
61 62
62 63
63 64 @Override
... ... @@ -184,6 +185,83 @@ public class TkDeviceProfileServiceImpl
184 185 return tbDeviceProfile;
185 186 }
186 187
  188 + @Override
  189 + public List<String> checkRuleChainIdUsedByDeviceProfiles(String tenantId, UUID ruleChainId) {
  190 + List<TkDeviceProfileEntity> entities=baseMapper.selectList(new LambdaQueryWrapper<TkDeviceProfileEntity>().eq(TkDeviceProfileEntity::getTenantId,
  191 + UUID.fromString(tenantId)).eq(TkDeviceProfileEntity::getDefaultRuleChainId,ruleChainId));
  192 + if(null == entities || entities.isEmpty()){
  193 + return null;
  194 + }
  195 + return entities.stream().map(entity->entity.getName()).collect(Collectors.toList());
  196 + }
  197 +
  198 + @Override
  199 + public void checkDeviceProfilesCanChangeRuleChain(List<String> deviceProfileIds, TenantId tenantId) {
  200 + List<UUID> queryDeviceProfileIds = deviceProfileIds.stream().map(UUID::fromString).collect(Collectors.toList());
  201 + //判断以上产品配置是否都属于该租户
  202 + List<TkDeviceProfileEntity> entities = baseMapper.selectList(new LambdaQueryWrapper<TkDeviceProfileEntity>().
  203 + eq(TkDeviceProfileEntity::getTenantId,tenantId.getId()).in(TkDeviceProfileEntity::getId,queryDeviceProfileIds));
  204 + if(null == entities || entities.size() != deviceProfileIds.size()){
  205 + throw new TkDataValidationException(ErrorMessage.NOT_BELONG_CURRENT_TENANT.getMessage());
  206 + }
  207 + Set<String> ruleChainIds = new HashSet<>(entities.stream().map(entity->entity.getDefaultRuleChainId().toString()).collect(Collectors.toList()));
  208 + //按规则链进行分类,找到具体的产品
  209 + Map<UUID,List<TkDeviceProfileEntity>> classification = entities.stream().collect(Collectors.groupingBy(TkDeviceProfileEntity::getDefaultRuleChainId));
  210 + //判断数据流转是否使用该规则链
  211 + checkDataConvertUsedDeviceProfile(tenantId.getId().toString(),new ArrayList<>(ruleChainIds),classification);
  212 + // 判断选中的产品是否被场景联动使用
  213 + checkSceneLinkageUsedDeviceProfile(
  214 + tenantId.getId().toString(), entities, deviceProfileIds, new ArrayList<>(ruleChainIds));
  215 + }
  216 +
  217 + private void checkDataConvertUsedDeviceProfile(String tenantId,List<String>ruleChainIds,Map<UUID,List<TkDeviceProfileEntity>> classification){
  218 + List<ConvertConfigDTO> convertConfigs = convertConfigService.getConvertConfigUsedByRuleChainIds(tenantId,ruleChainIds,1);
  219 + if(null !=convertConfigs && !convertConfigs.isEmpty()){
  220 + convertConfigs.stream().forEach(convertEntity->{
  221 + //找出这个规则链里面,有哪些产品被数据流转使用了
  222 + JsonNode datasource = convertEntity.getDatasourceContent();
  223 + if(null != datasource){
  224 + JsonNode usedDeviceProfileIds = datasource.get("convertProducts");
  225 + List<String> ids = null;
  226 + if(usedDeviceProfileIds.isArray()){
  227 + Iterator<JsonNode> iteratorNodes = usedDeviceProfileIds.iterator();
  228 + while (iteratorNodes.hasNext()){
  229 + ids.add(iteratorNodes.next().asText());
  230 + }
  231 + }
  232 + if(null != ids){
  233 + classification.entrySet().forEach(key->{
  234 + for (TkDeviceProfileEntity entity : classification.get(key)) {
  235 + if(ids.contains(entity.getId().toString())){
  236 + throw new TkDataValidationException(String.format(ErrorMessage.
  237 + CHOICE_DEVICE_PROFILE_RULE_CHAIN_IS_USED_FOR_CONVERT.getMessage(),entity.getName(),convertEntity.getName()));
  238 + }
  239 + }
  240 + });
  241 +
  242 + }
  243 + }
  244 + });
  245 + }
  246 + }
  247 + private void checkSceneLinkageUsedDeviceProfile(String tenantId,List<TkDeviceProfileEntity> entityList,List<String> choiceDeviceProfileIds,List<String> ruleChainIds){
  248 + //通过选中产品ID列表,判断是否有被场景联动使用
  249 + SceneLinkageDeviceProfileDTO usedSceneLinkage = sceneLinkageService.checkDeviceProfileIdsUsedForSceneLinkage(tenantId,choiceDeviceProfileIds,ruleChainIds);
  250 + if(null != usedSceneLinkage){
  251 + //被场景联动使用了,才进行逻辑处理
  252 + String sceneName = usedSceneLinkage.getSceneName();
  253 + List<String> deviceProfileIds = usedSceneLinkage.getDeviceProfileIds();
  254 + if(null != deviceProfileIds && !deviceProfileIds.isEmpty()){
  255 + entityList.forEach(deviceProfileEntity->{
  256 + if(deviceProfileIds.contains(deviceProfileEntity.getId().toString())){
  257 + throw new TkDataValidationException(String.format(ErrorMessage.
  258 + CHOICE_DEVICE_PROFILE_RULE_CHAIN_IS_USED_FOR_SCENE.getMessage(),
  259 + deviceProfileEntity.getName(),sceneName));
  260 + }
  261 + });
  262 + }
  263 + }
  264 + }
187 265 private void setDeviceScriptId(DeviceProfile profile, DeviceProfileTransportConfiguration transportConfiguration) {
188 266 JsonNode jsonNode = JacksonUtil.convertValue(transportConfiguration, JsonNode.class);
189 267 if (null != jsonNode) {
... ... @@ -266,9 +344,10 @@ public class TkDeviceProfileServiceImpl
266 344
267 345 @Override
268 346 public List<DeviceProfileDTO> findDeviceProfile(
269   - TenantId tenantId, String scriptId, DeviceTypeEnum deviceType, DeviceTransportType transportType,Boolean isSceneLinkage) {
  347 + TenantId tenantId, String scriptId, DeviceTypeEnum deviceType, DeviceTransportType transportType,
  348 + Boolean isSceneLinkage,String ruleChainId) {
270 349 List<TkDeviceProfileEntity> listEntity =
271   - baseMapper.profileByScriptId(tenantId.getId(), scriptId, deviceType, transportType, null,isSceneLinkage);
  350 + baseMapper.profileByScriptId(tenantId.getId(), scriptId, deviceType, transportType, null,isSceneLinkage,ruleChainId);
272 351 return listEntity.stream().map(entity -> {
273 352 return CopyUtils.copyAndReturn(entity, new DeviceProfileDTO());
274 353 }
... ... @@ -291,7 +370,7 @@ public class TkDeviceProfileServiceImpl
291 370 if (null == deviceProfileIds || deviceProfileIds.isEmpty()) {
292 371 return null;
293 372 }
294   - return baseMapper.profileByScriptId(tenantId.getId(), null, deviceType, transportType, deviceProfileIds,false);
  373 + return baseMapper.profileByScriptId(tenantId.getId(), null, deviceType, transportType, deviceProfileIds,false,null);
295 374 }
296 375
297 376 @Override
... ... @@ -299,7 +378,11 @@ public class TkDeviceProfileServiceImpl
299 378 if (tenantId == null || null == ids) {
300 379 throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
301 380 }
302   - return baseMapper.profileByTransportAndIds(tenantId, ids, transportType);
  381 + List<TkDeviceProfileEntity> entities = baseMapper.profileByTransportAndIds(tenantId, ids, transportType);
  382 + if(null == entities || entities.isEmpty()){
  383 + return null;
  384 + }
  385 + return entities.stream().map(entity->entity.getDTO(DeviceProfileDTO.class)).collect(Collectors.toList());
303 386 }
304 387
305 388 @Override
... ...
... ... @@ -42,4 +42,14 @@ public class TkDoActionServiceImpl extends AbstractBaseService<DoActionMapper, T
42 42 .map(doAction -> doAction.getDTO(DoActionDTO.class))
43 43 .collect(Collectors.toList());
44 44 }
  45 +
  46 + @Override
  47 + public List<DoActionDTO> findDoActionsBySceneLinkageIds(String tenantId, List<String> sceneLinkageIds) {
  48 + List<TkDoActionEntity> entities = baseMapper.selectList(new LambdaQueryWrapper<TkDoActionEntity>().eq(TkDoActionEntity::getTenantId,tenantId)
  49 + .in(TkDoActionEntity::getSceneLinkageId,sceneLinkageIds));
  50 + if(null !=entities && !entities.isEmpty()){
  51 + return entities.stream().map(entity->entity.getDTO(DoActionDTO.class)).collect(Collectors.toList());
  52 + }
  53 + return null;
  54 + }
45 55 }
... ...
... ... @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 4 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
5 5 import lombok.RequiredArgsConstructor;
6 6 import org.springframework.stereotype.Service;
  7 +import org.thingsboard.server.common.data.yunteng.dto.scene.DoConditionDTO;
7 8 import org.thingsboard.server.dao.yunteng.entities.TkDoConditionEntity;
8 9 import org.thingsboard.server.dao.yunteng.mapper.DoConditionMapper;
9 10 import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
... ... @@ -20,12 +21,16 @@ import java.util.List;
20 21 @RequiredArgsConstructor
21 22 public class TkDoConditionServiceImpl extends AbstractBaseService<DoConditionMapper, TkDoConditionEntity>
22 23 implements DoConditionService {
23   - private final DoConditionMapper triggerMapper;
  24 + private final DoConditionMapper baseMapper;
24 25 @Override
25 26 public List<TkDoConditionEntity> getConditions(String sceneId) {
26 27 LambdaQueryWrapper filter = new QueryWrapper<TkDoConditionEntity>().lambda()
27 28 .eq(TkDoConditionEntity::getSceneLinkageId,sceneId);
28   - return triggerMapper.selectList(filter);
  29 + return baseMapper.selectList(filter);
29 30 }
30 31
  32 + @Override
  33 + public List<DoConditionDTO> listByDeviceProfileIds(String tenantId, List<String> deviceProfileIds) {
  34 + return baseMapper.listByDeviceProfileIds(tenantId,deviceProfileIds);
  35 + }
31 36 }
... ...
... ... @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.JsonNode;
7 7 import com.fasterxml.jackson.databind.node.ObjectNode;
8 8 import java.util.*;
9 9 import java.util.concurrent.atomic.AtomicBoolean;
  10 +import java.util.concurrent.atomic.AtomicReference;
10 11 import java.util.stream.Collectors;
11 12 import lombok.RequiredArgsConstructor;
12 13 import org.apache.commons.lang3.StringUtils;
... ... @@ -635,7 +636,54 @@ public class TkSceneLinkageServiceImpl
635 636 }
636 637
637 638 @Override
638   - public SceneLinkageDTO selectById( String id) {
639   - return baseMapper.findById(id);
  639 + public SceneLinkageDTO selectById(String tenantId,String id) {
  640 + return baseMapper.findById(tenantId,id);
  641 + }
  642 + @Override
  643 + public SceneLinkageDeviceProfileDTO checkDeviceProfileIdsUsedForSceneLinkage(String tenantId, List<String> deviceProfileIds,List<String> ruleChainIds) {
  644 + //先判断触发器是否被场景联动使用
  645 + List<TriggerDTO> triggers = triggerService.getTriggersByDeviceProfileIds(tenantId,deviceProfileIds);
  646 + if(null != triggers && !triggers.isEmpty()){
  647 + TriggerDTO triggerDTO = triggers.get(0);
  648 + return new SceneLinkageDeviceProfileDTO(triggerDTO.getSceneLinkageId(),triggerDTO.getSceneLinkageName(),List.of(triggerDTO.getDeviceProfileId()));
  649 + }
  650 + //再判断执行条件是否被场景联动使用
  651 + List<DoConditionDTO> doConditions = doConditionService.listByDeviceProfileIds(tenantId,deviceProfileIds);
  652 + if(null != doConditions && !doConditions.isEmpty()){
  653 + DoConditionDTO doCondition = doConditions.get(0);
  654 + return new SceneLinkageDeviceProfileDTO(doCondition.getSceneLinkageId(),doCondition.getSceneLinkageName(),List.of(doCondition.getDeviceProfileId()));
  655 + }
  656 + //最后判断执行动作是否被场景联动使用
  657 + List<TkSceneLinkageEntity>entities = baseMapper.selectList(new LambdaQueryWrapper<TkSceneLinkageEntity>().eq(TkSceneLinkageEntity::getTenantId,tenantId)
  658 + .in(TkSceneLinkageEntity::getRuleChainId,ruleChainIds));
  659 + if(null !=entities && !entities.isEmpty()){
  660 + List<String> sceneLinkageIds = entities.stream().map(entity->entity.getId()).collect(Collectors.toList());
  661 + List<DoActionDTO> doActionList = doActionService.findDoActionsBySceneLinkageIds(tenantId,sceneLinkageIds);
  662 + if(null !=doActionList && !doActionList.isEmpty()){
  663 + for (DoActionDTO entity :doActionList){
  664 + if(entity.getOutTarget().equals(ActionTypeEnum.DEVICE_OUT)){
  665 + if(deviceProfileIds.contains(entity.getDeviceProfileId())){
  666 + return new SceneLinkageDeviceProfileDTO(entity.getSceneLinkageId(), entity.getSceneLinkageName(), List.of(entity.getDeviceProfileId()));
  667 + }
  668 + }
  669 + if(entity.getOutTarget().equals(ActionTypeEnum.MSG_NOTIFY)){
  670 + JsonNode doContext = entity.getDoContext();
  671 + if(null !=doContext){
  672 + JsonNode clearRuleJsonNode = doContext.get("clearRule");
  673 + if(null !=clearRuleJsonNode && clearRuleJsonNode.isArray()){
  674 + Iterator<JsonNode> iteratorNodes = clearRuleJsonNode.iterator();
  675 + while (iteratorNodes.hasNext()){
  676 + String deviceProfileId = iteratorNodes.next().get("deviceProfileId").asText();
  677 + if(deviceProfileIds.contains(deviceProfileId)){
  678 + return new SceneLinkageDeviceProfileDTO(entity.getSceneLinkageId(), entity.getSceneLinkageName(), List.of(deviceProfileId));
  679 + }
  680 + }
  681 + }
  682 + }
  683 + }
  684 + }
  685 + }
  686 + }
  687 + return null;
640 688 }
641 689 }
... ...
... ... @@ -39,4 +39,9 @@ public class TkTriggerServiceImpl extends AbstractBaseService<TriggerMapper, TkT
39 39 .map(item -> item.getDTO(TriggerDTO.class))
40 40 .collect(Collectors.toList());
41 41 }
  42 +
  43 + @Override
  44 + public List<TriggerDTO> getTriggersByDeviceProfileIds(String tenantId, List<String> deviceProfileIds) {
  45 + return triggerMapper.listByDeviceProfileIds(tenantId,deviceProfileIds);
  46 + }
42 47 }
... ...
1 1 package org.thingsboard.server.dao.yunteng.mapper;
2 2
3 3 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
4 5 import org.apache.ibatis.annotations.Mapper;
5 6 import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertConfigDTO;
6 8 import org.thingsboard.server.dao.yunteng.ConvertConfig;
7 9
8 10 import java.util.List;
  11 +import java.util.Map;
9 12
10 13 @Mapper
11 14 public interface ConvertConfigMapper extends BaseMapper<ConvertConfig> {
  15 + IPage<ConvertConfigDTO> getConvertPage(
  16 + IPage<?> page,@Param("tenantId") String tenantId, @Param("queryMap") Map<String, Object> queryMap);
12 17 boolean updateConvertStatusByIds(
13 18 @Param("tenantId") String tenantId, @Param("ids") List<String> ids, @Param("status") Integer status);
14 19 }
... ...
... ... @@ -16,4 +16,6 @@ import java.util.List;
16 16 @Mapper
17 17 public interface DoActionMapper extends BaseMapper<TkDoActionEntity> {
18 18 List<DoActionDTO> listBySceneId(@Param("sceneId") String sceneId);
  19 +
  20 + List<DoActionDTO> listBySceneLinkageIds(@Param("tenantId") String tenantId,@Param("sceneLinkageIds") List<String> sceneLinkageIds);
19 21 }
... ...
... ... @@ -16,4 +16,6 @@ import java.util.List;
16 16 @Mapper
17 17 public interface DoConditionMapper extends BaseMapper<TkDoConditionEntity> {
18 18 List<DoConditionDTO> listBySceneId(@Param("sceneId") String sceneId);
  19 +
  20 + List<DoConditionDTO> listByDeviceProfileIds(@Param("tenantId")String tenantId,@Param("deviceProfileIds")List<String> deviceProfileIds);
19 21 }
... ...
... ... @@ -30,6 +30,6 @@ public interface SceneLinkageMapper extends BaseMapper<TkSceneLinkageEntity> {
30 30 * @param id
31 31 * @return
32 32 */
33   - SceneLinkageDTO findById( @Param("id") String id);
  33 + SceneLinkageDTO findById(@Param("tenantId") String tenantId, @Param("id") String id);
34 34
35 35 }
... ...
... ... @@ -5,9 +5,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
5 5 import org.apache.ibatis.annotations.Mapper;
6 6 import org.apache.ibatis.annotations.Param;
7 7 import org.thingsboard.server.common.data.DeviceTransportType;
8   -import org.thingsboard.server.common.data.id.DeviceProfileId;
9   -import org.thingsboard.server.common.data.id.TenantId;
10   -import org.thingsboard.server.common.data.yunteng.dto.*;
11 8 import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
12 9 import org.thingsboard.server.common.data.yunteng.enums.TransportTypeEnum;
13 10 import org.thingsboard.server.dao.yunteng.entities.TkDeviceProfileEntity;
... ... @@ -39,9 +36,10 @@ public interface TkDeviceProfileMapper extends BaseMapper<TkDeviceProfileEntity>
39 36 @Param("deviceType") DeviceTypeEnum deviceType,
40 37 @Param("transportType")DeviceTransportType transportType,
41 38 @Param("deviceProfileIds")List<UUID> deviceProfileIds,
42   - @Param("isSceneLinkage") Boolean isSceneLinkage);
  39 + @Param("isSceneLinkage") Boolean isSceneLinkage,
  40 + @Param("ruleChainId") String ruleChainId);
43 41
44   - List<DeviceProfileDTO> profileByTransportAndIds(
  42 + List<TkDeviceProfileEntity> profileByTransportAndIds(
45 43 @Param("tenantId") UUID tenantId,
46 44 @Param("projectIds") List<String> projectIds,
47 45 @Param("deviceType") TransportTypeEnum transportType);
... ...
... ... @@ -17,4 +17,6 @@ import java.util.List;
17 17 public interface TriggerMapper extends BaseMapper<TkTriggerEntity> {
18 18
19 19 List<TriggerDTO> listBySceneId(@Param("sceneId") String sceneId);
  20 +
  21 + List<TriggerDTO> listByDeviceProfileIds(@Param("tenantId")String tenantId,@Param("deviceProfileIds")List<String> deviceProfileIds);
20 22 }
... ...
1 1 package org.thingsboard.server.dao.yunteng.service;
2 2
  3 +import org.thingsboard.server.common.data.id.RuleChainId;
  4 +import org.thingsboard.server.common.data.id.TenantId;
3 5 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
4 6 import org.thingsboard.server.common.data.rule.RuleNode;
5 7 import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertConfigDTO;
... ... @@ -21,7 +23,7 @@ public interface ConvertConfigService extends BaseService<ConvertConfig> {
21 23
22 24 boolean deleteConvertConfig(DeleteDTO deleteDTO, Integer nodeType);
23 25
24   - ConvertConfigDTO findConvertConfigDTOByName(String tenantId,String name,Integer nodeType);
  26 + ConvertConfigDTO findConvertConfigDTOByName(String tenantId,String name,String type,Integer nodeType);
25 27 /**
26 28 * 通过数据转换的IDS获取需要组装的节点
27 29 *
... ... @@ -57,12 +59,35 @@ public interface ConvertConfigService extends BaseService<ConvertConfig> {
57 59 * 检查该租户下是否已启用转换脚本状态
58 60 *
59 61 * @param tenantId 租户ID
  62 + * @param ruleChainId 规则链ID
60 63 * @return true已启用 false未启用
61 64 */
62   - boolean checkConvertJSStatusEnable(String tenantId);
  65 + boolean checkConvertJSStatusEnable(String tenantId,String ruleChainId);
63 66
64 67 boolean deleteRuleNode(
65 68 List<RuleNode> nodes, RuleChainMetaData ruleChainMetaData, Integer nodeType,String tenantId);
66 69
67 70 void addRuleNode(List<RuleNode> nodes, RuleChainMetaData ruleChainMetaData, Integer nodeType,String tenantId);
  71 +
  72 + RuleChainMetaData getTenantRuleChainMetaData(TenantId tenantId, RuleChainId ruleChainId, List<RuleNode> nodes,
  73 + int status, int nodeType, String nodeConnectionName);
  74 +
  75 + /**
  76 + * 根据规则链ID删除对应的转换脚本
  77 + * @param tenantId
  78 + * @param ruleChainId
  79 + * @param nodeType
  80 + * @return
  81 + */
  82 + boolean deleteConvertConfigByRuleChainId(String tenantId,String ruleChainId,Integer nodeType);
  83 +
  84 +
  85 + /**
  86 + * 检查数据流转或规则链转换脚本使用了以下规则链
  87 + * @param tenantId 租户ID
  88 + * @param ruleChainIds 规则链ID列表
  89 + * @param nodeType 0 转换脚本 1数据流转
  90 + * @return 返回使用以下规则链的数据流转或规则链转换脚本信息
  91 + */
  92 + List<ConvertConfigDTO> getConvertConfigUsedByRuleChainIds(String tenantId,List<String> ruleChainIds,Integer nodeType);
68 93 }
... ...
... ... @@ -16,4 +16,6 @@ public interface DoActionService extends BaseService<TkDoActionEntity>{
16 16 List<TkDoActionEntity> getActionsByAll(String sceneId,String tenantId);
17 17
18 18 List<DoActionDTO> findDoActionByAlarmProfileIds(String tenantId, Set<String> alarmProfileIds);
  19 +
  20 + List<DoActionDTO> findDoActionsBySceneLinkageIds(String tenantId,List<String> sceneLinkageIds);
19 21 }
... ...
1 1 package org.thingsboard.server.dao.yunteng.service;
2 2
  3 +import org.thingsboard.server.common.data.yunteng.dto.scene.DoConditionDTO;
3 4 import org.thingsboard.server.dao.yunteng.entities.TkDoConditionEntity;
4 5
5 6 import java.util.List;
... ... @@ -11,4 +12,6 @@ import java.util.List;
11 12 */
12 13 public interface DoConditionService extends BaseService<TkDoConditionEntity>{
13 14 List<TkDoConditionEntity> getConditions(String sceneId);
  15 +
  16 + List<DoConditionDTO> listByDeviceProfileIds(String tenantId,List<String> deviceProfileIds);
14 17 }
... ...
... ... @@ -2,6 +2,7 @@ package org.thingsboard.server.dao.yunteng.service;
2 2 import com.fasterxml.jackson.databind.JsonNode;
3 3 import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
4 4 import org.thingsboard.server.common.data.yunteng.dto.scene.SceneLinkageDTO;
  5 +import org.thingsboard.server.common.data.yunteng.dto.scene.SceneLinkageDeviceProfileDTO;
5 6 import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
6 7 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
7 8 import org.thingsboard.server.dao.yunteng.entities.TkSceneLinkageEntity;
... ... @@ -92,6 +93,14 @@ public interface SceneLinkageService extends BaseService<TkSceneLinkageEntity>{
92 93 * 详情
93 94 * @return
94 95 */
95   - SceneLinkageDTO selectById(String id);
  96 + SceneLinkageDTO selectById(String tenantId,String id);
96 97
  98 + /**
  99 + * 判断哪些产品被产品联动使用了,并返回被使用的产品ID列表
  100 + * @param tenantId 租户ID
  101 + * @param deviceProfileIds 检查的场景联动
  102 + * @param ruleChainIds 规则链ID列表
  103 + * @return
  104 + */
  105 + SceneLinkageDeviceProfileDTO checkDeviceProfileIdsUsedForSceneLinkage(String tenantId, List<String> deviceProfileIds,List<String> ruleChainIds);
97 106 }
... ...
... ... @@ -23,8 +23,8 @@ public interface TkDeviceProfileService extends TbBaseService<TkDeviceProfileEnt
23 23
24 24 TkPageData<DeviceProfileDTO> page(Map<String, Object> queryMap, boolean isTenantAdmin);
25 25
26   - List<DeviceProfileDTO> findDeviceProfile(
27   - TenantId tenantId, String scriptId, DeviceTypeEnum deviceType, DeviceTransportType transportType,Boolean isSceneLinkage);
  26 + List<DeviceProfileDTO> findDeviceProfile(TenantId tenantId, String scriptId, DeviceTypeEnum deviceType,
  27 + DeviceTransportType transportType,Boolean isSceneLinkage,String ruleChainId);
28 28
29 29 List<TkDeviceProfileEntity> findCustomerDeviceProfiles(
30 30 TenantId tenantId, CustomerId customerId, DeviceTypeEnum deviceType,DeviceTransportType transportType);
... ... @@ -64,4 +64,19 @@ public interface TkDeviceProfileService extends TbBaseService<TkDeviceProfileEnt
64 64
65 65 DeviceProfile buildTbDeviceProfileFromDeviceProfileDTO(DeviceProfileDTO deviceProfileDTO, User user);
66 66
  67 + /**
  68 + * 判断规则链ID被哪些产品使用了
  69 + * @param tenantId 租户ID
  70 + * @param ruleChainId 规则链ID
  71 + * @return 产品名称列表
  72 + */
  73 + List<String> checkRuleChainIdUsedByDeviceProfiles(String tenantId,UUID ruleChainId);
  74 +
  75 + /**
  76 + * 检查产品(设备配置)是否允许修改规则链
  77 + * @param deviceProfileIds 设备配置ID列表
  78 + * @param tenantId 租户ID
  79 + */
  80 + void checkDeviceProfilesCanChangeRuleChain(List<String> deviceProfileIds,TenantId tenantId);
  81 +
67 82 }
... ...
... ... @@ -12,4 +12,6 @@ import java.util.List;
12 12 */
13 13 public interface TriggerService extends BaseService<TkTriggerEntity>{
14 14 List<TriggerDTO> getTrigger(String sceneId);
  15 +
  16 + List<TriggerDTO> getTriggersByDeviceProfileIds(String tenantId, List<String> deviceProfileIds);
15 17 }
... ...
... ... @@ -9,6 +9,11 @@
9 9 <result property="configuration" column="configuration"
10 10 typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
11 11 <result property="tenantId" column="tenant_id"/>
  12 + <result property="ruleChainId" column="rule_chain_id"/>
  13 + <result property="ruleChainName" column="rule_chain_name"/>
  14 + <result property="datasourceType" column="datasource_type" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
  15 + <result property="datasourceContent" column="datasource_content"
  16 + typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
12 17 <result property="status" column="status"/>
13 18 <result property="nodeType" column="node_type"/>
14 19 <result property="createTime" column="create_time"/>
... ... @@ -17,6 +22,10 @@
17 22 <result property="updater" column="updater"/>
18 23 <result property="remark" column="remark"/>
19 24 </resultMap>
  25 + <sql id="columns">
  26 + tcc.id,tcc.name,tcc.type,tcc.configuration,tcc.tenant_id,tcc.rule_chain_id,tcc.status,tcc.node_type,
  27 + tcc.datasource_type,tcc.datasource_content,tcc.create_time,tcc.update_time,tcc.creator,tcc.updater,tcc.remark
  28 + </sql>
20 29 <update id="updateConvertStatusByIds">
21 30 UPDATE tk_convert_config
22 31 SET status =#{status}
... ... @@ -30,4 +39,27 @@
30 39 </if>
31 40 </where>
32 41 </update>
  42 + <select id="getConvertPage" resultMap="convertMap">
  43 + SELECT
  44 + <include refid="columns"/>,rc.name as rule_chain_name
  45 + FROM tk_convert_config tcc LEFT JOIN rule_chain rc ON tcc.rule_chain_id = rc.id ::TEXT
  46 + <where>
  47 + tcc.tenant_id = #{tenantId}
  48 + <if test="queryMap.name != null and queryMap.name != ''">
  49 + AND tcc.name LIKE concat('%',#{queryMap.name}::TEXT,'%')
  50 + </if>
  51 + <if test="queryMap.status != null">
  52 + AND tcc.status = #{queryMap.status}
  53 + </if>
  54 + <if test="queryMap.nodeType != null">
  55 + AND tcc.node_type = #{queryMap.nodeType}
  56 + </if>
  57 + <if test="queryMap.startTime != null and queryMap.endTime != null">
  58 + AND tcc.create_time &gt;= #{queryMap.startTime} AND tcc.create_time &lt; #{queryMap.endTime}
  59 + </if>
  60 + <if test="queryMap.ruleChainId != null and queryMap.ruleChainId != ''">
  61 + AND tcc.rule_chain_id = #{queryMap.ruleChainId}
  62 + </if>
  63 + </where>
  64 + </select>
33 65 </mapper>
... ...
... ... @@ -15,6 +15,7 @@
15 15 <result property="commandType" column="command_type"/>
16 16 <result property="thingsModelId" column="things_model_id"/>
17 17 <result property="sceneLinkageId" column="scene_linkage_id"/>
  18 + <result property="sceneLinkageName" column="scene_linkage_name"/>
18 19 <result property="deviceProfileId" column="device_profile_id"/>
19 20 <result property="alarmProfileId" column="alarm_profile_id"/>
20 21 <result property="tenantId" column="tenant_id"/>
... ... @@ -24,12 +25,21 @@
24 25 <result property="creator" column="creator"/>
25 26 </resultMap>
26 27 <sql id="columns">
27   - id,device_id,entity_type,device_type,do_context,out_target,call_type,scene_linkage_id,alarm_profile_id,
28   - tenant_id,updater,update_time,create_time,creator,command_type,things_model_id,device_profile_id
  28 + tda.id,tda.device_id,tda.entity_type,tda.device_type,tda.do_context,tda.out_target,tda.call_type,tda.scene_linkage_id,tda.alarm_profile_id,
  29 + tda.tenant_id,tda.updater,tda.update_time,tda.create_time,tda.creator,tda.command_type,tda.things_model_id,tda.device_profile_id
29 30 </sql>
30 31 <select id="listBySceneId" resultMap="actionDTO">
31 32 SELECT
32 33 <include refid="columns"/>
33   - FROM tk_do_action WHERE scene_linkage_id = #{sceneId}
  34 + FROM tk_do_action tda WHERE tda.scene_linkage_id = #{sceneId}
  35 + </select>
  36 + <select id="listBySceneLinkageIds" resultMap="actionDTO">
  37 + SELECT
  38 + <include refid="columns"/>,tsl.name as scene_linkage_name
  39 + FROM tk_do_action tda LEFT JOIN tk_scene_linkage tsl ON tsl.id = tda.scene_linkage_id
  40 + WHERE tda.tenant_id = #{tenantId} AND tda.scene_linkage_id IN
  41 + <foreach collection="sceneLinkageIds" item="sceneLinkageId" open="(" separator="," close=")">
  42 + #{sceneLinkageId}
  43 + </foreach>
34 44 </select>
35 45 </mapper>
... ...
... ... @@ -12,6 +12,7 @@
12 12 typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
13 13 <result property="triggerType" column="trigger_type" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
14 14 <result property="sceneLinkageId" column="scene_linkage_id"/>
  15 + <result property="sceneLinkageName" column="scene_linkage_name"/>
15 16 <result property="tenantId" column="tenant_id"/>
16 17 <result property="updater" column="updater"/>
17 18 <result property="deviceProfileId" column="device_profile_id"/>
... ... @@ -21,13 +22,24 @@
21 22 </resultMap>
22 23
23 24 <sql id="columns">
24   - id,entity_id,entity_type,device_type,trigger_condition,trigger_type,scene_linkage_id,tenant_id
25   - ,creator,updater,create_time,update_time,device_profile_id
  25 + tdc.id,tdc.entity_id,tdc.entity_type,tdc.device_type,tdc.trigger_condition,tdc.trigger_type,tdc.scene_linkage_id,tdc.tenant_id
  26 + ,tdc.creator,tdc.updater,tdc.create_time,tdc.update_time,tdc.device_profile_id
26 27 </sql>
27 28
28 29 <select id="listBySceneId" resultMap="conditionDTO">
29 30 SELECT
30 31 <include refid="columns"/>
31   - FROM tk_do_condition WHERE scene_linkage_id = #{sceneId}
  32 + FROM tk_do_condition tdc WHERE tdc.scene_linkage_id = #{sceneId}
  33 + </select>
  34 +
  35 + <select id="listByDeviceProfileIds" resultMap="conditionDTO">
  36 + SELECT
  37 + <include refid="columns"/>,tsl.name as scene_linkage_name
  38 + FROM tk_do_condition tdc
  39 + LEFT JOIN tk_scene_linkage tsl ON tdc.scene_linkage_id = tsl.id
  40 + WHERE tdc.tenant_id = #{tenantId} AND tdc.device_profile_id IN
  41 + <foreach collection="deviceProfileIds" item="deviceProfileId" open="(" separator="," close=")">
  42 + #{deviceProfileId}
  43 + </foreach>
32 44 </select>
33 45 </mapper>
... ...
... ... @@ -6,6 +6,8 @@
6 6 <result property="id" column="id"/>
7 7 <result property="name" column="name"/>
8 8 <result property="organizationId" column="organization_id"/>
  9 + <result property="ruleChainId" column="rule_chain_id"/>
  10 + <result property="ruleChainName" column="rule_chain_name"/>
9 11 <result property="status" column="status"/>
10 12 <result property="description" column="description"/>
11 13 <result property="tenantId" column="tenant_id"/>
... ... @@ -20,14 +22,15 @@
20 22
21 23 </resultMap>
22 24 <sql id="columns">
23   - s.id,s.name,s.organization_id,s.status,s.description,s.tenant_id,s.updater,s.update_time,s.create_time,s.creator
  25 + s.id,s.name,s.organization_id,s.rule_chain_id,s.status,s.description,s.tenant_id,s.updater,s.update_time,s.create_time,s.creator
24 26 </sql>
25 27 <select id="getScenePage" resultMap="sceneLinkageMap">
26 28 SELECT
27   - <include refid="columns"/>,su.real_name creator_name
  29 + <include refid="columns"/>,su.real_name creator_name,rc.name as rule_chain_name
28 30 FROM tk_scene_linkage s
29 31 LEFT JOIN sys_user su ON su.id = s.creator
30 32 LEFT JOIN tk_organization io ON io.id = s.organization_id
  33 + LEFT JOIN rule_chain rc ON rc.id::TEXT = s.rule_chain_id
31 34 <where>
32 35 <if test="queryMap.tenantId !=null and queryMap.tenantId !=''">
33 36 AND s.tenant_id = #{queryMap.tenantId}
... ... @@ -44,6 +47,9 @@
44 47 #{organizationId}
45 48 </foreach>
46 49 </if>
  50 + <if test="queryMap.ruleChainId != null and queryMap.ruleChainId != ''">
  51 + AND s.rule_chain_id = #{queryMap.ruleChainId}
  52 + </if>
47 53 <if test="queryMap.currentUser !=null">
48 54 AND s.creator = #{queryMap.currentUser}
49 55 </if>
... ... @@ -58,6 +64,7 @@
58 64 LEFT JOIN sys_user su ON su.id = s.creator
59 65 LEFT JOIN tk_organization io ON io.id = s.organization_id
60 66 <where>
  67 + s.tenant_id = #{tenantId}
61 68 <if test="id !=null">
62 69 AND s.id = #{id}
63 70 </if>
... ...
... ... @@ -107,6 +107,9 @@
107 107 <if test="scriptId !=null and scriptId !=''">
108 108 AND base.script_id = #{scriptId}
109 109 </if>
  110 + <if test="ruleChainId !=null and ruleChainId !=''">
  111 + AND base.default_rule_chain_id::TEXT = #{ruleChainId}
  112 + </if>
110 113 <if test="deviceType !=null">
111 114 AND base.device_type = #{deviceType}
112 115 </if>
... ...
... ... @@ -13,6 +13,7 @@
13 13 typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
14 14 <result property="triggerType" column="trigger_type" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
15 15 <result property="sceneLinkageId" column="scene_linkage_id"/>
  16 + <result property="sceneLinkageName" column="scene_linkage_name"/>
16 17 <result property="tenantId" column="tenant_id"/>
17 18 <result property="updater" column="updater"/>
18 19 <result property="updateTime" column="update_time"/>
... ... @@ -21,13 +22,24 @@
21 22 </resultMap>
22 23
23 24 <sql id="columns">
24   - id,entity_id,entity_type,device_type,trigger_condition,trigger_type,scene_linkage_id,tenant_id,creator
25   - ,updater,create_time,update_time,device_profile_id
  25 + tt.id,tt.entity_id,tt.entity_type,tt.device_type,tt.trigger_condition,tt.trigger_type,tt.scene_linkage_id,tt.tenant_id,tt.creator
  26 + ,tt.updater,tt.create_time,tt.update_time,tt.device_profile_id
26 27 </sql>
27 28
28 29 <select id="listBySceneId" resultMap="triggerDTO">
29 30 SELECT
30 31 <include refid="columns"/>
31   - FROM tk_trigger WHERE scene_linkage_id = #{sceneId}
  32 + FROM tk_trigger tt WHERE tt.scene_linkage_id = #{sceneId}
  33 + </select>
  34 +
  35 + <select id="listByDeviceProfileIds" resultMap="triggerDTO">
  36 + SELECT
  37 + <include refid="columns"/>,tsl.name as scene_linkage_name
  38 + FROM tk_trigger tt
  39 + LEFT JOIN tk_scene_linkage tsl ON tt.scene_linkage_id = tsl.id
  40 + WHERE tt.tenant_id = #{tenantId} AND tt.device_profile_id IN
  41 + <foreach collection="deviceProfileIds" item="deviceProfileId" open="(" separator="," close=")">
  42 + #{deviceProfileId}
  43 + </foreach>
32 44 </select>
33 45 </mapper>
... ...