贴皮排单分页接口异常修复

This commit is contained in:
gaoqr
2026-08-14 17:34:58 +08:00
parent 87407366c2
commit a45fc887f6
3 changed files with 79 additions and 9 deletions
@@ -1,6 +1,7 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo; package com.cf.imes.module.executor.controller.admin.veneer.vo;
import com.cf.imes.module.executor.controller.admin.plan.vo.PlanOrderRespVO; import com.cf.imes.module.executor.controller.admin.plan.vo.PlanOrderRespVO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -30,6 +31,10 @@ public class VeneerPlanPageRespVO {
@Schema(description = "贴皮信息,格式为材质-颜色-厚度mm") @Schema(description = "贴皮信息,格式为材质-颜色-厚度mm")
private String veneerInfo; private String veneerInfo;
@JsonIgnore
@Schema(hidden = true)
private Long sourceVeneerId;
@Schema(description = "排单关联的订单主键ID集合,JSON数组格式") @Schema(description = "排单关联的订单主键ID集合,JSON数组格式")
private String orderNos; private String orderNos;
@@ -35,12 +35,14 @@ import com.cf.imes.module.executor.dal.dataobject.ordermodel.OrderModelDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderPlateVeneerDO; import com.cf.imes.module.executor.dal.dataobject.veneer.OrderPlateVeneerDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderVeneerGoodsDO; import com.cf.imes.module.executor.dal.dataobject.veneer.OrderVeneerGoodsDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderVeneerPlanDO; import com.cf.imes.module.executor.dal.dataobject.veneer.OrderVeneerPlanDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerPlannedPlateCountDO; import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerPlannedPlateCountDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerPlanStatisticsDO; import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerPlanStatisticsDO;
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper; import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.OrderVeneerPlanBatchMapper; import com.cf.imes.module.executor.dal.mysql.veneer.OrderVeneerPlanBatchMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.OrderVeneerGoodsMapper; import com.cf.imes.module.executor.dal.mysql.veneer.OrderVeneerGoodsMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerPlanMapper; import com.cf.imes.module.executor.dal.mysql.veneer.VeneerPlanMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerMapper;
import com.cf.imes.module.executor.enums.VeneerPlanStatusEnum; import com.cf.imes.module.executor.enums.VeneerPlanStatusEnum;
import com.cf.imes.module.executor.enums.VeneerPlateProcessStatusEnum; import com.cf.imes.module.executor.enums.VeneerPlateProcessStatusEnum;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@@ -130,9 +132,19 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
VeneerPlanStatusEnum.NOCUTTING.getStatus(), VeneerPlanStatusEnum.NOCUTTING.getStatus(),
VeneerPlanStatusEnum.OPTIMIZED.getStatus()); VeneerPlanStatusEnum.OPTIMIZED.getStatus());
/** 新增贴皮允许覆盖全部排单阶段,已结束开料的排单新增后重新进入开料中。 */
private static final List<Integer> PLAN_ADD_PLATE_STATUSES = List.of(
VeneerPlanStatusEnum.NOCUTTING.getStatus(),
VeneerPlanStatusEnum.OPTIMIZED.getStatus(),
VeneerPlanStatusEnum.OPENING.getStatus(),
VeneerPlanStatusEnum.OPENED.getStatus());
@Resource @Resource
private VeneerPlanMapper veneerPlanMapper; private VeneerPlanMapper veneerPlanMapper;
@Resource
private VeneerMapper veneerMapper;
@Resource @Resource
private OrderVeneerPlanBatchMapper orderVeneerPlanBatchMapper; private OrderVeneerPlanBatchMapper orderVeneerPlanBatchMapper;
@@ -351,7 +363,7 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void addPlanPlate(VeneerPlanAddPlateReqVO req) { public void addPlanPlate(VeneerPlanAddPlateReqVO req) {
Long planId = req == null ? null : req.getPlanId(); Long planId = req == null ? null : req.getPlanId();
OrderVeneerPlanDO plan = validatePlanStatuses(planId, PLAN_EDITABLE_STATUSES); OrderVeneerPlanDO plan = validatePlanStatuses(planId, PLAN_ADD_PLATE_STATUSES);
List<Long> veneerIds = normalizePlanVeneerIds( List<Long> veneerIds = normalizePlanVeneerIds(
req == null ? null : req.getVeneerIds()); req == null ? null : req.getVeneerIds());
@@ -383,7 +395,9 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
} }
} }
refreshPlanStatistics(plan); // 与普通订单排单一致:开料中允许追加,已结束开料追加后恢复为开料中。
refreshPlanStatistics(plan, PLAN_ADD_PLATE_STATUSES,
VeneerPlanStatusEnum.OPENED.getStatus().equals(plan.getStatus()));
refreshAffectedPlannedVeneerPlateCount(veneers); refreshAffectedPlannedVeneerPlateCount(veneers);
} }
@@ -456,10 +470,46 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
IPage<VeneerPlanPageRespVO> page = veneerPlanMapper.selectPlanPage( IPage<VeneerPlanPageRespVO> page = veneerPlanMapper.selectPlanPage(
new PageDTO<>(req.getPageNo(), req.getPageSize()), new PageDTO<>(req.getPageNo(), req.getPageSize()),
req); req);
fillPlanVeneerInfo(page.getRecords());
fillPlanOrderList(page.getRecords()); fillPlanOrderList(page.getRecords());
return new PageResult<>(page.getRecords(), page.getTotal()); return new PageResult<>(page.getRecords(), page.getTotal());
} }
/** 分页完成后按来源贴皮ID批量补充贴皮信息,避免MyCat执行跨分片JOIN及全局排序。 */
private void fillPlanVeneerInfo(List<VeneerPlanPageRespVO> plans) {
if (CollUtil.isEmpty(plans)) {
return;
}
List<Long> veneerIds = plans.stream()
.map(VeneerPlanPageRespVO::getSourceVeneerId)
.filter(Objects::nonNull)
.distinct()
.toList();
Map<Long, VeneerDO> veneerMap = new HashMap<>(veneerIds.size());
for (List<Long> batch : CollUtil.split(veneerIds, PLAN_STAT_BATCH_SIZE)) {
for (VeneerDO veneer : veneerMapper.selectBatchIds(batch)) {
veneerMap.put(veneer.getId(), veneer);
}
}
for (VeneerPlanPageRespVO plan : plans) {
VeneerDO veneer = veneerMap.get(plan.getSourceVeneerId());
if (veneer == null) {
continue;
}
List<String> parts = new ArrayList<>(3);
if (StrUtil.isNotBlank(veneer.getMaterial())) {
parts.add(veneer.getMaterial());
}
if (StrUtil.isNotBlank(veneer.getColor())) {
parts.add(veneer.getColor());
}
if (veneer.getThickness() != null) {
parts.add(veneer.getThickness().stripTrailingZeros().toPlainString() + "mm");
}
plan.setVeneerInfo(String.join("-", parts));
}
}
@Override @Override
public List<VeneerPlanPlateRespVO> getPlanPlateList(Long planId) { public List<VeneerPlanPlateRespVO> getPlanPlateList(Long planId) {
if (planId == null) { if (planId == null) {
@@ -708,12 +758,19 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
* @param plan 更新前读取的贴皮排单 * @param plan 更新前读取的贴皮排单
*/ */
private void refreshPlanStatistics(OrderVeneerPlanDO plan) { private void refreshPlanStatistics(OrderVeneerPlanDO plan) {
refreshPlanStatistics(plan, PLAN_EDITABLE_STATUSES, false);
}
/** 按指定允许状态重新统计排单,并可将已结束排单重新打开为开料中。 */
private void refreshPlanStatistics(OrderVeneerPlanDO plan,
List<Integer> expectedStatuses,
boolean reopenCutting) {
VeneerPlanStatisticsDO statistics = veneerPlanMapper.selectPlanStatistics(plan.getId()); VeneerPlanStatisticsDO statistics = veneerPlanMapper.selectPlanStatistics(plan.getId());
if (statistics == null || statistics.getVeneerNum() == null if (statistics == null || statistics.getVeneerNum() == null
|| statistics.getVeneerArea() == null || statistics.getVeneerNum() <= 0) { || statistics.getVeneerArea() == null || statistics.getVeneerNum() <= 0) {
throw new ServiceException(VENEER_PLAN_PLATE_STATUS_CHANGED); throw new ServiceException(VENEER_PLAN_PLATE_STATUS_CHANGED);
} }
updatePlanStatistics(plan, statistics); updatePlanStatistics(plan, statistics, expectedStatuses, reopenCutting);
} }
/** /**
@@ -724,14 +781,26 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
*/ */
private void updatePlanStatistics( private void updatePlanStatistics(
OrderVeneerPlanDO plan, VeneerPlanStatisticsDO statistics) { OrderVeneerPlanDO plan, VeneerPlanStatisticsDO statistics) {
updatePlanStatistics(plan, statistics, PLAN_EDITABLE_STATUSES, false);
}
/** 使用指定状态范围及version乐观锁覆盖贴皮排单汇总信息。 */
private void updatePlanStatistics(OrderVeneerPlanDO plan,
VeneerPlanStatisticsDO statistics,
List<Integer> expectedStatuses,
boolean reopenCutting) {
// 订单集合是读取快照,以当前排单剩余贴皮为准重新生成,避免新增或移除后数据漂移。 // 订单集合是读取快照,以当前排单剩余贴皮为准重新生成,避免新增或移除后数据漂移。
String orderNos = JSON.toJSONString( String orderNos = JSON.toJSONString(
veneerPlanMapper.selectPlanOrderIdList(plan.getId())); veneerPlanMapper.selectPlanOrderIdList(plan.getId()));
int version = plan.getVersion(); int version = plan.getVersion();
int updated = veneerPlanMapper.update(new LambdaUpdateWrapper<OrderVeneerPlanDO>() int updated = veneerPlanMapper.update(new LambdaUpdateWrapper<OrderVeneerPlanDO>()
.eq(OrderVeneerPlanDO::getId, plan.getId()) .eq(OrderVeneerPlanDO::getId, plan.getId())
.in(OrderVeneerPlanDO::getStatus, PLAN_EDITABLE_STATUSES) .in(OrderVeneerPlanDO::getStatus, expectedStatuses)
.eq(OrderVeneerPlanDO::getVersion, version) .eq(OrderVeneerPlanDO::getVersion, version)
.set(reopenCutting, OrderVeneerPlanDO::getStatus,
VeneerPlanStatusEnum.OPENING.getStatus())
.set(reopenCutting, OrderVeneerPlanDO::getProduceTime, null)
.set(reopenCutting, OrderVeneerPlanDO::getFinishTime, null)
.set(OrderVeneerPlanDO::getVeneerNum, statistics.getVeneerNum()) .set(OrderVeneerPlanDO::getVeneerNum, statistics.getVeneerNum())
.set(OrderVeneerPlanDO::getVeneerArea, statistics.getVeneerArea()) .set(OrderVeneerPlanDO::getVeneerArea, statistics.getVeneerArea())
.set(OrderVeneerPlanDO::getOrderNos, orderNos) .set(OrderVeneerPlanDO::getOrderNos, orderNos)
@@ -17,8 +17,7 @@
ovp.sort, ovp.sort,
ovp.process_id AS processId, ovp.process_id AS processId,
ovp.process_name AS processName, ovp.process_name AS processName,
CONCAT_WS('-', NULLIF(v.material, ''), NULLIF(v.color, ''), ovp.source_veneer_id AS sourceVeneerId,
CONCAT(CAST(v.thickness AS CHAR), 'mm')) AS veneerInfo,
ovp.order_nos AS orderNos, ovp.order_nos AS orderNos,
ovp.status, ovp.status,
ovp.is_scheduled AS isScheduled, ovp.is_scheduled AS isScheduled,
@@ -34,9 +33,6 @@
ovp.create_time AS createTime, ovp.create_time AS createTime,
ovp.produce_time AS produceTime ovp.produce_time AS produceTime
FROM order_veneer_plan ovp FROM order_veneer_plan ovp
JOIN veneers v ON v.id = ovp.source_veneer_id
AND v.organ_id = ovp.organ_id
AND v.deleted = false
WHERE ovp.deleted = false WHERE ovp.deleted = false
<if test="req.id != null and req.id != ''"> <if test="req.id != null and req.id != ''">
AND CAST(ovp.id AS CHAR) LIKE CONCAT('%', #{req.id}, '%') AND CAST(ovp.id AS CHAR) LIKE CONCAT('%', #{req.id}, '%')