| | |
| | | package com.aps.core.service.impl; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import com.aps.common.core.utils.poi.ExcelUtil; |
| | | import com.aps.common.core.utils.uuid.IdUtils; |
| | | import com.aps.common.core.web.domain.AjaxResult; |
| | | import com.aps.core.domain.ApsPartPlan; |
| | | import com.aps.core.domain.ApsResourceDateStat; |
| | | import com.aps.core.domain.ApsResourceGroup; |
| | | import com.aps.core.mapper.ApsAbnormalProcessAnalysisMapper; |
| | | import com.aps.core.mapper.ApsResourceGroupMapper; |
| | | import com.aps.core.service.IApsAbnormalProcessAnalysisService; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.poi.ss.usermodel.*; |
| | | import org.apache.poi.ss.util.CellRangeAddress; |
| | | import org.apache.poi.util.IOUtils; |
| | | import org.apache.poi.util.Removal; |
| | | import org.apache.poi.xssf.streaming.SXSSFCell; |
| | | import org.apache.poi.xssf.streaming.SXSSFRow; |
| | | import org.apache.poi.xssf.streaming.SXSSFSheet; |
| | | import org.apache.poi.xssf.streaming.SXSSFWorkbook; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import com.aps.core.mapper.ApsPartRouteStatMapper; |
| | | import com.aps.core.domain.ApsPartRouteStat; |
| | | import com.aps.core.service.IApsPartRouteStatService; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import static java.util.stream.Collectors.groupingBy; |
| | | |
| | |
| | | * @author zhl |
| | | * @date 2025-04-11 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class ApsPartRouteStatServiceImpl implements IApsPartRouteStatService |
| | | { |
| | | |
| | | @Autowired |
| | | private ApsPartRouteStatMapper apsPartRouteStatMapper; |
| | | @Autowired |
| | | private ApsResourceGroupMapper resourceGroupMapper; |
| | | @Autowired |
| | | private ApsResourceGroupMapper apsResourceGroupMapper; |
| | | |
| | | @Resource |
| | | private IApsAbnormalProcessAnalysisService analysisService; |
| | | |
| | | /** |
| | | * 查询零件统计表 |
| | |
| | | /** |
| | | * 查询零件工序并更新计划开工日期 |
| | | * */ |
| | | @Transactional |
| | | @Override |
| | | public void updatePartRoutPlanDate() { |
| | | List<ApsPartRouteStat> tempList = apsPartRouteStatMapper.selectPartRoutStat(); |
| | | /*对tempList 按照 workOrderNo 进行分组*/ |
| | | Map<String, List<ApsPartRouteStat>> groupByWorkOrderNo = tempList.stream().collect(groupingBy(ApsPartRouteStat::getWorkOrderNo)); |
| | | /*本次计算批次号*/ |
| | | String batchNum = IdUtils.fastSimpleUUID(); |
| | | apsPartRouteStatMapper.deleteLastBatch(batchNum); |
| | | for (Map.Entry<String, List<ApsPartRouteStat>> entry : groupByWorkOrderNo.entrySet()) { |
| | | /*取出每个零件工单的工艺路线信息*/ |
| | | List<ApsPartRouteStat> apsPartRouteStatList = entry.getValue(); |
| | |
| | | /*临时保存 上一道工序的工序总工时*/ |
| | | ApsPartRouteStat last=null; |
| | | for (int i = 0; i <apsPartRouteStatList.size(); i++) { |
| | | ApsPartRouteStat stat = apsPartRouteStatList.get(0); |
| | | ApsPartRouteStat stat = apsPartRouteStatList.get(i); |
| | | /*判断当前工序 当前工序只有一条*/ |
| | | if (stat.getCurrentProcessNumber().equals(stat.getRoadProcessNumber())) { |
| | | /* 对 stat.getProcessPlanStartDay() 和当前日期 进行对比,只对比到日,不用管十分秒*/ |
| | | if (stat.getProcessPlanStartDay().toLocalDate().isBefore(LocalDateTime.now().toLocalDate())) { |
| | | stat.setProcessPlanStartDay(LocalDateTime.now()); |
| | | LocalDate startLocalDate = LocalDate.ofInstant(stat.getProcessPlanStartDay().toInstant(), ZoneId.systemDefault()); |
| | | LocalDate nowLocalDate = LocalDate.now(); |
| | | if (startLocalDate.isBefore(nowLocalDate)) { |
| | | stat.setProcessPlanStartDay(new Date()); |
| | | } |
| | | } |
| | | /*未开工工序的计划开工日=上一道工序的计划开工日+上一道工序的工序总工时。*/ |
| | | if (stat.getCurrentProcessNumber().compareTo(stat.getRoadProcessNumber()) > 0) { |
| | | if (stat.getCurrentProcessNumber().compareTo(stat.getRoadProcessNumber()) < 0) { |
| | | if (last != null) { |
| | | stat.setProcessPlanStartDay(last.getProcessPlanStartDay().plusHours(last.getProcessTotalTime())); |
| | | LocalDateTime lastStartDate = LocalDateTime.ofInstant(last.getProcessPlanStartDay().toInstant(), ZoneId.systemDefault()); |
| | | lastStartDate.plusHours(last.getProcessTotalTime().longValue()); |
| | | stat.setProcessPlanStartDay(Date.from(lastStartDate.atZone(ZoneId.systemDefault()).toInstant())); |
| | | } |
| | | } |
| | | /*保存上一步计算的 开工日*/ |
| | | last = stat; |
| | | stat.setId(IdUtils.fastUUID().toString()); |
| | | stat.setBatchNumber(batchNum); |
| | | stat.setDelFlag("0"); |
| | | apsPartRouteStatMapper.insertApsPartRouteStat(stat); |
| | | } |
| | | } |
| | | apsPartRouteStatMapper.deleteLastBatch(batchNum); |
| | | /*计算并保存 工序异常信息*/ |
| | | analysisService.batchSaveAbnormalInfo(); |
| | | } |
| | | /** 查询资源日历表 |
| | | */ |
| | | @Override |
| | | public AjaxResult selectResourceDateStat() { |
| | | /*查出所有统计的数据*/ |
| | | AjaxResult result = new AjaxResult(200, "生成成功"); |
| | | List<ApsResourceDateStat> list = apsPartRouteStatMapper.selectResourceDateStat(); |
| | | /*求出计划的最大时间,没有 设置为当前时间+15天*/ |
| | | ApsResourceDateStat apsResourceDateStat = list.stream().max(Comparator.comparing(ApsResourceDateStat::getPlanDay)).orElse(null); |
| | | LocalDate maxPlanDay = LocalDate.now().plus(15, ChronoUnit.DAYS); |
| | | if(apsResourceDateStat!=null){ |
| | | maxPlanDay=apsResourceDateStat.getPlanDay(); |
| | | } |
| | | /*组织出日期表头*/ |
| | | List<String> planDays = new ArrayList<>(); |
| | | LocalDate startDay = LocalDate.now(); |
| | | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | while (startDay .isBefore( maxPlanDay)){ |
| | | planDays.add(startDay.format(formatter)); |
| | | startDay=startDay.plus(1,ChronoUnit.DAYS); |
| | | } |
| | | /*根据日期表头的顺序,组织出每个日期下的统计项目*/ |
| | | List<ApsResourceDateStat> targetList = new ArrayList<>(); |
| | | for (String planDay : planDays) { |
| | | ApsResourceDateStat apsResourceDateStat1 = list.stream() |
| | | .filter(item -> item.getPlanDay().equals(LocalDate.parse(planDay, formatter))) |
| | | .findFirst().orElse(null); |
| | | if(apsResourceDateStat1!=null){ |
| | | targetList.add(apsResourceDateStat1); |
| | | }else{ |
| | | ApsResourceDateStat apsResourceDateStat2 = new ApsResourceDateStat(); |
| | | apsResourceDateStat2.setPlanDay( LocalDate.parse(planDay, formatter)); |
| | | targetList.add(apsResourceDateStat2); |
| | | List<ApsResourceGroup> resourceGroupList = apsResourceGroupMapper.selectApsResourceGroupList(new ApsResourceGroup()); |
| | | if (!list.isEmpty()) { |
| | | /*求出计划的最大时间,没有 设置为当前时间+15天*/ |
| | | ApsResourceDateStat apsResourceDateStat = list.stream().max(Comparator.comparing(ApsResourceDateStat::getPlanDay)).orElse(null); |
| | | LocalDate maxPlanDay = LocalDate.now().plus(15, ChronoUnit.DAYS); |
| | | if (apsResourceDateStat != null) { |
| | | maxPlanDay = apsResourceDateStat.getPlanDay(); |
| | | } |
| | | /*组织出日期表头*/ |
| | | List<String> planDays = new ArrayList<>(); |
| | | LocalDate startDay = LocalDate.now(); |
| | | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | while (!startDay.isAfter(maxPlanDay)) { |
| | | planDays.add(startDay.format(formatter)); |
| | | startDay = startDay.plus(1, ChronoUnit.DAYS); |
| | | } |
| | | /*组织出列头数据*/ |
| | | |
| | | /*准备资源组信息*/ |
| | | List<Map<String, List<ApsResourceDateStat>>> targetList = new ArrayList<>(); |
| | | resourceGroupList.forEach(resourceGroup -> { |
| | | String resourceName=resourceGroup.getResourceGroupName(); |
| | | /*根据日期表头的顺序,组织出每个日期下的统计项目*/ |
| | | Map<String, List<ApsResourceDateStat>> maps = new HashMap<>(Map.of()); |
| | | List<ApsResourceDateStat> currentDaysResouces=new ArrayList<>(); |
| | | for (String planDay : planDays) { |
| | | /*查找当前计划日期下的所有资源组的数据*/ |
| | | Optional<ApsResourceDateStat> first = list.stream() |
| | | .filter(item -> |
| | | item.getPlanDay().equals(LocalDate.parse(planDay, formatter)) |
| | | && item.getResourceGroupName().equals(resourceName) |
| | | ).collect(Collectors.toList()).stream().findFirst(); |
| | | if(first.isPresent()){ |
| | | currentDaysResouces.add(first.get()); |
| | | } |
| | | else { |
| | | ApsResourceDateStat empty = new ApsResourceDateStat(); |
| | | empty.setPlanDay(LocalDate.parse(planDay, formatter)); |
| | | empty.setDesignTimes(resourceGroup.getDevicesQuantity().intValue()*resourceGroup.getTheoryHours().intValue()); |
| | | empty.setRequireTimes(0); |
| | | empty.setResourceName(resourceName); |
| | | empty.setResourceGroupName(resourceName); |
| | | empty.setCapacityLoad(BigDecimal.ZERO); |
| | | currentDaysResouces.add(empty); |
| | | } |
| | | }; |
| | | maps.put(resourceName, currentDaysResouces); |
| | | targetList.add(maps); |
| | | }); |
| | | result.put("planTitle", planDays); |
| | | result.put("planTable", targetList); |
| | | } |
| | | AjaxResult result=new AjaxResult(200,"生成成功") |
| | | .put("planTitle",planDays) |
| | | .put("planTable",targetList); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public void exportExcel(HttpServletResponse response) { |
| | | SXSSFWorkbook wb = new SXSSFWorkbook(500); |
| | | wb.createSheet(); |
| | | wb.setSheetName(0, "零件统计表"); |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
| | | response.setCharacterEncoding("utf-8"); |
| | | |
| | | Map<String, CellStyle> styles = createStyles(wb); |
| | | CellStyle title = styles.get("title"); |
| | | try |
| | | { |
| | | |
| | | AjaxResult stat = selectResourceDateStat(); |
| | | List<String> days = (List<String>) stat.get("planTitle"); |
| | | List<Map<String, List<ApsResourceDateStat>>> table= (List<Map<String, List<ApsResourceDateStat>>>) stat.get("planTable"); |
| | | SXSSFSheet sheet = wb.getSheetAt(0); |
| | | /*填写日期列 和 工时列*/ |
| | | SXSSFRow rowDay = sheet.createRow(0); |
| | | SXSSFRow rowTitle = sheet.createRow(1); |
| | | |
| | | SXSSFCell daytitle = rowDay.createCell(0); |
| | | daytitle.setCellValue("日期"); |
| | | daytitle.setCellStyle(title); |
| | | SXSSFCell titleCell = rowTitle.createCell(0); |
| | | titleCell.setCellValue("资源组"); |
| | | titleCell.setCellStyle(title); |
| | | |
| | | for (int i = 0; i < days.size(); i++) { |
| | | SXSSFCell dateCell = rowDay.createCell(i * 3 + 1); |
| | | SXSSFCell designHoursCell = rowTitle.createCell(i * 3 + 1); |
| | | SXSSFCell requireHoursCell = rowTitle.createCell(i * 3 + 2); |
| | | SXSSFCell loadCell = rowTitle.createCell(i * 3 + 3); |
| | | dateCell.setCellValue(days.get(i)); |
| | | designHoursCell.setCellValue("设计工时"); |
| | | requireHoursCell.setCellValue("需求工时"); |
| | | loadCell.setCellValue("产能负荷"); |
| | | /*set cell style*/ |
| | | dateCell.setCellStyle(title); |
| | | designHoursCell.setCellStyle(title); |
| | | requireHoursCell.setCellStyle(title); |
| | | loadCell.setCellStyle(title); |
| | | |
| | | /*合并日期单元格*/ |
| | | sheet.addMergedRegion( new CellRangeAddress(0, 0, i*3+1, i*3+3)); |
| | | } |
| | | for (int i = 0; i < table.size(); i++) { |
| | | Map<String, List<ApsResourceDateStat>> resourceList = table.get(i); |
| | | /*创建数据行*/ |
| | | SXSSFRow dataRow = sheet.createRow(i+2); |
| | | for( Map.Entry<String, List<ApsResourceDateStat>> entry : resourceList.entrySet()){ |
| | | String resourceName = entry.getKey(); |
| | | List<ApsResourceDateStat> resourceDateStats = entry.getValue(); |
| | | dataRow.createCell(0).setCellValue(resourceName); |
| | | for (int j = 0; j < resourceDateStats.size(); j++) { |
| | | ApsResourceDateStat apsResourceDateStat = resourceDateStats.get(j); |
| | | dataRow.createCell(j*3+1).setCellValue(apsResourceDateStat.getDesignTimes()); |
| | | dataRow.createCell(j*3+2).setCellValue(apsResourceDateStat.getRequireTimes()); |
| | | dataRow.createCell(j*3+3).setCellValue(apsResourceDateStat.getCapacityLoad().doubleValue()+"%"); |
| | | } |
| | | } |
| | | |
| | | } |
| | | wb.write(response.getOutputStream()); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | log.error("导出Excel异常{}", e.getMessage()); |
| | | } |
| | | finally |
| | | { |
| | | IOUtils.closeQuietly(wb); |
| | | } |
| | | |
| | | } |
| | | private Map<String,CellStyle> createStyles(SXSSFWorkbook wb) |
| | | { |
| | | Map<String,CellStyle> styles=new HashMap<>(); |
| | | CellStyle style = wb.createCellStyle(); |
| | | style.setAlignment(HorizontalAlignment.CENTER); |
| | | style.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | Font titleFont = wb.createFont(); |
| | | titleFont.setFontName("Arial"); |
| | | titleFont.setFontHeightInPoints((short) 12); |
| | | titleFont.setBold(true); |
| | | style.setFont(titleFont); |
| | | DataFormat dataFormat = wb.createDataFormat(); |
| | | style.setDataFormat(dataFormat.getFormat("@")); |
| | | styles.put("title", style); |
| | | return styles; |
| | | } |
| | | |
| | | |
| | | } |