diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/veneer/vo/VeneerPlanPageRespVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/veneer/vo/VeneerPlanPageRespVO.java index 7d9e86f2c..ec9c77a99 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/veneer/vo/VeneerPlanPageRespVO.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/veneer/vo/VeneerPlanPageRespVO.java @@ -1,10 +1,12 @@ package com.cf.imes.module.executor.controller.admin.veneer.vo; +import com.cf.imes.module.executor.controller.admin.plan.vo.PlanOrderRespVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.List; /** * 已排贴皮排单分页响应参数。 @@ -28,6 +30,12 @@ public class VeneerPlanPageRespVO { @Schema(description = "贴皮信息,格式为材质-颜色-厚度mm") private String veneerInfo; + @Schema(description = "排单关联的订单主键ID集合,JSON数组格式") + private String orderNos; + + @Schema(description = "排单关联的订单信息") + private List orderList; + @Schema(description = "排单状态:0-未开料/新单,1-已优化,2-开料中,3-已开料") private Integer status; diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/veneer/OrderVeneerPlanDO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/veneer/OrderVeneerPlanDO.java index 80c7ef61d..c4ec5c0f8 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/veneer/OrderVeneerPlanDO.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/veneer/OrderVeneerPlanDO.java @@ -76,6 +76,11 @@ public class OrderVeneerPlanDO extends BaseDO { */ private Long sourceVeneerId; + /** + * 排单关联的订单主键ID集合,使用 JSON 数组格式存储。 + */ + private String orderNos; + /** * 贴皮数量,A/B面分别计数。 */ diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/veneer/VeneerPlanMapper.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/veneer/VeneerPlanMapper.java index dabf4fdda..bb689f511 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/veneer/VeneerPlanMapper.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/veneer/VeneerPlanMapper.java @@ -89,6 +89,14 @@ public interface VeneerPlanMapper extends BaseMapperX { */ VeneerPlanStatisticsDO selectPlanStatistics(@Param("planId") Long planId); + /** + * 查询指定排单当前关联的订单主键ID集合。 + * + * @param planId 贴皮排单ID + * @return 去重并按订单ID升序排列的订单ID集合 + */ + List selectPlanOrderIdList(@Param("planId") Long planId); + /** * 按版本物理删除已无关联贴皮且未进入开料阶段的排单。 * diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/veneer/VeneerPlanServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/veneer/VeneerPlanServiceImpl.java index 7010d260a..61e220cc7 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/veneer/VeneerPlanServiceImpl.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/veneer/VeneerPlanServiceImpl.java @@ -2,6 +2,7 @@ package com.cf.imes.module.executor.service.veneer; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; @@ -9,8 +10,10 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.security.core.LoginUser; import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; +import com.cf.imes.module.executor.controller.admin.plan.vo.PlanOrderRespVO; import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerPlanAddPlateReqVO; import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerPlanCreateReqVO; import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerPlanGroupReqVO; @@ -44,13 +47,16 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; 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.GOODS_PLATE_UPDATE_CONCURRENCY_ERROR; import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PLATE_UPDATE_CONCURRENCY_ERROR; @@ -208,6 +214,7 @@ public class VeneerPlanServiceImpl implements VeneerPlanService { .sort(++sort) .planTime(planTime) .sourceVeneerId(sourceVeneerId) + .orderNos(buildOrderNos(group)) .veneerNum(group.size()) .veneerArea(calculateVeneerArea(group)) .operator(loginUser.getNickname()) @@ -391,6 +398,7 @@ public class VeneerPlanServiceImpl implements VeneerPlanService { IPage page = veneerPlanMapper.selectPlanPage( new PageDTO<>(req.getPageNo(), req.getPageSize()), req); + fillPlanOrderList(page.getRecords()); return new PageResult<>(page.getRecords(), page.getTotal()); } @@ -592,6 +600,9 @@ public class VeneerPlanServiceImpl implements VeneerPlanService { */ private void updatePlanStatistics( OrderVeneerPlanDO plan, VeneerPlanStatisticsDO statistics) { + // 订单集合是读取快照,以当前排单剩余贴皮为准重新生成,避免新增或移除后数据漂移。 + String orderNos = JSON.toJSONString( + veneerPlanMapper.selectPlanOrderIdList(plan.getId())); int version = plan.getVersion(); int updated = veneerPlanMapper.update(new LambdaUpdateWrapper() .eq(OrderVeneerPlanDO::getId, plan.getId()) @@ -599,12 +610,75 @@ public class VeneerPlanServiceImpl implements VeneerPlanService { .eq(OrderVeneerPlanDO::getVersion, version) .set(OrderVeneerPlanDO::getVeneerNum, statistics.getVeneerNum()) .set(OrderVeneerPlanDO::getVeneerArea, statistics.getVeneerArea()) + .set(OrderVeneerPlanDO::getOrderNos, orderNos) .set(OrderVeneerPlanDO::getVersion, version + 1)); if (updated != 1) { throw new ServiceException(VENEER_PLAN_PLATE_STATUS_CHANGED); } } + /** + * 从同一贴皮商品分组提取订单ID,生成稳定有序的 JSON 数组快照。 + * + * @param veneers 当前贴皮排单包含的贴皮记录 + * @return 去重、升序排列后的订单ID JSON数组 + */ + private String buildOrderNos(List veneers) { + List orderIds = veneers.stream() + .map(OrderPlateVeneerDO::getOrderId) + .filter(Objects::nonNull) + .distinct() + .sorted() + .toList(); + return JSON.toJSONString(orderIds); + } + + /** + * 根据排单中冗余的订单ID快照,批量加载当前页全部订单并回填订单信息。 + * 查询次数只与分页请求相关,不随贴皮明细数量增加。 + * + * @param plans 当前页贴皮排单 + */ + private void fillPlanOrderList(List plans) { + if (CollUtil.isEmpty(plans)) { + return; + } + Set orderIds = plans.stream() + .map(VeneerPlanPageRespVO::getOrderNos) + .filter(StrUtil::isNotBlank) + .flatMap(orderNos -> parseOrderIds(orderNos).stream()) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + Map orderMap = new HashMap<>(orderIds.size()); + if (CollUtil.isNotEmpty(orderIds)) { + for (OrderDO order : orderMapper.selectByIds(orderIds)) { + orderMap.put(order.getId(), order); + } + } + for (VeneerPlanPageRespVO plan : plans) { + List orderList = parseOrderIds(plan.getOrderNos()).stream() + .map(orderMap::get) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(OrderDO::getId).reversed()) + .map(order -> BeanUtils.toBean(order, PlanOrderRespVO.class)) + .toList(); + plan.setOrderList(orderList); + } + } + + /** + * 解析贴皮排单中的订单ID JSON快照。 + * + * @param orderNos 订单ID JSON数组 + * @return 订单ID列表;快照为空时返回空列表 + */ + private List parseOrderIds(String orderNos) { + if (StrUtil.isBlank(orderNos)) { + return List.of(); + } + return JSON.parseArray(orderNos).toJavaList(Long.class); + } + /** * 根据本次新增或移除贴皮的归属范围重新统计订单及订单材质数量。 * diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/resources/mapper/veneer/VeneerPlanMapper.xml b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/resources/mapper/veneer/VeneerPlanMapper.xml index e57e3fe61..2d795fe03 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/resources/mapper/veneer/VeneerPlanMapper.xml +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/resources/mapper/veneer/VeneerPlanMapper.xml @@ -10,6 +10,7 @@ ovp.process_name AS processName, CONCAT_WS('-', NULLIF(v.material, ''), NULLIF(v.color, ''), CONCAT(CAST(v.thickness AS CHAR), 'mm')) AS veneerInfo, + ovp.order_nos AS orderNos, ovp.status, ovp.is_scheduled AS isScheduled, ovp.veneer_num AS veneerNum, @@ -124,6 +125,14 @@ AND opv.plan_id = #{planId} + + DELETE FROM order_veneer_plan WHERE deleted = false