chenhj
2026-04-24 8b749305a8e8c3f4bf669f6980edf2bbb7bfa9c7
src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -26,7 +27,9 @@
import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -135,12 +138,11 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(ProductionPlanDto dto) {
        if (StringUtils.isBlank(dto.getApplyNo())) {
            throw new ServiceException("新增失败,申请单编号不能为空");
        }
        checkApplyNoUnique(dto.getApplyNo(), null);
        if (StringUtils.isBlank(dto.getMpsNo())) {
            dto.setMpsNo(generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
        }else checkMpsNoUnique(dto.getMpsNo(), null);
        dto.setStatus(PLAN_STATUS_WAIT);
        dto.setSource("内部");
        return productionPlanMapper.insert(dto) > 0;
    }
@@ -160,21 +162,21 @@
            throw new BaseException("编辑失败,该生产计划已下发或部分下发,禁止编辑");
        }
        if (StringUtils.isNotBlank(dto.getApplyNo()) && !dto.getApplyNo().equals(old.getApplyNo())) {
            checkApplyNoUnique(dto.getApplyNo(), dto.getId());
        if (StringUtils.isNotBlank(dto.getMpsNo()) && !dto.getMpsNo().equals(old.getMpsNo())) {
            checkMpsNoUnique(dto.getMpsNo(), dto.getId());
        }
        return productionPlanMapper.updateById(dto) > 0;
    }
    private void checkApplyNoUnique(String applyNo, Long excludeId) {
    private void checkMpsNoUnique(String mpsNo, Long excludeId) {
        LambdaQueryWrapper<ProductionPlan> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ProductionPlan::getApplyNo, applyNo);
        wrapper.eq(ProductionPlan::getMpsNo, mpsNo);
        if (excludeId != null) {
            wrapper.ne(ProductionPlan::getId, excludeId);
        }
        if (productionPlanMapper.selectCount(wrapper) > 0) {
            throw new ServiceException("申请单编号 " + applyNo + " 已存在");
            throw new ServiceException("生产计划号 " + mpsNo + " 已存在");
        }
    }
@@ -202,7 +204,6 @@
        if (file == null || file.isEmpty()) {
            throw new ServiceException("导入数据不能为空");
        }
        ExcelUtil<ProductionPlanImportDto> excelUtil = new ExcelUtil<>(ProductionPlanImportDto.class);
        List<ProductionPlanImportDto> list;
        try {
@@ -210,77 +211,54 @@
        } catch (Exception e) {
            throw new ServiceException("Excel解析失败");
        }
        if (list == null || list.isEmpty()) {
            throw new ServiceException("Excel没有数据");
        }
        Set<String> applyNos = new HashSet<>();
        Set<String> materialCodes = new HashSet<>();
        Set<String> mpsNos = new HashSet<>();
        for (int i = 0; i < list.size(); i++) {
            ProductionPlanImportDto dto = list.get(i);
            String applyNo = dto.getApplyNo();
            String materialCode = dto.getMaterialCode();
            if (StringUtils.isEmpty(applyNo)) {
                throw new ServiceException("导入失败:第 " + (i + 2) + " 行申请单编号不能为空");
            String mpsNo = dto.getMpsNo();
            if (StringUtils.isEmpty(mpsNo)) {
                generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
            }
            if (!applyNos.add(applyNo)) {
                throw new ServiceException("导入失败:Excel 中存在重复的申请单编号 " + applyNo);
            if (!mpsNos.add(mpsNo)) {
                throw new ServiceException("导入失败:Excel 中存在重复的申请单编号 " + mpsNo);
            }
            if (StringUtils.isEmpty(materialCode)) {
                throw new ServiceException("导入失败:第 " + (i + 2) + " 行物料编码不能为空");
            }
            String strength = dto.getStrength();
            if (StringUtils.isNotEmpty(strength) && !"A3.5".equals(strength) && !"A5.0".equals(strength)) {
                throw new ServiceException("导入失败:第 " + (i + 2) + " 行强度只能是 A3.5 或 A5.0");
            }
            materialCodes.add(materialCode);
        }
        Long existApplyNoCount = baseMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery()
                .in(ProductionPlan::getApplyNo, applyNos));
                .in(ProductionPlan::getMpsNo, mpsNos));
        if (existApplyNoCount > 0) {
            List<String> existApplyNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery()
                            .in(ProductionPlan::getApplyNo, applyNos))
            List<String> existMpsNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery()
                            .in(ProductionPlan::getMpsNo, mpsNos))
                    .stream()
                    .map(ProductionPlan::getApplyNo)
                    .map(ProductionPlan::getMpsNo)
                    .collect(Collectors.toList());
            throw new ServiceException("导入失败,申请单编号已存在: " + String.join(", ", existApplyNos));
            throw new ServiceException("导入失败,生产计划号已存在: " + String.join(", ", existMpsNos));
        }
        LocalDateTime now = LocalDateTime.now();
        List<ProductionPlan> entityList = list.stream().map(dto -> {
            ProductionPlan entity = new ProductionPlan();
            BeanUtils.copyProperties(dto, entity);
            entity.setStatus(PLAN_STATUS_WAIT);
            entity.setSource("内部");
            entity.setCreateTime(now);
            entity.setUpdateTime(now);
            return entity;
        }).collect(Collectors.toList());
        this.saveBatch(entityList);
    }
    @Override
    public void exportProdData(HttpServletResponse response, List<Long> ids) {
        List<ProductionPlan> list;
        if (ids != null && !ids.isEmpty()) {
            list = baseMapper.selectBatchIds(ids);
        } else {
            list = baseMapper.selectList(null);
        }
        List<ProductionPlanDto> list = productionPlanMapper.selectWithMaterialByIds(ids);
        List<ProductionPlanImportDto> exportList = new ArrayList<>();
        for (ProductionPlan entity : list) {
        for (ProductionPlanDto entity : list) {
            ProductionPlanImportDto dto = new ProductionPlanImportDto();
            BeanUtils.copyProperties(entity, dto);
            exportList.add(dto);
        }
        ExcelUtil<ProductionPlanImportDto> util = new ExcelUtil<>(ProductionPlanImportDto.class);
        util.exportExcel(response, exportList, "销售生产需求数据");
        util.exportExcel(response, exportList, "主生产计划");
    }
    private String formatPlanIds(List<Long> planIds) {
@@ -290,4 +268,22 @@
                .map(String::valueOf)
                .collect(Collectors.joining(",", "[", "]"));
    }
    private String generateNextPlanNo(String datePrefix) {
        QueryWrapper<ProductionPlan> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("mps_no", "JH" + datePrefix);
        queryWrapper.orderByDesc("mps_no");
        queryWrapper.last("LIMIT 1");
        ProductionPlan latestPlan = productionPlanMapper.selectOne(queryWrapper);
        int sequence = 1;
        if (latestPlan != null && latestPlan.getMpsNo() != null && !latestPlan.getMpsNo().isEmpty()) {
            String sequenceStr = latestPlan.getMpsNo().substring(("JH" + datePrefix).length());
            try {
                sequence = Integer.parseInt(sequenceStr) + 1;
            } catch (NumberFormatException e) {
                sequence = 1;
            }
        }
        return "JH" + datePrefix + String.format("%04d", sequence);
    }
}