sfd
2025-05-26 2a64b537e8e3bce9ce030585a3da17d48379c0ad
aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlate/ApsPlateProcessShopStatServiceImpl.java
@@ -2,11 +2,15 @@
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.aps.common.core.utils.DateUtils;
import com.aps.common.core.utils.bean.BeanUtils;
import com.aps.common.core.web.domain.AjaxResult;
import com.aps.common.security.utils.DictUtils;
import com.aps.common.security.utils.SecurityUtils;
@@ -16,9 +20,14 @@
import com.aps.core.domain.ApsPlate.ApsPlateProcessShopStat;
import com.aps.core.domain.ApsPlate.ApsPlateProcessStat;
import com.aps.core.mapper.*;
import com.aps.core.service.ApsPlate.IApsPlateProcessStatService;
import com.aps.system.api.domain.SysDictData;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
@@ -53,6 +62,9 @@
    @Resource
    private ApsPlatePlanMapper apsPlatePlanMapper;
    @Autowired
    private IApsPlateProcessStatService apsPlateProcessStatService;
    /**
@@ -126,61 +138,73 @@
    /**
     * 保存钣金车间统计
     */
    @Transactional
    @Transactional( rollbackFor =Exception.class)
    @Override
    public void saveShopStat() {
        try {
            // 开始之前先删除所有历史数据
        // 定义该功能使用数据源为南通的工厂
        final String plant = "FORTUNA";
        final String major="BJ";
        // 查询相关数据
        ApsPlatePlan platePlan = new ApsPlatePlan();
        platePlan.setPlant(plant);
        log.info("开始执行钣金计划大表");
        List<ApsPlatePlan> planList = apsPlatePlanMapper.selectApsPlatePlanList(platePlan);
        ApsShop apsShop = new ApsShop();
        apsShop.setPlantCode(plant);
        List<ApsShop> shopList = shopMapper.selectApsShopList(apsShop);
        ApsStandardProcess process = new ApsStandardProcess();
        process.setPlant(plant);
        process.setMajor(major);
        List<ApsStandardProcess> shopProcesses = standardProcessMapper.selectApsStandardProcessList(process);
        if (!planList.isEmpty() &&  !shopList.isEmpty() &&  !shopProcesses.isEmpty()) {
            log.info("钣金计划大表:删除所有历史数据");
            apsPlateProcessStatMapper.deleteAll();
            apsPlateProcessShopStatMapper.deleteAll();
            // 定义该功能使用数据源为南通的工厂
            final String plant = "FORTUNA";
            final String major="钣金";
            // 查询相关数据
            ApsPlatePlan platePlan = new ApsPlatePlan();
            platePlan.setPlant(plant);
            List<ApsPlatePlan> planList = apsPlatePlanMapper.selectApsPlatePlanList(platePlan);
            List<ApsPlateProcessStat> statList = apsPlateProcessStatMapper.selectApsPlateProcessStatList(new ApsPlateProcessStat());
            ApsShop apsShop = new ApsShop();
            apsShop.setPlantCode(plant);
            List<ApsShop> shopList = shopMapper.selectApsShopList(apsShop);
            ApsStandardProcess process = new ApsStandardProcess();
            process.setPlant(plant);
            process.setMajor(major);
            List<ApsStandardProcess> shopProcesses = standardProcessMapper.selectApsStandardProcessList(process);
            if (planList.isEmpty() || shopList.isEmpty() || shopProcesses.isEmpty()) {
                log.warn("计划列表、车间列表或工序列表为空,无法生成统计信息");
                return;
            }
            // 构建车间名称到工序名称的映射
            Map<String, List<String>> shopToProcessNames = shopProcesses.stream()
            log.info("钣金计划大表:推算倒排钣金工序计划完工日期和计划开工时间");
            List<ApsPlateProcessStat> statList =apsPlateProcessStatService.computePlateProcessStat();
                // 构建车间名称到工序名称的映射
            Map<String, List<String>> shopToProcessNames = shopProcesses.stream().filter(x -> null!=x.getWorkShop())
                    .collect(Collectors.groupingBy(ApsStandardProcess::getWorkShop,
                            Collectors.mapping(ApsStandardProcess::getProcessName, Collectors.toList())
                    ));
            // 批量插入统计数据
            log.info("钣金计划大表:计算每个工单中每个车间的开始、结束时间");
            List<ApsPlateProcessShopStat> statsToInsert = new ArrayList<>();
            for (ApsPlatePlan plan : planList) {
                for (ApsShop shop : shopList) {
            log.info("钣金计划大表V1:开始计算每个工单车间工时");
            planList.stream().parallel().forEach(plan -> {
                shopList.stream().parallel().forEach(shop -> {
                    ApsPlateProcessShopStat stat = createShopStat(plan, shop, shopToProcessNames, statList);
                    statsToInsert.add(stat);
                }
                });
            });
            log.info("钣金计划大表:批量保存工序开工和完工时间");
            List<List<ApsPlateProcessStat>> processStatBatchList = ListUtil.split(statList, 1000);
            processStatBatchList.stream().parallel().forEach(batch -> apsPlateProcessStatMapper.batchInsertPlateStat(batch));
            log.info("钣金计划大表:批量保存工单-车间时间信息");
            List<List<ApsPlateProcessShopStat>> shopStatBatchList = ListUtil.split(statsToInsert, 1000);
            shopStatBatchList.stream().parallel().forEach(batch -> apsPlateProcessShopStatMapper.batchInsert(batch));
        }else {
            if(shopProcesses.isEmpty()){
                log.error("钣金计划大表:未找到标准工序数据!");
                throw  new RuntimeException("未找到标准工序数据!");
            }
            // 批量插入以提高性能
            if (!statsToInsert.isEmpty()) {
                int batchSize = 1000;
                for (int i = 0; i < statsToInsert.size(); i += batchSize) {
                    int end = Math.min(i + batchSize, statsToInsert.size());
                    List<ApsPlateProcessShopStat> batch = statsToInsert.subList(i, end);
                    apsPlateProcessShopStatMapper.batchInsert(batch);
                }
            if(shopList.isEmpty()){
                log.error("钣金计划大表:未找到车间数据!");
                throw  new RuntimeException("未找到车间数据!");
            }
        } catch (Exception e) {
            log.error("保存钣金车间统计时发生异常", e);
            throw new RuntimeException("保存钣金车间统计失败", e);
            if(planList.isEmpty()){
                log.error("钣金计划大表:未找到工单数据!");
                throw  new RuntimeException("未找到工单数据!");
            }
        }
        log.info("钣金计划大表:完成");
    }
    /**
@@ -199,7 +223,6 @@
        stat.setWorkCenter(plan.getWorkCenter());
        stat.setProcessNumber(plan.getProcessNumber());
        try {
            List<String> processNames = shopToProcessNames.getOrDefault(shopName, Collections.emptyList());
            if (!processNames.isEmpty()) {
@@ -241,7 +264,8 @@
                }
            }
        } catch (Exception e) {
            log.error("computer error:"+ JSONObject.toJSONString(stat));
            log.error("钣金计划大表 error:"+ JSONObject.toJSONString(stat));
            throw new RuntimeException("计算车间统计数据异常!");
        }
        return stat;
    }
@@ -257,7 +281,7 @@
        ApsShop apsShop = new ApsShop();
        apsShop.setPlantCode(PLANT_CODE);
        apsShop.setStatus("1");
        // 获取车间列表并处理空值
        List<String> shopList = Optional.ofNullable(shopMapper.selectApsShopList(apsShop))
                .orElse(Collections.emptyList())
@@ -266,8 +290,7 @@
                .toList();
        // 获取计划列表和状态列表
        List<ApsPlatePlan> planList = Optional.ofNullable(apsPlatePlanMapper.selectApsPlatePlanList(platePlan))
                .orElse(Collections.emptyList());
        List<ApsPlateProcessShopPlanStat> planList = apsPlateProcessShopStatMapper.selectPlatePlanBaseTable();
        List<ApsPlateProcessShopStat> shopStates = Optional.ofNullable(apsPlateProcessShopStatMapper.selectApsPlateProcessShopStatList(new ApsPlateProcessShopStat()))
                .orElse(Collections.emptyList());
@@ -281,26 +304,22 @@
        List<SysDictData> documentStatusDic = DictUtils.getDictCache("aps_document_status");
        // 构建结果列表
        List<ApsPlateProcessShopPlanStat> shopPlanStats = planList.stream()
                .map(plan -> {
                    ApsPlateProcessShopPlanStat shopPlanStat = new ApsPlateProcessShopPlanStat();
                    BeanUtils.copyProperties(plan, shopPlanStat); // 确保目标对象是合法的单个对象实例
        planList.stream().parallel().forEach(
                 plan -> {
                    // 根据 docNo 获取对应的 shopStatList
                    List<ApsPlateProcessShopStat> shopStatList = shopStatesByDocNo.getOrDefault(plan.getDocumentNumber(), Collections.emptyList());
                    shopPlanStat.setDeptPlans(shopStatList);
                    plan.setDeptPlans(shopStatList);
                    if (businessTypeDic != null) {
                        businessTypeDic.stream().filter(x -> x.getDictValue().equals(plan.getBusinessType())).findFirst()
                                .ifPresent(sysDictData -> shopPlanStat.setBusinessType(sysDictData.getDictLabel()));
                                .ifPresent(sysDictData -> plan.setBusinessType(sysDictData.getDictLabel()));
                    }
                    if (documentStatusDic != null) {
                        documentStatusDic.stream().filter(x->x.getDictValue().equals(plan.getDocumentStatus()))
                                .findFirst().ifPresent(sysDictData -> shopPlanStat.setDocumentStatus(sysDictData.getDictLabel()));
                                .findFirst().ifPresent(sysDictData -> plan.setDocumentStatus(sysDictData.getDictLabel()));
                    }
                    return shopPlanStat;
                }).toList();
        });
        // 构建返回结果
        AjaxResult success = AjaxResult.success(shopPlanStats);
        AjaxResult success = AjaxResult.success(planList);
        success.put("shopNames", shopList);
        return success;
    }
@@ -314,7 +333,7 @@
        response.setCharacterEncoding("utf-8");
        Map<String, CellStyle> styles = createStyles(wb);
        CellStyle title = styles.get("title");
        CellStyle titleStyle = styles.get("title");
        try
        {
@@ -324,222 +343,58 @@
            SXSSFSheet sheet = wb.getSheetAt(0);
            /*填写日期列 和 工时列*/
            SXSSFRow rowTitle = sheet.createRow(0);
            SXSSFCell mainPartNumberTitle = rowTitle.createCell(0);
            mainPartNumberTitle.setCellValue("主件料号");
            mainPartNumberTitle.setCellStyle(title);
            SXSSFCell businessTypeTitle = rowTitle.createCell(1);
            businessTypeTitle.setCellValue("业务类型");
            businessTypeTitle.setCellStyle(title);
            SXSSFCell documentNumberTitle = rowTitle.createCell(2);
            documentNumberTitle.setCellValue("单据号");
            documentNumberTitle.setCellStyle(title);
            SXSSFCell requirementTypeTitle = rowTitle.createCell(3);
            requirementTypeTitle.setCellValue("需求分类");
            requirementTypeTitle.setCellStyle(title);
            SXSSFCell documentStatusTitle = rowTitle.createCell(4);
            documentStatusTitle.setCellValue("单据状态");
            documentStatusTitle.setCellStyle(title);
            SXSSFCell approveDateTitle = rowTitle.createCell(5);
            approveDateTitle.setCellValue("审核时间");
            approveDateTitle.setCellStyle(title);
            SXSSFCell workCenterTitle = rowTitle.createCell(6);
            workCenterTitle.setCellValue("当前工序");
            workCenterTitle.setCellStyle(title);
            SXSSFCell departmentTitle = rowTitle.createCell(7);
            departmentTitle.setCellValue("当前工序负责人");
            departmentTitle.setCellStyle(title);
            SXSSFCell crtPcsStsTitle = rowTitle.createCell(8);
            crtPcsStsTitle.setCellValue("当前工序状态");
            crtPcsStsTitle.setCellStyle(title);
            SXSSFCell nextProcessTitle = rowTitle.createCell(9);
            nextProcessTitle.setCellValue("下一工序");
            nextProcessTitle.setCellStyle(title);
            Map<Integer, String> FrontTitleMap = initFrontTitle(shopNames);
            FrontTitleMap.forEach((index, titleName) -> {
                createCell(rowTitle, index, titleName, titleStyle);
            });
            SXSSFCell nextProcessDeparmentTitle = rowTitle.createCell(10);
            nextProcessDeparmentTitle.setCellValue("下一工序负责人");
            nextProcessDeparmentTitle.setCellStyle(title);
            SXSSFCell itemNumberTitle = rowTitle.createCell(11);
            itemNumberTitle.setCellValue("料号");
            itemNumberTitle.setCellStyle(title);
            SXSSFCell drawingNoTitle = rowTitle.createCell(12);
            drawingNoTitle.setCellValue("图号");
            drawingNoTitle.setCellStyle(title);
            SXSSFCell versionNumberTitle = rowTitle.createCell(13);
            versionNumberTitle.setCellValue("版本号");
            versionNumberTitle.setCellStyle(title);
            SXSSFCell lowNumTitle = rowTitle.createCell(14);
            lowNumTitle.setCellValue("低阶码");
            lowNumTitle.setCellStyle(title);
            SXSSFCell productionQuantityTitle = rowTitle.createCell(15);
            productionQuantityTitle.setCellValue("生产数量");
            productionQuantityTitle.setCellStyle(title);
            SXSSFCell planSendDateTitle = rowTitle.createCell(16);
            planSendDateTitle.setCellValue("工单计划下发时间");
            planSendDateTitle.setCellStyle(title);
            SXSSFCell planEndDayTitle = rowTitle.createCell(17);
            planEndDayTitle.setCellValue("系统完工时间");
            planEndDayTitle.setCellStyle(title);
            String firstShopName = shopNames.get(0);
            SXSSFCell firstShopBeginDateTitle = rowTitle.createCell(18);
            firstShopBeginDateTitle.setCellValue(firstShopName+"开工时间");
            firstShopBeginDateTitle.setCellStyle(title);
            SXSSFCell firstShopEndDateTitle = rowTitle.createCell(19);
            firstShopEndDateTitle.setCellValue(firstShopName+"完工时间");
            firstShopEndDateTitle.setCellStyle(title);
            /*焊接件齐套*/
            SXSSFCell hanJieQiTaoTitle= rowTitle.createCell(20);
            hanJieQiTaoTitle.setCellValue("焊接件齐套开始时间");
            hanJieQiTaoTitle.setCellStyle(title);
            int i1 = 19;
            for (int i = 1; i < shopNames.size(); i++) {
                String shopName = shopNames.get(i);
                SXSSFCell beginDateCell = rowTitle.createCell(i * 2 + i1);
                SXSSFCell endDateCell = rowTitle.createCell(i * 2 + i1+1);
                beginDateCell.setCellValue(shopName+"开工时间");
                endDateCell.setCellValue(shopName+"完工时间");
                beginDateCell.setCellStyle(title);
                endDateCell.setCellStyle(title);
            }
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (int i = 0; i < table.size(); i++) {
                ApsPlateProcessShopPlanStat plan = table.get(i);
                //JSONObject jsonObject = (JSONObject) JSONObject.toJSON(plan);
                ObjectMapper mapper = new ObjectMapper();
                ObjectNode node = mapper.valueToTree(plan);
                SXSSFRow dataRow  = sheet.createRow(i+1);
                //主件料号
                SXSSFCell mainPartNumberCell = dataRow.createCell(0);
                mainPartNumberCell.setCellValue(plan.getMainPartNumber());
                //业务类型;
                SXSSFCell businessTypeCell= dataRow.createCell(1);
                businessTypeCell.setCellValue(plan.getBusinessType());
                LinkedHashMap<String,String>  frontTitles= frontTitleName();
                ArrayList<Map.Entry<String, String>> frontTitlesList = new ArrayList<Map.Entry<String, String>>(
                        frontTitles.entrySet());
                //单据号;
                SXSSFCell documentNumberCell = dataRow.createCell(2);
                documentNumberCell.setCellValue(plan.getDocumentNumber());
                for (int i1 = 0; i1 < frontTitlesList.size(); i1++) {
                //需求分类;
                SXSSFCell requirementTypeCell = dataRow.createCell(3);
                requirementTypeCell.setCellValue(plan.getRequirementType());
                    Map.Entry<String, String> entry = frontTitlesList.get(i1);
                    String filedKey = entry.getKey();
                    String fieldValue= node.get(filedKey).textValue();
                    createCell(dataRow, i1,fieldValue , null);
                }
                // 单据状态
                SXSSFCell documentStatusCell = dataRow.createCell(4);
                documentStatusCell.setCellValue(plan.getDocumentStatus());
                // 审核时间
                SXSSFCell approveDateCell = dataRow.createCell(5);
                approveDateCell.setCellValue("");
                //当前工序
                SXSSFCell workCenterCell = dataRow.createCell(6);
                workCenterCell.setCellValue(plan.getWorkCenter());
                //当前工序负责人;
                SXSSFCell departmentCell = dataRow.createCell(7);
                departmentCell.setCellValue(plan.getDepartment());
                /*当前工序状态*/
                SXSSFCell crtPcsStsCell = dataRow.createCell(8);
                crtPcsStsCell.setCellValue(plan.getOpStatus());
                //下一工序
                SXSSFCell nextProcessCell = dataRow.createCell(9);
                nextProcessCell.setCellValue(plan.getNextOpName());
                //下一工序工序负责人
                SXSSFCell nextProcessDeparmentCell = dataRow.createCell(10);
                nextProcessDeparmentCell.setCellValue(plan.getNextProcessDeparment());
                //料号
                SXSSFCell itemNumberCell = dataRow.createCell(11);
                itemNumberCell.setCellValue(plan.getItemNumber());
                // 图号
                SXSSFCell drawingNoCell = dataRow.createCell(12);
                drawingNoCell.setCellValue(plan.getDrawingNo());
               //版本号
                SXSSFCell versionNumberCell = dataRow.createCell(13);
                versionNumberCell.setCellValue(plan.getVersionNumber());
                //低阶码
                SXSSFCell lowNumCell = dataRow.createCell(14);
                lowNumCell.setCellValue("");
                //生产数量
                SXSSFCell productionQuantityCell = dataRow.createCell(15);
                productionQuantityCell.setCellValue(plan.getProductionQuantity().toString());
                //工单计划下发时间
                SXSSFCell planSendDateCell = dataRow.createCell(16);
                planSendDateCell.setCellValue("");
                //系统完工时间
                SXSSFCell planEndDayCell = dataRow.createCell(17);
                planEndDayCell.setCellValue(dateFormat.format(plan.getPlanEndDay()));
                SXSSFCell firstShopBeginDateCell = dataRow.createCell(18);
                SXSSFCell firstShopEndDateCell = dataRow.createCell(19);
                plan.getDeptPlans().stream().filter(x->x.getShopName().equals(firstShopName)).findFirst().ifPresent(x->{
                    firstShopBeginDateCell.setCellValue(x.getPlanStartDate());
                    firstShopEndDateCell.setCellValue(x.getPlanEndDate());
                });
                /*焊接件齐套*/
                SXSSFCell hanJieQiTaoCell = dataRow.createCell(20);
                hanJieQiTaoCell.setCellValue("");
                for (int j = 1; j< shopNames.size(); j++) {
                    String shopName = shopNames.get(j);
                    SXSSFCell beginDateCell = dataRow.createCell(j * 2 + i1);
                    SXSSFCell endDateCell = dataRow.createCell(j * 2 + i1+1);
                int shopBeginIndex = frontTitlesList.size();
                for (int j = 0; j< shopNames.size(); j++) {
                    String shopName = shopNames.get(0);
                    SXSSFCell beginDateCell = dataRow.createCell(j * 2 + shopBeginIndex);
                    SXSSFCell endDateCell = dataRow.createCell(j * 2 + shopBeginIndex+1);
                    plan.getDeptPlans().stream().filter(x->x.getShopName().equals(shopName)).findFirst().ifPresent(x->{
                        beginDateCell.setCellValue(x.getPlanStartDate());
                        endDateCell.setCellValue(x.getPlanEndDate());
                    });
                }
                LinkedHashMap<String,String>  backTitles= backTitleName();
                ArrayList<Map.Entry<String, String>> backTitlesList = new ArrayList<Map.Entry<String, String>>(
                        backTitles.entrySet());
                int backBeginIndex = shopBeginIndex+shopNames.size()*2;
                for (int i1 = 0; i1 < backTitlesList.size(); i1++) {
                    Map.Entry<String, String> entry = backTitlesList.get(i1);
                    String filedKey = entry.getKey();
                    String fieldValue= node.get(filedKey).textValue();
                    createCell(dataRow, i1+backBeginIndex,fieldValue , null);
                }
            }
            for (int i = 0; i <  rowTitle.getLastCellNum(); i++) {
                sheet.setColumnWidth(i, 20 * 256);
            }
            wb.write(response.getOutputStream());
        }
        catch (Exception e)
@@ -552,6 +407,79 @@
        }
    }
    private  LinkedHashMap<String,String>  frontTitleName(){
        LinkedHashMap<String,String> map = new LinkedHashMap<>();
        map.put("mainPartNumber","主件料号");
        map.put("customer","主件客户");
        map.put("requireTrackId","建树行");
        map.put("businessType","业务类型");
        map.put("documentNumber","单据号");
        map.put("itemNumber","料号");
        map.put("drawingNo","图号");
        map.put("versionNumber","版本号");
        map.put("lowOrderCode","低阶码");
        map.put("productionQuantity","生产数量");
        map.put("requirementType","需求分类");
        map.put("documentStatus","单据状态");
        map.put("approveOn","审核时间");
        map.put("processNumber","工序号");
        map.put("workCenter","当前工序");
        map.put("department","当前工序责任人");
        map.put("opStatus","状态");
        map.put("nextOpName","下一道工序");
        map.put("planEndDay","系统完工时间");
        return map;
    }
    private LinkedHashMap<String,String>  backTitleName(){
        LinkedHashMap<String,String> map = new LinkedHashMap<>();
        map.put("orderCreateTime","工单创建时间");
        map.put("startWorkDate","工单开工时间");
        map.put("remainedProcess","剩余工序");
        return map;
    }
    private  Map<Integer,String> initFrontTitle(List<String> shopNames) {
        Map<Integer,String> map = new HashMap<>();
        Map<String,String>  frontTitles= frontTitleName();
        AtomicInteger index= new AtomicInteger();
        frontTitles.forEach((key,value)->{
            map.put(index.get(), value);
            index.getAndIncrement();
        });
        for (int i = 0; i < shopNames.size(); i++) {
            map.put(i * 2 + index.get(),shopNames.get(i) + "开始时间");
            map.put(i * 2 + index.get()+1,shopNames.get(i) + "结束时间");
        }
        Map<String,String>  backTitles= backTitleName();
        AtomicInteger begBackIndex= new AtomicInteger(frontTitles.size() + shopNames.size() * 2);
        backTitles.forEach((key,value)->{
            map.put(begBackIndex.get(),value);
            begBackIndex.getAndIncrement();
        });
        return map;
    }
    private static void createCell(SXSSFRow rowTitle, int column, String titleName, CellStyle cellStyle) {
        SXSSFCell cell = rowTitle.createCell(column);
        cell.setCellValue(titleName);
        if(null!=cellStyle){
            cell.setCellStyle(cellStyle);
        }
    }
    private Map<String,CellStyle> createStyles(SXSSFWorkbook wb)
    {
        Map<String,CellStyle> styles=new HashMap<>();