package com.aps.core.service.impl;
|
|
import java.text.SimpleDateFormat;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import com.alibaba.fastjson.JSONObject;
|
import com.aps.common.core.utils.DateUtils;
|
import com.aps.common.core.utils.bean.BeanUtils;
|
import com.aps.common.core.web.domain.AjaxResult;
|
import com.aps.common.security.utils.DictUtils;
|
import com.aps.common.security.utils.SecurityUtils;
|
import com.aps.core.domain.*;
|
import com.aps.core.mapper.*;
|
import com.aps.system.api.domain.SysDictData;
|
import jakarta.annotation.Resource;
|
import jakarta.servlet.http.HttpServletResponse;
|
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.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;
|
|
|
/**
|
* 查询钣金车间统计
|
*
|
* @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
|
@Override
|
public void saveShopStat() {
|
try {
|
// 开始之前先删除所有历史数据
|
apsPlateProcessShopStatMapper.deleteAll();
|
|
// 定义该功能使用数据源为南通的工厂
|
final String plant = "FORTUNA";
|
final String major="钣金";
|
// 查询相关数据
|
ApsPlatePlan platePlan = new ApsPlatePlan();
|
platePlan.setPlant(plant);
|
List<ApsPlatePlan> planList = apsPlatePlanMapper.selectApsPlatePlanList(platePlan);
|
|
List<ApsPlateProcessStat> statList = apsPlateProcessStatMapper.selectApsPlateProcessStatList(new ApsPlateProcessStat());
|
|
ApsShop apsShop = new ApsShop();
|
apsShop.setPlantCode(plant);
|
List<ApsShop> shopList = shopMapper.selectApsShopList(apsShop);
|
|
ApsStandardProcess process = new ApsStandardProcess();
|
process.setPlant(plant);
|
process.setMajor(major);
|
List<ApsStandardProcess> shopProcesses = standardProcessMapper.selectApsStandardProcessList(process);
|
if (planList.isEmpty() || shopList.isEmpty() || shopProcesses.isEmpty()) {
|
log.warn("计划列表、车间列表或工序列表为空,无法生成统计信息");
|
return;
|
}
|
// 构建车间名称到工序名称的映射
|
Map<String, List<String>> shopToProcessNames = shopProcesses.stream()
|
.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);
|
}
|
}
|
// 批量插入以提高性能
|
if (!statsToInsert.isEmpty()) {
|
int batchSize = 1000;
|
for (int i = 0; i < statsToInsert.size(); i += batchSize) {
|
int end = Math.min(i + batchSize, statsToInsert.size());
|
List<ApsPlateProcessShopStat> batch = statsToInsert.subList(i, end);
|
apsPlateProcessShopStatMapper.batchInsert(batch);
|
}
|
}
|
} catch (Exception e) {
|
log.error("保存钣金车间统计时发生异常", e);
|
throw new RuntimeException("保存钣金车间统计失败", e);
|
}
|
}
|
|
/**
|
* 创建单个车间统计对象
|
*/
|
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));
|
}
|
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);
|
|
// 获取车间列表并处理空值
|
List<String> shopList = Optional.ofNullable(shopMapper.selectApsShopList(apsShop))
|
.orElse(Collections.emptyList())
|
.stream()
|
.map(ApsShop::getShopName)
|
.toList();
|
|
// 获取计划列表和状态列表
|
List<ApsPlatePlan> planList = Optional.ofNullable(apsPlatePlanMapper.selectApsPlatePlanList(platePlan))
|
.orElse(Collections.emptyList());
|
|
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");
|
|
// 构建结果列表
|
List<ApsPlateProcessShopPlanStat> shopPlanStats = planList.stream()
|
.map(plan -> {
|
ApsPlateProcessShopPlanStat shopPlanStat = new ApsPlateProcessShopPlanStat();
|
BeanUtils.copyProperties(plan, shopPlanStat); // 确保目标对象是合法的单个对象实例
|
|
// 根据 docNo 获取对应的 shopStatList
|
List<ApsPlateProcessShopStat> shopStatList = shopStatesByDocNo.getOrDefault(plan.getDocumentNumber(), Collections.emptyList());
|
shopPlanStat.setDeptPlans(shopStatList);
|
if (businessTypeDic != null) {
|
businessTypeDic.stream().filter(x -> x.getDictValue().equals(plan.getBusinessType())).findFirst()
|
.ifPresent(sysDictData -> shopPlanStat.setBusinessType(sysDictData.getDictLabel()));
|
}
|
if (documentStatusDic != null) {
|
documentStatusDic.stream().filter(x->x.getDictValue().equals(plan.getDocumentStatus()))
|
.findFirst().ifPresent(sysDictData -> shopPlanStat.setDocumentStatus(sysDictData.getDictLabel()));
|
}
|
return shopPlanStat;
|
}).toList();
|
// 构建返回结果
|
AjaxResult success = AjaxResult.success(shopPlanStats);
|
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 title = 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);
|
SXSSFCell mainPartNumberTitle = rowTitle.createCell(0);
|
mainPartNumberTitle.setCellValue("主件料号");
|
mainPartNumberTitle.setCellStyle(title);
|
|
SXSSFCell businessTypeTitle = rowTitle.createCell(1);
|
businessTypeTitle.setCellValue("业务类型");
|
businessTypeTitle.setCellStyle(title);
|
|
SXSSFCell documentNumberTitle = rowTitle.createCell(2);
|
documentNumberTitle.setCellValue("单据号");
|
documentNumberTitle.setCellStyle(title);
|
|
SXSSFCell requirementTypeTitle = rowTitle.createCell(3);
|
requirementTypeTitle.setCellValue("需求分类");
|
requirementTypeTitle.setCellStyle(title);
|
|
SXSSFCell documentStatusTitle = rowTitle.createCell(4);
|
documentStatusTitle.setCellValue("单据状态");
|
documentStatusTitle.setCellStyle(title);
|
|
SXSSFCell workCenterTitle = rowTitle.createCell(5);
|
workCenterTitle.setCellValue("当前工序");
|
workCenterTitle.setCellStyle(title);
|
|
SXSSFCell departmentTitle = rowTitle.createCell(6);
|
departmentTitle.setCellValue("当前工序负责人");
|
departmentTitle.setCellStyle(title);
|
|
SXSSFCell nextProcessDeparmentTitle = rowTitle.createCell(7);
|
nextProcessDeparmentTitle.setCellValue("下一工序负责人");
|
nextProcessDeparmentTitle.setCellStyle(title);
|
|
SXSSFCell itemNumberTitle = rowTitle.createCell(8);
|
itemNumberTitle.setCellValue("料号");
|
itemNumberTitle.setCellStyle(title);
|
|
SXSSFCell drawingNoTitle = rowTitle.createCell(9);
|
drawingNoTitle.setCellValue("图号");
|
drawingNoTitle.setCellStyle(title);
|
|
SXSSFCell versionNumberTitle = rowTitle.createCell(10);
|
versionNumberTitle.setCellValue("版本号");
|
versionNumberTitle.setCellStyle(title);
|
|
SXSSFCell productionQuantityTitle = rowTitle.createCell(11);
|
productionQuantityTitle.setCellValue("生产数量");
|
productionQuantityTitle.setCellStyle(title);
|
|
SXSSFCell planEndDayTitle = rowTitle.createCell(12);
|
planEndDayTitle.setCellValue("计划完工日");
|
planEndDayTitle.setCellStyle(title);
|
|
|
|
int i1 = 13;
|
for (int i = 0; i < shopNames.size(); i++) {
|
String shopName = shopNames.get(i);
|
SXSSFCell beginDateCell = rowTitle.createCell(i * 2 + i1);
|
SXSSFCell endDateCell = rowTitle.createCell(i * 2 + i1+1);
|
beginDateCell.setCellValue(shopName+"开工时间");
|
endDateCell.setCellValue(shopName+"完工时间");
|
beginDateCell.setCellStyle(title);
|
endDateCell.setCellStyle(title);
|
}
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
for (int i = 0; i < table.size(); i++) {
|
ApsPlateProcessShopPlanStat plan = table.get(i);
|
|
SXSSFRow dataRow = sheet.createRow(i+1);
|
|
SXSSFCell mainPartNumberCell = dataRow.createCell(0);
|
mainPartNumberCell.setCellValue(plan.getMainPartNumber());
|
|
//mainPartNumberCell.setCellStyle(title);
|
|
SXSSFCell businessTypeCell= dataRow.createCell(1);
|
businessTypeCell.setCellValue(plan.getBusinessType());
|
//businessTypeCell.setCellStyle(title);
|
|
SXSSFCell documentNumberCell = dataRow.createCell(2);
|
documentNumberCell.setCellValue(plan.getDocumentNumber());
|
// documentNumberCell.setCellStyle(title);
|
|
SXSSFCell requirementTypeCell = dataRow.createCell(3);
|
requirementTypeCell.setCellValue(plan.getRequirementType());
|
// requirementTypeCell.setCellStyle(title);
|
|
SXSSFCell documentStatusCell = dataRow.createCell(4);
|
documentStatusCell.setCellValue(plan.getDocumentStatus());
|
// documentStatusCell.setCellStyle(title);
|
|
SXSSFCell workCenterCell = dataRow.createCell(5);
|
workCenterCell.setCellValue(plan.getWorkCenter());
|
// workCenterCell.setCellStyle(title);
|
|
SXSSFCell departmentCell = dataRow.createCell(6);
|
departmentCell.setCellValue(plan.getDepartment());
|
|
SXSSFCell nextProcessDeparmentCell = dataRow.createCell(7);
|
nextProcessDeparmentCell.setCellValue(plan.getNextProcessDeparment());
|
|
|
SXSSFCell itemNumberCell = dataRow.createCell(8);
|
itemNumberCell.setCellValue(plan.getItemNumber());
|
// itemNumberCell.setCellStyle(title);
|
|
SXSSFCell drawingNoCell = dataRow.createCell(9);
|
drawingNoCell.setCellValue(plan.getDrawingNo());
|
// drawingNoCell.setCellStyle(title);
|
|
SXSSFCell versionNumberCell = dataRow.createCell(10);
|
versionNumberCell.setCellValue(plan.getVersionNumber());
|
// versionNumberCell.setCellStyle(title);
|
|
SXSSFCell productionQuantityCell = dataRow.createCell(11);
|
productionQuantityCell.setCellValue(plan.getProductionQuantity().toString());
|
// productionQuantityCell.setCellStyle(title);
|
|
SXSSFCell planEndDayCell = dataRow.createCell(12);
|
planEndDayCell.setCellValue(dateFormat.format(plan.getPlanEndDay()));
|
// planEndDayCell.setCellStyle(title);
|
|
for (int j = 0; j< shopNames.size(); j++) {
|
String shopName = shopNames.get(j);
|
SXSSFCell beginDateCell = dataRow.createCell(j * 2 + i1);
|
SXSSFCell endDateCell = dataRow.createCell(j * 2 + i1+1);
|
plan.getDeptPlans().stream().filter(x->x.getShopName().equals(shopName)).findFirst().ifPresent(x->{
|
beginDateCell.setCellValue(x.getPlanStartDate());
|
endDateCell.setCellValue(x.getPlanEndDate());
|
});
|
}
|
|
|
}
|
|
for (int i = 0; i < 24; i++) {
|
|
sheet.setColumnWidth(i, 20 * 256);
|
}
|
|
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;
|
}
|
|
|
}
|