1、新增装配清单中根据装配设置对应加工状态的部件列表接口;2、新增装配清单加工接口;

This commit is contained in:
gaoqr
2026-03-04 11:18:55 +08:00
parent c982d11c6f
commit c468f61791
17 changed files with 912 additions and 28 deletions
@@ -190,4 +190,7 @@ public class ErrorCodeConstants {
public static final ErrorCode ORDER_COMPONENT_DELETE_PLATE_IN_PLAN = new ErrorCode(1_003_010_001, "order.component.delete.plate.in.plan");
public static final ErrorCode ORDER_COMPONENT_RESTORE_PARENT_IS_DELETED = new ErrorCode(1_003_010_002, "order.component.restore.parent.is.deleted");
public static final ErrorCode ORDER_COMPONENT_NO_NEED_TO_RESTORE = new ErrorCode(1_003_010_003, "order.component.no.need.to.restore");
public static final ErrorCode ORDER_COMPONENT_PROCESSED_REPEAT = new ErrorCode(1_003_010_004, "order.component.processed.repeat");
public static final ErrorCode ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR = new ErrorCode(1_003_010_005, "order.component.assembly.config.query.error");
public static final ErrorCode ORDER_COMPONENT_NOT_PROCESS = new ErrorCode(1_003_010_006, "order.component.not.process");
}
@@ -0,0 +1,47 @@
package com.cf.imes.module.executor.controller.admin.assemblylist;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderComponentRespVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderDetailComponentListReqVO;
import com.cf.imes.module.executor.service.assemblylist.AssemblyListService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/28 18:20
*/
@Tag(name = "管理后台 - 装配清单管理")
@RestController
@RequestMapping("/executor/assembly")
@Validated
public class AssemblyListController {
@Resource
private AssemblyListService assemblyListService;
@PostMapping("/list")
@Operation(summary = "装配清单-获取部件列表")
public CommonResult<List<OrderComponentRespVO>> getComponentList(@RequestBody OrderDetailComponentListReqVO reqVO) {
return CommonResult.success(assemblyListService.getComponentList(reqVO));
}
@PostMapping("/process/{id}")
@Operation(summary = "装配清单-处理部件")
@Parameter(name = "id", description = "部件编号", required = true, example = "1024")
public CommonResult<Boolean> processComponent(@PathVariable Long id) {
assemblyListService.processComponent(id);
return CommonResult.success(true);
}
}
@@ -0,0 +1,58 @@
package com.cf.imes.module.executor.controller.admin.ordercomponent.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 Long 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;
}
@@ -1,24 +0,0 @@
package com.cf.imes.module.executor.controller.admin.ordercomponent.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Schema(description = "管理后台 - 订单部件板件详情 - 部件树 order component Response VO")
@Data
public class OrderComponentTreeRespVO {
@Schema(description = "部件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "部件父id", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Long pid;
@Schema(description = "部件名", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "子节点")
private List<OrderComponentTreeRespVO> children = new ArrayList<>();
}
@@ -15,8 +15,19 @@ import java.util.Arrays;
@RequiredArgsConstructor
@Getter
public enum OrderComponentProcessStatusEnum implements IntArrayValuable {
/**
* 不加工
*/
NOT_PROCESS(0),
/**
* 未加工
*/
UNPROCESSED(1),
/**
* 已加工
*/
PROCESSED(2);
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(OrderComponentProcessStatusEnum::getStatus).toArray();
@@ -27,4 +38,14 @@ public enum OrderComponentProcessStatusEnum implements IntArrayValuable {
}
private final Integer status;
// from value
public static OrderComponentProcessStatusEnum fromValue(Integer value) {
for (OrderComponentProcessStatusEnum unit : OrderComponentProcessStatusEnum.values()) {
if (unit.getStatus().equals(value)) {
return unit;
}
}
return null;
}
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.executor.framework.rpc.config;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.system.api.application.ApplicationApi;
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.dataSource.DataSourceApi;
import com.cf.imes.module.system.api.dict.DictDataApi;
@@ -22,6 +23,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {AdminUserApi.class, MachineApi.class, DictDataApi.class,
FileApi.class, ProcessGroupApi.class, FileApi.class, DataSourceApi.class, ApplicationApi.class,
ProcessApi.class, OrganApi.class, SystemConfigApi.class, CustomPlateNoSeqApi.class, PermissionApi.class, SettingApi.class})
ProcessApi.class, OrganApi.class, SystemConfigApi.class, CustomPlateNoSeqApi.class, PermissionApi.class, SettingApi.class,
AssemblyConfigApi.class})
public class RpcConfiguration {
}
@@ -0,0 +1,29 @@
package com.cf.imes.module.executor.service.assemblylist;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderComponentRespVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderDetailComponentListReqVO;
import java.util.List;
/**
* 装配清单 Service
*
* @author Gqr
* @since 2026/2/28 11:16
*/
public interface AssemblyListService {
/**
* 获取部件列表,根据装配设置对应加工状态
*
* @param reqVO
* @return
*/
List<OrderComponentRespVO> getComponentList(OrderDetailComponentListReqVO reqVO);
/**
* 加工部件
*
* @param id
*/
void processComponent(Long id);
}
@@ -0,0 +1,622 @@
package com.cf.imes.module.executor.service.assemblylist;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.enums.DeletedCodeEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderComponentRespVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderComponentTreeCompareVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderDetailComponentListReqVO;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.dal.dataobject.ordercomponent.OrderComponentDO;
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
import com.cf.imes.module.executor.dal.mysql.ordercomponent.OrderComponentMapper;
import com.cf.imes.module.executor.enums.ordercomponent.OrderComponentProcessStatusEnum;
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
import com.cf.imes.module.system.api.assemblyconfig.dto.AssemblyConfigRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
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.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_NOT_EXIST;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_NOT_PROCESS;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_PROCESSED_REPEAT;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_NOT_EXISTS;
/**
* 装配清单 ServiceImpl 实现类
*
* @author Gqr
* @since 2026/2/28 11:17
*/
@Service
public class AssemblyListServiceImpl implements AssemblyListService {
@Resource
private OrderComponentMapper orderComponentMapper;
@Resource
private OrderMapper orderMapper;
@Resource
private AssemblyConfigApi assemblyConfigApi;
@Override
public List<OrderComponentRespVO> getComponentList(OrderDetailComponentListReqVO reqVO) {
Set<Long> componentIds = reqVO.getComponentIds();
if (CollUtil.isEmpty(componentIds)) {
return Collections.emptyList();
}
// 校验订单
Long orderId = reqVO.getOrderId();
OrderDO orderDO = orderMapper.selectById(orderId);
AssertUtils.notEmpty(orderDO, ORDER_NOT_EXISTS);
// 查询入参部件
List<OrderComponentDO> componentDOS = orderComponentMapper.selectByIds(componentIds);
if (CollUtil.isEmpty(componentDOS) || componentDOS.size() != componentIds.size()) {
throw new ServiceException(ORDER_COMPONENT_NOT_EXIST);
}
// 查询部件的所有顶级id
List<Long> topIds = componentDOS.stream()
.map(OrderComponentDO::getTopId)
.toList();
OrderComponentProcessStatusEnum orderComponentProcessStatusEnum = OrderComponentProcessStatusEnum.fromValue(reqVO.getProcessStatus());
if (OrderComponentProcessStatusEnum.NOT_PROCESS.equals(orderComponentProcessStatusEnum)) {
// 不加工
return getNotProcessComponentList(reqVO, topIds);
} else if (OrderComponentProcessStatusEnum.UNPROCESSED.equals(orderComponentProcessStatusEnum)) {
// 未加工
return getUnProcessedComponentList(reqVO, topIds);
} else if (OrderComponentProcessStatusEnum.PROCESSED.equals(orderComponentProcessStatusEnum)) {
// 已加工
return getProcessedComponentList(reqVO, topIds);
} else {
return getUnProcessedComponentList(reqVO, topIds);
}
}
/**
* 根据装配设置计算部件节点的加工状态
*
* @param topComponentList
*/
private List<OrderComponentTreeCompareVO> calculateProcessingStatusAccordingToAssemblyConfig(List<OrderComponentDO> topComponentList) {
// 构建树
List<OrderComponentTreeCompareVO> orderComponentTreeRespVOS = buildTree(topComponentList);
// 查询对应的装配设置
List<String> topComponentNames = orderComponentTreeRespVOS.stream().map(OrderComponentTreeCompareVO::getName).distinct().toList();
// 根据名称查询组织装配设置
CommonResult<List<AssemblyConfigRespDTO>> assemblyConfigByComponentNameListResult = assemblyConfigApi.getAssemblyConfigByPartNameList(topComponentNames);
if(assemblyConfigByComponentNameListResult.isError()) {
throw new ServiceException(ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR);
}
List<AssemblyConfigRespDTO> assemblyConfigByComponentNameList = assemblyConfigByComponentNameListResult.getData();
// 构造name+结构hash的索引Map
Map<Pair<String, String>, String> configMap = assemblyConfigByComponentNameList.stream()
.collect(Collectors.toMap(
dto -> new Pair<>(dto.getComponentName(), dto.getStructureHash()),
AssemblyConfigRespDTO::getStructureJson,
(v1, v2) -> v1 // 如果重复保留第一个
));
// 从当前树的顶级中匹配name+hash,匹配上的存id:json用于解析加工状态
Map<Long, String> result = orderComponentTreeRespVOS.stream()
.map(vo -> {
String structureJson = configMap.get(
new Pair<>(vo.getName(), vo.getStructureHash())
);
return structureJson == null
? null
: Map.entry(vo.getId(), structureJson);
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
// 解压json,逐级解析加工信息
for (OrderComponentTreeCompareVO compareVO : orderComponentTreeRespVOS) {
String structureZipJson = result.get(compareVO.getId());
if (CharSequenceUtil.isNotEmpty(structureZipJson)) {
// json解析出配置结构
String structureJson = JsonUtils.unzipString(structureZipJson);
OrderComponentTreeCompareVO structure = JSON.parseObject(structureJson, OrderComponentTreeCompareVO.class);
// 把结构上的加工状态赋值到结果上
processRecursive(structure, compareVO);
}
}
return orderComponentTreeRespVOS;
}
/**
* 查询已配置的部件列表
*
* @return
*/
private List<OrderComponentRespVO> getProcessedComponentList(OrderDetailComponentListReqVO reqVO, List<Long> topIds) {
// 根据部件的topid查询树上所有已加工节点
List<OrderComponentDO> topProcessedComponentList = orderComponentMapper.selectList(new LambdaQueryWrapperX<OrderComponentDO>()
.in(OrderComponentDO::getTopId, topIds)
.eq(OrderComponentDO::getOrderId, reqVO.getOrderId())
.eqIfPresent(OrderComponentDO::getDeleted, reqVO.isDeleted())
.likeIfPresent(OrderComponentDO::getName, reqVO.getName())
.eqIfPresent(OrderComponentDO::getProcessStatus, reqVO.getProcessStatus())
.select(OrderComponentDO::getId, OrderComponentDO::getPid, OrderComponentDO::getName, OrderComponentDO::getProcessStatus));
return BeanUtil.copyToList(topProcessedComponentList, OrderComponentRespVO.class);
}
/**
* 查询未加工的部件列表
*
* @param topIds
* @param reqVO
* @return
*/
private List<OrderComponentRespVO> getUnProcessedComponentList(OrderDetailComponentListReqVO reqVO, List<Long> topIds) {
// 根据部件的topid查询树上所有已加工节点
List<OrderComponentDO> topUnProcessedComponentList = orderComponentMapper.selectList(new LambdaQueryWrapperX<OrderComponentDO>()
.in(OrderComponentDO::getTopId, topIds)
.eq(OrderComponentDO::getOrderId, reqVO.getOrderId())
.eqIfPresent(OrderComponentDO::getDeleted, reqVO.isDeleted())
.likeIfPresent(OrderComponentDO::getName, reqVO.getName())
.ne(OrderComponentDO::getProcessStatus, OrderComponentProcessStatusEnum.PROCESSED.getStatus())
.select(OrderComponentDO::getId, OrderComponentDO::getPid, OrderComponentDO::getName, OrderComponentDO::getProcessStatus));
// 计算部件状态
List<OrderComponentTreeCompareVO> treeCompareVOS = calculateProcessingStatusAccordingToAssemblyConfig(topUnProcessedComponentList);
List<OrderComponentRespVO> result = new ArrayList<>();
// 树形扁平化
for (OrderComponentTreeCompareVO vo : treeCompareVOS) {
flatTree(vo, result);
}
return result;
}
/**
* 查询不加工的部件列表
*
* @param topIds
* @param reqVO
* @return
*/
private List<OrderComponentRespVO> getNotProcessComponentList(OrderDetailComponentListReqVO reqVO, List<Long> topIds) {
// 根据部件的topid查询树上所有节点
List<OrderComponentDO> topComponentList = orderComponentMapper.selectList(new LambdaQueryWrapperX<OrderComponentDO>()
.in(OrderComponentDO::getTopId, topIds)
.eq(OrderComponentDO::getOrderId, reqVO.getOrderId())
.eqIfPresent(OrderComponentDO::getDeleted, reqVO.isDeleted())
.likeIfPresent(OrderComponentDO::getName, reqVO.getName())
.select(OrderComponentDO::getId, OrderComponentDO::getPid, OrderComponentDO::getName, OrderComponentDO::getProcessStatus));
// 计算部件状态
List<OrderComponentTreeCompareVO> treeCompareVOS = calculateProcessingStatusAccordingToAssemblyConfig(topComponentList);
List<OrderComponentRespVO> result = new ArrayList<>();
// 树形扁平化
for (OrderComponentTreeCompareVO vo : treeCompareVOS) {
flatTree(vo, result);
}
return result.stream().filter(o -> ObjectUtil.equals(o.getProcessStatus(), OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus())).toList();
}
/**
* 构建树
*
* @param list
* @return
*/
private List<OrderComponentTreeCompareVO> buildTree(List<OrderComponentDO> list) {
if (list == null || list.isEmpty()) return Collections.emptyList();
Map<Long, OrderComponentTreeCompareVO> map = new HashMap<>(list.size());
List<OrderComponentTreeCompareVO> roots = new ArrayList<>();
// 1、初始化节点
for (OrderComponentDO node : list) {
OrderComponentTreeCompareVO vo = new OrderComponentTreeCompareVO();
vo.setName(node.getName());
vo.setChildren(new ArrayList<>());
vo.setProcess(true);
vo.setProcessStatus(node.getProcessStatus());
vo.setId(node.getId());
vo.setPid(node.getPid());
vo.setLevel(node.getLevel());
map.put(node.getId(), vo);
}
// 2、组装树 + 设置 sourceComponentId
for (OrderComponentDO node : list) {
OrderComponentTreeCompareVO vo = map.get(node.getId());
if (node.getPid() == 0) {
roots.add(vo);
} else {
OrderComponentTreeCompareVO parent = map.get(node.getPid());
if (parent != null) parent.getChildren().add(vo);
}
}
// 3、递归排序 + 生成 hash
for (OrderComponentTreeCompareVO root : roots) {
computeHashRecursively(root);
}
return roots;
}
/**
* 递归排序 children + 生成结构 hash
*
* @param node
*/
private void computeHashRecursively(OrderComponentTreeCompareVO node) {
List<OrderComponentTreeCompareVO> children = node.getChildren();
if (children != null && !children.isEmpty()) {
// 按 name 排序保证 hash 稳定
children.sort(Comparator.comparing(OrderComponentTreeCompareVO::getName));
}
// 生成结构字符串并 hash
String structureStr = buildStructureString(node);
node.setStructureHash(DigestUtil.sha256Hex(structureStr));
// 默认是加工的
node.setProcess(true);
}
/**
* 构建结构字符串(name + children
*
* @param node
* @return
*/
private String buildStructureString(OrderComponentTreeCompareVO node) {
StringBuilder sb = new StringBuilder();
sb.append(node.getName());
List<OrderComponentTreeCompareVO> children = node.getChildren();
if (children != null && !children.isEmpty()) {
sb.append("(");
for (OrderComponentTreeCompareVO child : children) {
sb.append(buildStructureString(child));
}
sb.append(")");
}
return sb.toString();
}
/**
* 逐级对比:当b状态不是已加工时,a的process是false,b的状态才是不加工
* @param a
* @param b
*/
private void processRecursive(
OrderComponentTreeCompareVO a,
OrderComponentTreeCompareVO b) {
// 1️⃣ 赋值当前层
if (ObjectUtil.notEqual(OrderComponentProcessStatusEnum.PROCESSED.getStatus(), b.getProcessStatus())) {
b.setProcessStatus(a.isProcess() ? OrderComponentProcessStatusEnum.UNPROCESSED.getStatus() : OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus());
} else {
b.setProcessStatus(a.getProcessStatus());
}
// 2️⃣ 处理子节点
List<OrderComponentTreeCompareVO> aChildren = a.getChildren();
List<OrderComponentTreeCompareVO> bChildren = b.getChildren();
if (aChildren == null || bChildren == null) {
return;
}
// 把A子节点转成Map,加速匹配
Map<String, OrderComponentTreeCompareVO> aChildMap =
new HashMap<>(aChildren.size());
for (OrderComponentTreeCompareVO aChild : aChildren) {
if (aChild != null) {
aChildMap.put(aChild.getName(), aChild);
}
}
for (OrderComponentTreeCompareVO bChild : bChildren) {
if (bChild == null) {
continue;
}
OrderComponentTreeCompareVO aChild =
aChildMap.get(bChild.getName());
if (aChild != null) {
processRecursive(aChild, bChild);
}
}
}
/**
* 树形扁平化
*
* @param node
* @param result
*/
private void flatTree(OrderComponentTreeCompareVO node,
List<OrderComponentRespVO> result) {
if (node == null) {
return;
}
// 1️⃣ 先加入自己
OrderComponentRespVO orderComponentTreeRespVO = new OrderComponentRespVO();
orderComponentTreeRespVO.setId(node.getId());
orderComponentTreeRespVO.setName(node.getName());
orderComponentTreeRespVO.setPid(node.getPid());
orderComponentTreeRespVO.setProcessStatus(node.getProcessStatus());
result.add(orderComponentTreeRespVO);
// 2️⃣ 再处理子节点
List<OrderComponentTreeCompareVO> children = node.getChildren();
if (children == null || children.isEmpty()) {
return;
}
for (OrderComponentTreeCompareVO child : children) {
flatTree(child, result);
}
}
@Override
public void processComponent(Long id) {
// 查询和校验部件
OrderComponentDO componentDO = orderComponentMapper.selectById(id);
AssertUtils.notEmpty(componentDO, ORDER_COMPONENT_NOT_EXIST);
AssertUtils.equals(componentDO.getProcessStatus(), OrderComponentProcessStatusEnum.PROCESSED.getStatus(), ORDER_COMPONENT_PROCESSED_REPEAT);
int level = componentDO.getLevel();
Long organId = componentDO.getOrganId();
Long orderId = componentDO.getOrderId();
// 查询和校验顶级部件
Long topId = componentDO.getTopId();
OrderComponentDO topComponentDO = orderComponentMapper.selectById(topId);
AssertUtils.notEmpty(topComponentDO, ORDER_COMPONENT_NOT_EXIST);
// 查询顶级部件下的所有节点
List<OrderComponentDO> topProcessedComponentList = orderComponentMapper.selectList(new LambdaQueryWrapperX<OrderComponentDO>()
.eq(OrderComponentDO::getTopId, topId)
.eqIfPresent(OrderComponentDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.select(OrderComponentDO::getId, OrderComponentDO::getPid, OrderComponentDO::getName, OrderComponentDO::getProcessStatus, OrderComponentDO::getLevel));
if (CollUtil.isEmpty(topProcessedComponentList)) {
return;
}
// 从顶级节点开始构建成树形
List<OrderComponentTreeCompareVO> treeCompareVOS = buildTree(topProcessedComponentList);
if (CollUtil.isEmpty(treeCompareVOS)) {
return;
}
OrderComponentTreeCompareVO currentTreeCompareVO = treeCompareVOS.get(0);
String structureHash = currentTreeCompareVO.getStructureHash();
// 根据顶级部件名查询装配设置
String name = topComponentDO.getName();
CommonResult<List<AssemblyConfigRespDTO>> assemblyConfigByComponentNameListResult = assemblyConfigApi.getAssemblyConfigByPartNameList(List.of(name));
if (assemblyConfigByComponentNameListResult.isError()) {
throw new ServiceException(ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR);
}
List<AssemblyConfigRespDTO> assemblyConfigByPartNameList = assemblyConfigByComponentNameListResult.getData();
if (CollUtil.isNotEmpty(assemblyConfigByPartNameList)) {
AssemblyConfigRespDTO assemblyConfig = assemblyConfigByPartNameList.get(0);
if (structureHash.equals(assemblyConfig.getStructureHash())) {
// 结构相同,解压配置json
String structureJson = assemblyConfig.getStructureJson();
OrderComponentTreeCompareVO structure = JSON.parseObject(JsonUtils.unzipString(structureJson), OrderComponentTreeCompareVO.class);
// 筛选出需要加工的部件id列表
List<Long> needProcessComponentIds = getNeedProcessIdsByAssemblyConfig(currentTreeCompareVO, structure, id);
if (CollUtil.isEmpty(needProcessComponentIds)) {
return;
}
// 更新加工状态
orderComponentMapper.update(new LambdaUpdateWrapper<OrderComponentDO>()
.in(OrderComponentDO::getId, needProcessComponentIds)
.eq(OrderComponentDO::getOrderId, orderId)
.eq(OrderComponentDO::getOrganId, organId)
.ge(OrderComponentDO::getLevel, level)
.eq(OrderComponentDO::getProcessStatus, OrderComponentProcessStatusEnum.UNPROCESSED.getStatus())
.eq(OrderComponentDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.set(OrderComponentDO::getProcessStatus, OrderComponentProcessStatusEnum.PROCESSED.getStatus())
);
}
} else {
// 没有对应的装配设置,更新未加工的本身和下级
List<Long> needProcessComponentIds = topProcessedComponentList.stream().filter(o ->
ObjectUtil.notEqual(OrderComponentProcessStatusEnum.PROCESSED.getStatus(), o.getProcessStatus()) && o.getLevel() >= level).map(OrderComponentDO::getId).toList();
if (CollUtil.isEmpty(needProcessComponentIds)) {
return;
}
orderComponentMapper.update(new LambdaUpdateWrapper<OrderComponentDO>()
.in(OrderComponentDO::getId, needProcessComponentIds)
.eq(OrderComponentDO::getOrderId, orderId)
.eq(OrderComponentDO::getOrganId, organId)
.ge(OrderComponentDO::getLevel, level)
.eq(OrderComponentDO::getProcessStatus, OrderComponentProcessStatusEnum.UNPROCESSED.getStatus())
.eq(OrderComponentDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.set(OrderComponentDO::getProcessStatus, OrderComponentProcessStatusEnum.PROCESSED.getStatus())
);
}
}
/**
* 点击加工入口方法
*/
public static List<Long> getNeedProcessIdsByAssemblyConfig(OrderComponentTreeCompareVO aRoot, OrderComponentTreeCompareVO bRoot, Long currentComponentId) {
if (aRoot == null || bRoot == null || currentComponentId == null) {
return Collections.emptyList();
}
// 1. 构建 B 的 processMap
Map<String, Boolean> processMap = buildProcessMap(bRoot);
// 2. 找到 A 中点击的节点
OrderComponentTreeCompareVO startNode = findNodeById(aRoot, currentComponentId);
if (startNode == null) {
return Collections.emptyList();
}
// 判断当前节点是否允许加工
String selfKey = buildKey(startNode.getName(), startNode.getLevel());
Boolean selfProcess = processMap.get(selfKey);
// 如果明确配置为 false,直接终止
if (Boolean.FALSE.equals(selfProcess)) {
throw new ServiceException(ORDER_COMPONENT_NOT_PROCESS);
}
// 3. 过滤需要加工的节点
return collectNeedProcessNodes(startNode, processMap);
}
/**
* 在 A 树中查找节点
*/
private static OrderComponentTreeCompareVO findNodeById(OrderComponentTreeCompareVO root, Long targetId) {
Deque<OrderComponentTreeCompareVO> stack = new ArrayDeque<>();
stack.push(root);
while (!stack.isEmpty()) {
OrderComponentTreeCompareVO node = stack.pop();
if (targetId.equals(node.getId())) {
return node;
}
if (node.getChildren() != null) {
for (OrderComponentTreeCompareVO child : node.getChildren()) {
stack.push(child);
}
}
}
return null;
}
/**
* 把 B 树扁平化成 Map<name_level, process>
*/
private static Map<String, Boolean> buildProcessMap(OrderComponentTreeCompareVO root) {
Map<String, Boolean> map = new HashMap<>();
Deque<NodeLevel<OrderComponentTreeCompareVO>> stack = new ArrayDeque<>();
stack.push(new NodeLevel<>(root, 0));
while (!stack.isEmpty()) {
NodeLevel<OrderComponentTreeCompareVO> current = stack.pop();
OrderComponentTreeCompareVO node = current.node;
int level = current.level;
String key = buildKey(node.getName(), level);
map.put(key, node.isProcess());
if (node.getChildren() != null) {
for (OrderComponentTreeCompareVO child : node.getChildren()) {
stack.push(new NodeLevel<>(child, level + 1));
}
}
}
return map;
}
/**
* 收集需要加工的节点
*/
private static List<Long> collectNeedProcessNodes(
OrderComponentTreeCompareVO startNode,
Map<String, Boolean> processMap) {
List<Long> result = new ArrayList<>();
Deque<OrderComponentTreeCompareVO> stack = new ArrayDeque<>();
stack.push(startNode);
while (!stack.isEmpty()) {
OrderComponentTreeCompareVO node = stack.pop();
String key = buildKey(node.getName(), node.getLevel());
Boolean configProcess = processMap.get(key);
boolean allowProcess = !Boolean.FALSE.equals(configProcess);
boolean alreadyProcessed = OrderComponentProcessStatusEnum.PROCESSED.getStatus().equals(node.getProcessStatus());
// 规则 1:B 中配置为 false → 不加入
// 规则 2:已经加工过 → 不加入
if (allowProcess && !alreadyProcessed) {
result.add(node.getId());
}
if (node.getChildren() != null) {
for (OrderComponentTreeCompareVO child : node.getChildren()) {
stack.push(child);
}
}
}
return result;
}
/**
* 构建匹配 key
*/
private static String buildKey(String name, Integer level) {
return name + "_" + level;
}
/**
* 用于保存节点和层级
*/
private static class NodeLevel<T> {
T node;
int level;
NodeLevel(T node, int level) {
this.node = node;
this.level = level;
}
}
}
@@ -29,4 +29,7 @@ veneer.import.org.classification.name.not.exist=第{0}行分类名称{1}不存
order.component.not.exist=订单部件不存在
order.component.delete.plate.in.plan=部件下存在已排单的板件,请移除部件后再次进行删除
order.component.restore.parent.is.deleted=该部件上级已被删除,请先恢复上级部件
order.component.no.need.to.restore=该部件未删除,无需恢复
order.component.no.need.to.restore=该部件未删除,无需恢复
order.component.processed.repeat=该部件已加工勿重复操作,请刷新列表后检查状态
order.component.assembly.config.query.error=装配设置查询失败,请检查服务状态
order.component.not.process=当前部件无需加工,请刷新列表后检查状态
@@ -29,4 +29,7 @@ veneer.import.org.classification.name.not.exist=第{0}行分類名稱{1}不存
order.component.not.exist=訂單部件不存在
order.component.delete.plate.in.plan=部件下存在已排單的板件,請移除部件後再次進行删除
order.component.restore.parent.is.deleted=該部件上級已被删除,請先恢復上級部件
order.component.no.need.to.restore=該部件未删除,無需恢復
order.component.no.need.to.restore=該部件未删除,無需恢復
order.component.processed.repeat=該部件已加工勿重複操作,請重繪清單後檢查狀態
order.component.assembly.config.query.error=裝配設定査詢失敗,請檢查服務狀態
order.component.not.process=當前部件無需加工,請重繪清單後檢查狀態
@@ -29,4 +29,7 @@ veneer.import.org.classification.name.not.exist=The classification name {1} does
order.component.not.exist=The order component does not exist
order.component.delete.plate.in.plan=There are already listed boards under the component. Please remove the component and delete it again
order.component.restore.parent.is.deleted=The upper level of this component has been deleted. Please restore the upper level component first
order.component.no.need.to.restore=This component has not been deleted and does not need to be restored
order.component.no.need.to.restore=This component has not been deleted and does not need to be restored
order.component.processed.repeat=This component has been processed and should not be operated repeatedly. Please refresh the list and check the status
order.component.assembly.config.query.error=Assembly settings query failed, please check service status
order.component.not.process=The current component does not require processing. Please refresh the list and check the status