package com.aps.core.service.impl.ApsPlate;
|
|
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.web.domain.AjaxResult;
|
import com.aps.common.security.utils.DictUtils;
|
import com.aps.common.security.utils.SecurityUtils;
|
import com.aps.core.domain.*;
|
import com.aps.core.domain.ApsPlate.ApsPlatePlan;
|
import com.aps.core.domain.ApsPlate.ApsPlateProcessShopPlanStat;
|
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;
|
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.service.ApsPlate.IApsPlateProcessShopStatService;
|
import org.springframework.transaction.annotation.Transactional;
|
|
/**
|
* 钣金车间统计Service业务层处理
|
*
|
* @author zhl
|
* @date 2025-04-23
|
*/
|
@Slf4j
|
@Service
|
public class ApsPlateProcessShopStatServiceImpl implements IApsPlateProcessShopStatService {
|
@Autowired
|
private ApsPlateProcessShopStatMapper apsPlateProcessShopStatMapper;
|
@Resource
|
private ApsPlateProcessStatMapper apsPlateProcessStatMapper;
|
|
@Resource
|
private ApsShopMapper shopMapper;
|
|
@Resource
|
private ApsStandardProcessMapper standardProcessMapper;
|
|
@Resource
|
private ApsPlatePlanMapper apsPlatePlanMapper;
|
@Autowired
|
private IApsPlateProcessStatService apsPlateProcessStatService;
|
|
|
|
/**
|
* 查询钣金车间统计
|
*
|
* @param id 钣金车间统计主键
|
* @return 钣金车间统计
|
*/
|
@Override
|
public ApsPlateProcessShopStat selectApsPlateProcessShopStatById(Long id) {
|
return apsPlateProcessShopStatMapper.selectApsPlateProcessShopStatById(id);
|
}
|
|
/**
|
* 查询钣金车间统计列表
|
*
|
* @param apsPlateProcessShopStat 钣金车间统计
|
* @return 钣金车间统计
|
*/
|
@Override
|
public List<ApsPlateProcessShopStat> selectApsPlateProcessShopStatList(ApsPlateProcessShopStat apsPlateProcessShopStat) {
|
return apsPlateProcessShopStatMapper.selectApsPlateProcessShopStatList(apsPlateProcessShopStat);
|
}
|
|
/**
|
* 新增钣金车间统计
|
*
|
* @param apsPlateProcessShopStat 钣金车间统计
|
* @return 结果
|
*/
|
@Override
|
public int insertApsPlateProcessShopStat(ApsPlateProcessShopStat apsPlateProcessShopStat) {
|
apsPlateProcessShopStat.setCreateTime(DateUtils.getNowDate());
|
return apsPlateProcessShopStatMapper.insertApsPlateProcessShopStat(apsPlateProcessShopStat);
|
}
|
|
/**
|
* 修改钣金车间统计
|
*
|
* @param apsPlateProcessShopStat 钣金车间统计
|
* @return 结果
|
*/
|
@Override
|
public int updateApsPlateProcessShopStat(ApsPlateProcessShopStat apsPlateProcessShopStat) {
|
apsPlateProcessShopStat.setUpdateTime(DateUtils.getNowDate());
|
return apsPlateProcessShopStatMapper.updateApsPlateProcessShopStat(apsPlateProcessShopStat);
|
}
|
|
/**
|
* 批量删除钣金车间统计
|
*
|
* @param ids 需要删除的钣金车间统计主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteApsPlateProcessShopStatByIds(Long[] ids) {
|
return apsPlateProcessShopStatMapper.deleteApsPlateProcessShopStatByIds(ids);
|
}
|
|
/**
|
* 删除钣金车间统计信息
|
*
|
* @param id 钣金车间统计主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteApsPlateProcessShopStatById(Long id) {
|
return apsPlateProcessShopStatMapper.deleteApsPlateProcessShopStatById(id);
|
}
|
|
/**
|
* 保存钣金车间统计
|
*/
|
@Transactional( rollbackFor =Exception.class)
|
@Override
|
public void saveShopStat() {
|
// 定义该功能使用数据源为南通的工厂
|
final String plant = "FORTUNA";
|
final String major="BJ";
|
// 查询相关数据
|
ApsPlatePlan platePlan = new ApsPlatePlan();
|
platePlan.setPlant(plant);
|
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()) {
|
// 开始之前先删除所有历史数据
|
apsPlateProcessStatMapper.deleteAll();
|
apsPlateProcessShopStatMapper.deleteAll();
|
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())
|
));
|
// 批量插入统计数据
|
List<ApsPlateProcessShopStat> statsToInsert = new ArrayList<>();
|
for (ApsPlatePlan plan : planList) {
|
for (ApsShop shop : shopList) {
|
ApsPlateProcessShopStat stat = createShopStat(plan, shop, shopToProcessNames, statList);
|
statsToInsert.add(stat);
|
}
|
}
|
List<List<ApsPlateProcessStat>> processStatBatchList = ListUtil.split(statList, 1000);
|
processStatBatchList.forEach(batch -> apsPlateProcessStatMapper.batchInsertPlateStat(batch));
|
|
|
List<List<ApsPlateProcessShopStat>> shopStatBatchList = ListUtil.split(statsToInsert, 1000);
|
shopStatBatchList.forEach(batch -> apsPlateProcessShopStatMapper.batchInsert(batch));
|
}else {
|
if(shopProcesses.isEmpty()){
|
throw new RuntimeException("未找到标准工序数据!");
|
}
|
if(shopList.isEmpty()){
|
throw new RuntimeException("未找到车间数据!");
|
}
|
if(planList.isEmpty()){
|
throw new RuntimeException("未找到工单数据!");
|
}
|
}
|
}
|
|
/**
|
* 创建单个车间统计对象
|
*/
|
private ApsPlateProcessShopStat createShopStat(ApsPlatePlan plan, ApsShop shop,
|
Map<String, List<String>> shopToProcessNames, List<ApsPlateProcessStat> statList) {
|
String shopName = shop.getShopName();
|
ApsPlateProcessShopStat stat = new ApsPlateProcessShopStat();
|
stat.setDocNo(plan.getDocumentNumber());
|
stat.setShopCode(shop.getShopCode());
|
stat.setShopName(shopName);
|
stat.setDelFlag("0");
|
stat.setCreateBy(SecurityUtils.getUsername());
|
stat.setCreateTime(DateUtils.getNowDate());
|
stat.setWorkCenter(plan.getWorkCenter());
|
stat.setProcessNumber(plan.getProcessNumber());
|
try {
|
|
List<String> processNames = shopToProcessNames.getOrDefault(shopName, Collections.emptyList());
|
if (!processNames.isEmpty()) {
|
// 根据工序名称,查询该工单下所有的工序信息
|
List<ApsPlateProcessStat> processStats = statList.stream()
|
.filter(x -> processNames.contains(x.getProcessName()) && x.getWorkOrderNo().equals(plan.getDocumentNumber())
|
&&x.getProcessPlanStartDay()!=null&&x.getProcessPlanEndDay()!=null
|
).toList();
|
if (!processStats.isEmpty()) {
|
// 取出工单下工序的最小开始时间和最大结束时间
|
List<Date> startDayList = processStats.stream().map(ApsPlateProcessStat::getProcessPlanStartDay).filter(Objects::nonNull).toList();
|
if (!startDayList.isEmpty()) {
|
if (startDayList.size() == 1) {
|
stat.setPlanStartDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", startDayList.get(0)));
|
} else {
|
Optional<Date> minStartDay = processStats.stream()
|
.map(ApsPlateProcessStat::getProcessPlanStartDay)
|
.min(Comparator.naturalOrder());
|
Date date = minStartDay.get();
|
stat.setPlanStartDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", date));
|
}
|
|
|
}
|
List<Date> endDayList = processStats.stream().map(ApsPlateProcessStat::getProcessPlanEndDay).filter(Objects::nonNull).toList();
|
if (!endDayList.isEmpty()) {
|
if (endDayList.size() == 1) {
|
stat.setPlanEndDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", endDayList.get(0)));
|
} else {
|
Optional<Date> maxEndDay = processStats.stream()
|
.map(ApsPlateProcessStat::getProcessPlanEndDay)
|
.max(Comparator.naturalOrder());
|
Date date = maxEndDay.get();
|
stat.setPlanEndDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", date));
|
}
|
|
}
|
|
}
|
}
|
} catch (Exception e) {
|
log.error("computer error:"+ JSONObject.toJSONString(stat));
|
throw new RuntimeException("计算车间统计数据异常!");
|
}
|
return stat;
|
}
|
|
@Override
|
public AjaxResult getShopPlanStat() {
|
// 提取硬编码值为常量
|
final String PLANT_CODE = "FORTUNA";
|
|
// 初始化对象
|
ApsPlatePlan platePlan = new ApsPlatePlan();
|
platePlan.setPlant(PLANT_CODE);
|
|
ApsShop apsShop = new ApsShop();
|
apsShop.setPlantCode(PLANT_CODE);
|
apsShop.setStatus("1");
|
// 获取车间列表并处理空值
|
List<String> shopList = Optional.ofNullable(shopMapper.selectApsShopList(apsShop))
|
.orElse(Collections.emptyList())
|
.stream()
|
.map(ApsShop::getShopName)
|
.toList();
|
|
// 获取计划列表和状态列表
|
List<ApsPlateProcessShopPlanStat> planList = apsPlateProcessShopStatMapper.selectPlatePlanBaseTable();
|
|
List<ApsPlateProcessShopStat> shopStates = Optional.ofNullable(apsPlateProcessShopStatMapper.selectApsPlateProcessShopStatList(new ApsPlateProcessShopStat()))
|
.orElse(Collections.emptyList());
|
|
// 提前对 shopStates 按 docNo 分组,减少重复流操作
|
Map<String, List<ApsPlateProcessShopStat>> shopStatesByDocNo = shopStates.stream()
|
.collect(Collectors.groupingBy(ApsPlateProcessShopStat::getDocNo));
|
|
|
List<SysDictData> businessTypeDic = DictUtils.getDictCache("aps_business_type");
|
List<SysDictData> documentStatusDic = DictUtils.getDictCache("aps_document_status");
|
|
// 构建结果列表
|
planList.forEach(
|
plan -> {
|
// 根据 docNo 获取对应的 shopStatList
|
List<ApsPlateProcessShopStat> shopStatList = shopStatesByDocNo.getOrDefault(plan.getDocumentNumber(), Collections.emptyList());
|
plan.setDeptPlans(shopStatList);
|
if (businessTypeDic != null) {
|
businessTypeDic.stream().filter(x -> x.getDictValue().equals(plan.getBusinessType())).findFirst()
|
.ifPresent(sysDictData -> plan.setBusinessType(sysDictData.getDictLabel()));
|
}
|
if (documentStatusDic != null) {
|
documentStatusDic.stream().filter(x->x.getDictValue().equals(plan.getDocumentStatus()))
|
.findFirst().ifPresent(sysDictData -> plan.setDocumentStatus(sysDictData.getDictLabel()));
|
}
|
});
|
// 构建返回结果
|
AjaxResult success = AjaxResult.success(planList);
|
success.put("shopNames", shopList);
|
return success;
|
}
|
|
@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 titleStyle = styles.get("title");
|
try
|
{
|
|
AjaxResult stat = getShopPlanStat();
|
List<String> shopNames = (List<String>) stat.get("shopNames");
|
List<ApsPlateProcessShopPlanStat> table= (List<ApsPlateProcessShopPlanStat>)stat.get("data");
|
SXSSFSheet sheet = wb.getSheetAt(0);
|
/*填写日期列 和 工时列*/
|
SXSSFRow rowTitle = sheet.createRow(0);
|
|
Map<Integer, String> FrontTitleMap = initFrontTitle(shopNames);
|
FrontTitleMap.forEach((index, titleName) -> {
|
createCell(rowTitle, index, titleName, titleStyle);
|
});
|
|
|
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);
|
|
LinkedHashMap<String,String> frontTitles= frontTitleName();
|
ArrayList<Map.Entry<String, String>> frontTitlesList = new ArrayList<Map.Entry<String, String>>(
|
frontTitles.entrySet());
|
|
for (int i1 = 0; i1 < frontTitlesList.size(); i1++) {
|
|
Map.Entry<String, String> entry = frontTitlesList.get(i1);
|
String filedKey = entry.getKey();
|
String fieldValue= node.get(filedKey).textValue();
|
createCell(dataRow, i1,fieldValue , null);
|
}
|
|
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)
|
{
|
log.error("导出Excel异常{}", e.getMessage());
|
}
|
finally
|
{
|
IOUtils.closeQuietly(wb);
|
}
|
|
}
|
|
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<>();
|
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;
|
}
|
|
|
}
|