1、新增cad拆单支持部件不加工状态判定;2、加工/恢复部件顶级部分加工状态判定处理;

This commit is contained in:
gaoqr
2026-05-29 17:57:59 +08:00
parent a1fbe33063
commit a1b5c12d0a
12 changed files with 875 additions and 139 deletions
@@ -108,4 +108,9 @@ public class OrderComponentDO extends BaseDO {
* 加工状态
*/
private Integer processStatus;
/**
* 附加加工状态:不加工/部分加工(只有顶级)
*/
private Integer extraProcessStatus;
}
@@ -1,6 +1,7 @@
package com.cf.imes.module.plan.framework.rpc.config;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
import com.cf.imes.module.system.api.customplateno.CustomPlateNoSeqApi;
import com.cf.imes.module.system.api.dict.DictDataApi;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
@@ -12,6 +13,6 @@ import org.springframework.context.annotation.Configuration;
* @author there
*/
@Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {AdminUserApi.class, DictDataApi.class, SystemConfigApi.class, CustomPlateNoSeqApi.class, FileApi.class})
@EnableFeignClients(clients = {AdminUserApi.class, DictDataApi.class, SystemConfigApi.class, CustomPlateNoSeqApi.class, FileApi.class, AssemblyConfigApi.class})
public class RpcConfiguration {
}
@@ -35,6 +35,7 @@ import com.cf.imes.module.plan.enums.ErrorCodeConstants;
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
import com.cf.imes.module.plan.service.orderImport.factory.WebCadOrderImportFactory;
import com.cf.imes.module.plan.service.orderImport.property.WebCadImportProperties;
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
@@ -118,6 +119,9 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
@Resource
private WebCadImportProperties webCadImportProperties;
@Resource
private AssemblyConfigApi assemblyConfigApi;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean webCadOrderImport(MultipartFile file) {
@@ -161,7 +165,7 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
WebCadDataReqVO webCadDataReqVO = mapper.readValue(parser, WebCadDataReqVO.class);
WebCadOrderImportFactory webCadOrderImportFactory = new WebCadOrderImportFactory(organId, orderDO, snowFlakeGenerator, orderMapper, orderBodyMapper, plateMapper,
idWorker, goodsMapper, customPlateNoGenerateService, systemConfigApi, webCadImportProperties.getCadImportPlateNumThreshold(), jdbcTemplate);
idWorker, goodsMapper, customPlateNoGenerateService, systemConfigApi, assemblyConfigApi, webCadImportProperties.getCadImportPlateNumThreshold(), jdbcTemplate);
// cad图纸文件id
cadViewFileId = webCadDataReqVO.getCadViewFileId();
@@ -20,6 +20,7 @@ import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateServic
import com.cf.imes.module.plan.service.orderImport.OrderImportTaskService;
import com.cf.imes.module.plan.service.orderImport.factory.WebCadOrderImportAsyncFactory;
import com.cf.imes.module.plan.service.orderImport.property.WebCadImportProperties;
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
@@ -76,6 +77,9 @@ public class WebCadOrderImportConsumer {
@Resource
private SystemConfigApi systemConfigApi;
@Resource
private AssemblyConfigApi assemblyConfigApi;
@Value("${chenfeng.plan.webcad.import.cadImportPlateNumThreshold:10000}")
private int cadImportPlateNumThreshold;
@@ -138,7 +142,7 @@ public class WebCadOrderImportConsumer {
log.info("====================【webcad异步拆单处理临时数据开始】====================");
WebCadOrderImportAsyncFactory webCadOrderImportAsyncFactory =
new WebCadOrderImportAsyncFactory(organId, orderMapper, snowFlakeGenerator, orderBodyMapper, plateMapper, idWorker,
orderImportTaskMapper, goodsMapper, customPlateNoGenerateService, systemConfigApi, orderImportTaskDO.getCreator(),
orderImportTaskMapper, goodsMapper, customPlateNoGenerateService, systemConfigApi, assemblyConfigApi, orderImportTaskDO.getCreator(),
cadImportPlateNumThreshold, jdbcTemplate);
webCadOrderImportAsyncFactory.analyzeTempData(taskId, webCadImportProperties.getTempFilePath());
log.info("====================【webcad异步拆单处理临时数据结束】====================");
@@ -5,6 +5,8 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
@@ -61,6 +63,9 @@ import com.cf.imes.module.plan.enums.ErrorCodeConstants;
import com.cf.imes.module.plan.enums.ordercomponent.OrderComponentProcessStatusEnum;
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
import com.cf.imes.module.plan.service.customplateno.vo.CustomPlateNoGenerateConfigVO;
import com.cf.imes.module.plan.service.orderImport.vo.OrderComponentTreeCompareVO;
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
import com.cf.imes.module.system.api.assemblyconfig.dto.AssemblyConfigRespDTO;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
import com.cf.imes.module.system.api.systemconfig.dto.SystemConfigRespDTO;
import com.cf.imes.module.system.api.systemconfig.dto.SystemConfigSealEdgeRespDTO;
@@ -83,10 +88,14 @@ import java.sql.Timestamp;
import java.sql.Types;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_GET_ORG_SEALEDGE_ERROR;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORDER_PLATENUM_CHECK_ERROR;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORG_SEALEDGE_ANALYZE_ERROR;
@@ -119,6 +128,8 @@ public class WebCadOrderImportAsyncFactory {
private SystemConfigApi systemConfigApi;
private AssemblyConfigApi assemblyConfigApi;
private GoodsMapper goodsMapper;
private CustomPlateNoGenerateService customPlateNoGenerateService;
@@ -207,6 +218,7 @@ public class WebCadOrderImportAsyncFactory {
GoodsMapper goodsMapper,
CustomPlateNoGenerateService customPlateNoGenerateService,
SystemConfigApi systemConfigApi,
AssemblyConfigApi assemblyConfigApi,
String operatorName,
int cadImportPlateNumThreshold,
JdbcTemplate jdbcTemplate) {
@@ -220,6 +232,7 @@ public class WebCadOrderImportAsyncFactory {
this.goodsMapper = goodsMapper;
this.customPlateNoGenerateService = customPlateNoGenerateService;
this.systemConfigApi = systemConfigApi;
this.assemblyConfigApi = assemblyConfigApi;
this.operatorName = operatorName;
now = LocalDateTime.now();
batchId = (Long) snowFlakeGenerator.nextId(null);
@@ -1764,91 +1777,336 @@ public class WebCadOrderImportAsyncFactory {
* @param reader
*/
private void processComponentList(JSONReader reader) {
reader.startArray();
while (reader.hasNext()) {
processComponent(reader, null, null, 0);
// 1. 构建树
List<OrderComponentTreeCompareVO> roots = buildTree(reader);
if (CollUtil.isEmpty(roots)) {
return;
}
reader.endArray();
orderComponentBatchInsertWithinThreshold(orderComponentDOS, true);
// 2. 查询配置
List<String> names = roots.stream()
.map(OrderComponentTreeCompareVO::getName)
.distinct()
.toList();
CommonResult<List<AssemblyConfigRespDTO>> result =
assemblyConfigApi.getNotProcessAssemblyConfigByPartNameList(names);
if (result.isError()) {
throw new ServiceException(ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR);
}
List<AssemblyConfigRespDTO> configList = result.getData();
// 3. hash计算
for (OrderComponentTreeCompareVO root : roots) {
computeHashRecursively(root);
}
// 4. 状态刷新
refreshComponentStatus(roots, configList);
// 5. 入库
List<OrderComponentDO> buffer = new ArrayList<>();
for (OrderComponentTreeCompareVO root : roots) {
createAndCacheComponent(root, null, null, 0);
}
orderComponentBatchInsertWithinThreshold(buffer, true);
}
/**
* 解析单个部件
* 创建部件并缓存
*
* @param reader
* @param componentGroupReqVO cad部件数据
* @param parentId 父级部件id
* @param topId 顶级部件id
* @param level 层级从0开始计算
*/
private void processComponent(JSONReader reader, Long parentId, Long topId, int level) {
if (parentId == null) {
private void createAndCacheComponent(OrderComponentTreeCompareVO componentGroupReqVO, Long parentId, Long topId, int level) {
if (ObjectUtil.isNull(parentId)) {
parentId = OrderComponentDO.PARENT_ID_ROOT;
}
Integer cadGroupId = componentGroupReqVO.getId();
Long componentId = (Long) snowFlakeGenerator.nextId(null);
// 顶级节点创建过一次后后续继续使用
if (ObjectUtil.isNull(topId)) {
topId = componentId;
}
OrderComponentDO componentDO = OrderComponentDO.builder()
.id(componentId)
.organId(organId)
.orderId(orderId)
.pid(parentId)
.topId(topId)
.name(componentGroupReqVO.getName())
.width(componentGroupReqVO.getWidth())
.height(componentGroupReqVO.getHeight())
.depth(componentGroupReqVO.getDepth())
.cadViewFileId(cadViewFileId)
.processStatus(OrderComponentProcessStatusEnum.UNPROCESSED.getStatus())
.extraProcessStatus(componentGroupReqVO.getProcessStatus())
.level(level)
.build();
componentDO.setCreateTime(now);
componentDO.setUpdateTime(now);
componentDO.setCreator(operatorName);
componentDO.setUpdater(operatorName);
componentDO.setDeleted(false);
Integer cadGroupId = null;
// 缓存部件
componentGroupMap.put(cadGroupId, componentId);
// 部件入库
orderComponentDOS.add(componentDO);
orderComponentBatchInsertWithinThreshold(orderComponentDOS, false);
// 继续处理下级
if (CollUtil.isNotEmpty(componentGroupReqVO.getChildren())) {
for (OrderComponentTreeCompareVO children : componentGroupReqVO.getChildren()) {
createAndCacheComponent(children, componentId, topId, level + 1);
}
}
}
/**
* 读取全部部件树
*
* @param reader
* @return
*/
private List<OrderComponentTreeCompareVO> buildTree(JSONReader reader) {
List<OrderComponentTreeCompareVO> roots = new ArrayList<>();
reader.startArray();
while (reader.hasNext()) {
roots.add(readNode(reader));
}
reader.endArray();
return roots;
}
/**
* 单个部件节点读取
*
* @param reader
* @return
*/
private OrderComponentTreeCompareVO readNode(JSONReader reader) {
Integer groupId = null;
String name = null;
WebCadDataComponentGroupReqVO.BoxSizeDTO boxSize = null;
List<OrderComponentTreeCompareVO> children = new ArrayList<>();
reader.startObject();
List<JSONReader> childrenReaders = new ArrayList<>();
while (reader.hasNext()) {
String key = reader.readString();
switch (key) {
case "groupID":
cadGroupId = reader.readInteger();
groupId = reader.readInteger();
break;
case "name":
name = reader.readString();
break;
case "boxSize":
boxSize = reader.readObject(WebCadDataComponentGroupReqVO.BoxSizeDTO.class);
break;
case "children":
// 当前节点生成 OrderComponentDO
Long componentId = (Long) snowFlakeGenerator.nextId(null);
if (topId == null) {
topId = componentId;
}
OrderComponentDO componentDO = OrderComponentDO.builder()
.id(componentId)
.organId(organId)
.orderId(orderId)
.pid(parentId)
.topId(topId)
.name(name)
.width(boxSize != null ? boxSize.getWidth() : null)
.height(boxSize != null ? boxSize.getHeight() : null)
.depth(boxSize != null ? boxSize.getDepth() : null)
.cadViewFileId(cadViewFileId)
.processStatus(OrderComponentProcessStatusEnum.UNPROCESSED.getStatus())
.level(level)
.build();
componentDO.setCreateTime(now);
componentDO.setUpdateTime(now);
componentDO.setCreator(operatorName);
componentDO.setUpdater(operatorName);
componentDO.setDeleted(false);
// 缓存组件id
componentGroupMap.put(cadGroupId, componentId);
// 逐条加入批量入库
orderComponentDOS.add(componentDO);
orderComponentBatchInsertWithinThreshold(orderComponentDOS, false);
reader.startArray();
while (reader.hasNext()) {
// 递归子节点
processComponent(reader, componentId, topId, level + 1); // 子节点在递归中生成组件DO
children.add(readNode(reader));
}
reader.endArray();
break;
default:
// 其他字段直接跳过
reader.readObject();
}
}
reader.endObject();
OrderComponentTreeCompareVO node = new OrderComponentTreeCompareVO();
node.setId(groupId == null ? null : groupId);
node.setName(name);
node.setChildren(children);
node.setProcessStatus(OrderComponentProcessStatusEnum.UNPROCESSED.getStatus());
if (boxSize != null) {
node.setWidth(boxSize.getWidth());
node.setHeight(boxSize.getHeight());
node.setDepth(boxSize.getDepth());
}
return node;
}
/**
* 递归生成 structureHash
*
* @return 当前节点结构字符串
*/
private void computeHashRecursively(OrderComponentTreeCompareVO node) {
List<OrderComponentTreeCompareVO> children = node.getChildren();
if (CollUtil.isNotEmpty(children)) {
children.sort(Comparator.comparing(OrderComponentTreeCompareVO::getName));
for (OrderComponentTreeCompareVO child : children) {
computeHashRecursively(child);
}
}
node.setStructureHash(
DigestUtil.sha256Hex(buildStructureString(node))
);
}
private String buildStructureString(OrderComponentTreeCompareVO node) {
StringBuilder sb = new StringBuilder();
sb.append(node.getName());
List<OrderComponentTreeCompareVO> children = node.getChildren();
if (CollUtil.isNotEmpty(children)) {
sb.append("(");
for (int i = 0; i < children.size(); i++) {
if (i > 0) {
sb.append(",");
}
sb.append(buildStructureString(children.get(i)));
}
sb.append(")");
}
return sb.toString();
}
/**
* 刷新组件树状态
*
* 规则:
* 1、当前节点配置 process=false => 不加工
* 2、任意直接子节点为“不加工” => 当前节点部分加工
* 3、否则 => 未加工
*/
private void refreshComponentStatus(
List<OrderComponentTreeCompareVO> roots,
List<AssemblyConfigRespDTO> configList) {
if (CollUtil.isEmpty(roots) || CollUtil.isEmpty(configList)) {
return;
}
Map<String, AssemblyConfigRespDTO> configMap =
configList.stream()
.collect(Collectors.toMap(
item -> buildKey(item.getComponentName(), item.getStructureHash()),
Function.identity(),
(a, b) -> a
));
for (OrderComponentTreeCompareVO root : roots) {
String key = buildKey(root.getName(), root.getStructureHash());
AssemblyConfigRespDTO config = configMap.get(key);
if (config == null) {
continue;
}
if (Boolean.TRUE.equals(config.getNotProcess())) {
root.setProcessStatus(OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus());
}
// 反序列化配置树
OrderComponentTreeCompareVO configTree =
JSONUtil.toBean(
JsonUtils.unzipString(
config.getStructureJson()
),
OrderComponentTreeCompareVO.class
);
// 递归同步状态
refreshStatus(root, configTree);
}
}
/**
* 递归同步不加工状态
*/
private void refreshStatus(
OrderComponentTreeCompareVO actualNode,
OrderComponentTreeCompareVO configNode) {
List<OrderComponentTreeCompareVO> actualChildren =
actualNode.getChildren();
List<OrderComponentTreeCompareVO> configChildren =
configNode.getChildren();
if (CollUtil.isEmpty(actualChildren)
|| CollUtil.isEmpty(configChildren)) {
return;
}
int size = Math.min(
actualChildren.size(),
configChildren.size()
);
for (int i = 0; i < size; i++) {
OrderComponentTreeCompareVO actualChild =
actualChildren.get(i);
OrderComponentTreeCompareVO configChild =
configChildren.get(i);
// 子节点不加工
if (!configChild.isProcess()) {
actualChild.setProcessStatus(
OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus()
);
}
refreshStatus(actualChild, configChild);
}
}
/**
* 构建key
*/
private String buildKey(String name, String hash) {
return name + "#" + hash;
}
@@ -5,6 +5,8 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
@@ -55,6 +57,9 @@ import com.cf.imes.module.plan.enums.ErrorCodeConstants;
import com.cf.imes.module.plan.enums.ordercomponent.OrderComponentProcessStatusEnum;
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
import com.cf.imes.module.plan.service.customplateno.vo.CustomPlateNoGenerateConfigVO;
import com.cf.imes.module.plan.service.orderImport.vo.OrderComponentTreeCompareVO;
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
import com.cf.imes.module.system.api.assemblyconfig.dto.AssemblyConfigRespDTO;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
import com.cf.imes.module.system.api.systemconfig.dto.SystemConfigRespDTO;
import com.cf.imes.module.system.api.systemconfig.dto.SystemConfigSealEdgeRespDTO;
@@ -71,11 +76,15 @@ import java.sql.Timestamp;
import java.sql.Types;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_GET_ORG_SEALEDGE_ERROR;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORDER_PLATENUM_CHECK_ERROR;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_ORDER_PLATENUM_REACH_THRESHOLD_ERROR;
@@ -106,6 +115,8 @@ public class WebCadOrderImportFactory {
private SystemConfigApi systemConfigApi;
private AssemblyConfigApi assemblyConfigApi;
private GoodsMapper goodsMapper;
private CustomPlateNoGenerateService customPlateNoGenerateService;
@@ -195,6 +206,7 @@ public class WebCadOrderImportFactory {
GoodsMapper goodsMapper,
CustomPlateNoGenerateService customPlateNoGenerateService,
SystemConfigApi systemConfigApi,
AssemblyConfigApi assemblyConfigApi,
int cadImportPlateNumThreshold,
JdbcTemplate jdbcTemplate) {
this.organId = organId;
@@ -208,6 +220,7 @@ public class WebCadOrderImportFactory {
this.goodsMapper = goodsMapper;
this.customPlateNoGenerateService = customPlateNoGenerateService;
this.systemConfigApi = systemConfigApi;
this.assemblyConfigApi = assemblyConfigApi;
operatorName = SecurityFrameworkUtils.getLoginUser().getNickname();
now = LocalDateTime.now();
sealEdgeConfigList = new ArrayList<>();
@@ -487,13 +500,284 @@ public class WebCadOrderImportFactory {
if (CollUtil.isEmpty(componentGroupReqVOS)) {
return;
}
for (WebCadDataComponentGroupReqVO componentGroupReqVO : componentGroupReqVOS) {
createAndCacheComponent(componentGroupReqVO, null, null, 0);
// 1、构建树 + 生成结构hash
List<OrderComponentTreeCompareVO> roots =
buildTree(componentGroupReqVOS);
// 2、查询装配配置
List<String> names = roots.stream()
.map(OrderComponentTreeCompareVO::getName)
.distinct()
.toList();
CommonResult<List<AssemblyConfigRespDTO>> configResult =
assemblyConfigApi.getNotProcessAssemblyConfigByPartNameList(names);
if (configResult.isError()) {
throw new ServiceException(
ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR
);
}
// 3、刷新组件状态
refreshComponentStatus(roots, configResult.getData());
for (OrderComponentTreeCompareVO root : roots) {
createAndCacheComponent(root, null, null, 0);
}
// 部件入库
orderComponentBatchInsertWithinThreshold(orderComponentDOS, true);
}
/**
* 构建运行时树
*
* 功能:
* 1、递归转换树结构
* 2、生成 structureHash
* 3、初始化默认状态
*/
private List<OrderComponentTreeCompareVO> buildTree(
List<WebCadDataComponentGroupReqVO> list) {
if (CollUtil.isEmpty(list)) {
return Collections.emptyList();
}
List<OrderComponentTreeCompareVO> roots = new ArrayList<>();
for (WebCadDataComponentGroupReqVO node : list) {
// 递归转换
OrderComponentTreeCompareVO root =
convertNode(node);
// 递归生成 hash
computeHashRecursively(root);
roots.add(root);
}
return roots;
}
/**
* 递归转换节点
*/
private OrderComponentTreeCompareVO convertNode(
WebCadDataComponentGroupReqVO node) {
OrderComponentTreeCompareVO vo =
new OrderComponentTreeCompareVO();
vo.setId(node.getGroupId() == null
? null
: node.getGroupId());
vo.setName(node.getName());
// 尺寸
if (ObjectUtil.isNotNull(node.getBoxSize())) {
vo.setWidth(node.getBoxSize().getWidth());
vo.setHeight(node.getBoxSize().getHeight());
vo.setDepth(node.getBoxSize().getDepth());
}
// 默认未加工
vo.setProcessStatus(
OrderComponentProcessStatusEnum.UNPROCESSED.getStatus()
);
List<OrderComponentTreeCompareVO> children =
new ArrayList<>();
if (CollUtil.isNotEmpty(node.getChildren())) {
for (WebCadDataComponentGroupReqVO child :
node.getChildren()) {
children.add(convertNode(child));
}
}
vo.setChildren(children);
return vo;
}
/**
* 递归生成 structureHash
*
* @return 当前节点结构字符串
*/
private String computeHashRecursively(
OrderComponentTreeCompareVO node) {
StringBuilder sb = new StringBuilder();
sb.append(node.getName());
List<OrderComponentTreeCompareVO> children =
node.getChildren();
if (CollUtil.isNotEmpty(children)) {
// 排序保证 hash 稳定
children.sort(
Comparator.comparing(
OrderComponentTreeCompareVO::getName
)
);
sb.append("(");
for (int i = 0; i < children.size(); i++) {
if (i > 0) {
sb.append(",");
}
// 递归子节点
sb.append(
computeHashRecursively(
children.get(i)
)
);
}
sb.append(")");
}
String structureStr = sb.toString();
// 当前节点 hash
node.setStructureHash(
DigestUtil.sha256Hex(structureStr)
);
return structureStr;
}
/**
* 刷新组件树状态
*
* 规则:
* 1、当前节点配置 process=false => 不加工
* 2、任意直接子节点为“不加工” => 当前节点部分加工
* 3、否则 => 未加工
*/
private void refreshComponentStatus(
List<OrderComponentTreeCompareVO> roots,
List<AssemblyConfigRespDTO> configList) {
if (CollUtil.isEmpty(roots)
|| CollUtil.isEmpty(configList)) {
return;
}
// 顶级配置索引
Map<String, AssemblyConfigRespDTO> configMap =
configList.stream()
.collect(Collectors.toMap(
item -> buildKey(
item.getComponentName(),
item.getStructureHash()
),
Function.identity(),
(a, b) -> a
));
for (OrderComponentTreeCompareVO root : roots) {
String rootKey = buildKey(
root.getName(),
root.getStructureHash()
);
AssemblyConfigRespDTO config = configMap.get(rootKey);
// 没有配置,默认整棵树未加工
if (config == null) {
continue;
}
// 顶级是否不加工
if (Boolean.TRUE.equals(config.getNotProcess())) {
root.setProcessStatus(
OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus()
);
}
// 反序列化配置树
OrderComponentTreeCompareVO configTree =
JSONUtil.toBean(
JsonUtils.unzipString(
config.getStructureJson()
),
OrderComponentTreeCompareVO.class
);
// 递归同步状态
refreshStatus(root, configTree);
}
}
/**
* 递归同步不加工状态
*/
private void refreshStatus(
OrderComponentTreeCompareVO actualNode,
OrderComponentTreeCompareVO configNode) {
List<OrderComponentTreeCompareVO> actualChildren =
actualNode.getChildren();
List<OrderComponentTreeCompareVO> configChildren =
configNode.getChildren();
if (CollUtil.isEmpty(actualChildren)
|| CollUtil.isEmpty(configChildren)) {
return;
}
int size = Math.min(
actualChildren.size(),
configChildren.size()
);
for (int i = 0; i < size; i++) {
OrderComponentTreeCompareVO actualChild =
actualChildren.get(i);
OrderComponentTreeCompareVO configChild =
configChildren.get(i);
// 子节点不加工
if (!configChild.isProcess()) {
actualChild.setProcessStatus(
OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus()
);
}
refreshStatus(actualChild, configChild);
}
}
/**
* 构建key
*/
private String buildKey(String name, String hash) {
return name + "#" + hash;
}
/**
* 创建部件并缓存
*
@@ -502,11 +786,11 @@ public class WebCadOrderImportFactory {
* @param topId 顶级部件id
* @param level 层级从0开始计算
*/
private void createAndCacheComponent(WebCadDataComponentGroupReqVO componentGroupReqVO, Long parentId, Long topId, int level) {
private void createAndCacheComponent(OrderComponentTreeCompareVO componentGroupReqVO, Long parentId, Long topId, int level) {
if (ObjectUtil.isNull(parentId)) {
parentId = OrderComponentDO.PARENT_ID_ROOT;
}
Integer cadGroupId = componentGroupReqVO.getGroupId();
Integer cadGroupId = componentGroupReqVO.getId();
Long componentId = (Long) snowFlakeGenerator.nextId(null);
// 顶级节点创建过一次后后续继续使用
if (ObjectUtil.isNull(topId)) {
@@ -519,11 +803,12 @@ public class WebCadOrderImportFactory {
.pid(parentId)
.topId(topId)
.name(componentGroupReqVO.getName())
.width(componentGroupReqVO.getBoxSize().getWidth())
.height(componentGroupReqVO.getBoxSize().getHeight())
.depth(componentGroupReqVO.getBoxSize().getDepth())
.width(componentGroupReqVO.getWidth())
.height(componentGroupReqVO.getHeight())
.depth(componentGroupReqVO.getDepth())
.cadViewFileId(cadViewFileId)
.processStatus(OrderComponentProcessStatusEnum.UNPROCESSED.getStatus())
.extraProcessStatus(componentGroupReqVO.getProcessStatus())
.level(level)
.build();
componentDO.setCreateTime(now);
@@ -539,7 +824,7 @@ public class WebCadOrderImportFactory {
orderComponentBatchInsertWithinThreshold(orderComponentDOS, false);
// 继续处理下级
if (CollUtil.isNotEmpty(componentGroupReqVO.getChildren())) {
for (WebCadDataComponentGroupReqVO children : componentGroupReqVO.getChildren()) {
for (OrderComponentTreeCompareVO children : componentGroupReqVO.getChildren()) {
createAndCacheComponent(children, componentId, topId, level + 1);
}
}
@@ -2052,13 +2337,14 @@ public class WebCadOrderImportFactory {
updater,
update_time,
deleted,
level
level,
extra_process_status
) VALUES (
?,?,?,?,?,?,
?,?,?,?,
?,?,?,?,
?,?,?,
?,?
?,?,?
)
""";
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@@ -2097,6 +2383,7 @@ public class WebCadOrderImportFactory {
ps.setTimestamp(17, Timestamp.valueOf(item.getUpdateTime()));
ps.setBoolean(18, item.getDeleted());
ps.setInt(19, item.getLevel());
ps.setInt(20, item.getExtraProcessStatus());
}
@Override
@@ -0,0 +1,73 @@
package com.cf.imes.module.plan.service.orderImport.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/28 16:13
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class OrderComponentTreeCompareVO {
/**
* 部件id
*/
private Integer id;
/**
* 父级id
*/
private Long pid;
/**
* 部件名称
*/
private String name;
/**
* 子部件
*/
private List<OrderComponentTreeCompareVO> children;
/**
* 是否加工
*/
private boolean process;
/**
* 加工状态
*/
private Integer processStatus;
/**
* 结构哈希
*/
@JsonIgnore
private String structureHash;
/**
* 部件级别
*/
private Integer level;
/**
* 宽度
*/
private Double width;
/**
* 高度
*/
private Double height;
/**
* 厚度
*/
private Double depth;
}