package com.aps.core.service.impl;
|
|
import cn.hutool.core.util.IdUtil;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.aps.common.core.utils.DateUtils;
|
import com.aps.common.core.utils.uuid.IdUtils;
|
import com.aps.common.security.utils.SecurityUtils;
|
import com.aps.core.domain.*;
|
import com.aps.core.domain.ApsPlate.ApsPlateStandardRequireError;
|
import com.aps.core.mapper.*;
|
import com.aps.core.service.IApsGasMaterialUsageService;
|
import com.aps.core.service.IApsGasPipingRouteStatService;
|
import com.aps.core.service.IApsStandardProcessService;
|
import com.aps.core.mapper.ApsPlateStandardRequireErrorMapper;
|
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.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.BeanUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.text.SimpleDateFormat;
|
import java.time.*;
|
import java.time.format.DateTimeFormatter;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static java.util.stream.Collectors.groupingBy;
|
|
/**
|
* 气体管路产能负载统计Service业务层处理
|
*
|
* @author hjy
|
* @date 2025-04-24
|
*/
|
@Slf4j
|
@Service
|
public class ApsGasPipingRouteStatServiceImpl implements IApsGasPipingRouteStatService
|
{
|
@Autowired
|
private ApsGasPipingRouteStatMapper apsGasPipingRouteStatMapper;
|
|
@Autowired
|
private ApsGasPipingPlanMapper apsGasPipingPlanMapper;
|
|
@Autowired
|
private ApsGasPipelineCapacityPlanMapper apsGasPipelineCapacityPlanMapper;
|
|
@Autowired
|
private IApsGasMaterialUsageService apsGasMaterialUsageService;
|
|
@Autowired
|
private IApsStandardProcessService apsStandardProcessService;
|
|
@Autowired
|
private ApsPlateStandardRequireErrorMapper apsPlateStandardRequireErrorMapper;
|
|
/**
|
* 查询气体管路产能负载统计
|
*
|
* @param id 气体管路产能负载统计主键
|
* @return 气体管路产能负载统计
|
*/
|
@Override
|
public ApsGasPipingRouteStat selectApsGasPipingRouteStatById(String id)
|
{
|
return apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatById(id);
|
}
|
|
/**
|
* 查询气体管路产能负载统计列表
|
*
|
* @param apsGasPipingRouteStat 气体管路产能负载统计
|
* @return 气体管路产能负载统计
|
*/
|
@Override
|
public List<ApsGasPipingRouteStat> selectApsGasPipingRouteStatList(ApsGasPipingRouteStat apsGasPipingRouteStat)
|
{
|
return apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatList(apsGasPipingRouteStat);
|
}
|
|
/**
|
* 新增气体管路产能负载统计
|
*
|
* @param apsGasPipingRouteStat 气体管路产能负载统计
|
* @return 结果
|
*/
|
@Override
|
public int insertApsGasPipingRouteStat(ApsGasPipingRouteStat apsGasPipingRouteStat)
|
{
|
apsGasPipingRouteStat.setCreateTime(DateUtils.getNowDate());
|
apsGasPipingRouteStat.setCreateBy(SecurityUtils.getUsername());
|
return apsGasPipingRouteStatMapper.insertApsGasPipingRouteStat(apsGasPipingRouteStat);
|
}
|
|
/**
|
* 修改气体管路产能负载统计
|
*
|
* @param apsGasPipingRouteStat 气体管路产能负载统计
|
* @return 结果
|
*/
|
@Override
|
public int updateApsGasPipingRouteStat(ApsGasPipingRouteStat apsGasPipingRouteStat)
|
{
|
apsGasPipingRouteStat.setUpdateBy(SecurityUtils.getUsername());
|
apsGasPipingRouteStat.setUpdateTime(DateUtils.getNowDate());
|
return apsGasPipingRouteStatMapper.updateApsGasPipingRouteStat(apsGasPipingRouteStat);
|
}
|
|
/**
|
* 批量删除气体管路产能负载统计
|
*
|
* @param ids 需要删除的气体管路产能负载统计主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteApsGasPipingRouteStatByIds(String[] ids)
|
{
|
return apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByIds(ids);
|
}
|
|
/**
|
* 删除气体管路产能负载统计信息
|
*
|
* @param id 气体管路产能负载统计主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteApsGasPipingRouteStatById(String id)
|
{
|
return apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatById(id);
|
}
|
|
@Override
|
public boolean computeCapacity() {
|
// PageHelper.startPage(1, 500);
|
List<ApsGasPipingPlan> apsGasPipingPlans = apsGasPipingPlanMapper.selectApsGasPipingPlanWithProcess(new ApsGasPipingPlan());
|
List<ApsGasPipingRouteStat> apsGasPipingRouteStatList = new ArrayList<>();
|
/*本次计算批次号*/
|
String batchNum = IdUtils.fastSimpleUUID();
|
try {
|
apsGasPipingPlans.forEach(apsGasPipingPlan -> {
|
List<ApsProcessRoute> apsProcessRoutes = apsGasPipingPlan.getApsProcessRoutes();
|
//按照工序序号升序排序
|
apsProcessRoutes.sort((a, b)->b.getProcessNumber().compareTo(a.getProcessNumber()));
|
//是否找到当前工序
|
boolean isCurrentProcess = false;
|
boolean lastProcessStartTimeIsBeforeNow = false;
|
ApsGasPipingRouteStat preApsProcessRoute = null;
|
for (int i=0;i<apsProcessRoutes.size();i++){
|
ApsProcessRoute apsProcessRoute = apsProcessRoutes.get(i);
|
ApsGasPipingRouteStat apsGasPipingRouteStat = new ApsGasPipingRouteStat();
|
//工单号
|
apsGasPipingRouteStat.setWorkOrderNo(apsGasPipingPlan.getDocumentNumber());
|
//料号
|
apsGasPipingRouteStat.setItemNumber(apsGasPipingPlan.getItemNumber());
|
//当前工序号
|
apsGasPipingRouteStat.setCurrentProcessNumber(new BigDecimal(apsGasPipingPlan.getProcessNumber()));
|
//生产数量
|
apsGasPipingRouteStat.setProductionQuantity(apsGasPipingPlan.getProductionQuantity());
|
//工序名称
|
apsGasPipingRouteStat.setProcessName(apsProcessRoute.getProcessName());
|
//工序号
|
apsGasPipingRouteStat.setRoadProcessNumber( new BigDecimal(apsProcessRoute.getProcessNumber()) );
|
//标准工时
|
apsGasPipingRouteStat.setStandardTime(apsProcessRoute.getStandardTime());
|
//专业
|
apsGasPipingRouteStat.setMajor(apsGasPipingPlan.getPlanType());
|
//工序总工时 等于 标准工时*生产数量
|
apsGasPipingRouteStat.setProcessTotalTime(apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()));
|
//计划开工日 如果是当前序
|
if(apsGasPipingPlan.getProcessNumber().equals(apsProcessRoute.getProcessNumber())) {
|
isCurrentProcess = true;
|
}
|
// 上一道工序的结束时间 = 上一道工序的开始时间 + 上一道工序的总工时
|
if(i==0){
|
LocalDate endLocalDate = LocalDate.ofInstant(apsGasPipingPlan.getPlanEndDay().toInstant(), ZoneId.systemDefault());
|
LocalDate nowLocalDate = LocalDate.now();
|
LocalDateTime planEndDay;
|
if(endLocalDate.isBefore(nowLocalDate)){
|
planEndDay = LocalDateTime.now();
|
}else{
|
planEndDay = apsGasPipingPlan.getPlanEndDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
}
|
apsGasPipingRouteStat.setProcessPlanEndDay(Date.from(planEndDay.atZone(ZoneId.systemDefault()).toInstant()));
|
long seconds = apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()).multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
|
LocalDateTime planStartDay = planEndDay.plusSeconds(-seconds);
|
apsGasPipingRouteStat.setProcessPlanStartDay(Date.from(planStartDay.atZone(ZoneId.systemDefault()).toInstant()));
|
if(planStartDay.isBefore(LocalDateTime.now())){
|
lastProcessStartTimeIsBeforeNow = true;
|
}
|
}else{
|
if(lastProcessStartTimeIsBeforeNow){
|
Date now = new Date();
|
apsGasPipingRouteStat.setProcessPlanStartDay(now);
|
apsGasPipingRouteStat.setProcessPlanEndDay(now);
|
}else{
|
apsGasPipingRouteStat.setProcessPlanEndDay(preApsProcessRoute.getProcessPlanStartDay());
|
LocalDateTime planEndDay = preApsProcessRoute.getProcessPlanStartDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
long seconds = apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()).multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
|
LocalDateTime planStartDay = planEndDay.plusSeconds(-seconds);
|
apsGasPipingRouteStat.setProcessPlanStartDay(Date.from(planStartDay.atZone(ZoneId.systemDefault()).toInstant()));
|
}
|
}
|
//插入 年 月 日
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
String formattedDate = sdf.format(apsGasPipingRouteStat.getProcessPlanStartDay());
|
String[] dateParts = formattedDate.split("-");
|
apsGasPipingRouteStat.setPlanStartYear(String.valueOf(Integer.parseInt(dateParts[0])));
|
apsGasPipingRouteStat.setPlanStartMonth(String.valueOf(Integer.parseInt(dateParts[1])));
|
apsGasPipingRouteStat.setPlanStartDay(String.valueOf(Integer.parseInt(dateParts[2])));
|
//标准用量 查询物料用量表
|
// ApsGasMaterialUsage apsGasMaterialUsage = new ApsGasMaterialUsage();
|
// apsGasMaterialUsage.setItemNumber(apsGasPipingPlan.getItemNumber());
|
// apsGasMaterialUsage.setProcessName(apsProcessRoute.getProcessName());
|
// List<ApsGasMaterialUsage> apsGasMaterialUsageList = apsGasMaterialUsageService.selectApsGasMaterialUsageList(apsGasMaterialUsage);
|
// apsGasPipingRouteStat.setStandardDosage(apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()));
|
//工序总用量 = 标准用量*生产数量
|
// apsGasPipingRouteStat.setProcessTotalDosage(apsGasPipingRouteStat.getStandardDosage().multiply(apsGasPipingPlan.getProductionQuantity()));
|
apsGasPipingRouteStat.setCreateTime(DateUtils.getNowDate());
|
apsGasPipingRouteStat.setCreateBy("auto");
|
apsGasPipingRouteStat.setBatchNumber(batchNum);
|
apsGasPipingRouteStat.setId(IdUtils.fastSimpleUUID());
|
apsGasPipingRouteStatList.add(apsGasPipingRouteStat);
|
preApsProcessRoute = apsGasPipingRouteStat;
|
if(isCurrentProcess){
|
break;
|
}
|
}
|
});
|
List<ApsGasPipingRouteStat> tempInsertList = new ArrayList<>();
|
for (int i = 0; i < apsGasPipingRouteStatList.size(); i++) {
|
tempInsertList.add(apsGasPipingRouteStatList.get(i));
|
if(tempInsertList.size()==500){
|
apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(tempInsertList);
|
tempInsertList = new ArrayList<>();
|
}else if(i==apsGasPipingRouteStatList.size()-1){
|
apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(tempInsertList);
|
}
|
}
|
apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByBatchNum(batchNum);
|
} catch (Exception e) {
|
e.printStackTrace();
|
return false;
|
}
|
return true;
|
}
|
|
public JSONObject getCapacityPlanDataBackup(ApsGasPipingRouteStat apsGasPipingRouteStat) {
|
JSONObject result = new JSONObject();
|
YearMonth yearMonth = YearMonth.parse(apsGasPipingRouteStat.getSearchEndDate());
|
int daysInMonth = yearMonth.lengthOfMonth();
|
LinkedHashSet<String> startPlanTimeSet = new LinkedHashSet<>();
|
//工序分组统计
|
LinkedHashMap<String, List<ApsResourceDateStat>> processMap = new LinkedHashMap<>();
|
List<HashMap<String, List<ApsResourceDateStat>>> processList = new ArrayList<>();
|
try {
|
//获取标准工序名称
|
ApsStandardProcess apsStandardProcess = new ApsStandardProcess();
|
apsStandardProcess.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路");
|
List<ApsStandardProcess> apsStandardProcessList = apsStandardProcessService.selectApsStandardProcessList(apsStandardProcess);
|
apsStandardProcessList.sort((a, b)->a.getProcessName().compareTo(b.getProcessName()));
|
for(ApsStandardProcess temp:apsStandardProcessList){
|
processMap.put(temp.getProcessName(), new ArrayList<ApsResourceDateStat>());
|
}
|
//获取工序计划产能数据
|
HashMap<String, ApsGasPipelineCapacityPlan> apsGasPipingPlanMap = new HashMap<>();
|
ApsGasPipelineCapacityPlan searchCapacityPlan = new ApsGasPipelineCapacityPlan();
|
searchCapacityPlan.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路");
|
if("day".equals(apsGasPipingRouteStat.getSearchType())){
|
searchCapacityPlan.setYear(yearMonth.getYear()+"");
|
searchCapacityPlan.setMonth(yearMonth.getMonthValue()+"");
|
for(int i=1;i<=daysInMonth;i++){
|
startPlanTimeSet.add(yearMonth +"-"+ (i<10?"0"+i:i));
|
}
|
}else if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
searchCapacityPlan.setYear(yearMonth.getYear()+"");
|
YearMonth start = YearMonth.of(Integer.parseInt(apsGasPipingRouteStat.getSearchStartDate().split("-")[0]), Integer.parseInt(apsGasPipingRouteStat.getSearchStartDate().split("-")[1]));
|
YearMonth end = YearMonth.of(Integer.parseInt(apsGasPipingRouteStat.getSearchEndDate().split("-")[0]), Integer.parseInt(apsGasPipingRouteStat.getSearchEndDate().split("-")[1]));
|
List<String> yearMonths = getYearMonthsInRange(start, end);
|
startPlanTimeSet.addAll(yearMonths);
|
}
|
List<ApsGasPipelineCapacityPlan> apsGasPipelineCapacityPlanList = apsGasPipelineCapacityPlanMapper.selectApsGasPipelineCapacityPlanList(searchCapacityPlan);
|
apsGasPipelineCapacityPlanList.forEach(apsGasPipelineCapacityPlan -> {
|
apsGasPipingPlanMap.put(apsGasPipelineCapacityPlan.getProcessName()+"-"+apsGasPipelineCapacityPlan.getYear()+"-"+(Integer.parseInt(apsGasPipelineCapacityPlan.getMonth())<10?"0"+apsGasPipelineCapacityPlan.getMonth():apsGasPipelineCapacityPlan.getMonth()),apsGasPipelineCapacityPlan);
|
});
|
//计算日产能数据
|
DateTimeFormatter formatter = null;
|
List<ApsGasPipingRouteStat> apsGasPipingRouteStats;
|
SimpleDateFormat simpleDateFormat = null;
|
apsGasPipingRouteStat.setSearchStartDate(apsGasPipingRouteStat.getSearchStartDate()+"-01 00:00:00");
|
apsGasPipingRouteStat.setSearchEndDate(apsGasPipingRouteStat.getSearchEndDate()+"-"+ daysInMonth +" 23:59:59");
|
if("day".equals(apsGasPipingRouteStat.getSearchType())){
|
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
}else if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
simpleDateFormat = new SimpleDateFormat("yyyy-MM");
|
}
|
ApsGasPipingRouteStat queryStatParam = new ApsGasPipingRouteStat();
|
BeanUtils.copyProperties(apsGasPipingRouteStat,queryStatParam);
|
queryStatParam.setMajor("");
|
apsGasPipingRouteStats = apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatList(queryStatParam);
|
//根据开工日进行升序排序
|
apsGasPipingRouteStats.sort((a, b)->a.getProcessPlanStartDay().compareTo(b.getProcessPlanStartDay()));
|
//工序开工日期
|
String planStartDate = "";
|
//统计所有工序对应的开工时间
|
for (ApsGasPipingRouteStat apsGasPipingRouteStatTemp : apsGasPipingRouteStats) {
|
if(processMap.containsKey(apsGasPipingRouteStatTemp.getProcessName())){
|
planStartDate = simpleDateFormat.format(apsGasPipingRouteStatTemp.getProcessPlanStartDay());
|
if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
planStartDate = planStartDate+"-01";
|
}
|
ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
|
apsResourceDateStat.setPlanDay(LocalDate.parse(planStartDate, formatter));
|
apsResourceDateStat.setResourceName(apsGasPipingRouteStatTemp.getProcessName());
|
//查询气柜管路产能规划表
|
apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(apsGasPipingRouteStatTemp.getProcessName()+"-"+planStartDate.substring(0, 7))!=null?apsGasPipingPlanMap.get(apsGasPipingRouteStatTemp.getProcessName()+"-"+planStartDate.substring(0, 7)).getDayProduceAllNum():new BigDecimal(0));
|
//查询料号工序产能表
|
apsResourceDateStat.setRequireTimes(apsGasPipingRouteStatTemp.getProcessTotalTime());
|
if(apsResourceDateStat.getDesignTimes().compareTo(BigDecimal.ZERO)>0){
|
apsResourceDateStat.setCapacityLoad(apsResourceDateStat.getRequireTimes()
|
.divide(apsResourceDateStat.getDesignTimes(), 2, RoundingMode.HALF_UP)
|
.multiply(new BigDecimal(100)));
|
}else{
|
apsResourceDateStat.setCapacityLoad(BigDecimal.valueOf(0));
|
}
|
// apsResourceDateStatList = new ArrayList<>();
|
|
List<ApsResourceDateStat> apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName());
|
apsResourceDateStatList.add(apsResourceDateStat);
|
processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList);
|
}
|
|
}
|
//聚合每道工序的开工时间和产能
|
processMap.forEach((processName, apsResourceDateStatList) -> {
|
LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
|
apsResourceDateStatList.forEach(apsResourceDateStat -> {
|
// startPlanTimeSet.add(apsResourceDateStat.getPlanDay().toString());
|
if(dayMap.containsKey(apsResourceDateStat.getPlanDay().toString())){
|
ApsResourceDateStat apsResourceDateStatTemp = dayMap.get(apsResourceDateStat.getPlanDay().toString());
|
if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7))!=null?apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7)).getMonthProduceAllNum():new BigDecimal(0));
|
}else{
|
apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7))!=null?apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7)).getDayProduceAllNum():new BigDecimal(0));
|
}
|
apsResourceDateStatTemp.setRequireTimes(apsResourceDateStatTemp.getRequireTimes().add(apsResourceDateStat.getRequireTimes()));
|
if(apsResourceDateStatTemp.getDesignTimes().compareTo(BigDecimal.ZERO) > 0){
|
apsResourceDateStatTemp.setCapacityLoad(apsResourceDateStatTemp.getRequireTimes()
|
.divide(apsResourceDateStatTemp.getDesignTimes(), 2, RoundingMode.HALF_UP)
|
.multiply(new BigDecimal(100)));
|
}else{
|
apsResourceDateStatTemp.setCapacityLoad(new BigDecimal(0));
|
}
|
apsResourceDateStatTemp.setResourceGroupName(processName);
|
apsResourceDateStatTemp.setPlanDay(apsResourceDateStat.getPlanDay());
|
dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStatTemp);
|
}else{
|
dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStat);
|
}
|
});
|
List<ApsResourceDateStat> tempList = new ArrayList<>();
|
dayMap.forEach((key, value) -> {
|
tempList.add(value);
|
});
|
HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
|
temp.put(processName, tempList);
|
processList.add(temp);
|
});
|
//排序时间标题
|
List<String> sortedStartPlanTimeList = new ArrayList<>(startPlanTimeSet);
|
Collections.sort(sortedStartPlanTimeList);
|
for (int i=0;i<processList.size();i++){
|
HashMap<String, List<ApsResourceDateStat>> temp = processList.get(i);
|
for (Map.Entry<String, List<ApsResourceDateStat>> entry : temp.entrySet()){
|
List<ApsResourceDateStat> apsResourceDateStatList = entry.getValue();
|
String key = entry.getKey();
|
List<ApsResourceDateStat> crtList = new ArrayList<>();
|
for(String tempTime:sortedStartPlanTimeList) {
|
if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
tempTime += "-01";
|
}
|
LocalDate crtDate = LocalDate.parse(tempTime, formatter);
|
Optional<ApsResourceDateStat> first = apsResourceDateStatList.stream().filter(x -> x.getPlanDay().equals(crtDate)).findFirst();
|
if (first.isPresent()) {
|
ApsResourceDateStat apsResourceDateStat = first.get();
|
crtList.add(apsResourceDateStat);
|
} else {
|
ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
|
apsResourceDateStat.setPlanDay(LocalDate.parse(tempTime, formatter));
|
if ("month".equals(apsGasPipingRouteStat.getSearchType())) {
|
apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)) != null ? apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)).getMonthProduceAllNum() : new BigDecimal(0));
|
} else {
|
apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)) != null ? apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)).getDayProduceAllNum() : new BigDecimal(0));
|
}
|
apsResourceDateStat.setRequireTimes(new BigDecimal(0));
|
apsResourceDateStat.setCapacityLoad(new BigDecimal(0));
|
apsResourceDateStat.setResourceName(entry.getKey());
|
apsResourceDateStat.setResourceGroupName(entry.getKey());
|
apsResourceDateStatList.add(apsResourceDateStat);
|
crtList.add(apsResourceDateStat);
|
}
|
temp.put(entry.getKey(), crtList);
|
processList.set(i, temp);
|
}
|
}
|
}
|
result.put("planTable", processList);
|
result.put("planTitle", sortedStartPlanTimeList);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return result;
|
}
|
|
@Override
|
public JSONObject getCapacityPlanData(ApsGasPipingRouteStat apsGasPipingRouteStat) {
|
JSONObject result = new JSONObject();
|
YearMonth yearMonth = YearMonth.parse(apsGasPipingRouteStat.getSearchEndDate());
|
int daysInMonth = yearMonth.lengthOfMonth();
|
LinkedHashSet<String> startPlanTimeSet = new LinkedHashSet<>();
|
//工序分组统计
|
LinkedHashMap<String, List<ApsResourceDateStat>> processMap = new LinkedHashMap<>();
|
List<HashMap<String, List<ApsResourceDateStat>>> processList = new ArrayList<>();
|
try {
|
//获取标准工序名称
|
ApsStandardProcess apsStandardProcess = new ApsStandardProcess();
|
apsStandardProcess.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路");
|
List<ApsStandardProcess> apsStandardProcessList = apsStandardProcessService.selectApsStandardProcessList(apsStandardProcess);
|
apsStandardProcessList.sort((a, b)->a.getProcessName().compareTo(b.getProcessName()));
|
for(ApsStandardProcess temp:apsStandardProcessList){
|
processMap.put(temp.getProcessName(), new ArrayList<ApsResourceDateStat>());
|
}
|
//获取工序计划产能数据
|
HashMap<String, ApsGasPipelineCapacityPlan> apsGasPipingPlanMap = new HashMap<>();
|
ApsGasPipelineCapacityPlan searchCapacityPlan = new ApsGasPipelineCapacityPlan();
|
searchCapacityPlan.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路");
|
if("day".equals(apsGasPipingRouteStat.getSearchType())){
|
searchCapacityPlan.setYear(yearMonth.getYear()+"");
|
searchCapacityPlan.setMonth(yearMonth.getMonthValue()+"");
|
for(int i=1;i<=daysInMonth;i++){
|
startPlanTimeSet.add(yearMonth +"-"+ (i<10?"0"+i:i));
|
}
|
}else if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
searchCapacityPlan.setYear(yearMonth.getYear()+"");
|
YearMonth start = YearMonth.of(Integer.parseInt(apsGasPipingRouteStat.getSearchStartDate().split("-")[0]), Integer.parseInt(apsGasPipingRouteStat.getSearchStartDate().split("-")[1]));
|
YearMonth end = YearMonth.of(Integer.parseInt(apsGasPipingRouteStat.getSearchEndDate().split("-")[0]), Integer.parseInt(apsGasPipingRouteStat.getSearchEndDate().split("-")[1]));
|
List<String> yearMonths = getYearMonthsInRange(start, end);
|
startPlanTimeSet.addAll(yearMonths);
|
}
|
List<ApsGasPipelineCapacityPlan> apsGasPipelineCapacityPlanList = apsGasPipelineCapacityPlanMapper.selectApsGasPipelineCapacityPlanList(searchCapacityPlan);
|
apsGasPipelineCapacityPlanList.forEach(apsGasPipelineCapacityPlan -> {
|
String key = apsGasPipelineCapacityPlan.getProcessName() + "-" + apsGasPipelineCapacityPlan.getOrgCode() + "-" + apsGasPipelineCapacityPlan.getYear() + "-" + (Integer.parseInt(apsGasPipelineCapacityPlan.getMonth())<10?"0"+apsGasPipelineCapacityPlan.getMonth():apsGasPipelineCapacityPlan.getMonth());
|
apsGasPipingPlanMap.put(key, apsGasPipelineCapacityPlan);
|
});
|
//计算日产能数据
|
DateTimeFormatter formatter = null;
|
List<ApsGasPipingRouteStat> apsGasPipingRouteStats;
|
SimpleDateFormat simpleDateFormat = null;
|
apsGasPipingRouteStat.setSearchStartDate(apsGasPipingRouteStat.getSearchStartDate()+"-01 00:00:00");
|
apsGasPipingRouteStat.setSearchEndDate(apsGasPipingRouteStat.getSearchEndDate()+"-"+ daysInMonth +" 23:59:59");
|
if("day".equals(apsGasPipingRouteStat.getSearchType())){
|
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
}else if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
simpleDateFormat = new SimpleDateFormat("yyyy-MM");
|
}
|
ApsGasPipingRouteStat queryStatParam = new ApsGasPipingRouteStat();
|
BeanUtils.copyProperties(apsGasPipingRouteStat,queryStatParam);
|
queryStatParam.setMajor(apsGasPipingRouteStat.getMajor());
|
queryStatParam.setPlant(apsGasPipingRouteStat.getPlant());
|
apsGasPipingRouteStats = apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatList(queryStatParam);
|
//根据开工日进行升序排序
|
apsGasPipingRouteStats.sort((a, b)->a.getProcessPlanStartDay().compareTo(b.getProcessPlanStartDay()));
|
//工序开工日期
|
String planStartDate = "";
|
//统计所有工序对应的开工时间
|
for (ApsGasPipingRouteStat apsGasPipingRouteStatTemp : apsGasPipingRouteStats) {
|
if(processMap.containsKey(apsGasPipingRouteStatTemp.getProcessName())){
|
planStartDate = simpleDateFormat.format(apsGasPipingRouteStatTemp.getProcessPlanStartDay());
|
if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
planStartDate = planStartDate+"-01";
|
}
|
ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
|
apsResourceDateStat.setPlanDay(LocalDate.parse(planStartDate, formatter));
|
apsResourceDateStat.setResourceName(apsGasPipingRouteStatTemp.getProcessName());
|
apsResourceDateStat.setPlant(apsGasPipingRouteStatTemp.getPlant());
|
//查询气柜管路产能规划表
|
String capacityKey = apsGasPipingRouteStatTemp.getProcessName() + "-" + apsGasPipingRouteStatTemp.getPlant() + "-" + planStartDate.substring(0, 7);
|
apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getDayProduceAllNum():new BigDecimal(0));
|
//查询料号工序产能表
|
apsResourceDateStat.setRequireTimes(apsGasPipingRouteStatTemp.getProcessTotalTime());
|
if(apsResourceDateStat.getDesignTimes().compareTo(BigDecimal.ZERO)>0){
|
apsResourceDateStat.setCapacityLoad(apsResourceDateStat.getRequireTimes()
|
.divide(apsResourceDateStat.getDesignTimes(), 2, RoundingMode.HALF_UP)
|
.multiply(new BigDecimal(100)));
|
}else{
|
apsResourceDateStat.setCapacityLoad(BigDecimal.valueOf(0));
|
}
|
|
List<ApsResourceDateStat> apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName());
|
apsResourceDateStatList.add(apsResourceDateStat);
|
processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList);
|
}
|
}
|
//聚合每道工序的开工时间和产能
|
for (Map.Entry<String, List<ApsResourceDateStat>> entry : processMap.entrySet()) {
|
String processName = entry.getKey();
|
List<ApsResourceDateStat> apsResourceDateStatList = entry.getValue();
|
|
if("day".equals(apsGasPipingRouteStat.getSearchType())) {
|
// 按天统计时保持原有逻辑,不按工厂分组
|
LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
|
|
// 首先,为所有日期创建初始记录
|
for(String date : startPlanTimeSet) {
|
ApsResourceDateStat initStat = new ApsResourceDateStat();
|
initStat.setPlanDay(LocalDate.parse(date, formatter));
|
initStat.setResourceName(processName);
|
initStat.setResourceGroupName(processName);
|
initStat.setRequireTimes(new BigDecimal(0));
|
String capacityKey = processName + "-" + date.substring(0,7);
|
initStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getDayProduceAllNum():new BigDecimal(0));
|
initStat.setCapacityLoad(new BigDecimal(0));
|
dayMap.put(date, initStat);
|
}
|
|
// 然后处理实际数据
|
for (ApsResourceDateStat apsResourceDateStat : apsResourceDateStatList) {
|
String dateKey = apsResourceDateStat.getPlanDay().toString();
|
if(dayMap.containsKey(dateKey)){
|
ApsResourceDateStat apsResourceDateStatTemp = dayMap.get(dateKey);
|
String capacityKey = processName + "-"+ apsResourceDateStat.getPlant() + "-" + dateKey.substring(0,7);
|
apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getDayProduceAllNum():new BigDecimal(0));
|
apsResourceDateStatTemp.setRequireTimes(apsResourceDateStatTemp.getRequireTimes().add(apsResourceDateStat.getRequireTimes()));
|
if(apsResourceDateStatTemp.getDesignTimes().compareTo(BigDecimal.ZERO) > 0){
|
apsResourceDateStatTemp.setCapacityLoad(apsResourceDateStatTemp.getRequireTimes()
|
.divide(apsResourceDateStatTemp.getDesignTimes(), 2, RoundingMode.HALF_UP)
|
.multiply(new BigDecimal(100)));
|
}else{
|
apsResourceDateStatTemp.setCapacityLoad(new BigDecimal(0));
|
}
|
apsResourceDateStatTemp.setResourceGroupName(processName);
|
apsResourceDateStatTemp.setPlanDay(apsResourceDateStat.getPlanDay());
|
dayMap.put(dateKey, apsResourceDateStatTemp);
|
}
|
}
|
|
List<ApsResourceDateStat> tempList = new ArrayList<>(dayMap.values());
|
HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
|
temp.put(processName, tempList);
|
processList.add(temp);
|
} else {
|
// 按月统计时才按工厂分组
|
if (apsResourceDateStatList.isEmpty()) {
|
// 从产能规划数据中获取所有的工厂
|
Set<String> plants = apsGasPipelineCapacityPlanList.stream()
|
.filter(plan -> plan.getProcessName().equals(processName))
|
.map(ApsGasPipelineCapacityPlan::getOrgCode)
|
.filter(orgCode -> orgCode != null && !orgCode.trim().isEmpty())
|
.collect(Collectors.toSet());
|
|
// 如果没有找到任何有效工厂,跳过这个工序
|
if (plants.isEmpty()) {
|
continue;
|
}
|
|
// 为每个工厂创建空记录
|
for (String plant : plants) {
|
LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
|
// 为每个月份创建记录
|
for(String monthDate : startPlanTimeSet) {
|
String tempTime = monthDate + "-01";
|
ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
|
apsResourceDateStat.setPlanDay(LocalDate.parse(tempTime, formatter));
|
apsResourceDateStat.setResourceName(processName);
|
apsResourceDateStat.setResourceGroupName(processName + "-" + plant);
|
apsResourceDateStat.setPlant(plant);
|
apsResourceDateStat.setRequireTimes(new BigDecimal(0));
|
String capacityKey = processName + "-" + plant + "-" + monthDate;
|
apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum():new BigDecimal(0));
|
apsResourceDateStat.setCapacityLoad(new BigDecimal(0));
|
dayMap.put(monthDate, apsResourceDateStat);
|
}
|
List<ApsResourceDateStat> tempList = new ArrayList<>(dayMap.values());
|
HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
|
temp.put(processName + "_" + plant, tempList);
|
processList.add(temp);
|
}
|
} else {
|
// 按工厂分组,并过滤掉plant为null或空字符串的记录
|
Map<String, List<ApsResourceDateStat>> plantGroups = apsResourceDateStatList.stream()
|
.filter(stat -> stat.getPlant() != null && !stat.getPlant().trim().isEmpty())
|
.collect(groupingBy(ApsResourceDateStat::getPlant));
|
|
// 如果过滤后没有有效的工厂数据,跳过这个工序
|
if (plantGroups.isEmpty()) {
|
continue;
|
}
|
|
// 对每个工厂的数据进行处理
|
for (Map.Entry<String, List<ApsResourceDateStat>> plantEntry : plantGroups.entrySet()) {
|
String plant = plantEntry.getKey();
|
// 再次确认plant不为空
|
if (plant == null || plant.trim().isEmpty()) {
|
continue;
|
}
|
List<ApsResourceDateStat> plantStats = plantEntry.getValue();
|
LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
|
|
// 首先为所有月份创建初始记录
|
for(String monthDate : startPlanTimeSet) {
|
String tempTime = monthDate + "-01";
|
ApsResourceDateStat initStat = new ApsResourceDateStat();
|
initStat.setPlanDay(LocalDate.parse(tempTime, formatter));
|
initStat.setResourceName(processName);
|
initStat.setResourceGroupName(processName + "-" + plant);
|
initStat.setPlant(plant);
|
initStat.setRequireTimes(new BigDecimal(0));
|
String capacityKey = processName + "-" + plant + "-" + monthDate;
|
initStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum():new BigDecimal(0));
|
initStat.setCapacityLoad(new BigDecimal(0));
|
dayMap.put(monthDate, initStat);
|
}
|
|
// 然后处理实际数据
|
for (ApsResourceDateStat stat : plantStats) {
|
String monthKey = stat.getPlanDay().toString().substring(0, 7);
|
if (dayMap.containsKey(monthKey)) {
|
ApsResourceDateStat existingStat = dayMap.get(monthKey);
|
String capacityKey = processName + "-" + plant + "-" + monthKey;
|
existingStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum():new BigDecimal(0));
|
existingStat.setRequireTimes(existingStat.getRequireTimes().add(stat.getRequireTimes()));
|
if(existingStat.getDesignTimes().compareTo(BigDecimal.ZERO) > 0){
|
existingStat.setCapacityLoad(existingStat.getRequireTimes()
|
.divide(existingStat.getDesignTimes(), 2, RoundingMode.HALF_UP)
|
.multiply(new BigDecimal(100)));
|
}
|
}
|
}
|
|
List<ApsResourceDateStat> tempList = new ArrayList<>(dayMap.values());
|
HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
|
temp.put(processName + "_" + plant, tempList);
|
processList.add(temp);
|
}
|
}
|
}
|
}
|
//排序时间标题
|
List<String> sortedStartPlanTimeList = new ArrayList<>(startPlanTimeSet);
|
Collections.sort(sortedStartPlanTimeList);
|
for (int i=0;i<processList.size();i++){
|
HashMap<String, List<ApsResourceDateStat>> temp = processList.get(i);
|
for (Map.Entry<String, List<ApsResourceDateStat>> entry : temp.entrySet()){
|
List<ApsResourceDateStat> apsResourceDateStatList = entry.getValue();
|
String key = entry.getKey();
|
List<ApsResourceDateStat> crtList = new ArrayList<>();
|
for(String tempTime:sortedStartPlanTimeList) {
|
if("month".equals(apsGasPipingRouteStat.getSearchType())){
|
tempTime += "-01";
|
}
|
LocalDate crtDate = LocalDate.parse(tempTime, formatter);
|
Optional<ApsResourceDateStat> first = apsResourceDateStatList.stream().filter(x -> x.getPlanDay().equals(crtDate)).findFirst();
|
if (first.isPresent()) {
|
ApsResourceDateStat apsResourceDateStat = first.get();
|
crtList.add(apsResourceDateStat);
|
} else {
|
ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
|
apsResourceDateStat.setPlanDay(LocalDate.parse(tempTime, formatter));
|
String[] keyParts = key.split("-");
|
String processNamePart = keyParts[0];
|
String plantPart = keyParts[1];
|
String capacityKey = processNamePart + "-" + plantPart + "-" + tempTime.substring(0,7);
|
if ("month".equals(apsGasPipingRouteStat.getSearchType())) {
|
apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey) != null ? apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum() : new BigDecimal(0));
|
} else {
|
apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey) != null ? apsGasPipingPlanMap.get(capacityKey).getDayProduceAllNum() : new BigDecimal(0));
|
}
|
apsResourceDateStat.setRequireTimes(new BigDecimal(0));
|
apsResourceDateStat.setCapacityLoad(new BigDecimal(0));
|
apsResourceDateStat.setResourceName(processNamePart);
|
apsResourceDateStat.setResourceGroupName(key);
|
apsResourceDateStat.setPlant(plantPart);
|
apsResourceDateStatList.add(apsResourceDateStat);
|
crtList.add(apsResourceDateStat);
|
}
|
temp.put(entry.getKey(), crtList);
|
processList.set(i, temp);
|
}
|
}
|
}
|
result.put("planTable", processList);
|
result.put("planTitle", sortedStartPlanTimeList);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return result;
|
}
|
|
@Override
|
public void exportExcel(HttpServletResponse response, ApsGasPipingRouteStat apsGasPipingRouteStat) {
|
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
|
{
|
JSONObject stat = getCapacityPlanData(apsGasPipingRouteStat);
|
List<String> days = (List<String>) stat.get("planTitle");
|
List<HashMap<String, List<ApsResourceDateStat>>> table= (List<HashMap<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().doubleValue());
|
dataRow.createCell(j*3+2).setCellValue(apsResourceDateStat.getRequireTimes().doubleValue());
|
if(apsResourceDateStat.getCapacityLoad()!=null){
|
dataRow.createCell(j*3+3).setCellValue(apsResourceDateStat.getCapacityLoad().doubleValue()+"%");
|
}else{
|
dataRow.createCell(j*3+3).setCellValue("%");
|
}
|
}
|
}
|
|
}
|
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;
|
}
|
|
public static List<String> getYearMonthsInRange(YearMonth start, YearMonth end) {
|
List<String> yearMonths = new ArrayList<>();
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
|
|
while (!start.isAfter(end)) {
|
yearMonths.add(start.format(formatter));
|
start = start.plusMonths(1);
|
}
|
|
return yearMonths;
|
}
|
|
@Override
|
public void saveGasPipingProcessStat(){
|
try {
|
String batchNum = IdUtils.fastSimpleUUID();
|
List<ApsGasPipingRouteStat> tempList = apsGasPipingRouteStatMapper.queryTempStat();
|
Map<String, List<ApsGasPipingRouteStat>> groupByOrderNo = tempList.stream().collect(groupingBy(ApsGasPipingRouteStat::getWorkOrderNo));
|
Boolean hasBefore = false;
|
LocalDateTime now = LocalDateTime.now();
|
for (Map.Entry<String, List<ApsGasPipingRouteStat>> entry : groupByOrderNo.entrySet()) {
|
List<ApsGasPipingRouteStat> statPerOrder = entry.getValue();
|
/*num 为根据完工时间排序出的序号,按此排序,可保证是按完工时间倒叙排列*/
|
statPerOrder.sort((a, b)->a.getNum().compareTo(b.getNum()));
|
ApsGasPipingRouteStat last=null;
|
for (int i = 0; i <statPerOrder.size(); i++) {
|
ApsGasPipingRouteStat stat = statPerOrder.get(i);
|
stat.setId(IdUtils.fastSimpleUUID());
|
stat.setBatchNumber(batchNum);
|
stat.setCreateBy(SecurityUtils.getUsername());
|
stat.setWarning(false);
|
if(i==0){
|
Date orderPlanEndDay = stat.getOrderPlanEndDay();
|
LocalDateTime transLocalDateTime = transLocalDateTime(orderPlanEndDay);
|
LocalTime endOfDay = LocalTime.of(23, 59, 59);
|
LocalDateTime orderPlanEndDayLocalDateTime = LocalDateTime.of( transLocalDateTime.toLocalDate(), endOfDay);
|
if(orderPlanEndDayLocalDateTime.isBefore(now)){
|
hasBefore = true;
|
stat.setWarning(true);
|
stat.setProcessPlanEndDay(transDate(now));
|
stat.setProcessPlanStartDay(transDate(now));
|
}else {
|
/*计划完工日=钣金计划工单完成时间*/
|
stat.setProcessPlanEndDay(transDate(orderPlanEndDayLocalDateTime));
|
/*计划开工日=钣金计划工单完成时间 - 工序总工时*/
|
long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
|
LocalDateTime lastPlanStartDt = orderPlanEndDayLocalDateTime.minusSeconds(seconds);
|
if(lastPlanStartDt.isBefore(now)){
|
hasBefore = true;
|
stat.setProcessPlanStartDay(transDate(now));
|
}else {
|
stat.setProcessPlanStartDay(transDate(lastPlanStartDt));
|
}
|
}
|
}
|
/*当工艺工序号 >= 工单当前工序 代表是未来工序,才进行计划开工日 和计划完工日的计算
|
* 当工艺工序号 < 工单当前工序 过去工序,不进行计算
|
* */
|
if( stat.getRouteProcessNumber().compareTo(stat.getCurrentProcessNumber())>=0){
|
/*倒排时 下一道工序存在 比当前时间小的计划时间,则当前计划开始和结束时间都是当前时间*/
|
if(hasBefore){
|
stat.setWarning(true);
|
stat.setProcessPlanEndDay(transDate(now));
|
stat.setProcessPlanStartDay(transDate(now));
|
}else{
|
/*下一道工序计划时间都正常时,*/
|
if (last != null) {
|
/*当前工序结束时间=下一道工序的开始时间*/
|
stat.setProcessPlanEndDay(last.getProcessPlanStartDay());
|
/*开始时间=结束时间-总工时*/
|
long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
|
LocalDateTime crtStartDt = transLocalDateTime(last.getProcessPlanStartDay()).minusSeconds(seconds);
|
/*如果开始时间小于当前时间*/
|
if(crtStartDt.isBefore(now)){
|
hasBefore=true;
|
stat.setWarning(true);
|
stat.setProcessPlanStartDay(transDate(now));
|
}else {
|
stat.setProcessPlanStartDay(transDate(crtStartDt));
|
}
|
}
|
}
|
}
|
last = stat;
|
apsGasPipingRouteStatMapper.insertApsGasPipingRouteStat(stat);
|
}
|
hasBefore=false;
|
|
}
|
apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByBatchNum(batchNum);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
};
|
|
private Date transDate(LocalDateTime localDateTime){
|
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
|
}
|
|
private LocalDateTime transLocalDateTime(Date date){
|
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
|
}
|
|
/**
|
* 保存钣金统计数据
|
*/
|
@Transactional
|
@Override
|
public void saveGasPipingRoutStateList() {
|
String batchNum = IdUtils.fastSimpleUUID();
|
List<ApsGasPipingRouteStat> tempList = apsGasPipingRouteStatMapper.queryTempStat();
|
Map<String, List<ApsGasPipingRouteStat>> groupByOrderNo = tempList.stream().collect(groupingBy(ApsGasPipingRouteStat::getWorkOrderNo));
|
|
LocalDateTime now = LocalDateTime.now();
|
/*待保存的数据*/
|
List<ApsGasPipingRouteStat> cptStateList = new ArrayList<>();
|
for (Map.Entry<String, List<ApsGasPipingRouteStat>> entry : groupByOrderNo.entrySet()) {
|
List<ApsGasPipingRouteStat> statPerOrder = entry.getValue();
|
/*num 为根据完工时间排序出的序号,按此排序,可保证是按完工时间倒叙排列*/
|
statPerOrder.sort((a, b)->a.getNum().compareTo(b.getNum()));
|
ApsGasPipingRouteStat last=null;
|
/*当前工序是否存在 计划开工时间 小于 当前的时间,如果存在后续设置为当前时间*/
|
boolean hasBefore = false;
|
for (int i = 0; i <statPerOrder.size(); i++) {
|
ApsGasPipingRouteStat stat = statPerOrder.get(i);
|
stat.setId(String.valueOf(IdUtil.getSnowflakeNextId()));
|
stat.setBatchNumber(batchNum);
|
stat.setCreateTime(DateUtils.getNowDate());
|
stat.setCreateBy(SecurityUtils.getUsername());
|
stat.setWarning(false);
|
stat.setDelFlag("0");
|
if(i==0){
|
Date orderPlanEndDay = stat.getOrderPlanEndDay();
|
LocalDateTime transLocalDateTime = transLocalDateTime(orderPlanEndDay);
|
LocalTime endOfDay = LocalTime.of(23, 59, 59);
|
LocalDateTime orderPlanEndDayLocalDateTime = LocalDateTime.of( transLocalDateTime.toLocalDate(), endOfDay);
|
if(orderPlanEndDayLocalDateTime.isBefore(now)){
|
hasBefore = true;
|
stat.setWarning(true);
|
stat.setProcessPlanEndDay(transDate(now));
|
stat.setProcessPlanStartDay(transDate(now));
|
}else {
|
/*计划完工日=钣金计划工单完成时间*/
|
stat.setProcessPlanEndDay(transDate(orderPlanEndDayLocalDateTime));
|
/*计划开工日=钣金计划工单完成时间 - 工序总工时*/
|
long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
|
LocalDateTime lastPlanStartDt = orderPlanEndDayLocalDateTime.minusSeconds(seconds);
|
if(lastPlanStartDt.isBefore(now)){
|
hasBefore = true;
|
stat.setProcessPlanStartDay(transDate(now));
|
}else {
|
stat.setProcessPlanStartDay(transDate(lastPlanStartDt));
|
}
|
}
|
}
|
/*当工艺工序号 >= 工单当前工序 代表是未来工序,才进行计划开工日 和计划完工日的计算
|
* 当工艺工序号 < 工单当前工序 过去工序,不进行计算
|
* */
|
if( stat.getRoadProcessNumber().compareTo(stat.getCurrentProcessNumber())>=0){
|
/*倒排时 下一道工序存在 比当前时间小的计划时间,则当前计划开始和结束时间都是当前时间*/
|
if(hasBefore){
|
stat.setWarning(true);
|
stat.setProcessPlanEndDay(transDate(now));
|
stat.setProcessPlanStartDay(transDate(now));
|
}else{
|
/*下一道工序计划时间都正常时,*/
|
if (last != null) {
|
/*当前工序结束时间=下一道工序的开始时间*/
|
stat.setProcessPlanEndDay(last.getProcessPlanStartDay());
|
/*开始时间=结束时间-总工时*/
|
long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
|
LocalDateTime crtStartDt = transLocalDateTime(last.getProcessPlanStartDay()).minusSeconds(seconds);
|
/*如果开始时间小于当前时间*/
|
if(crtStartDt.isBefore(now)){
|
hasBefore=true;
|
stat.setWarning(true);
|
stat.setProcessPlanStartDay(transDate(now));
|
}else {
|
stat.setProcessPlanStartDay(transDate(crtStartDt));
|
}
|
}
|
}
|
}
|
if(stat.getProcessPlanStartDay()!=null){
|
String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(stat.getProcessPlanStartDay()).toString().split("-");
|
stat.setPlanStartYear(strNow[0]);
|
stat.setPlanStartMonth(strNow[1]);
|
stat.setPlanStartDay(strNow[2]);
|
}
|
last = stat;
|
cptStateList.add(stat);
|
}
|
}
|
// 批量插入以提高性能
|
if (!cptStateList.isEmpty()) {
|
int batchSize = 1000;
|
int size = cptStateList.size();
|
for (int i = 0; i < size; i += batchSize) {
|
int end = Math.min(i + batchSize, size);
|
List<ApsGasPipingRouteStat> batch = cptStateList.subList(i, end);
|
apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(batch);
|
log.info("批量插入数据,开始位置:{},结束位置:{}", i, end);
|
}
|
}
|
apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByBatchNum(batchNum);
|
log.info("批量插入数据完成,batchNum:"+batchNum);
|
}
|
|
/**
|
* 根据手工气体预测数据和手工气体工单数据生成统计数据
|
*
|
* @return 结果
|
*/
|
@Override
|
@Transactional
|
public int generateGasPipingRouteStatData() {
|
int count = 0;
|
|
// 清空之前的数据
|
apsGasPipingRouteStatMapper.deleteAll();
|
|
// 生成批次号
|
String batchNumber = IdUtils.fastSimpleUUID();
|
List<ApsGasPipingRouteStat> statList = new ArrayList<>();
|
|
// 处理手工气体预测数据 - 使用联合查询获取所有相关数据
|
List<Map<String, Object>> predictionDataList = apsGasPipingRouteStatMapper.selectPredictionRouteData();
|
|
// 按物料代码分组,便于处理同一物料的不同工序
|
Map<String, List<Map<String, Object>>> predictionGroups = predictionDataList.stream()
|
.collect(Collectors.groupingBy(data -> data.get("material_code").toString()));
|
|
// 处理每个物料的工艺路线
|
for (String materialCode : predictionGroups.keySet()) {
|
List<Map<String, Object>> materialData = predictionGroups.get(materialCode);
|
|
// 按工序号排序
|
materialData.sort((a, b) -> {
|
String numA = a.get("process_number").toString();
|
String numB = b.get("process_number").toString();
|
return numA.compareTo(numB);
|
});
|
|
// 获取所有工序的信息并创建统计记录
|
List<ApsGasPipingRouteStat> processList = new ArrayList<>();
|
for (Map<String, Object> data : materialData) {
|
ApsGasPipingRouteStat stat = new ApsGasPipingRouteStat();
|
stat.setId(IdUtils.fastSimpleUUID());
|
stat.setWorkOrderNo(""); // 预测数据没有工单号
|
stat.setItemNumber(data.get("material_code").toString());
|
stat.setProcessName(data.get("process_name").toString());
|
stat.setRoadProcessNumber(new BigDecimal(data.get("process_number").toString()));
|
|
// 生产数量和标准工时
|
BigDecimal quantity = new BigDecimal(data.get("predict_quantity").toString()).setScale(4, RoundingMode.HALF_UP);
|
BigDecimal standardTime = new BigDecimal(data.get("standard_time").toString()).setScale(4, RoundingMode.HALF_UP);
|
|
stat.setProductionQuantity(quantity);
|
stat.setStandardTime(standardTime);
|
stat.setProcessTotalTime(standardTime.multiply(quantity).setScale(4, RoundingMode.HALF_UP));
|
|
// 工厂、专业和车间
|
stat.setPlant(data.get("factory").toString());
|
stat.setMajor(data.get("domain") != null ? data.get("domain").toString() : "");
|
stat.setWorkshop(data.get("workshop") != null ? data.get("workshop").toString() : "");
|
|
// 批次号和创建信息
|
stat.setBatchNumber(batchNumber);
|
stat.setCreateBy(SecurityUtils.getUsername());
|
stat.setCreateTime(truncateToSeconds(DateUtils.getNowDate()));
|
|
processList.add(stat);
|
}
|
|
// 计算计划完工日和计划开工日
|
if (!processList.isEmpty()) {
|
int lastIndex = processList.size() - 1;
|
|
// 最后一道工序的计划完工日期为预测日期
|
ApsGasPipingRouteStat lastProcess = processList.get(lastIndex);
|
Date predictDate = (Date) materialData.get(lastIndex).get("predict_date");
|
lastProcess.setProcessPlanEndDay(truncateToSeconds(predictDate));
|
|
// 标记是否出现过时间冲突的情况
|
boolean hasTimeConflict = false;
|
|
// 计算每个工序的计划开工日和完工日 - 从最后一道工序开始倒推
|
for (int i = lastIndex; i >= 0; i--) {
|
ApsGasPipingRouteStat current = processList.get(i);
|
|
// 如果当前是最后一道工序,计划开工日 = 计划完工日 - 工序总工时
|
if (i == lastIndex) {
|
hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
|
} else {
|
// 非最后一道工序,计划完工日为下一道工序的计划开工日
|
ApsGasPipingRouteStat next = processList.get(i + 1);
|
current.setProcessPlanEndDay(next.getProcessPlanStartDay());
|
|
// 如果已经出现时间冲突,后续工序的计划开工日和计划完工日都设为当前时间
|
if (hasTimeConflict) {
|
current.setProcessPlanStartDay(truncateToSeconds(new Date()));
|
} else {
|
// 否则正常计算,并检查是否出现时间冲突
|
hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
|
}
|
}
|
|
// 设置年、月、日
|
setDateComponents(current);
|
}
|
|
statList.addAll(processList);
|
}
|
}
|
|
// 处理手工气体工单数据 - 使用联合查询获取所有相关数据
|
List<Map<String, Object>> moDataList = apsGasPipingRouteStatMapper.selectMoRouteData();
|
|
// 获取所有的MO数据,用于检查哪些MO没有关联到工艺路线
|
List<Map<String, Object>> allMoData = apsGasPipingRouteStatMapper.selectAllMoData();
|
|
// 记录已关联工艺路线的MO编号
|
Set<String> processedMoSet = new HashSet<>();
|
|
// 按工单号分组,便于处理同一工单的不同工序
|
Map<String, List<Map<String, Object>>> moGroups = moDataList.stream()
|
.collect(Collectors.groupingBy(data -> data.get("work_order_no").toString()));
|
|
// 处理每个工单的工艺路线
|
for (String workOrderNo : moGroups.keySet()) {
|
List<Map<String, Object>> workOrderData = moGroups.get(workOrderNo);
|
|
// 标记该工单已处理
|
processedMoSet.add(workOrderNo);
|
|
// 按工序号排序
|
workOrderData.sort((a, b) -> {
|
String numA = a.get("process_number").toString();
|
String numB = b.get("process_number").toString();
|
return numA.compareTo(numB);
|
});
|
|
// 获取所有工序的信息并创建统计记录
|
List<ApsGasPipingRouteStat> processList = new ArrayList<>();
|
for (Map<String, Object> data : workOrderData) {
|
ApsGasPipingRouteStat stat = new ApsGasPipingRouteStat();
|
stat.setId(IdUtils.fastSimpleUUID());
|
stat.setWorkOrderNo(data.get("work_order_no").toString());
|
stat.setItemNumber(data.get("material_code").toString());
|
stat.setProcessName(data.get("process_name").toString());
|
stat.setRoadProcessNumber(new BigDecimal(data.get("process_number").toString()));
|
|
// 生产数量和标准工时
|
BigDecimal quantity = new BigDecimal(data.get("quantity").toString()).setScale(4, RoundingMode.HALF_UP);
|
BigDecimal standardTime = new BigDecimal(data.get("standard_time").toString()).setScale(4, RoundingMode.HALF_UP);
|
|
stat.setProductionQuantity(quantity);
|
stat.setStandardTime(standardTime);
|
stat.setProcessTotalTime(standardTime.multiply(quantity).setScale(4, RoundingMode.HALF_UP));
|
|
// 工厂、专业和车间
|
stat.setPlant(data.get("factory").toString());
|
stat.setMajor(data.get("domain") != null ? data.get("domain").toString() : "");
|
stat.setWorkshop(data.get("workshop") != null ? data.get("workshop").toString() : "");
|
|
// 批次号和创建信息
|
stat.setBatchNumber(batchNumber);
|
stat.setCreateBy(SecurityUtils.getUsername());
|
stat.setCreateTime(truncateToSeconds(DateUtils.getNowDate()));
|
|
processList.add(stat);
|
}
|
|
// 计算计划完工日和计划开工日
|
if (!processList.isEmpty()) {
|
int lastIndex = processList.size() - 1;
|
|
// 最后一道工序的计划完工日期为工单计划完工日期
|
ApsGasPipingRouteStat lastProcess = processList.get(lastIndex);
|
Date planEnd = (Date) workOrderData.get(0).get("plan_end");
|
lastProcess.setProcessPlanEndDay(truncateToSeconds(planEnd));
|
|
// 标记是否出现过时间冲突的情况
|
boolean hasTimeConflict = false;
|
|
// 计算每个工序的计划开工日和完工日 - 从最后一道工序开始倒推
|
for (int i = lastIndex; i >= 0; i--) {
|
ApsGasPipingRouteStat current = processList.get(i);
|
|
// 如果当前是最后一道工序,计划开工日 = 计划完工日 - 工序总工时
|
if (i == lastIndex) {
|
hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
|
} else {
|
// 非最后一道工序,计划完工日为下一道工序的计划开工日
|
ApsGasPipingRouteStat next = processList.get(i + 1);
|
current.setProcessPlanEndDay(next.getProcessPlanStartDay());
|
|
// 如果已经出现时间冲突,后续工序的计划开工日和计划完工日都设为当前时间
|
if (hasTimeConflict) {
|
current.setProcessPlanStartDay(truncateToSeconds(new Date()));
|
} else {
|
// 否则正常计算,并检查是否出现时间冲突
|
hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
|
}
|
}
|
|
// 设置年、月、日
|
setDateComponents(current);
|
}
|
|
statList.addAll(processList);
|
}
|
}
|
|
// 处理没有关联到工艺路线的MO数据
|
List<ApsPlateStandardRequireError> errorList = new ArrayList<>();
|
for (Map<String, Object> moData : allMoData) {
|
String workOrderNo = moData.get("mo").toString();
|
// 如果该工单没有被处理过,说明没有关联到工艺路线
|
if (!processedMoSet.contains(workOrderNo)) {
|
ApsPlateStandardRequireError error = ApsPlateStandardRequireError.builder()
|
.id(Long.valueOf(IdUtils.fastSimpleUUID().hashCode()))
|
.batchNumber(batchNumber)
|
.requireId(IdUtil.getSnowflakeNextId())
|
.docNum(workOrderNo)
|
.itemNum(moData.get("material_code").toString())
|
.orgCode(moData.get("factory").toString())
|
.message("标准工艺路线不存在")
|
.delFlag("0")
|
.build();
|
|
// 设置基类属性
|
error.setCreateBy(SecurityUtils.getUsername());
|
error.setCreateTime(truncateToSeconds(DateUtils.getNowDate()));
|
|
errorList.add(error);
|
}
|
}
|
|
// 批量插入异常数据
|
if (!errorList.isEmpty()) {
|
apsPlateStandardRequireErrorMapper.batchInsert(errorList);
|
}
|
|
// 批量插入数据
|
if (!statList.isEmpty()) {
|
for (int i = 0; i < statList.size(); i += 500) {
|
int endIndex = Math.min(i + 500, statList.size());
|
List<ApsGasPipingRouteStat> batch = statList.subList(i, endIndex);
|
count += apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(batch);
|
}
|
}
|
|
return count;
|
}
|
|
/**
|
* 计算工序计划开工日,并判断是否发生时间冲突
|
*
|
* @param stat 当前工序统计对象
|
* @param hasTimeConflict 之前是否已经发生时间冲突
|
* @return 是否发生时间冲突
|
*/
|
private boolean calculateProcessPlanStartDay(ApsGasPipingRouteStat stat, boolean hasTimeConflict) {
|
Date planEndDay = stat.getProcessPlanEndDay();
|
if (planEndDay == null) {
|
return hasTimeConflict;
|
}
|
|
// 计算工序总工时对应的秒数
|
long processTotalTimeSeconds = stat.getProcessTotalTime()
|
.multiply(BigDecimal.valueOf(60 * 60))
|
.longValue();
|
|
// 获取当前时间并精确到秒级别
|
Date now = truncateToSeconds(new Date());
|
|
// 计算开工日期并精确到秒级别
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(planEndDay);
|
|
// 分批减去秒数,避免int溢出
|
long seconds = processTotalTimeSeconds;
|
while (seconds > 0) {
|
int step = (seconds > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) seconds;
|
calendar.add(Calendar.SECOND, -step);
|
seconds -= step;
|
}
|
|
Date calculatedStartDay = truncateToSeconds(calendar.getTime());
|
|
// 如果计划完工日期小于等于当前时间,则计划开工日也设为计划完工日(当前时间)
|
if (planEndDay.compareTo(now) <= 0) {
|
stat.setProcessPlanStartDay(truncateToSeconds(planEndDay));
|
return true; // 发生时间冲突
|
}
|
// 如果计算出的计划开工日小于等于当前时间,则设为当前时间
|
else if (calculatedStartDay.compareTo(now) <= 0) {
|
stat.setProcessPlanStartDay(now);
|
return true; // 首次出现时间冲突
|
}
|
// 否则正常设置计划开工日
|
else {
|
stat.setProcessPlanStartDay(calculatedStartDay);
|
return hasTimeConflict; // 保持原有冲突状态
|
}
|
}
|
|
/**
|
* 将日期精确到秒级别,去除毫秒信息
|
*
|
* @param date 原始日期
|
* @return 精确到秒的日期
|
*/
|
private Date truncateToSeconds(Date date) {
|
if (date == null) {
|
return null;
|
}
|
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(date);
|
calendar.set(Calendar.MILLISECOND, 0);
|
return calendar.getTime();
|
}
|
|
/**
|
* 设置日期相关组件(年、月、日)
|
*/
|
private void setDateComponents(ApsGasPipingRouteStat stat) {
|
if (stat.getProcessPlanStartDay() != null) {
|
SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
|
SimpleDateFormat monthFormat = new SimpleDateFormat("MM");
|
SimpleDateFormat dayFormat = new SimpleDateFormat("dd");
|
|
stat.setPlanStartYear(yearFormat.format(stat.getProcessPlanStartDay()));
|
stat.setPlanStartMonth(monthFormat.format(stat.getProcessPlanStartDay()));
|
stat.setPlanStartDay(dayFormat.format(stat.getProcessPlanStartDay()));
|
}
|
}
|
|
/**
|
* 聚合气体管路产能负载统计数据
|
* 在Service层完成聚合处理,支持多维度分组
|
*
|
* @param params 聚合参数
|
* @return 聚合结果
|
*/
|
@Override
|
public Map<String, Object> aggregateGasPipingRouteStat(Map<String, Object> params) {
|
Map<String, Object> result = new HashMap<>();
|
List<Map<String, Object>> plantTable = new ArrayList<>();
|
|
// 获取时间颗粒度参数
|
String timeGranularity = params.containsKey("timeGranularity") ?
|
(String) params.get("timeGranularity") : "day"; // 默认为"日"粒度
|
|
// 获取row维度的聚合字段 - 默认为工序名称(processName)
|
String rowGroupBy = params.containsKey("rowGroupBy") ?
|
(String) params.get("rowGroupBy") : "processName";
|
|
// 确定分组维度 - 工厂、专业、车间
|
boolean groupByPlant = params.containsKey("groupByPlant") && Boolean.TRUE.equals(params.get("groupByPlant"));
|
boolean groupByMajor = params.containsKey("groupByMajor") && Boolean.TRUE.equals(params.get("groupByMajor"));
|
boolean groupByWorkshop = params.containsKey("groupByWorkshop") && Boolean.TRUE.equals(params.get("groupByWorkshop"));
|
// 如果rowGroupBy已经是某个维度,则该维度不需要再次分组
|
if ("plant".equals(rowGroupBy)) groupByPlant = false;
|
if ("major".equals(rowGroupBy)) groupByMajor = false;
|
if ("workshop".equals(rowGroupBy)) groupByWorkshop = false;
|
|
// 构建查询条件
|
Map<String, Object> queryParams = new HashMap<>();
|
|
// 设置查询条件 - 分类条件
|
if (params.containsKey("plant")) {
|
Object plantParam = params.get("plant");
|
if (plantParam instanceof List) {
|
queryParams.put("plants", plantParam);
|
} else if (plantParam instanceof String) {
|
// 处理可能的逗号分隔字符串
|
String plantStr = (String) plantParam;
|
if (plantStr.contains(",")) {
|
List<String> plantList = Arrays.asList(plantStr.split(","));
|
queryParams.put("plants", plantList);
|
} else {
|
queryParams.put("plant", plantStr);
|
}
|
}
|
}
|
|
if (params.containsKey("major")) {
|
Object majorParam = params.get("major");
|
if (majorParam instanceof List) {
|
queryParams.put("majors", majorParam);
|
} else if (majorParam instanceof String) {
|
// 处理可能的逗号分隔字符串
|
String majorStr = (String) majorParam;
|
if (majorStr.contains(",")) {
|
List<String> majorList = Arrays.asList(majorStr.split(","));
|
queryParams.put("majors", majorList);
|
} else {
|
queryParams.put("major", majorStr);
|
}
|
}
|
}
|
|
if (params.containsKey("workshop")) {
|
Object workshopParam = params.get("workshop");
|
if (workshopParam instanceof List) {
|
queryParams.put("workshops", workshopParam);
|
} else if (workshopParam instanceof String) {
|
// 处理可能的逗号分隔字符串
|
String workshopStr = (String) workshopParam;
|
if (workshopStr.contains(",")) {
|
List<String> workshopList = Arrays.asList(workshopStr.split(","));
|
queryParams.put("workshops", workshopList);
|
} else {
|
queryParams.put("workshop", workshopStr);
|
}
|
}
|
}
|
|
// 确定时间范围
|
List<String> timePoints = new ArrayList<>();
|
|
if ("day".equalsIgnoreCase(timeGranularity)) {
|
// "日"粒度:传入一个月份,聚合该月每一天的数据
|
if (!params.containsKey("yearMonth")) {
|
result.put("plantTable", plantTable);
|
result.put("message", "日粒度聚合需要指定yearMonth参数");
|
return result;
|
}
|
|
String yearMonth = (String) params.get("yearMonth");
|
// 生成指定月份中的每一天
|
YearMonth ym = YearMonth.parse(yearMonth);
|
int daysInMonth = ym.lengthOfMonth();
|
|
for (int day = 1; day <= daysInMonth; day++) {
|
String dayStr = String.format("%02d", day);
|
timePoints.add(yearMonth + "-" + dayStr);
|
}
|
|
// 设置查询参数
|
String[] ymParts = yearMonth.split("-");
|
queryParams.put("yearStart", ymParts[0]);
|
queryParams.put("monthStart", ymParts[1]);
|
queryParams.put("yearEnd", ymParts[0]);
|
queryParams.put("monthEnd", ymParts[1]);
|
|
} else if ("month".equalsIgnoreCase(timeGranularity)) {
|
// "月"粒度:传入一个时间区间,聚合该区间内每个月的数据
|
if (!params.containsKey("startDate") || !params.containsKey("endDate")) {
|
result.put("plantTable", plantTable);
|
result.put("message", "月粒度聚合需要指定startDate和endDate参数");
|
return result;
|
}
|
|
String startDate = (String) params.get("startDate");
|
String endDate = (String) params.get("endDate");
|
|
// 解析开始和结束年月
|
YearMonth start = YearMonth.parse(startDate);
|
YearMonth end = YearMonth.parse(endDate);
|
|
// 生成区间内的每个月
|
timePoints = getYearMonthsInRange(start, end);
|
|
// 设置查询参数
|
String[] startParts = startDate.split("-");
|
String[] endParts = endDate.split("-");
|
queryParams.put("yearStart", startParts[0]);
|
queryParams.put("monthStart", startParts[1]);
|
queryParams.put("yearEnd", endParts[0]);
|
queryParams.put("monthEnd", endParts[1]);
|
}
|
|
if (timePoints.isEmpty()) {
|
result.put("plantTable", plantTable);
|
result.put("message", "未能生成有效的时间点列表");
|
return result;
|
}
|
|
// 查询原始数据(不依赖数据库聚合)
|
List<Map<String, Object>> rawData = apsGasPipingRouteStatMapper.selectRawStatData(queryParams);
|
|
if (rawData.isEmpty()) {
|
result.put("plantTable", plantTable);
|
result.put("timePoints", timePoints);
|
return result;
|
}
|
|
// 在Service层完成聚合
|
// 使用组合key来实现多维度分组(动态rowGroupBy字段 + 可选的工厂/专业/车间)
|
Map<String, Map<String, Object>> groupInfoMap = new HashMap<>();
|
Map<String, Map<String, BigDecimal>> groupTimeDataMap = new HashMap<>();
|
|
// 遍历原始数据,按多维度分组进行聚合
|
for (Map<String, Object> data : rawData) {
|
// 获取行分组字段值
|
String rowGroupValue = getStringValue(data, rowGroupBy);
|
if (rowGroupValue == null || rowGroupValue.trim().isEmpty()) {
|
log.warn("跳过处理:{} 字段值为空", rowGroupBy);
|
continue;
|
}
|
|
// 获取工序名称(用于日志和后续处理)
|
String processName = getStringValue(data, "processName");
|
|
// 处理开工日期
|
Date processPlanStartDay = (Date) data.get("processPlanStartDay");
|
if (processPlanStartDay == null) {
|
log.warn("跳过处理:计划开工日为null, {}={}", rowGroupBy, rowGroupValue);
|
continue;
|
}
|
|
// 构建分组键 - 基于row分组字段和可选的其他维度
|
String plant = getStringValue(data, "plant");
|
String major = getStringValue(data, "major");
|
String workshop = getStringValue(data, "workshop");
|
|
StringBuilder groupKeyBuilder = new StringBuilder(rowGroupValue);
|
|
// 根据用户选择的分组维度添加到分组键
|
if (groupByPlant && plant != null) {
|
groupKeyBuilder.append("_PLANT_").append(plant);
|
}
|
if (groupByMajor && major != null) {
|
groupKeyBuilder.append("_MAJOR_").append(major);
|
}
|
if (groupByWorkshop && workshop != null) {
|
groupKeyBuilder.append("_WORKSHOP_").append(workshop);
|
}
|
|
String groupKey = groupKeyBuilder.toString();
|
|
// 记录分组的基本信息(只记录一次)
|
if (!groupInfoMap.containsKey(groupKey)) {
|
Map<String, Object> groupInfo = new HashMap<>();
|
groupInfo.put(rowGroupBy, rowGroupValue);
|
groupInfo.put("plant", plant);
|
groupInfo.put("major", major);
|
groupInfo.put("workshop", workshop);
|
groupInfo.put("processName", processName);
|
groupInfoMap.put(groupKey, groupInfo);
|
}
|
|
// 计算时间点Key
|
String timeKey;
|
LocalDate planStartLocalDate = processPlanStartDay.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
|
if ("day".equalsIgnoreCase(timeGranularity)) {
|
// 日粒度: 2025-05-25
|
timeKey = planStartLocalDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
|
} else {
|
// 月粒度: 2025-05
|
timeKey = planStartLocalDate.getYear() + "-" + String.format("%02d", planStartLocalDate.getMonthValue());
|
}
|
|
// 获取该分组的时间点映射,如果不存在则创建
|
if (!groupTimeDataMap.containsKey(groupKey)) {
|
groupTimeDataMap.put(groupKey, new HashMap<>());
|
}
|
Map<String, BigDecimal> timeMap = groupTimeDataMap.get(groupKey);
|
|
// 累加该分组在该时间点的工时数据
|
BigDecimal processTotalTime = getBigDecimalValue(data, "processTotalTime");
|
if (processTotalTime != null) {
|
BigDecimal currentTotal = timeMap.getOrDefault(timeKey, BigDecimal.ZERO);
|
timeMap.put(timeKey, currentTotal.add(processTotalTime));
|
}
|
}
|
|
// 构建最终返回的数据结构
|
for (String groupKey : groupInfoMap.keySet()) {
|
Map<String, Object> rowEntry = new HashMap<>();
|
Map<String, Object> rowDetail = new HashMap<>();
|
|
// 获取该分组的基本信息
|
Map<String, Object> groupInfo = groupInfoMap.get(groupKey);
|
String rowGroupValue = (String) groupInfo.get(rowGroupBy);
|
|
// 添加分组基本信息
|
if (groupByPlant) {
|
rowDetail.put("plant", groupInfo.get("plant"));
|
}
|
if (groupByMajor) {
|
rowDetail.put("major", groupInfo.get("major"));
|
}
|
if (groupByWorkshop) {
|
rowDetail.put("workshop", groupInfo.get("workshop"));
|
}
|
|
// 保留工序名称信息,以便前端展示
|
if (!"processName".equals(rowGroupBy)) {
|
rowDetail.put("processName", groupInfo.get("processName"));
|
}
|
|
// 添加时间数据
|
List<Map<String, Object>> timeDataList = new ArrayList<>();
|
Map<String, BigDecimal> timeMap = groupTimeDataMap.getOrDefault(groupKey, new HashMap<>());
|
|
for (String timePoint : timePoints) {
|
Map<String, Object> pointData = new HashMap<>();
|
pointData.put("planDay", timePoint);
|
pointData.put("designTimes", 0); // 设计工时暂时给0
|
|
// 获取该时间点的需求工时,如果不存在则设为0
|
BigDecimal requireTimes = timeMap.getOrDefault(timePoint, BigDecimal.ZERO);
|
pointData.put("requireTimes", requireTimes);
|
|
// 计算产能负荷(暂时为0)
|
pointData.put("capacityLoad", 0);
|
|
timeDataList.add(pointData);
|
}
|
|
rowDetail.put("timeData", timeDataList);
|
rowEntry.put(rowGroupValue, rowDetail);
|
plantTable.add(rowEntry);
|
}
|
|
result.put("plantTable", plantTable);
|
result.put("timePoints", timePoints);
|
result.put("rowGroupBy", rowGroupBy);
|
|
return result;
|
}
|
|
/**
|
* 从Map中安全获取String值
|
*/
|
private String getStringValue(Map<String, Object> data, String key) {
|
Object value = data.get(key);
|
if (value == null) {
|
return null;
|
}
|
return value.toString();
|
}
|
|
/**
|
* 从Map中安全获取BigDecimal值
|
*/
|
private BigDecimal getBigDecimalValue(Map<String, Object> data, String key) {
|
Object value = data.get(key);
|
if (value == null) {
|
return null;
|
}
|
|
if (value instanceof BigDecimal) {
|
return (BigDecimal) value;
|
} else if (value instanceof Number) {
|
return new BigDecimal(((Number) value).toString());
|
} else if (value instanceof String) {
|
try {
|
return new BigDecimal((String) value);
|
} catch (NumberFormatException e) {
|
log.warn("无法将值转换为BigDecimal: {}", value);
|
return null;
|
}
|
}
|
|
return null;
|
}
|
}
|