demand: 新增规则增加循环校验,增加校验组树接口
committer: heyu
This commit is contained in:
parent
2d7f021860
commit
2d5da6200d
@ -128,9 +128,23 @@ public class EmisTransPlanRuleController extends EmisBaseController {
|
|||||||
/**
|
/**
|
||||||
* 查询供应商线路规划树结构
|
* 查询供应商线路规划树结构
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('emis:emisTransPlanRule:tree')")
|
// @PreAuthorize("@ss.hasPermi('emis:emisTransPlanRule:tree')")
|
||||||
@GetMapping("/tree")
|
@GetMapping("/tree")
|
||||||
public TableDataInfo tree(EmisTransPlanRule emisTransPlanRule) {
|
public TableDataInfo tree(EmisTransPlanRule emisTransPlanRule) {
|
||||||
return getDataTable(emisTransPlanRuleService.selectEmisTransPlanRuleTree(emisTransPlanRule));
|
return getDataTable(emisTransPlanRuleService.selectEmisTransPlanRuleTree(emisTransPlanRule));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验规则是否能组树
|
||||||
|
*/
|
||||||
|
// @PreAuthorize("@ss.hasPermi('emis:emisTransPlanRule:tree')")
|
||||||
|
@GetMapping("/checkTree")
|
||||||
|
public TableDataInfo checkTree(EmisTransPlanRule emisTransPlanRule) {
|
||||||
|
List<String> cycles = emisTransPlanRuleService.checkTree(emisTransPlanRule);
|
||||||
|
if (cycles == null || cycles.isEmpty()) {
|
||||||
|
cycles = new java.util.ArrayList<>();
|
||||||
|
cycles.add("未检测到循环引用");
|
||||||
|
}
|
||||||
|
return getDataTable(cycles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -173,4 +173,11 @@ public interface EmisTransPlanRuleMapper {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<EmisTransPlanRule> checkTransPlanRule(EmisTransPlanRule emisTransPlanRule);
|
List<EmisTransPlanRule> checkTransPlanRule(EmisTransPlanRule emisTransPlanRule);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param emisTransPlanRule
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<EmisTransPlanRule> selectEmisTransPlanRuleListWithoutName(EmisTransPlanRule emisTransPlanRule);
|
||||||
}
|
}
|
||||||
@ -4211,11 +4211,19 @@ public class EmisBaseService {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
errorMsg.append(" -> ");
|
errorMsg.append(" -> ");
|
||||||
}
|
}
|
||||||
errorMsg.append("节点ID:").append(cyclePath.get(i));
|
Long id = cyclePath.get(i);
|
||||||
|
EmisTransPlanRule node = findNodeById(id);
|
||||||
|
if (node != null) {
|
||||||
|
errorMsg.append(node.getLineName()).append("-")
|
||||||
|
.append(node.getProductTypeName()).append("-")
|
||||||
|
.append(node.getStartSiteName()).append("-")
|
||||||
|
.append(node.getNextSiteName()).append("-")
|
||||||
|
.append(node.getSupplierName());
|
||||||
|
} else {
|
||||||
|
errorMsg.append("节点ID:").append(id);
|
||||||
}
|
}
|
||||||
errorMsg.append("\n循环引用发生在节点ID:").append(source.getId());
|
}
|
||||||
errorMsg.append(",该节点在路径中重复出现");
|
errorMsg.append("\n循环引用发生在节点,详细信息见上");
|
||||||
|
|
||||||
throw new RuntimeException(errorMsg.toString());
|
throw new RuntimeException(errorMsg.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4245,6 +4253,18 @@ public class EmisBaseService {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增方法:根据ID查找节点
|
||||||
|
private EmisTransPlanRule findNodeById(Long id) {
|
||||||
|
// 由于deepCopyNode递归时无法直接访问所有节点,这里可通过全量查询实现,实际生产建议优化
|
||||||
|
List<EmisTransPlanRule> allRules = emisTransPlanRuleMapper.selectEmisTransPlanRuleList(new EmisTransPlanRule());
|
||||||
|
for (EmisTransPlanRule rule : allRules) {
|
||||||
|
if (rule.getId() != null && rule.getId().equals(id)) {
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查月结客户首次签约日期,首次签约之前开的不允许修改
|
* 检查月结客户首次签约日期,首次签约之前开的不允许修改
|
||||||
*
|
*
|
||||||
|
|||||||
@ -74,4 +74,12 @@ public interface IEmisTransPlanRuleService {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
int draftSubmitRule(EmisTransPlanRule emisTransPlanRule) throws EmisBizError;
|
int draftSubmitRule(EmisTransPlanRule emisTransPlanRule) throws EmisBizError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验供应商线路规划树结构中的循环引用
|
||||||
|
*
|
||||||
|
* @param emisTransPlanRule 查询条件
|
||||||
|
* @return 循环引用提示信息列表
|
||||||
|
*/
|
||||||
|
List<String> checkTree(EmisTransPlanRule emisTransPlanRule);
|
||||||
}
|
}
|
||||||
@ -82,6 +82,12 @@ public class EmisTransPlanRuleServiceImpl extends EmisBaseService implements IEm
|
|||||||
checkDate(emisTransPlanRule);
|
checkDate(emisTransPlanRule);
|
||||||
// 检查重复
|
// 检查重复
|
||||||
checkDuplicate(emisTransPlanRule);
|
checkDuplicate(emisTransPlanRule);
|
||||||
|
// 校验循环引用
|
||||||
|
EmisTransPlanRule checkRule = new EmisTransPlanRule();
|
||||||
|
checkRule.setProductType(emisTransPlanRule.getProductType());
|
||||||
|
List<EmisTransPlanRule> allRules = emisTransPlanRuleMapper.selectEmisTransPlanRuleListWithoutName(checkRule);
|
||||||
|
allRules.add(emisTransPlanRule);
|
||||||
|
buildTree(allRules, emisTransPlanRule);
|
||||||
return emisTransPlanRuleMapper.insertEmisTransPlanRule(emisTransPlanRule);
|
return emisTransPlanRuleMapper.insertEmisTransPlanRule(emisTransPlanRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,13 +156,19 @@ public class EmisTransPlanRuleServiceImpl extends EmisBaseService implements IEm
|
|||||||
|
|
||||||
// 检查重复
|
// 检查重复
|
||||||
checkDuplicate(emisTransPlanRule);
|
checkDuplicate(emisTransPlanRule);
|
||||||
|
// 校验循环引用
|
||||||
|
EmisTransPlanRule checkRule = new EmisTransPlanRule();
|
||||||
|
checkRule.setProductType(emisTransPlanRule.getProductType());
|
||||||
|
List<EmisTransPlanRule> allRules = emisTransPlanRuleMapper.selectEmisTransPlanRuleListWithoutName(checkRule);
|
||||||
|
allRules.add(emisTransPlanRule);
|
||||||
|
buildTree(allRules, emisTransPlanRule);
|
||||||
return emisTransPlanRuleMapper.insertEmisTransPlanRule(emisTransPlanRule);
|
return emisTransPlanRuleMapper.insertEmisTransPlanRule(emisTransPlanRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nameToCode(EmisTransPlanRule emisTransPlanRule) throws EmisBizError {
|
private void nameToCode(EmisTransPlanRule emisTransPlanRule) throws EmisBizError {
|
||||||
// 线路
|
// 线路
|
||||||
List<Map<String, String>> lineInfo = emisTransPlanRuleMapper.selectLineInfoByNames(Collections.singletonList(emisTransPlanRule.getLineName()));
|
List<Map<String, String>> lineInfo = emisTransPlanRuleMapper
|
||||||
|
.selectLineInfoByNames(Collections.singletonList(emisTransPlanRule.getLineName()));
|
||||||
if (lineInfo == null || lineInfo.isEmpty()) {
|
if (lineInfo == null || lineInfo.isEmpty()) {
|
||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的线路:" + emisTransPlanRule.getLineName());
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的线路:" + emisTransPlanRule.getLineName());
|
||||||
}
|
}
|
||||||
@ -164,9 +176,11 @@ public class EmisTransPlanRuleServiceImpl extends EmisBaseService implements IEm
|
|||||||
|
|
||||||
// 产品类型(支持多个,逗号分隔)
|
// 产品类型(支持多个,逗号分隔)
|
||||||
String[] productTypeNames = emisTransPlanRule.getProductTypeName().split(",");
|
String[] productTypeNames = emisTransPlanRule.getProductTypeName().split(",");
|
||||||
List<Map<String, String>> productTypeInfo = emisTransPlanRuleMapper.selectProductTypeInfoByNamesAndLineCode(Arrays.asList(productTypeNames),lineInfo.get(0).get("code"));
|
List<Map<String, String>> productTypeInfo = emisTransPlanRuleMapper
|
||||||
|
.selectProductTypeInfoByNamesAndLineCode(Arrays.asList(productTypeNames), lineInfo.get(0).get("code"));
|
||||||
if (productTypeInfo == null || productTypeInfo.isEmpty()) {
|
if (productTypeInfo == null || productTypeInfo.isEmpty()) {
|
||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的产品类型:" + emisTransPlanRule.getProductTypeName());
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR,
|
||||||
|
"未找到对应的产品类型:" + emisTransPlanRule.getProductTypeName());
|
||||||
}
|
}
|
||||||
if (productTypeInfo.size() != productTypeNames.length) {
|
if (productTypeInfo.size() != productTypeNames.length) {
|
||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "部分产品类型未找到:" + emisTransPlanRule.getProductTypeName());
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "部分产品类型未找到:" + emisTransPlanRule.getProductTypeName());
|
||||||
@ -177,14 +191,16 @@ public class EmisTransPlanRuleServiceImpl extends EmisBaseService implements IEm
|
|||||||
emisTransPlanRule.setProductType(productTypeCodes);
|
emisTransPlanRule.setProductType(productTypeCodes);
|
||||||
|
|
||||||
// 起始网点
|
// 起始网点
|
||||||
List<Map<String, String>> startSiteInfo = emisTransPlanRuleMapper.selectSiteInfoByNames(Collections.singletonList(emisTransPlanRule.getStartSiteName()));
|
List<Map<String, String>> startSiteInfo = emisTransPlanRuleMapper
|
||||||
|
.selectSiteInfoByNames(Collections.singletonList(emisTransPlanRule.getStartSiteName()));
|
||||||
if (startSiteInfo == null || startSiteInfo.isEmpty()) {
|
if (startSiteInfo == null || startSiteInfo.isEmpty()) {
|
||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的起始网点:" + emisTransPlanRule.getStartSiteName());
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的起始网点:" + emisTransPlanRule.getStartSiteName());
|
||||||
}
|
}
|
||||||
emisTransPlanRule.setStartSiteCode(startSiteInfo.get(0).get("code"));
|
emisTransPlanRule.setStartSiteCode(startSiteInfo.get(0).get("code"));
|
||||||
|
|
||||||
// 下一网点
|
// 下一网点
|
||||||
List<Map<String, String>> nextSiteInfo = emisTransPlanRuleMapper.selectSiteInfoByNames(Collections.singletonList(emisTransPlanRule.getNextSiteName()));
|
List<Map<String, String>> nextSiteInfo = emisTransPlanRuleMapper
|
||||||
|
.selectSiteInfoByNames(Collections.singletonList(emisTransPlanRule.getNextSiteName()));
|
||||||
if (nextSiteInfo == null || nextSiteInfo.isEmpty()) {
|
if (nextSiteInfo == null || nextSiteInfo.isEmpty()) {
|
||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的下一网点:" + emisTransPlanRule.getNextSiteName());
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的下一网点:" + emisTransPlanRule.getNextSiteName());
|
||||||
}
|
}
|
||||||
@ -192,7 +208,8 @@ public class EmisTransPlanRuleServiceImpl extends EmisBaseService implements IEm
|
|||||||
|
|
||||||
// 供应商(支持多个,逗号分隔)
|
// 供应商(支持多个,逗号分隔)
|
||||||
String[] supplierNames = emisTransPlanRule.getSupplierName().split(",");
|
String[] supplierNames = emisTransPlanRule.getSupplierName().split(",");
|
||||||
List<Map<String, String>> supplierInfo = emisTransPlanRuleMapper.selectSupplierInfoByNames(Arrays.asList(supplierNames));
|
List<Map<String, String>> supplierInfo = emisTransPlanRuleMapper
|
||||||
|
.selectSupplierInfoByNames(Arrays.asList(supplierNames));
|
||||||
if (supplierInfo == null || supplierInfo.isEmpty()) {
|
if (supplierInfo == null || supplierInfo.isEmpty()) {
|
||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的供应商:" + emisTransPlanRule.getSupplierName());
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "未找到对应的供应商:" + emisTransPlanRule.getSupplierName());
|
||||||
}
|
}
|
||||||
@ -293,7 +310,6 @@ public class EmisTransPlanRuleServiceImpl extends EmisBaseService implements IEm
|
|||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "产品名称不能为空");
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "产品名称不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (StringUtil.isBlank(emisTransPlanRule.getStartSiteName())) {
|
if (StringUtil.isBlank(emisTransPlanRule.getStartSiteName())) {
|
||||||
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "起始网点名称不能为空");
|
throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "起始网点名称不能为空");
|
||||||
}
|
}
|
||||||
@ -346,4 +362,388 @@ public class EmisTransPlanRuleServiceImpl extends EmisBaseService implements IEm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public List<EmisTransPlanRule> buildTree(List<EmisTransPlanRule> allRules,
|
||||||
|
// EmisTransPlanRule emisTransPlanRule) {
|
||||||
|
// // 按lineCode分组
|
||||||
|
// Map<String, List<EmisTransPlanRule>> groupByLine = allRules.stream()
|
||||||
|
// .collect(Collectors.groupingBy(EmisTransPlanRule::getLineCode));
|
||||||
|
//
|
||||||
|
// List<EmisTransPlanRule> result = new ArrayList<>();
|
||||||
|
//
|
||||||
|
// // 处理每个lineCode分组
|
||||||
|
// for (Map.Entry<String, List<EmisTransPlanRule>> lineEntry :
|
||||||
|
// groupByLine.entrySet()) {
|
||||||
|
// List<EmisTransPlanRule> lineRules = lineEntry.getValue();
|
||||||
|
// if (lineRules.isEmpty()) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// //
|
||||||
|
// 按productType分组(支持productType和productTypeName为逗号分隔的多个类型,且一一对应,且每个rule只保留一个type和typeName)
|
||||||
|
// Map<String, List<EmisTransPlanRule>> groupByProductType = new HashMap<>();
|
||||||
|
// for (EmisTransPlanRule rule : lineRules) {
|
||||||
|
// if (rule.getProductType() != null) {
|
||||||
|
// String[] types = rule.getProductType().split(",");
|
||||||
|
// String[] typeNames = rule.getProductTypeName() != null ?
|
||||||
|
// rule.getProductTypeName().split(",")
|
||||||
|
// : new String[0];
|
||||||
|
// for (int i = 0; i < types.length; i++) {
|
||||||
|
// String type = types[i].trim();
|
||||||
|
// if (!type.isEmpty()) {
|
||||||
|
// EmisTransPlanRule newRule = new EmisTransPlanRule();
|
||||||
|
// BeanUtils.copyProperties(rule, newRule);
|
||||||
|
// newRule.setProductType(type);
|
||||||
|
// if (i < typeNames.length) {
|
||||||
|
// newRule.setProductTypeName(typeNames[i].trim());
|
||||||
|
// } else {
|
||||||
|
// newRule.setProductTypeName(null);
|
||||||
|
// }
|
||||||
|
// groupByProductType.computeIfAbsent(type, k -> new
|
||||||
|
// ArrayList<>()).add(newRule);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// //
|
||||||
|
// 分组内去重(lineCode、productType、startSiteCode、nextSiteCode、supplierCode、startDate、endDate都相同只保留一条)
|
||||||
|
// for (Map.Entry<String, List<EmisTransPlanRule>> entry :
|
||||||
|
// groupByProductType.entrySet()) {
|
||||||
|
// List<EmisTransPlanRule> rules = entry.getValue();
|
||||||
|
// Set<String> uniqueKeys = new HashSet<>();
|
||||||
|
// List<EmisTransPlanRule> deduped = new ArrayList<>();
|
||||||
|
// for (EmisTransPlanRule rule : rules) {
|
||||||
|
// String key = (rule.getLineCode() == null ? "" : rule.getLineCode()) + "|"
|
||||||
|
// + (rule.getProductType() == null ? "" : rule.getProductType()) + "|"
|
||||||
|
// + (rule.getStartSiteCode() == null ? "" : rule.getStartSiteCode()) + "|"
|
||||||
|
// + (rule.getNextSiteCode() == null ? "" : rule.getNextSiteCode()) + "|"
|
||||||
|
// + (rule.getSupplierCode() == null ? "" : rule.getSupplierCode()) + "|"
|
||||||
|
// + (rule.getStartDate() == null ? "" : rule.getStartDate().toString()) + "|"
|
||||||
|
// + (rule.getEndDate() == null ? "" : rule.getEndDate().toString());
|
||||||
|
// if (uniqueKeys.add(key)) {
|
||||||
|
// deduped.add(rule);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// entry.setValue(deduped);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Map<String, List<EmisTransPlanRule>> tempMap = new HashMap<>();
|
||||||
|
// if (StringUtil.isNotBlank(emisTransPlanRule.getProductType())) {
|
||||||
|
// Iterator<Map.Entry<String, List<EmisTransPlanRule>>> iterator =
|
||||||
|
// groupByProductType.entrySet()
|
||||||
|
// .iterator();
|
||||||
|
// while (iterator.hasNext()) {
|
||||||
|
// Map.Entry<String, List<EmisTransPlanRule>> entry = iterator.next();
|
||||||
|
// if (emisTransPlanRule.getProductType().equals(entry.getKey())) {
|
||||||
|
// tempMap.put(entry.getKey(), entry.getValue());
|
||||||
|
// groupByProductType = tempMap;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 处理每个productType分组
|
||||||
|
// for (Map.Entry<String, List<EmisTransPlanRule>> productEntry :
|
||||||
|
// groupByProductType.entrySet()) {
|
||||||
|
// List<EmisTransPlanRule> productRules = productEntry.getValue();
|
||||||
|
//
|
||||||
|
// // 构建站点关系树
|
||||||
|
// Map<String, List<EmisTransPlanRule>> nodeMap = new HashMap<>();
|
||||||
|
// for (EmisTransPlanRule rule : productRules) {
|
||||||
|
// String key = rule.getNextSiteCode() != null ? rule.getNextSiteCode() :
|
||||||
|
// rule.getStartSiteCode();
|
||||||
|
// if (key != null) {
|
||||||
|
// nodeMap.computeIfAbsent(key, k -> new ArrayList<>()).add(rule);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 按startSiteCode分组,找出所有可能的父节点
|
||||||
|
// Map<String, List<EmisTransPlanRule>> parentGroups = productRules.stream()
|
||||||
|
// .filter(rule -> rule.getStartSiteCode() != null)
|
||||||
|
// .collect(Collectors.groupingBy(EmisTransPlanRule::getStartSiteCode));
|
||||||
|
//
|
||||||
|
// // 设置父子关系
|
||||||
|
// for (Map.Entry<String, List<EmisTransPlanRule>> parentGroup :
|
||||||
|
// parentGroups.entrySet()) {
|
||||||
|
// String startSiteCode = parentGroup.getKey();
|
||||||
|
// List<EmisTransPlanRule> children = parentGroup.getValue();
|
||||||
|
//
|
||||||
|
// // 获取所有可能的父节点
|
||||||
|
// List<EmisTransPlanRule> parents = nodeMap.get(startSiteCode);
|
||||||
|
// if (parents != null) {
|
||||||
|
// for (EmisTransPlanRule parent : parents) {
|
||||||
|
// if (parent.getChildren() == null) {
|
||||||
|
// parent.setChildren(new ArrayList<>());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 添加所有子节点到父节点的children列表中
|
||||||
|
// for (EmisTransPlanRule child : children) {
|
||||||
|
// if (!parent.getChildren().contains(child)) {
|
||||||
|
// parent.getChildren().add(child);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 找出顶级节点(没有父节点的节点)
|
||||||
|
// List<EmisTransPlanRule> topLevelNodes = productRules.stream()
|
||||||
|
// .filter(rule -> {
|
||||||
|
// // 检查该节点是否作为其他节点的子节点
|
||||||
|
// boolean isChild = productRules.stream()
|
||||||
|
// .anyMatch(potential -> potential.getChildren() != null
|
||||||
|
// && potential.getChildren().contains(rule));
|
||||||
|
// return !isChild;
|
||||||
|
// })
|
||||||
|
// .collect(Collectors.toList());
|
||||||
|
//
|
||||||
|
// // 将顶级节点直接添加到结果中(进行深度复制)
|
||||||
|
// for (EmisTransPlanRule node : topLevelNodes) {
|
||||||
|
// result.add(deepCopyNode(node));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 递归设置父ID和祖先节点ID(以treeId为准)
|
||||||
|
// for (EmisTransPlanRule root : result) {
|
||||||
|
// setParentAndAncestors(root, null, "");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 递归设置父ID和祖先节点ID
|
||||||
|
// *
|
||||||
|
// * @param node 当前节点
|
||||||
|
// * @param parentId 父节点ID
|
||||||
|
// * @param ancestors 祖先节点ID字符串
|
||||||
|
// */
|
||||||
|
// private void setParentAndAncestors(EmisTransPlanRule node, String parentId,
|
||||||
|
// String ancestors) {
|
||||||
|
// if (node == null) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// // 设置父ID
|
||||||
|
// node.setParentId(parentId);
|
||||||
|
//
|
||||||
|
// // 设置祖先节点ID
|
||||||
|
// node.setAncestors(ancestors);
|
||||||
|
// // 处理子节点,子节点的祖先包含当前节点和当前节点的所有祖先
|
||||||
|
// if (node.getChildren() != null && !node.getChildren().isEmpty()) {
|
||||||
|
// String childAncestors = ancestors.isEmpty() ? node.getTreeId() : ancestors +
|
||||||
|
// "," + node.getTreeId();
|
||||||
|
// for (EmisTransPlanRule child : node.getChildren()) {
|
||||||
|
// setParentAndAncestors(child, node.getTreeId(), childAncestors);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 深度复制节点及其子节点
|
||||||
|
// *
|
||||||
|
// * @param source 源节点
|
||||||
|
// * @return 复制后的新节点
|
||||||
|
// */
|
||||||
|
// private EmisTransPlanRule deepCopyNode(EmisTransPlanRule source) {
|
||||||
|
// return deepCopyNode(source, new HashSet<>(), new ArrayList<>());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 深度复制节点及其子节点(带循环引用检测)
|
||||||
|
// *
|
||||||
|
// * @param source 源节点
|
||||||
|
// * @param visitedIds 已访问的节点ID集合
|
||||||
|
// * @param visitPath 访问路径,用于记录循环引用的路径
|
||||||
|
// * @return 复制后的新节点
|
||||||
|
// */
|
||||||
|
// private EmisTransPlanRule deepCopyNode(EmisTransPlanRule source, Set<Long>
|
||||||
|
// visitedIds, List<Long> visitPath) {
|
||||||
|
// if (source == null) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 检查循环引用
|
||||||
|
// if (visitedIds.contains(source.getId())) {
|
||||||
|
// // 找到循环引用的起始位置
|
||||||
|
// int cycleStartIndex = visitPath.indexOf(source.getId());
|
||||||
|
// if (cycleStartIndex != -1) {
|
||||||
|
// // 构建循环路径
|
||||||
|
// List<Long> cyclePath = visitPath.subList(cycleStartIndex, visitPath.size());
|
||||||
|
// cyclePath.add(source.getId());
|
||||||
|
//
|
||||||
|
// // 构建详细的错误信息
|
||||||
|
// StringBuilder errorMsg = new StringBuilder();
|
||||||
|
// errorMsg.append("检测到循环引用!循环路径:");
|
||||||
|
// for (int i = 0; i < cyclePath.size(); i++) {
|
||||||
|
// if (i > 0) {
|
||||||
|
// errorMsg.append(" -> ");
|
||||||
|
// }
|
||||||
|
// Long id = cyclePath.get(i);
|
||||||
|
// EmisTransPlanRule node = findNodeById(id);
|
||||||
|
// if (node != null) {
|
||||||
|
// errorMsg.append(node.getLineName()).append("-")
|
||||||
|
// .append(node.getProductTypeName()).append("-")
|
||||||
|
// .append(node.getStartSiteName()).append("-")
|
||||||
|
// .append(node.getNextSiteName()).append("-")
|
||||||
|
// .append(node.getSupplierName());
|
||||||
|
// } else {
|
||||||
|
// errorMsg.append("节点ID:").append(id);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// errorMsg.append("\n循环引用发生在节点,详细信息见上");
|
||||||
|
// throw new RuntimeException(errorMsg.toString());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 添加到已访问集合和路径中
|
||||||
|
// visitedIds.add(source.getId());
|
||||||
|
// visitPath.add(source.getId());
|
||||||
|
//
|
||||||
|
// EmisTransPlanRule copy = new EmisTransPlanRule();
|
||||||
|
// BeanUtils.copyProperties(source, copy);
|
||||||
|
//
|
||||||
|
// // 为每个新节点生成唯一treeId
|
||||||
|
// copy.setTreeId(com.xdadan.erp.common.utils.idgen.UUID.fastUUID().toString());
|
||||||
|
//
|
||||||
|
// // 递归复制子节点
|
||||||
|
// if (source.getChildren() != null) {
|
||||||
|
// List<EmisTransPlanRule> copiedChildren = new ArrayList<>();
|
||||||
|
// for (EmisTransPlanRule child : source.getChildren()) {
|
||||||
|
// copiedChildren.add(deepCopyNode(child, visitedIds, visitPath));
|
||||||
|
// }
|
||||||
|
// copy.setChildren(copiedChildren);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 从路径中移除当前节点(回溯)
|
||||||
|
// visitPath.remove(visitPath.size() - 1);
|
||||||
|
//
|
||||||
|
// return copy;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 新增方法:根据ID查找节点
|
||||||
|
// private EmisTransPlanRule findNodeById(Long id) {
|
||||||
|
// // 由于deepCopyNode递归时无法直接访问所有节点,这里可通过全量查询实现,实际生产建议优化
|
||||||
|
// List<EmisTransPlanRule> allRules =
|
||||||
|
// emisTransPlanRuleMapper.selectEmisTransPlanRuleList(new EmisTransPlanRule());
|
||||||
|
// for (EmisTransPlanRule rule : allRules) {
|
||||||
|
// if (rule.getId() != null && rule.getId().equals(id)) {
|
||||||
|
// return rule;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> checkTree(EmisTransPlanRule emisTransPlanRule) {
|
||||||
|
List<EmisTransPlanRule> allRules = emisTransPlanRuleMapper.selectEmisTransPlanRuleList(emisTransPlanRule);
|
||||||
|
return buildTreeForCheck(allRules);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅校验循环引用并收集所有循环引用提示
|
||||||
|
*
|
||||||
|
* @param allRules 所有规则
|
||||||
|
* @return 循环引用提示信息列表
|
||||||
|
*/
|
||||||
|
public List<String> buildTreeForCheck(List<EmisTransPlanRule> allRules) {
|
||||||
|
List<String> cycleMessages = new ArrayList<>();
|
||||||
|
// 按lineCode+productType分组
|
||||||
|
Map<String, List<EmisTransPlanRule>> groupMap = new HashMap<>();
|
||||||
|
for (EmisTransPlanRule rule : allRules) {
|
||||||
|
String[] types = rule.getProductType() != null ? rule.getProductType().split(",") : new String[0];
|
||||||
|
String[] typeNames = rule.getProductTypeName() != null ? rule.getProductTypeName().split(",")
|
||||||
|
: new String[0];
|
||||||
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
String type = types[i].trim();
|
||||||
|
if (!type.isEmpty()) {
|
||||||
|
EmisTransPlanRule newRule = new EmisTransPlanRule();
|
||||||
|
BeanUtils.copyProperties(rule, newRule);
|
||||||
|
newRule.setProductType(type);
|
||||||
|
if (i < typeNames.length) {
|
||||||
|
newRule.setProductTypeName(typeNames[i].trim());
|
||||||
|
} else {
|
||||||
|
newRule.setProductTypeName(null);
|
||||||
|
}
|
||||||
|
String key = (newRule.getLineCode() == null ? "" : newRule.getLineCode()) + "|" + type;
|
||||||
|
groupMap.computeIfAbsent(key, k -> new ArrayList<>()).add(newRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 每组独立校验
|
||||||
|
for (List<EmisTransPlanRule> group : groupMap.values()) {
|
||||||
|
// 构建邻接表:startSiteCode -> List<rule>
|
||||||
|
Map<String, List<EmisTransPlanRule>> adjMap = new HashMap<>();
|
||||||
|
for (EmisTransPlanRule rule : group) {
|
||||||
|
if (rule.getStartSiteCode() != null) {
|
||||||
|
adjMap.computeIfAbsent(rule.getStartSiteCode(), k -> new ArrayList<>()).add(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 全局visited,避免重复DFS
|
||||||
|
Set<Long> globalVisited = new HashSet<>();
|
||||||
|
for (EmisTransPlanRule rule : group) {
|
||||||
|
if (rule.getId() != null && !globalVisited.contains(rule.getId())) {
|
||||||
|
dfsCheckCycle(rule, adjMap, new HashSet<>(), new ArrayList<>(), cycleMessages, globalVisited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cycleMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DFS检测循环引用并收集路径,避免死循环
|
||||||
|
*/
|
||||||
|
private void dfsCheckCycle(
|
||||||
|
EmisTransPlanRule node,
|
||||||
|
Map<String, List<EmisTransPlanRule>> adjMap,
|
||||||
|
Set<Long> pathSet,
|
||||||
|
List<EmisTransPlanRule> path,
|
||||||
|
List<String> cycleMessages,
|
||||||
|
Set<Long> globalVisited) {
|
||||||
|
if (node.getId() == null)
|
||||||
|
return;
|
||||||
|
if (pathSet.contains(node.getId())) {
|
||||||
|
// 检测到环,收集路径
|
||||||
|
int idx = -1;
|
||||||
|
for (int i = 0; i < path.size(); i++) {
|
||||||
|
if (path.get(i).getId().equals(node.getId())) {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (idx != -1) {
|
||||||
|
List<EmisTransPlanRule> cyclePath = new ArrayList<>(path.subList(idx, path.size()));
|
||||||
|
cyclePath.add(node);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < cyclePath.size(); i++) {
|
||||||
|
if (i > 0)
|
||||||
|
sb.append(" -> ");
|
||||||
|
EmisTransPlanRule n = cyclePath.get(i);
|
||||||
|
sb.append(
|
||||||
|
(n.getLineName() == null ? "" : n.getLineName()) + "-" +
|
||||||
|
(n.getProductTypeName() == null ? "" : n.getProductTypeName()) + "-" +
|
||||||
|
(n.getStartSiteName() == null ? "" : n.getStartSiteName()) + "-" +
|
||||||
|
(n.getNextSiteName() == null ? "" : n.getNextSiteName()) + "-" +
|
||||||
|
(n.getSupplierName() == null ? "" : n.getSupplierName()));
|
||||||
|
}
|
||||||
|
cycleMessages.add("检测到循环引用: " + sb.toString());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (globalVisited.contains(node.getId()))
|
||||||
|
return; // 已经全局遍历过,跳过
|
||||||
|
pathSet.add(node.getId());
|
||||||
|
path.add(node);
|
||||||
|
if (node.getNextSiteCode() != null) {
|
||||||
|
List<EmisTransPlanRule> nextList = adjMap.get(node.getNextSiteCode());
|
||||||
|
if (nextList != null) {
|
||||||
|
for (EmisTransPlanRule next : nextList) {
|
||||||
|
dfsCheckCycle(next, adjMap, pathSet, path, cycleMessages, globalVisited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path.remove(path.size() - 1);
|
||||||
|
pathSet.remove(node.getId());
|
||||||
|
globalVisited.add(node.getId());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -61,6 +61,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
order by id desc
|
order by id desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectEmisTransPlanRuleListWithoutName" parameterType="EmisTransPlanRule" resultMap="EmisTransPlanRuleResult">
|
||||||
|
select r.*
|
||||||
|
from emis_trans_plan_rule r
|
||||||
|
<where>
|
||||||
|
r.del_flag = '0'
|
||||||
|
<if test="lineCode != null and lineCode != ''"> and r.line_code = #{lineCode}</if>
|
||||||
|
<if test="productType != null and productType != ''"> and ( FIND_IN_SET(#{productType},r.product_type) )</if>
|
||||||
|
<if test="startSiteCode != null and startSiteCode != ''"> and r.start_site_code = #{startSiteCode}</if>
|
||||||
|
<if test="nextSiteCode != null and nextSiteCode != ''"> and r.next_site_code = #{nextSiteCode}</if>
|
||||||
|
<if test="manager != null and manager != ''"> and r.manager = #{manager}</if>
|
||||||
|
<if test="supplierCode != null and supplierCode != ''"> and ( FIND_IN_SET(#{supplierCode},r.supplier_code) )</if>
|
||||||
|
<if test="startDate != null"> and r.start_date = #{startDate}</if>
|
||||||
|
<if test="endDate != null"> and r.end_date = #{endDate}</if>
|
||||||
|
</where>
|
||||||
|
order by id desc
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="checkTransPlanRule" parameterType="EmisTransPlanRule" resultMap="EmisTransPlanRuleResult">
|
<select id="checkTransPlanRule" parameterType="EmisTransPlanRule" resultMap="EmisTransPlanRuleResult">
|
||||||
select r.*
|
select r.*
|
||||||
from emis_trans_plan_rule r
|
from emis_trans_plan_rule r
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user