liu
2026-10-19 31f9b2e3e6a1cffb83c838f1db1d6251b708f983
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/maintenanceplan/MesProMaintenancePlanServiceImpl.java
@@ -2,10 +2,14 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.api.purchase.ErpPurchasePlanApi;
import cn.iocoder.yudao.module.erp.api.purchase.PurchasePlanApi;
import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchasePlanCreateReqDTO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.maintenanceplan.vo.MesProMaintenancePlanImportExcelVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.maintenanceplan.vo.MesProMaintenancePlanImportRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.maintenanceplan.vo.MesProMaintenancePlanPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.maintenanceplan.vo.MesProMaintenancePlanSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
@@ -15,9 +19,11 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.maintenanceplan.MesProMaintenancePlanItemDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.maintenanceplan.MesProMaintenancePlanItemMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.maintenanceplan.MesProMaintenancePlanMapper;
import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderTypeEnum;
import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamService;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
import jakarta.annotation.Resource;
@@ -27,7 +33,9 @@
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -74,9 +82,11 @@
    private MesMdItemService itemService;
    @Resource
    private ErpPurchasePlanApi erpPurchasePlanApi;
    private PurchasePlanApi purchasePlanApi;
    @Resource
    private MesProWorkOrderService workOrderService;
    @Resource
    private MesMdAutoCodeRecordService autoCodeRecordService;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -199,7 +209,7 @@
        createReqDTO.setPlanDate(plan.getPlanDate());
        createReqDTO.setRemark("来源计划: " + plan.getCode());
        createReqDTO.setItems(items);
        return erpPurchasePlanApi.createPurchasePlan(createReqDTO);
        return purchasePlanApi.createPurchasePlan(createReqDTO);
    }
    @Override
@@ -216,6 +226,7 @@
        }
        // 3. 组装工单
        MesProWorkOrderSaveReqVO workOrderReq = new MesProWorkOrderSaveReqVO();
        workOrderReq.setCode(generateWorkOrderCode());
        workOrderReq.setName(plan.getName());
        workOrderReq.setType(convertPlanTypeToWorkOrderType(plan.getPlanType()));
        workOrderReq.setOrderSourceType(MesProWorkOrderSourceTypeEnum.MAINTENANCE_PLAN.getType());
@@ -230,6 +241,70 @@
        updateObj.setWorkOrderId(workOrderId);
        planMapper.updateById(updateObj);
        return workOrderId;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MesProMaintenancePlanImportRespVO importPlanList(List<MesProMaintenancePlanImportExcelVO> importList,
                                                            boolean updateSupport) {
        if (CollUtil.isEmpty(importList)) {
            throw exception(MES_PRO_MAINTENANCE_PLAN_IMPORT_LIST_IS_EMPTY);
        }
        MesProMaintenancePlanImportRespVO respVO = MesProMaintenancePlanImportRespVO.builder()
                .createNames(new ArrayList<>()).updateNames(new ArrayList<>())
                .failureNames(new LinkedHashMap<>()).build();
        // 1. 按计划名称分组(同一计划名称的多行合并为一个计划,每行一条备件/物资明细)
        int rowIndex = 1;
        Map<String, List<MesProMaintenancePlanImportExcelVO>> groupMap = new LinkedHashMap<>();
        for (MesProMaintenancePlanImportExcelVO item : importList) {
            if (StrUtil.isBlank(item.getName())) {
                respVO.getFailureNames().put("第 " + rowIndex + " 行", "计划名称不能为空");
                rowIndex++;
                continue;
            }
            groupMap.computeIfAbsent(item.getName(), k -> new ArrayList<>()).add(item);
            rowIndex++;
        }
        // 2. 逐组处理
        groupMap.forEach((name, rows) -> {
            MesProMaintenancePlanImportExcelVO main = rows.get(0);
            List<MesProMaintenancePlanSaveReqVO.Item> items = new ArrayList<>();
            for (MesProMaintenancePlanImportExcelVO row : rows) {
                if (StrUtil.isBlank(row.getItemCode())) {
                    respVO.getFailureNames().put(name, "物料/备件编码不能为空");
                    return;
                }
                MesMdItemDO item = itemService.getItemByCode(row.getItemCode().trim());
                if (item == null) {
                    respVO.getFailureNames().put(name, "物料/备件编码[" + row.getItemCode() + "]不存在");
                    return;
                }
                MesProMaintenancePlanSaveReqVO.Item it = new MesProMaintenancePlanSaveReqVO.Item();
                it.setItemId(item.getId());
                it.setQuantity(row.getItemQuantity());
                it.setRemark(row.getItemRemark());
                items.add(it);
            }
            MesProMaintenancePlanSaveReqVO reqVO = BeanUtils.toBean(main, MesProMaintenancePlanSaveReqVO.class);
            reqVO.setItems(items);
            MesProMaintenancePlanDO existPlan = planMapper.selectByName(name);
            try {
                if (existPlan == null) {
                    reqVO.setId(null);
                    createPlan(reqVO);
                    respVO.getCreateNames().add(name);
                } else if (updateSupport) {
                    reqVO.setId(existPlan.getId());
                    updatePlan(reqVO);
                    respVO.getUpdateNames().add(name);
                } else {
                    respVO.getFailureNames().put(name, "计划名称已存在");
                }
            } catch (ServiceException e) {
                respVO.getFailureNames().put(name, e.getMessage());
            }
        });
        return respVO;
    }
    /**
@@ -269,6 +344,22 @@
                + String.format("%03d", (int) (Math.random() * 1000));
    }
    /**
     * 生成工单编码
     *
     * 优先使用编码规则;若环境中未配置 PRO_WORK_ORDER_CODE 规则,则降级为时间戳编码,避免生成工单被阻断
     */
    private String generateWorkOrderCode() {
        try {
            return autoCodeRecordService.generateAutoCode(
                    MesMdAutoCodeRuleCodeEnum.PRO_WORK_ORDER_CODE.getCode());
        } catch (Exception e) {
            log.warn("[generateWorkOrderCode] 编码规则 {} 不存在,使用时间戳生成",
                    MesMdAutoCodeRuleCodeEnum.PRO_WORK_ORDER_CODE.getCode(), e);
            return "WO" + DateUtil.format(java.time.LocalDateTime.now(), "yyyyMMddHHmmssSSS");
        }
    }
    private MesProMaintenancePlanDO validatePlanExists(Long id) {
        MesProMaintenancePlanDO plan = planMapper.selectById(id);
        if (plan == null) {