evoToK3Cloud/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java
2026-04-12 10:11:15 +08:00

2463 lines
122 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ruoyi.system.controller;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.HashSet;
import java.util.stream.Collectors;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ruoyi.common.excel.DefaultExcelListener;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.FtpUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.VersionComparator;
import com.ruoyi.common.utils.file.SmbUtil;
import com.ruoyi.common.poi.ExcelTemplateProc;
import com.ruoyi.common.poi.DynamicDataMapping;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.dto.MaterialUseDTO;
import com.ruoyi.system.domain.dto.ProcessRouteDTO;
import com.ruoyi.system.domain.ProcessRouteExcelDTO1;
import com.ruoyi.system.domain.dto.excuteDrawing.RigidChainModelDTO;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.domain.vo.BomDataVO;
import com.ruoyi.system.mapper.FigureSaveMapper;
import com.ruoyi.system.mapper.ProcessOrderProMapper;
import com.ruoyi.system.mapper.SafetyStockMapper;
import com.ruoyi.system.runner.JdUtil;
import com.ruoyi.system.service.*;
import lombok.RequiredArgsConstructor;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.bo.ProcessOrderProBo;
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import shade.com.alibaba.fastjson2.JSON;
import shade.com.alibaba.fastjson2.JSONObject;
/**
* 生产项目
* @author tzy
* @date 2024-10-22
*/
@Validated
@RequiredArgsConstructor
@RestController
@Slf4j
@RequestMapping("/system/orderPro")
public class ProcessOrderProController extends BaseController {
private final IProcessOrderProService iProcessOrderProService;
@Autowired
private final IMrpResultCheckService iMrpResultCheckService;
private final ProcessOrderProMapper processOrderProMapper;
private final IImMaterialService imMaterialService;
private final ISafetyStockService safetyStockService;
private final IProcessRouteService processRouteService;
private final SafetyStockMapper stockMapper;
private final FigureSaveMapper figureSaveMapper;
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy年MM月dd日");
/**
* 查询项目令号列表
*/
@SaCheckPermission("system:orderPro:list")
@GetMapping("/list")
public TableDataInfo<ProcessOrderProVo> list(ProcessOrderProBo bo, PageQuery pageQuery) {
return iProcessOrderProService.queryPageList(bo, pageQuery);
}
@SaCheckPermission("system:orderPro:processlist")
@GetMapping("/processlist")
public List<ProcessRoute> processList(ProcessOrderProBo bo) {
return iProcessOrderProService.selectProList(bo);
}
/**
* 导出项目令号列表
*/
@SaCheckPermission("system:orderPro:export")
@Log(title = "项目令号", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ProcessOrderProBo bo, HttpServletResponse response) {
List<ProcessOrderProVo> list = iProcessOrderProService.queryList(bo);
ExcelUtil.exportExcel(list, "项目令号", ProcessOrderProVo.class, response);
}
/**
* 获取项目令号详细信息
*
* @param id 主键
*/
@SaCheckPermission("system:orderPro:query")
@GetMapping("/{id}")
public R<ProcessOrderProVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(iProcessOrderProService.queryById(id));
}
/**
* 新增项目令号
*/
@SaCheckPermission("system:orderPro:add")
@Log(title = "项目令号", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ProcessOrderProBo bo) {
boolean result = iProcessOrderProService.insertByBo(bo);
return toAjax(result);
}
/**
* 修改项目令号
*/
@SaCheckPermission("system:orderPro:edit")
@Log(title = "项目令号", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ProcessOrderProBo bo) {
return toAjax(iProcessOrderProService.updateByBo(bo));
}
/**
* 清空项目关联数据(保留项目)
*
* @param ids 主键串
*/
@SaCheckPermission("system:orderPro:clear")
@Log(title = "清空项目数据", businessType = BusinessType.CLEAN)
@DeleteMapping("/clear/{ids}")
public R<Void> clear(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return iProcessOrderProService.clearProjectData(Arrays.asList(ids));
}
/**
* 删除项目令号
*
* @param ids 主键串
*/
@SaCheckPermission("system:orderPro:remove")
@Log(title = "项目令号", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return iProcessOrderProService.deleteWithValidByIds(Arrays.asList(ids), true);
}
/**
* 推送钉钉卡片
*/
@SaCheckPermission("system:orderPro:pushDingTalkCard")
@Log(title = "推送钉钉卡片", businessType = BusinessType.UPDATE)
@PostMapping("/pushDingTalkCard/{id}")
public R<Void> pushDingTalkCard(@PathVariable Long id) {
iProcessOrderProService.pushDingTalkCard(id);
return R.ok();
}
@SaCheckPermission("system:orderPro:getExcel")
@Log(title = "获取项目生产数据表", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/getExcel")
public R<Void> getExcel(@Validated(AddGroup.class) @RequestBody ProcessOrderProBo bo) {
// 获取项目生产数据表 获取项目令号 也是文件夹的名称
SmbUtil.downloadExcelFiles(bo.getProductionOrderNo());
// 在本地读取EXCEL 文件
String ExcelName = "D:\\file\\" + bo.getProductionOrderNo() + ".xlsx";
try {
File file = new File(ExcelName);
if (file.exists()) {
// 读取Excel的sheet6 从第三行开始 读取到第4列 无数据的跳过
DefaultExcelListener<ProcessRoute> listener = new DefaultExcelListener<>(true);
EasyExcel.read(ExcelName, ProcessRoute.class, listener).sheet(6).headRowNumber(3).doRead();
List<ProcessRoute> list = listener.getExcelResult().getList();
for (ProcessRoute processRoute : list) {
System.out.println(processRoute.getMaterialCode());
System.out.println(processRoute.getMaterialName());
System.out.println(processRoute.getMaterial());
System.out.println(processRoute.getDiscWeight());
System.out.println("===================================================================");
}
} else {
throw new ServiceException("没有数据");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
//读取excel文件sheet
return toAjax(iProcessOrderProService.insertByBo(bo));
}
/**
* 批量更新项目令号的计划开始和结束时间
* 根据工艺路线中的工序获取每个项目令号的最早开始时间和最晚结束时间并更新到ProcessOrderPro
*/
@PostMapping("/batchUpdateProjectTimeRanges")
public void batchUpdateProjectTimeRanges() {
iProcessOrderProService.batchUpdateProjectTimeRanges();
}
@SaCheckPermission("system:orderPro:addProduct")
@Log(title = "排产计划", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/addProduct")
public R<Void> addProduct(@Validated(AddGroup.class) @RequestBody RigidChainModelDTO orderPro) {
iProcessOrderProService.addProduct(orderPro);
return R.ok();
}
@SaCheckPermission("system:orderPro:executDrawing")
@Log(title = "执行出图", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/executDrawing")
public R<Void> executDrawing(@RequestBody ProcessOrderProBo orderPro) {
String s = iProcessOrderProService.executDrawing(orderPro);
return R.ok(s);
}
@GetMapping("/executDrawing/progress/{id}")
public SseEmitter executDrawingProgress(@PathVariable Long id) {
return iProcessOrderProService.startDrawingSse(id);
}
/**
* 上传dwg图纸
*
* @param filePath
* @return
*/
@SaCheckPermission("system:orderPro:uploadDwg")
@Log(title = "上传dwg图纸", businessType = BusinessType.uploadDwg)
@PostMapping("/uploadDwg")
@ResponseBody
public R<Void> uploadContractPDF(@RequestParam("ids") List<Long> ids, @RequestParam("file") MultipartFile filePath) {
String originalFilename = filePath.getOriginalFilename();
if (StringUtils.isEmpty(originalFilename)) {
return R.fail("获取文件名称错误!!");
}
String suffix = originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
if (!"dwg".equalsIgnoreCase(suffix)) {
return R.fail("禁止非法文件上传!!");
}
List<String> results = new ArrayList<>();
for (Long id : ids) {
if (id == null) {
results.add("ID为空已跳过");
continue;
}
String res = iProcessOrderProService.uploadContractPDF(id.intValue(), originalFilename, filePath);
results.add("ID=" + id + ":" + res);
}
return R.ok(StringUtils.join(results, ","));
}
/**
* 下载PDF并生成zip包
*/
@SaCheckPermission("system:orderPro:uploadPDF")
@Log(title = "下载PDF", businessType = BusinessType.UPDATE)
@CrossOrigin(origins = "*", allowedHeaders = "*", exposedHeaders = {"Content-Disposition", "Content-Length"})
@GetMapping("/uploadPDF")
public void uploadPDF(@RequestParam Long id, HttpServletResponse response) {
try {
// CORS headers for all responses (success and error)
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length");
// 调用service方法获取文件路径
R<String> result = iProcessOrderProService.uploadPDF(id);
if (result.getCode() != 200) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":" + result.getCode() + ",\"msg\":\"" + result.getMsg() + "\"}");
return;
}
String filePath = result.getMsg();
File file = new File(filePath);
// 检查文件是否存在
if (!file.exists()) {
response.setStatus(HttpStatus.NOT_FOUND.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":404,\"msg\":\"文件不存在\"}");
return;
}
// 设置响应头
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(file.getName(), "UTF-8") + "\"");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length");
// 写入文件流
try (FileInputStream fis = new FileInputStream(file);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int length;
while ((length = fis.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
}
} catch (Exception e) {
log.error("下载PDF文件失败", e);
try {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.getWriter().write("下载失败: " + e.getMessage());
} catch (IOException ex) {
log.error("写入错误响应失败", ex);
}
}
}
/**
* 下载ZIP包
*/
@SaCheckPermission("system:orderPro:downloadZip")
@Log(title = "下载ZIP包", businessType = BusinessType.OTHER)
@GetMapping("/downloadZip/{id}")
public void downloadZip(@PathVariable Long id, HttpServletResponse response) {
try {
// 获取ZIP包路径
R<String> result = iProcessOrderProService.uploadPDF(id);
if (result.getCode() != 200) {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("生成ZIP包失败: " + result.getMsg());
return;
}
String zipPath = result.getData();
File zipFile = new File(zipPath);
if (!zipFile.exists()) {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("ZIP文件不存在: " + zipPath);
return;
}
// 设置响应头
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=" +
java.net.URLEncoder.encode(zipFile.getName(), "UTF-8"));
response.setContentLength((int) zipFile.length());
// 写入文件流
try (FileInputStream fis = new FileInputStream(zipFile);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
}
} catch (Exception e) {
try {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("下载失败: " + e.getMessage());
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
@GetMapping("/overdue")
public List<OverdueProjectVo> getOverdueProjects() {
return iProcessOrderProService.getOverdueProjects();
}
/**
* 刷新并计算项目延期状态
*/
@SaCheckPermission("system:orderPro:list")
@GetMapping("/refreshDelayStatus")
public R<Void> refreshDelayStatus() {
iProcessOrderProService.refreshDelayStatus();
return R.ok();
}
@SaCheckPermission("system:orderPro:geMRPResults")
@Log(title = "获取MRP复核结果", businessType = BusinessType.OTHER)
@PostMapping("/getMRPResults/{id}")
public R<List<MrpResultCheck>> geMRPResults(@PathVariable Long id) {
return iMrpResultCheckService.getMRPResults(id);
}
@SaCheckPermission("system:orderPro:getRouteLog")
@Log(title = "获取工艺上传结果", businessType = BusinessType.OTHER)
@PostMapping("/getRouteLog/{id}")
public R<String> getRouteLog(@PathVariable("id") Long id) throws JsonProcessingException {
return iProcessOrderProService.getRouteLog(id);
}
@SaCheckPermission("system:orderPro:exportRoute")
@Log(title = "下载工艺生产表", businessType = BusinessType.EXPORT)
@PostMapping("/exportRoute")
public void exportRoute(@RequestParam("id") Long id, HttpServletResponse response) {
try {
ProcessOrderPro orderPro = processOrderProMapper.selectById(id);
// 下载Excel文件
SmbUtil.downloadExcelFiles(orderPro.getProductionOrderNo());
// 构建文件路径
String excelName = "D:\\file\\" + orderPro.getProductionOrderNo() + "汇总表.xlsx";
String rawDataFile = "D:\\file\\RawDataTable.xlsx";
File file = new File(excelName);
if (!file.exists()) {
throw new ServiceException("项目 " + orderPro.getProductionOrderNo() + " 未出图");
}
// 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格
List<ProductionOrderVo> allDataList = readExcelWithPOI(excelName,orderPro.getProductionOrderNo());
List<ProcessRoute> routeList = readExcelPOIRoute(excelName,orderPro.getProductionOrderNo());
// 2. 读取原始表数据
List<BomDataVO> rawDataList = readRawDataTable(rawDataFile);
// 3. 数据分类处理
List<VMIDataVO> vmiList = new ArrayList<>(); // 009开头
List<ElecOutDataVO> elecOutList = new ArrayList<>(); // 两个空格和017开头
List<SupProvidDataVO> supplierList = new ArrayList<>(); // 甲供件
List<EVOProductsDataVO> evoProductsList = new ArrayList<>(); // 伊特
List<ProductionOrderVo> processDataList = new ArrayList<>(); // 工艺数据(剩余数据)
// 分类逻辑
for (ProductionOrderVo item : allDataList) {
String materialCode = item.getDrawingNo();
String remark = item.getRemark(); // 使用备注字段
// 009开头的加入VMI表
if (materialCode != null) {
String drawingNo = item.getDrawingNo();
String drawingName = item.getDrawingName();
if (drawingName != null) {
ImMaterial material = imMaterialService.selectByCodeAndName(drawingNo, drawingName);
if (material != null) {
//判断是否是VMI物料
if ("true".equals(material.getClassificationName())) {
// 检查是否已存在相同的DrawingNo
boolean found = false;
for (VMIDataVO existingVmi : vmiList) {
if (drawingNo.equals(existingVmi.getDrawingNo())) {
// 将数量和批次数量相加
Integer currentQuantity = existingVmi.getQuantity() != null ? existingVmi.getQuantity() : 0;
Integer itemQuantity = item.getQuantity() != null ? item.getQuantity().intValue() : 0;
existingVmi.setQuantity(currentQuantity + itemQuantity);
Integer currentBatchQuantity = existingVmi.getBatchQuantity() != null ? existingVmi.getBatchQuantity() : 0;
Integer itemBatchQuantity = item.getBatchQuantity() != null ? Integer.parseInt(item.getBatchQuantity()) : 0;
existingVmi.setBatchQuantity(currentBatchQuantity + itemBatchQuantity);
found = true;
break;
}
}
// 如果没有找到相同的DrawingNo则添加新的VMI数据
if (!found) {
VMIDataVO vmiData = convertToVMIDataVO(item);
vmiList.add(vmiData);
}
continue; // 已分类,跳过后续检查
}
}
}
// 电气外包分类条件:物料编码开头空格/特定前缀 或 备注包含"外购"
if (materialCode.startsWith(" ")
|| materialCode.startsWith("009301") || materialCode.startsWith("009999")
|| materialCode.startsWith("017003") || materialCode.startsWith("017002")
|| materialCode.startsWith("009001") || materialCode.startsWith("009081")
|| (remark != null && remark.contains("外购"))) {
// 过滤安全库存:如果属于安全库存,则进入工艺数据列表
Boolean isSafeStock = safetyStockService.isSafeCode(materialCode.trim());
if (isSafeStock) {
// 属于安全库存,添加到工艺数据列表
processDataList.add(item);
continue; // 已分类,跳过后续检查
} else {
// 不属于安全库存检查是否已存在相同的DrawingNo
boolean found = false;
for (ElecOutDataVO existingElec : elecOutList) {
if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingElec.getDrawingNo())) {
// 将数量和批次数量相加
Double currentQuantity = existingElec.getQuantity() != null ? existingElec.getQuantity() : 0.0;
Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
Double newQuantity = currentQuantity + itemQuantity;
existingElec.setQuantity(newQuantity);
// 批次数量相加String类型
String currentBatchQuantity = existingElec.getBatchQuantity() != null ? (existingElec.getBatchQuantity()).toString() : "0";
String itemBatchQuantity = item.getBatchQuantity() != null ? item.getBatchQuantity() : "0";
try {
Integer currentBatch = Integer.valueOf(currentBatchQuantity);
Integer itemBatch = Integer.valueOf(itemBatchQuantity);
String newBatchQuantity = String.valueOf(currentBatch + itemBatch);
existingElec.setBatchQuantity(Integer.valueOf(newBatchQuantity));
} catch (NumberFormatException e) {
// 如果转换失败,保持原值
existingElec.setBatchQuantity(Integer.valueOf(currentBatchQuantity));
}
found = true;
break;
}
}
// 如果没有找到相同的DrawingNo则添加新的电气外包数据
if (!found) {
ElecOutDataVO elecData = convertToElecOutDataVO(item);
elecOutList.add(elecData);
}
continue; // 已分类,跳过后续检查
}
}
// 备注是甲供件的
if (remark != null && remark.contains("甲供件")) {
SupProvidDataVO supplierData = convertToSupProvidDataVO(item);
supplierList.add(supplierData);
continue; // 已分类,跳过后续检查
}
// 备注是伊特
if (remark != null && remark.contains("伊特")) {
EVOProductsDataVO evoData = convertToEVOProductsDataVO(item);
evoProductsList.add(evoData);
continue; // 已分类,跳过后续检查
}
}
// 其他数据作为工艺数据(剩余数据)
// 检查是否已存在相同的DrawingNo
boolean found = false;
for (ProductionOrderVo existingProcess : processDataList) {
if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingProcess.getDrawingNo())) {
// 将数量和批次数量相加
Double currentQuantity = existingProcess.getQuantity() != null ? existingProcess.getQuantity() : 0.0;
Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
Double newQuantity = currentQuantity + itemQuantity;
existingProcess.setQuantity(newQuantity);
// 批次数量相加String类型
String currentBatchQuantity = existingProcess.getBatchQuantity() != null ? existingProcess.getBatchQuantity() : "0";
String itemBatchQuantity = item.getBatchQuantity() != null ? item.getBatchQuantity() : "0";
try {
Integer currentBatch = Integer.valueOf(currentBatchQuantity);
Integer itemBatch = Integer.valueOf(itemBatchQuantity);
String newBatchQuantity = String.valueOf(currentBatch + itemBatch);
existingProcess.setBatchQuantity(newBatchQuantity);
} catch (NumberFormatException e) {
// 如果转换失败,保持原值
existingProcess.setBatchQuantity(currentBatchQuantity);
}
found = true;
break;
}
}
// 如果没有找到相同的DrawingNo则添加新的工艺数据
if (!found) {
processDataList.add(item);
}
}
// 使用Excel模板文件
String templatePath = "jpg/生产及工艺计划模版.xlsx";
String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx";
// 准备模板数据
Map<String, Object> staticDataMap = new HashMap<>();
staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo());
staticDataMap.put("productionName", orderPro.getProductionName());
//获取工艺数据信息
List<ProcessRoute> excelDTOList = iProcessOrderProService.getRouteAndBomDetail(routeList, processDataList, orderPro);
excelDTOList.sort(Comparator.comparing(ProcessRoute::getMaterial, Comparator.nullsLast((m1, m2) -> {
// 总装部件优先
boolean isTotal1 = "总装部件".equals(m1);
boolean isTotal2 = "总装部件".equals(m2);
if (isTotal1 && !isTotal2) return -1;
if (!isTotal1 && isTotal2) return 1;
if (isTotal1 && isTotal2) return 0;
// 其他材质按字母顺序排序
if (m1 == null && m2 == null) return 0;
if (m1 == null) return 1;
if (m2 == null) return -1;
return m1.compareTo(m2);
})
).thenComparing(
ProcessRoute::getMaterialCode,
Comparator.nullsLast(new VersionComparator())
));
// 准备动态数据映射
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
// 添加生产订单数据
if (!allDataList.isEmpty()) {
List<Map<String, Object>> productionDataList = convertProductionOrderToMapList(allDataList, orderPro.getProductionOrderNo());
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProductionOrder", productionDataList));
}
// 添加工艺数据第七个sheet工艺及生产计划表
if (!processDataList.isEmpty()) {
List<Map<String, Object>> processDataMapList = convertProductionOrderToMapList(processDataList, orderPro.getProductionOrderNo());
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessData", processDataMapList));
}
// 添加VMI数据
if (!vmiList.isEmpty()) {
List<Map<String, Object>> vmiDataList = convertVMIDataToMapList(vmiList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("VMIDataVO", vmiDataList));
}
// 添加电气外购数据
if (!elecOutList.isEmpty()) {
List<Map<String, Object>> elecDataList = convertElecOutDataToMapList(elecOutList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ElecOutDataVO", elecDataList));
}
// 添加BOM数据
if (!rawDataList.isEmpty()) {
List<Map<String, Object>> bomDataList = convertBomDataToMapList(rawDataList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("BomDataVO", bomDataList));
}
// 添加甲供件数据
if (!supplierList.isEmpty()) {
List<Map<String, Object>> supplierDataList = convertSupProvidDataToMapList(supplierList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("SupProvidDataVO", supplierDataList));
}
// 添加伊特产品数据
if (!evoProductsList.isEmpty()) {
List<Map<String, Object>> evoDataList = convertEVOProductsDataToMapList(evoProductsList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList));
}
/* // 添加伊特产品数据
if (!excelDTOList.isEmpty()) {
List<Map<String, Object>> evoRouteDataList = convertRouteDataToMapList(excelDTOList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessRouteExcelDTO", evoRouteDataList));
}*/
// 使用模板导出Excel
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, outputPath, staticDataMap, dynamicDataMappingList);
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(orderPro.getProductionOrderNo() + "_分类BOM表", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 将生成的文件写入响应
File outputFile = new File(outputPath);
if (outputFile.exists()) {
try (FileInputStream fis = new FileInputStream(outputFile);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int length;
while ((length = fis.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
}
// 删除临时文件
outputFile.delete();
}
} catch (Exception e) {
log.error("导出分类BOM表失败", e);
throw new RuntimeException("导出失败: " + e.getMessage());
}
}
private List<ProcessRoute> readExcelPOIRoute(String excelName, String name) {
List<ProcessRoute> resultList = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(excelName);
XSSFWorkbook workbook = new XSSFWorkbook(fis)) {
XSSFSheet sheet = workbook.getSheetAt(6); // 读取第一个sheet
// 从第3行开始读取headRowNumber=2所以从第3行开始
for (int rowIndex = 3; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
XSSFRow row = sheet.getRow(rowIndex);
if (row == null) {
continue;
}
ProcessRoute vo = new ProcessRoute();
// 根据列索引读取数据,保留原始空格
vo.setMaterialCode(getCellValueAsString(row.getCell(0))); // 图号
vo.setRouteDescription(name); // 图号
vo.setMaterialName(getCellValueAsString(row.getCell(1))); // 名称
vo.setMaterial(getCellValueAsString(row.getCell(2))); // 数量
vo.setDiscWeight(getCellValueAsDouble(row.getCell(3)));
vo.setRawMaterialCode(getCellValueAsString(row.getCell(4)));
vo.setRawMaterialName(getCellValueAsString(row.getCell(5)));
vo.setBomMaterial(getCellValueAsString(row.getCell(6)));
vo.setBomUnit(getCellValueAsString(row.getCell(9)));
vo.setBomDanZhong(getCellValueAsDouble(row.getCell(7)));
vo.setDiscUsage(getCellValueAsString(row.getCell(8)));
// 单重
vo.setBatchQuantity(getCellValueAsLong(row.getCell(18))); // 批次数量
vo.setUnitQuantity(getCellValueAsDouble(row.getCell(17))); // 批次数量
vo.setXuEndTime(getCellValueAsDate(row.getCell(21))); // 批次数量
vo.setXuStartTime(getCellValueAsDate(row.getCell(20))); // 批次数量
resultList.add(vo);
}
log.info("使用POI读取Excel成功共{}条记录", resultList.size());
} catch (Exception e) {
log.error("使用POI读取Excel失败", e);
throw new ServiceException("读取Excel文件失败: " + e.getMessage());
}
return resultList;
}
private List<ProcessRoute> readExcelPOIRoute3(String excelName, String name) {
List<ProcessRoute> resultList = new ArrayList<>();
try {
// 匹配真实的 "工艺及生产计划表" (第7个Sheet通常是索引6)
int sheetIndex = 6;
// 使用 EasyExcel 读取数据到专门的 DTO
List<ProcessRouteExcelDTO1> easyExcelList = EasyExcel.read(excelName)
.head(ProcessRouteExcelDTO1.class)
.sheet(sheetIndex) // 对应表里的第7个Sheet
.headRowNumber(3) // 数据从第4行开始
.doReadSync();
log.info("使用EasyExcel读取Excel成功{}",JSONObject.toJSONString(easyExcelList));
// 过滤空行,并处理跨行继承(父物料继承逻辑)
String currentMaterialCode = null;
String currentMaterialName = null;
String currentMaterial = null;
Double currentWeight = null;
for (ProcessRouteExcelDTO1 dto : easyExcelList) {
// 如果是完全空的行,跳过 (关键字段都为空认为空行)
if (dto == null || (
(dto.getMaterialCode() == null || dto.getMaterialCode().trim().isEmpty()) &&
(dto.getRawMaterialCode() == null || dto.getRawMaterialCode().trim().isEmpty()) &&
dto.getProcessNo() == null)) {
continue;
}
// 判断是否为新父物料 (有主件编码)
if (dto.getMaterialCode() != null && !dto.getMaterialCode().trim().isEmpty()) {
currentMaterialCode = dto.getMaterialCode();
currentMaterialName = dto.getMaterialName();
currentMaterial = dto.getMaterial();
currentWeight = dto.getDiscWeight();
} else {
// 没有主件编码但如果有BOM编码或者有工序信息则继承上一行的主件信息
if ((dto.getRawMaterialCode() != null && !dto.getRawMaterialCode().trim().isEmpty()) || dto.getProcessNo() != null) {
dto.setMaterialCode(currentMaterialCode);
dto.setMaterialName(currentMaterialName);
dto.setMaterial(currentMaterial);
dto.setDiscWeight(currentWeight);
}
}
// 转换为数据库实体对象
ProcessRoute row = new ProcessRoute();
row.setRouteDescription(name);
row.setMaterialCode(dto.getMaterialCode());
row.setMaterialName(dto.getMaterialName());
row.setMaterial(dto.getMaterial());
row.setDiscWeight(dto.getDiscWeight());
row.setRawMaterialCode(dto.getRawMaterialCode());
row.setRawMaterialName(dto.getRawMaterialName());
row.setBomMaterial(dto.getBomMaterial());
row.setBomDanZhong(dto.getBomDanZhong());
row.setDiscUsage(dto.getDiscUsage());
row.setBomUnit(dto.getBomUnit());
row.setProcessNo(dto.getProcessNo());
row.setWorkCenter(dto.getWorkCenter());
row.setProcessName(dto.getProcessName());
row.setProcessDescription(dto.getProcessDescription());
row.setProcessControl(dto.getProcessControl());
row.setActivityDuration(dto.getActivityDuration());
row.setActivityUnit(dto.getActivityUnit());
row.setUnitQuantity(dto.getUnitQuantity());
row.setBatchQuantity(dto.getBatchQuantity());
row.setXuStartTime(dto.getXuStartTime());
row.setXuEndTime(dto.getXuEndTime());
resultList.add(row);
}
log.info("EasyExcel读取完成共 {} 条记录", resultList.size());
} catch (Exception e) {
log.error("读取Excel失败", e);
throw new ServiceException("读取Excel文件失败: " + e.getMessage());
}
//最终成为的数据
log.info("最终成为的数据:{}", JSONObject.toJSONString(resultList));
return resultList;
}
/**
* 读取RawDataTable数据
*/
private List<BomDataVO> readRawDataTable(String filePath) {
List<BomDataVO> dataList = new ArrayList<>();
try {
File file = new File(filePath);
if (!file.exists()) {
log.warn("RawDataTable.xlsx文件不存在: {}", filePath);
return dataList;
}
// 读取Excel数据
DefaultExcelListener<BomDataVO> listener = new DefaultExcelListener<>(true);
EasyExcel.read(filePath, BomDataVO.class, listener)
.sheet(0) // 读取第一个sheet
.headRowNumber(2) // 从第1行开始读取
.doRead();
dataList = listener.getExcelResult().getList();
log.info("成功读取RawDataTable数据共{}条记录", dataList.size());
} catch (Exception e) {
log.error("读取RawDataTable数据失败", e);
}
return dataList;
}
/**
* 转换为Map列表用于模板
*/
private List<Map<String, Object>> convertToMapList(List<ProcessRoute> routeList, ProcessOrderPro orderPro) {
List<Map<String, Object>> mapList = new ArrayList<>();
for (ProcessRoute route : routeList) {
Map<String, Object> map = new HashMap<>();
map.put("materialCode", route.getMaterialCode());
map.put("materialName", route.getMaterialName());
map.put("material", route.getMaterial());
map.put("unitWeight", route.getDiscWeight());
map.put("quantity", route.getUnitQuantity());
map.put("batchQuantity", route.getBatchQuantity());
map.put("workCenter", route.getWorkCenter());
map.put("processName", route.getProcessName());
map.put("processDescription", route.getProcessDescription());
map.put("productionOrderNo", orderPro.getProductionOrderNo());
map.put("productionName", orderPro.getProductionName());
mapList.add(map);
}
return mapList;
}
/**
* 使用POI直接读取Excel文件保留前后空格
*/
private List<ProductionOrderVo> readExcelWithPOI(String excelPath,String orderName) {
return readExcelWithPOISheetIndex(excelPath, orderName, 0, 2);
}
private List<ProductionOrderVo> readExcelWithPOISheetIndex(String excelPath, String orderName, int sheetIndex, int startRow) {
List<ProductionOrderVo> resultList = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(excelPath);
XSSFWorkbook workbook = new XSSFWorkbook(fis)) {
if (sheetIndex >= workbook.getNumberOfSheets()) {
log.warn("Excel file does not have {} sheets", sheetIndex + 1);
return resultList;
}
XSSFSheet sheet = workbook.getSheetAt(sheetIndex);
// 从 startRow 开始读取
for (int rowIndex = startRow; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
XSSFRow row = sheet.getRow(rowIndex);
if (row == null) {
continue;
}
ProductionOrderVo vo = new ProductionOrderVo();
// 根据列索引读取数据,保留原始空格
vo.setId(getCellValueAsLong(row.getCell(0)));
vo.setProductionOrderNo(orderName);
vo.setDrawingNo(getCellValueAsString(row.getCell(1))); // 图号
vo.setDrawingName(getCellValueAsString(row.getCell(2))); // 名称
vo.setQuantity(getCellValueAsDouble(row.getCell(3))); // 数量
vo.setMaterial(getCellValueAsString(row.getCell(4))); // 材料
vo.setSingleWeight(getCellValueAsDouble(row.getCell(5))); // 单重
vo.setTotalWeight(getCellValueAsDouble(row.getCell(6))); // 总重
vo.setRemark(getCellValueAsString(row.getCell(7))); // 备注
vo.setBatchQuantity(getCellValueAsString(row.getCell(8))); // 批次数量
vo.setParentPart(getCellValueAsString(row.getCell(9))); // 上级部件
vo.setParentDrawingNo(getCellValueAsString(row.getCell(10))); // 上级部件图号
vo.setMainProducts(getCellValueAsString(row.getCell(11))); // 主产品图号
vo.setMainProductsName(getCellValueAsString(row.getCell(12))); // 主产品名称
resultList.add(vo);
}
log.info("使用POI读取Excel sheet {} 成功,共{}条记录", sheetIndex, resultList.size());
} catch (Exception e) {
log.error("使用POI读取Excel失败", e);
throw new ServiceException("读取Excel文件失败: " + e.getMessage());
}
return resultList;
}
/**
* 获取单元格的字符串值,保留前后空格
*/
private String getCellValueAsString(XSSFCell cell) {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case STRING:
// 直接从POI获取原始字符串保留前后空格
String value = cell.getStringCellValue();
return value;
case NUMERIC:
return String.valueOf(cell.getNumericCellValue());
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
return cell.getCellFormula();
default:
return null;
}
}
/**
* 获取单元格的Date值
*/
private Date getCellValueAsDate(XSSFCell cell) {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case NUMERIC:
if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
return cell.getDateCellValue();
}
return null;
case STRING:
try {
String dateStr = cell.getStringCellValue();
if (dateStr == null || dateStr.trim().isEmpty()) {
return null;
}
// 尝试解析字符串日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sdf.parse(dateStr);
} catch (ParseException e) {
sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(dateStr);
}
} catch (Exception e) {
return null;
}
default:
return null;
}
}
/**
* 获取单元格的Long值
*/
private Long getCellValueAsLong(XSSFCell cell) {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case NUMERIC:
return (long) cell.getNumericCellValue();
case STRING:
try {
return Long.valueOf(cell.getStringCellValue());
} catch (NumberFormatException e) {
return null;
}
default:
return null;
}
}
/**
* 获取单元格的Double值
*/
private Double getCellValueAsDouble(XSSFCell cell) {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case NUMERIC:
return cell.getNumericCellValue();
case STRING:
try {
return Double.valueOf(cell.getStringCellValue());
} catch (NumberFormatException e) {
return null;
}
default:
return null;
}
}
/**
* 获取字符串的Unicode表示
*/
private String getUnicodeString(String str) {
StringBuilder sb = new StringBuilder();
for (char c : str.toCharArray()) {
sb.append("\\u").append(String.format("%04x", (int) c));
}
return sb.toString();
}
/**
* 转换ProductionOrder为Map列表用于模板
*/
private List<Map<String, Object>> convertProductionOrderToMapList(List<ProductionOrderVo> productionOrderList, String proName) {
List<Map<String, Object>> mapList = new ArrayList<>();
for (ProductionOrderVo item : productionOrderList) {
Map<String, Object> map = new HashMap<>();
map.put("productionOrderNo", proName);
map.put("drawingNo", item.getDrawingNo());
map.put("drawingName", item.getDrawingName());
map.put("quantity", item.getQuantity());
map.put("material", item.getMaterial());
map.put("singleWeight", item.getSingleWeight());
map.put("totalWeight", item.getTotalWeight());
map.put("remark", item.getRemark());
map.put("parentPart", item.getParentPart());
map.put("parentDrawingNo", item.getParentDrawingNo());
map.put("batchQuantity", item.getBatchQuantity());
// 为了兼容模板也提供数字格式的batchQuantity
Integer batchQuantityInt = null;
if (item.getBatchQuantity() != null && !item.getBatchQuantity().isEmpty()) {
try {
batchQuantityInt = Integer.valueOf(item.getBatchQuantity());
} catch (NumberFormatException e) {
// 如果转换失败,保持原值
map.put("batchQuantityInt", null);
}
}
map.put("batchQuantityInt", batchQuantityInt);
map.put("mainProducts", item.getMainProducts());
map.put("mainProductsName", item.getMainProductsName());
mapList.add(map);
}
return mapList;
}
/**
* 转换BOM数据为Map列表用于模板
*/
private List<Map<String, Object>> convertBomDataToMapList(List<BomDataVO> bomDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
for (BomDataVO bom : bomDataList) {
Map<String, Object> map = new HashMap<>();
map.put("index", bom.getIndex());
map.put("drawingNo", bom.getDrawingNo());
map.put("name", bom.getName());
map.put("quantity", bom.getQuantity());
map.put("material", bom.getMaterial());
map.put("unitWeight", bom.getUnitWeight());
map.put("totalWeight", bom.getTotalWeight());
map.put("remark", bom.getRemark());
map.put("component", bom.getComponent());
map.put("componentDrawingNo", bom.getComponentDrawingNo());
mapList.add(map);
}
return mapList;
}
/**
* 转换ProductionOrder为VMIDataVO
*/
private VMIDataVO convertToVMIDataVO(ProductionOrderVo item) {
VMIDataVO vmiData = new VMIDataVO();
vmiData.setIndex(null); // ProductionOrder没有index字段
vmiData.setDrawingNo(item.getDrawingNo());
vmiData.setName(item.getDrawingName());
vmiData.setQuantity(item.getQuantity() != null ? item.getQuantity().intValue() : null);
vmiData.setMaterial(item.getMaterial());
vmiData.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null);
vmiData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null);
vmiData.setRemark(item.getRemark());
vmiData.setBatchQuantity(item.getBatchQuantity() != null ? Integer.valueOf(item.getBatchQuantity()) : null);
return vmiData;
}
/**
* 转换ProductionOrder为ElecOutDataVO
*/
private ElecOutDataVO convertToElecOutDataVO(ProductionOrderVo item) {
ElecOutDataVO elecData = new ElecOutDataVO();
elecData.setIndex(null); // ProductionOrder没有index字段
elecData.setDrawingNo(item.getDrawingNo());
elecData.setName(item.getDrawingName());
elecData.setQuantity(Double.valueOf(item.getQuantity() != null ? item.getQuantity().intValue() : null));
elecData.setMaterial(item.getMaterial());
elecData.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null);
elecData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null);
elecData.setRemark(item.getRemark());
elecData.setBatchQuantity(item.getBatchQuantity() != null ? Integer.valueOf(item.getBatchQuantity()) : null);
return elecData;
}
/**
* 转换ProductionOrder为SupProvidDataVO
*/
private SupProvidDataVO convertToSupProvidDataVO(ProductionOrderVo item) {
SupProvidDataVO supplierData = new SupProvidDataVO();
supplierData.setIndex(null); // ProductionOrder没有index字段
supplierData.setDrawingNo(item.getDrawingNo());
supplierData.setName(item.getDrawingName());
supplierData.setQuantity(item.getQuantity() != null ? item.getQuantity().intValue() : null);
supplierData.setMaterial(item.getMaterial());
supplierData.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null);
supplierData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null);
supplierData.setRemark(item.getRemark());
supplierData.setBatchQuantity(item.getBatchQuantity() != null ? Integer.valueOf(item.getBatchQuantity()) : null);
return supplierData;
}
/**
* 转换ProductionOrder为EVOProductsDataVO
*/
private EVOProductsDataVO convertToEVOProductsDataVO(ProductionOrderVo item) {
EVOProductsDataVO evoData = new EVOProductsDataVO();
evoData.setIndex(null); // ProductionOrder没有index字段
evoData.setDrawingNo(item.getDrawingNo());
evoData.setName(item.getDrawingName());
evoData.setQuantity(item.getQuantity() != null ? item.getQuantity().intValue() : null);
evoData.setMaterial(item.getMaterial());
evoData.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null);
evoData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null);
evoData.setRemark(item.getRemark());
evoData.setBatchQuantity(item.getBatchQuantity() != null ? Integer.valueOf(item.getBatchQuantity()) : null);
return evoData;
}
/**
* 转换VMIDataVO为Map列表用于模板
*/
private List<Map<String, Object>> convertVMIDataToMapList(List<VMIDataVO> vmiDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (VMIDataVO item : vmiDataList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("drawingNo", item.getDrawingNo());
map.put("name", item.getName());
map.put("quantity", item.getQuantity());
map.put("material", item.getMaterial());
map.put("unitWeight", item.getUnitWeight());
map.put("totalWeight", item.getTotalWeight());
map.put("remark", item.getRemark());
map.put("batchQuantity", item.getBatchQuantity());
mapList.add(map);
index++;
}
return mapList;
}
/**
* 转换ElecOutDataVO为Map列表用于模板
*/
private List<Map<String, Object>> convertElecOutDataToMapList(List<ElecOutDataVO> elecOutDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (ElecOutDataVO item : elecOutDataList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("drawingNo", item.getDrawingNo());
map.put("name", item.getName());
map.put("quantity", item.getQuantity());
map.put("material", item.getMaterial());
map.put("unitWeight", item.getUnitWeight());
map.put("totalWeight", item.getTotalWeight());
map.put("remark", item.getRemark());
map.put("batchQuantity", item.getBatchQuantity());
mapList.add(map);
index++;
}
return mapList;
}
/**
* 转换SupProvidDataVO为Map列表用于模板
*/
private List<Map<String, Object>> convertSupProvidDataToMapList(List<SupProvidDataVO> supplierDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (SupProvidDataVO item : supplierDataList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("drawingNo", item.getDrawingNo());
map.put("name", item.getName());
map.put("quantity", item.getQuantity());
map.put("material", item.getMaterial());
map.put("unitWeight", item.getUnitWeight());
map.put("totalWeight", item.getTotalWeight());
map.put("remark", item.getRemark());
map.put("batchQuantity", item.getBatchQuantity());
mapList.add(map);
index++;
}
return mapList;
}
/**
* 转换EVOProductsDataVO为Map列表用于模板
*/
private List<Map<String, Object>> convertEVOProductsDataToMapList(List<EVOProductsDataVO> evoProductsDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (EVOProductsDataVO item : evoProductsDataList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("drawingNo", item.getDrawingNo());
map.put("name", item.getName());
map.put("quantity", item.getQuantity());
map.put("material", item.getMaterial());
map.put("unitWeight", item.getUnitWeight());
map.put("totalWeight", item.getTotalWeight());
map.put("remark", item.getRemark());
map.put("batchQuantity", item.getBatchQuantity());
mapList.add(map);
index++;
}
return mapList;
}
private String formatDate(Date date) {
return date == null ? "" : DATE_FORMAT.format(date);
}
/**
* 转换工艺VO为Map列表用于模板
*/
private List<Map<String, Object>> convertRouteDataToMapList(List<ProcessRoute> routeDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (ProcessRoute item : routeDataList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("routeDescription", item.getRouteDescription()); // 生产令号
map.put("materialCode", item.getMaterialCode()); // 物料编码
map.put("materialName", item.getMaterialName()); // 物料名称
map.put("material", item.getMaterial()); // 材质
map.put("discWeight", item.getDiscWeight()); // 单重KG
map.put("processNo", item.getProcessNo()); // 工序号
map.put("workCenter", item.getWorkCenter()); // 工作中心
map.put("processName", item.getProcessName()); // 工序名称
map.put("processDescription", item.getProcessDescription()); // 工序说明
map.put("processControl", item.getProcessControl()); // 工序控制
map.put("activityDuration", item.getActivityDuration()); // 活动时长
map.put("activityUnit", item.getActivityUnit()); // 活动单位
map.put("unitQuantity", item.getUnitQuantity()); // 单台数量
map.put("batchQuantity", item.getBatchQuantity()); // 本批数量
map.put("firstBatchQuantity", item.getFirstBatchQuantity()); // 首批数量
map.put("planStartTime", formatDate(item.getPlanStartTime()));
map.put("planEndTime", formatDate(item.getPlanEndTime()));
map.put("xuStartTime", formatDate(item.getXuStartTime()));
map.put("xuEndTime", formatDate(item.getXuEndTime()));
mapList.add(map);
index++;
}
return mapList;
}
@SaCheckPermission("system:orderPro:exportRoute2")
@Log(title = "下载工艺生产表2", businessType = BusinessType.EXPORT)
@GetMapping ("/exportRoute2")
public void exportRoute2(@RequestParam("id") Long id, HttpServletResponse response) {
try {
ProcessOrderPro orderPro = processOrderProMapper.selectById(id);
// 下载Excel文件
SmbUtil.downloadExcelFiles(orderPro.getProductionOrderNo());
// 构建文件路径
String excelName = "D:\\file\\" + orderPro.getProductionOrderNo() + "汇总表.xlsx";
String rawDataFile = "D:\\file\\RawDataTable.xlsx";
File file = new File(excelName);
if (!file.exists()) {
throw new ServiceException("项目 " + orderPro.getProductionOrderNo() + " 未出图");
}
// 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格
List<ProductionOrderVo> allDataList = readExcelWithPOI(excelName,orderPro.getProductionOrderNo());
List<ProcessRoute> routeList = readExcelPOIRoute(excelName,orderPro.getProductionOrderNo());
List<ProcessRoute> routes = new ArrayList<>();
List<Map<String, Object>> kingdeeBomRows = new ArrayList<>();
for (ProcessRoute base : routeList) {
String materialCode = base.getMaterialCode();
//如果项目零号是CP 跳过安全库存物料
LambdaQueryWrapper<SafetyStock> wr = new LambdaQueryWrapper<>();
wr.eq(SafetyStock::getMaterialCode, materialCode);
SafetyStock safetyStock = stockMapper.selectOne(wr);
if (safetyStock != null && base.getRouteDescription().startsWith("CP")) {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
item.setRawMaterialCode(base.getRawMaterialCode());
item.setRawMaterialName(base.getRawMaterialName());
item.setBomMaterial(base.getBomMaterial());
item.setBomDanZhong(base.getBomDanZhong());
item.setDiscUsage(base.getDiscUsage());
item.setBomUnit(base.getBomUnit());
routes.add(item);
continue;
}
if (StringUtils.isBlank(materialCode)) {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
item.setRawMaterialCode(base.getRawMaterialCode());
item.setRawMaterialName(base.getRawMaterialName());
item.setBomMaterial(base.getBomMaterial());
item.setBomDanZhong(base.getBomDanZhong());
item.setDiscUsage(base.getDiscUsage());
item.setBomUnit(base.getBomUnit());
routes.add(item);
continue;
}
String bomversion = JdUtil.readGetTheLatestVersion(materialCode);
List<MaterialUseDTO> bomItems = StringUtils.isNotBlank(bomversion) ? JdUtil.getMaterialUseXByVer(bomversion) : Collections.emptyList();
List<ProcessRouteDTO> routeGuDing = JdUtil.getRouteGuDing(materialCode);
if (routeGuDing != null && !routeGuDing.isEmpty()) {
routeGuDing.stream().forEach(r -> {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
// 保留Excel读取的BOM字段防止组焊件数据丢失
item.setRawMaterialCode(base.getRawMaterialCode());
item.setRawMaterialName(base.getRawMaterialName());
item.setBomMaterial(base.getBomMaterial());
item.setBomDanZhong(base.getBomDanZhong());
item.setDiscUsage(base.getDiscUsage());
item.setBomUnit(base.getBomUnit());
// 不写入BOM字段保持纯工艺数据行 (原注释,现已修改)
item.setProcessNo(r.getProcessNo());
item.setWorkCenter(r.getWorkCenter());
item.setProcessName(r.getProcessName());
item.setProcessDescription(r.getProcessDescription());
item.setProcessControl(r.getProcessControl());
item.setActivityDuration(r.getActivityDuration());
item.setActivityUnit(r.getActivityUnit());
item.setRawMaterialCode(base.getRawMaterialCode());
item.setRawMaterialName(base.getRawMaterialName());
item.setBomMaterial(base.getBomMaterial());
item.setBomDanZhong(base.getBomDanZhong());
item.setDiscUsage(base.getDiscUsage());
item.setBomUnit(base.getBomUnit());
routes.add(item);
});
} else {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
// 保留Excel读取的BOM字段防止组焊件数据丢失
item.setRawMaterialCode(base.getRawMaterialCode());
item.setRawMaterialName(base.getRawMaterialName());
item.setBomMaterial(base.getBomMaterial());
item.setBomDanZhong(base.getBomDanZhong());
item.setDiscUsage(base.getDiscUsage());
item.setBomUnit(base.getBomUnit());
// 不写入BOM字段保持纯工艺数据行 (原注释,现已修改)
routes.add(item);
}
if (bomItems != null && !bomItems.isEmpty()) {
for (MaterialUseDTO b : bomItems) {
Map<String, Object> bomMap = new HashMap<>();
bomMap.put("routeDescription", base.getRouteDescription());
bomMap.put("materialCode", base.getMaterialCode());
bomMap.put("materialName", base.getMaterialName());
bomMap.put("material", base.getMaterial());
bomMap.put("discWeight", base.getDiscWeight());
bomMap.put("rawMaterialCode", b.getMaterialCode());
bomMap.put("rawMaterialName", b.getMaterialName());
bomMap.put("bomMaterial", b.getCaizhi());
bomMap.put("bomDanZhong", b.getDanzhong());
if (b.getChildUnit().equals("")) {
bomMap.put("discUsage", (b.getFenzi() != null && b.getFenmu() != null) ? (b.getFenzi() + "/" + b.getFenmu()) : null);
} else {
bomMap.put("discUsage", (b.getFenzi() != null && b.getFenmu() != null) ? b.getFenzi() : null);
}
bomMap.put("bomUnit", b.getChildUnit());
kingdeeBomRows.add(bomMap);
}
}
}
// 用生成的 routes 替换原始 routeList保持原序展开后的结构用于后续导出
routeList = routes;
// 2. 读取原始表数据
List<BomDataVO> rawDataList = readRawDataTable(rawDataFile);
// 3. 数据分类处理
List<VMIDataVO> vmiList = new ArrayList<>(); // 009开头
List<ElecOutDataVO> elecOutList = new ArrayList<>(); // 两个空格和017开头
List<SupProvidDataVO> supplierList = new ArrayList<>(); // 甲供件
List<EVOProductsDataVO> evoProductsList = new ArrayList<>(); // 伊特
List<ProductionOrderVo> processDataList = new ArrayList<>(); // 工艺数据(剩余数据)
// 分类逻辑
for (ProductionOrderVo item : allDataList) {
String materialCode = item.getDrawingNo();
String remark = item.getRemark(); // 使用备注字段
// 009开头的加入VMI表
if (materialCode != null) {
String drawingNo = item.getDrawingNo();
String drawingName = item.getDrawingName();
if (drawingName != null) {
ImMaterial material = imMaterialService.selectByCodeAndName(drawingNo, drawingName);
if (material != null) {
//判断是否是VMI物料
if ("true".equals(material.getClassificationName())) {
// 检查是否已存在相同的DrawingNo
boolean found = false;
for (VMIDataVO existingVmi : vmiList) {
if (drawingNo.equals(existingVmi.getDrawingNo())) {
// 将数量和批次数量相加
Integer currentQuantity = existingVmi.getQuantity() != null ? existingVmi.getQuantity() : 0;
Integer itemQuantity = item.getQuantity() != null ? item.getQuantity().intValue() : 0;
existingVmi.setQuantity(currentQuantity + itemQuantity);
Integer currentBatchQuantity = existingVmi.getBatchQuantity() != null ? existingVmi.getBatchQuantity() : 0;
Integer itemBatchQuantity = item.getBatchQuantity() != null ? Integer.parseInt(item.getBatchQuantity()) : 0;
existingVmi.setBatchQuantity(currentBatchQuantity + itemBatchQuantity);
found = true;
break;
}
}
// 如果没有找到相同的DrawingNo则添加新的VMI数据
if (!found) {
VMIDataVO vmiData = convertToVMIDataVO(item);
vmiList.add(vmiData);
}
continue; // 已分类,跳过后续检查
}
}
}
// 电气外包分类条件:物料编码开头空格/特定前缀 或 备注包含"外购"
if (materialCode.startsWith(" ")
|| materialCode.startsWith("009301") || materialCode.startsWith("009999") || materialCode.startsWith("017003") || materialCode.startsWith("017002")
|| materialCode.startsWith("009001") || materialCode.startsWith("009081") || (remark != null && remark.contains("外购"))) {
// 过滤安全库存:如果属于安全库存,则进入工艺数据列表
Boolean isSafeStock = safetyStockService.isSafeCode(materialCode.trim());
if (isSafeStock) {
// 属于安全库存,添加到工艺数据列表
processDataList.add(item);
continue; // 已分类,跳过后续检查
} else {
// 不属于安全库存检查是否已存在相同的DrawingNo
boolean found = false;
for (ElecOutDataVO existingElec : elecOutList) {
if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingElec.getDrawingNo())) {
// 将数量和批次数量相加
Double currentQuantity = existingElec.getQuantity() != null ? existingElec.getQuantity() : 0.0;
Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
Double newQuantity = currentQuantity + itemQuantity;
existingElec.setQuantity(newQuantity);
// 批次数量相加String类型
String currentBatchQuantity = existingElec.getBatchQuantity() != null ? (existingElec.getBatchQuantity()).toString() : "0";
String itemBatchQuantity = item.getBatchQuantity() != null ? item.getBatchQuantity() : "0";
try {
Integer currentBatch = Integer.valueOf(currentBatchQuantity);
Integer itemBatch = Integer.valueOf(itemBatchQuantity);
String newBatchQuantity = String.valueOf(currentBatch + itemBatch);
existingElec.setBatchQuantity(Integer.valueOf(newBatchQuantity));
} catch (NumberFormatException e) {
// 如果转换失败,保持原值
existingElec.setBatchQuantity(Integer.valueOf(currentBatchQuantity));
}
found = true;
break;
}
}
// 如果没有找到相同的DrawingNo则添加新的电气外包数据
if (!found) {
ElecOutDataVO elecData = convertToElecOutDataVO(item);
elecOutList.add(elecData);
}
continue; // 已分类,跳过后续检查
}
}
// 备注是甲供件的
if (remark != null && remark.contains("甲供件")) {
SupProvidDataVO supplierData = convertToSupProvidDataVO(item);
supplierList.add(supplierData);
continue; // 已分类,跳过后续检查
}
// 备注是伊特
if (remark != null && remark.contains("伊特")) {
EVOProductsDataVO evoData = convertToEVOProductsDataVO(item);
evoProductsList.add(evoData);
continue; // 已分类,跳过后续检查
}
}
// 检查是否已存在相同的DrawingNo
boolean found = false;
for (ProductionOrderVo existingProcess : processDataList) {
if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingProcess.getDrawingNo())) {
// 将数量和批次数量相加
Double currentQuantity = existingProcess.getQuantity() != null ? existingProcess.getQuantity() : 0.0;
Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
Double newQuantity = currentQuantity + itemQuantity;
existingProcess.setQuantity(newQuantity);
// 批次数量相加String类型
String currentBatchQuantity = existingProcess.getBatchQuantity() != null ? existingProcess.getBatchQuantity() : "0";
String itemBatchQuantity = item.getBatchQuantity() != null ? item.getBatchQuantity() : "0";
try {
Integer currentBatch = Integer.valueOf(currentBatchQuantity);
Integer itemBatch = Integer.valueOf(itemBatchQuantity);
String newBatchQuantity = String.valueOf(currentBatch + itemBatch);
existingProcess.setBatchQuantity(newBatchQuantity);
} catch (NumberFormatException e) {
// 如果转换失败,保持原值
existingProcess.setBatchQuantity(currentBatchQuantity);
}
found = true;
break;
}
}
// 如果没有找到相同的DrawingNo则添加新的工艺数据
if (!found) {
processDataList.add(item);
}
}
// 使用Excel模板文件
String templatePath = "jpg/生产及工艺计划模版.xlsx";
String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx";
// 准备模板数据
Map<String, Object> staticDataMap = new HashMap<>();
staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo());
staticDataMap.put("productionName", orderPro.getProductionName());
// 准备动态数据映射
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
// 添加生产订单数据
if (!allDataList.isEmpty()) {
List<Map<String, Object>> productionDataList = convertProductionOrderToMapList(allDataList, orderPro.getProductionOrderNo());
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProductionOrder", productionDataList));
}
// 添加工艺数据第七个sheet工艺及生产计划表
if (!processDataList.isEmpty()) {
List<Map<String, Object>> processDataMapList = convertProductionOrderToMapList(processDataList, orderPro.getProductionOrderNo());
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessData", processDataMapList));
}
// 添加VMI数据
if (!vmiList.isEmpty()) {
List<Map<String, Object>> vmiDataList = convertVMIDataToMapList(vmiList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("VMIDataVO", vmiDataList));
}
// 添加电气外购数据
if (!elecOutList.isEmpty()) {
List<Map<String, Object>> elecDataList = convertElecOutDataToMapList(elecOutList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ElecOutDataVO", elecDataList));
}
// 添加BOM数据
if (!rawDataList.isEmpty()) {
List<Map<String, Object>> bomDataList = convertBomDataToMapList(rawDataList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("BomDataVO", bomDataList));
}
// 添加甲供件数据
if (!supplierList.isEmpty()) {
List<Map<String, Object>> supplierDataList = convertSupProvidDataToMapList(supplierList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("SupProvidDataVO", supplierDataList));
}
// 添加伊特产品数据
if (!evoProductsList.isEmpty()) {
List<Map<String, Object>> evoDataList = convertEVOProductsDataToMapList(evoProductsList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList));
}
if (!kingdeeBomRows.isEmpty()) {
List<Map<String, Object>> bomDataList2 = convertKingdeeBomToMapList(kingdeeBomRows);
// 合并到 RouteBomData 中统一按物料分组导出方案A
}
// 添加伊特产品数据
if (!routeList.isEmpty()) {
// 合并到 RouteBomData 中统一按物料分组导出方案A
}
// 方案A合并工艺与BOM为单一数据集并按物料分组
if (!routeList.isEmpty() || !kingdeeBomRows.isEmpty()) {
List<Map<String, Object>> routeBomDataList = convertRouteBomToMapList(routeList, kingdeeBomRows);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("RouteBomData", routeBomDataList));
}
// 使用模板导出Excel
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, outputPath, staticDataMap, dynamicDataMappingList);
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(orderPro.getProductionOrderNo() + "_分类BOM表", "UTF-8")
.replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 将生成的文件写入响应
File outputFile = new File(outputPath);
if (outputFile.exists()) {
try (FileInputStream fis = new FileInputStream(outputFile);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int length;
while ((length = fis.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
}
// 删除临时文件
outputFile.delete();
}
} catch (Exception e) {
log.error("导出分类BOM表失败", e);
throw new RuntimeException("导出失败: " + e.getMessage());
}
}
/**
* 合并工艺路线与金蝶BOM行按物料编码分组生成统一的 RouteBomData 列表
* 每条记录包含两类rowType=route工艺行或 rowType=bomBOM行以便模板在同一块中连续展示
*/
private List<Map<String, Object>> convertRouteBomToMapList(List<ProcessRoute> routeDataList, List<Map<String, Object>> kingdeeBomRows) {
Map<String, List<Map<String, Object>>> grouped = new LinkedHashMap<>();
// 追加BOM数据到对应物料分组若该物料此前未出现则在最后新增一个分组
for (Map<String, Object> row : kingdeeBomRows) {
String mcode = Objects.toString(row.get("materialCode"), "").trim();
String childCode = Objects.toString(row.get("rawMaterialCode"), "").trim();
String parentMaterial = Objects.toString(row.get("material"), "").trim();
if (mcode.isEmpty() || childCode.isEmpty()) {
continue;
}
/* if ("总装部件".equals(parentMaterial)) {
continue;
}*/
grouped.computeIfAbsent(mcode, k -> new ArrayList<>());
Map<String, Object> map = new HashMap<>();
map.put("rowType", "bom");
map.put("routeDescription", Objects.toString(row.get("routeDescription"), ""));
map.put("materialCode", mcode);
map.put("materialName", Objects.toString(row.get("materialName"), ""));
map.put("material", Objects.toString(row.get("material"), ""));
map.put("discWeight", Objects.toString(row.get("discWeight"), ""));
map.put("stateImportance", Objects.toString(row.get("stateImportance"), ""));
// 工艺占位当前行类型为BOM工艺字段置空
map.put("processNo", "");
map.put("workCenter", "");
map.put("processName", "");
map.put("processDescription", "");
map.put("processControl", "");
map.put("activityDuration", "");
map.put("activityUnit", "");
map.put("unitQuantity", "");
map.put("batchQuantity", "");
map.put("firstBatchQuantity", "");
map.put("planStartTime", "");
map.put("planEndTime", "");
map.put("xuStartTime", "");
map.put("xuEndTime", "");
// BOM具体字段
map.put("rawMaterialCode", childCode);
map.put("rawMaterialName", Objects.toString(row.get("rawMaterialName"), ""));
map.put("bomMaterial", Objects.toString(row.get("bomMaterial"), ""));
map.put("bomDanZhong", Objects.toString(row.get("bomDanZhong"), ""));
map.put("discUsage", Objects.toString(row.get("discUsage"), ""));
map.put("bomUnit", Objects.toString(row.get("bomUnit"), ""));
grouped.get(mcode).add(map);
}
// 先按工艺数据建立分组与顺序
for (ProcessRoute item : routeDataList) {
String mcode = Objects.toString(item.getMaterialCode(), "").trim();
boolean noRoute =
Objects.toString(item.getMaterialCode(), "").trim().isEmpty() &&
Objects.toString(item.getMaterialName(), "").trim().isEmpty() &&
Objects.toString(item.getMaterial(), "").trim().isEmpty() &&
item.getDiscWeight() == null &&
item.getProcessNo() == null &&
Objects.toString(item.getWorkCenter(), "").trim().isEmpty() &&
Objects.toString(item.getProcessName(), "").trim().isEmpty() &&
Objects.toString(item.getProcessDescription(), "").trim().isEmpty() &&
Objects.toString(item.getProcessControl(), "").trim().isEmpty() &&
item.getActivityDuration() == null &&
Objects.toString(item.getActivityUnit(), "").trim().isEmpty() &&
item.getUnitQuantity() == null &&
item.getBatchQuantity() == null &&
Objects.toString(item.getFirstBatchQuantity(), "").trim().isEmpty() &&
item.getPlanStartTime() == null &&
item.getPlanEndTime() == null &&
item.getXuStartTime() == null &&
item.getXuEndTime() == null;
if (noRoute) {
continue;
}
grouped.computeIfAbsent(mcode, k -> new ArrayList<>());
Map<String, Object> map = new HashMap<>();
map.put("rowType", "route");
map.put("routeDescription", Objects.toString(item.getRouteDescription(), ""));
map.put("materialCode", mcode);
map.put("materialName", Objects.toString(item.getMaterialName(), ""));
map.put("material", Objects.toString(item.getMaterial(), ""));
map.put("discWeight", Objects.toString(item.getDiscWeight(), ""));
map.put("stateImportance", Objects.toString(item.getStateImportance(), ""));
map.put("processNo", item.getProcessNo());
map.put("workCenter", Objects.toString(item.getWorkCenter(), ""));
map.put("processName", Objects.toString(item.getProcessName(), ""));
map.put("processDescription", Objects.toString(item.getProcessDescription(), ""));
map.put("processControl", Objects.toString(item.getProcessControl(), ""));
map.put("activityDuration", Objects.toString(item.getActivityDuration(), ""));
map.put("activityUnit", Objects.toString(item.getActivityUnit(), ""));
map.put("unitQuantity", item.getUnitQuantity());
map.put("batchQuantity", item.getBatchQuantity());
map.put("firstBatchQuantity", Objects.toString(item.getFirstBatchQuantity(), ""));
map.put("planStartTime", formatDate(item.getPlanStartTime()));
map.put("planEndTime", formatDate(item.getPlanEndTime()));
map.put("xuStartTime", formatDate(item.getXuStartTime()));
map.put("xuEndTime", formatDate(item.getXuEndTime()));
// 如果工艺数据自带BOM信息如从Excel读取的组焊件子件则保留否则置空
map.put("rawMaterialCode", Objects.toString(item.getRawMaterialCode(), ""));
map.put("rawMaterialName", Objects.toString(item.getRawMaterialName(), ""));
map.put("bomMaterial", Objects.toString(item.getBomMaterial(), ""));
map.put("bomDanZhong", Objects.toString(item.getBomDanZhong(), ""));
map.put("discUsage", Objects.toString(item.getDiscUsage(), ""));
map.put("bomUnit", Objects.toString(item.getBomUnit(), ""));
grouped.get(mcode).add(map);
}
// 展平为顺序列表并补齐序号
List<Map<String, Object>> result = new ArrayList<>();
int index = 1;
for (Map.Entry<String, List<Map<String, Object>>> entry : grouped.entrySet()) {
for (Map<String, Object> m : entry.getValue()) {
m.put("index", index++);
result.add(m);
}
}
return result;
}
private List<Map<String, Object>> convertKingdeeBomToMapList(List<Map<String, Object>> kingdeeBomRows) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (Map<String, Object> row : kingdeeBomRows) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("routeDescription", row.get("routeDescription"));
map.put("materialCode", row.get("materialCode"));
map.put("materialName", row.get("materialName"));
map.put("material", row.get("material"));
map.put("discWeight", row.get("discWeight"));
map.put("stateImportance", row.get("stateImportance"));
map.put("rawMaterialCode", row.get("rawMaterialCode"));
map.put("rawMaterialName", row.get("rawMaterialName"));
map.put("bomMaterial", row.get("bomMaterial"));
map.put("bomDanZhong", row.get("bomDanZhong"));
map.put("discUsage", row.get("discUsage"));
map.put("bomUnit", row.get("bomUnit"));
mapList.add(map);
index++;
}
return mapList;
}
@SaCheckPermission("system:orderPro:exportRoute3")
@Log(title = "下载工艺生产表3", businessType = BusinessType.EXPORT)
@GetMapping ("/exportRoute3")
public void exportRoute3(@RequestParam("id") Long id, HttpServletResponse response) {
try {
String outputPath = generateRoute3Excel(id);
if (outputPath == null) {
throw new ServiceException("生成文件失败");
}
ProcessOrderPro orderPro = processOrderProMapper.selectById(id);
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(orderPro.getProductionOrderNo() + "_分类BOM表", "UTF-8")
.replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 将生成的文件写入响应
File outputFile = new File(outputPath);
if (outputFile.exists()) {
try (FileInputStream fis = new FileInputStream(outputFile);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int length;
while ((length = fis.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
}
// 删除临时文件
outputFile.delete();
}
} catch (Exception e) {
log.error("导出分类BOM表失败", e);
throw new RuntimeException("导出失败: " + e.getMessage());
}
}
public String generateRoute3Excel(Long id) throws Exception {
return generateRoute3Excel(id, false);
}
public String generateRoute3Excel(Long id, boolean isDrawing) throws Exception {
ProcessOrderPro orderPro = processOrderProMapper.selectById(id);
// 下载Excel文件
// 1. 解析年份
String productionCode = orderPro.getProductionOrderNo();
String year = "2025"; // 默认
if (productionCode != null) {
if (productionCode.startsWith("EY")) {
if (productionCode.length() >= 4) {
try {
Integer.parseInt(productionCode.substring(2, 4));
year = "20" + productionCode.substring(2, 4);
} catch (Exception e) {}
}
} else {
int firstDash = productionCode.indexOf("-");
if (firstDash >= 0 && firstDash + 3 <= productionCode.length()) {
try {
Integer.parseInt(productionCode.substring(firstDash + 1, firstDash + 3));
year = "20" + productionCode.substring(firstDash + 1, firstDash + 3);
} catch (Exception e) {}
}
}
}
// 2. 构建FTP路径和本地路径
String ftpPath = "/" + year + "/" + productionCode;
String localPath = "D:\\file\\";
// 3. 下载文件 (下载汇总表.xlsx 和 RawDataTable.xlsx)
FtpUtil.downloadFtpDirectoryFiles("192.168.5.18", "admin", "hbyt2025", 21, ftpPath, localPath, "汇总表.xlsx");
FtpUtil.downloadFtpDirectoryFiles("192.168.5.18", "admin", "hbyt2025", 21, ftpPath, localPath, "RawDataTable.xlsx");
// 构建文件路径
String excelName = "D:\\file\\" + orderPro.getProductionOrderNo() + "汇总表.xlsx";
String rawDataFile = "D:\\file\\" + "RawDataTable.xlsx";
File file = new File(excelName);
if (!file.exists() || file.length() == 0) {
// 如果文件不存在或为空(下载失败),抛出业务异常
throw new ServiceException("项目 " + orderPro.getProductionOrderNo() + " 汇总表下载失败或不存在");
}
// 1. 读取第一个sheet的数据list
List<ProductionOrderVo> allDataList = readExcelWithPOI(excelName,orderPro.getProductionOrderNo());
List<ProcessRoute> routeList = readExcelPOIRoute3(excelName,orderPro.getProductionOrderNo());
log.info("routeList: {}", routeList);
List<ProcessRoute> routes = new ArrayList<>();
List<Map<String, Object>> kingdeeBomRows = new ArrayList<>();
// 用于去重的Set
Set<String> routeKeySet = new HashSet<>();
Set<String> bomKeySet = new HashSet<>();
/* for (ProcessRoute base : routeList) {
String processDescription = base.getRouteDescription();
String materialCode = base.getMaterialCode();
String materialName = base.getMaterialName();
//如果项目零号是CP 跳过安全库存物料
LambdaQueryWrapper<SafetyStock> wr = new LambdaQueryWrapper<>();
wr.eq(SafetyStock::getMaterialCode, materialCode);
SafetyStock safetyStock = stockMapper.selectOne(wr);
if (safetyStock != null && base.getRouteDescription().startsWith("CP")) {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
item.setXuEndTime(base.getXuEndTime());
item.setXuStartTime(base.getXuStartTime());
// 生成唯一键用于去重
String routeKey = base.getRouteDescription() + "-" + base.getMaterialCode() + "-" + (base.getProcessNo() != null ? base.getProcessNo() : "");
if (!routeKeySet.contains(routeKey)) {
routes.add(item);
routeKeySet.add(routeKey);
}
continue;
}
if (StringUtils.isBlank(materialCode)) {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
item.setXuEndTime(base.getXuEndTime());
item.setXuStartTime(base.getXuStartTime());
// 生成唯一键用于去重
String routeKey = base.getRouteDescription() + "-" + (base.getMaterialCode() != null ? base.getMaterialCode() : "") + "-" + (base.getProcessNo() != null ? base.getProcessNo() : "");
if (!routeKeySet.contains(routeKey)) {
routes.add(item);
routeKeySet.add(routeKey);
}
continue;
}
//List<ProcessRouteDTO> routeGuDing = JdUtil.getRouteGuDing(materialCode);processRouteService
List<MaterialBom> bomItems = processRouteService.getProcessMaterialList(materialCode, materialName, processDescription);
List<ProcessRoute> routeGuDing = processRouteService.getProcessRoutesByOrder(processDescription, materialCode);
if (routeGuDing != null && !routeGuDing.isEmpty()) {
routeGuDing.forEach(r -> {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
// 保留Excel读取的BOM字段防止组焊件数据丢失
item.setRawMaterialCode(base.getRawMaterialCode());
item.setRawMaterialName(base.getRawMaterialName());
item.setBomMaterial(base.getBomMaterial());
item.setBomDanZhong(base.getBomDanZhong());
item.setDiscUsage(base.getDiscUsage());
item.setBomUnit(base.getBomUnit());
// 添加工艺信息
item.setProcessNo(r.getProcessNo());
item.setWorkCenter(r.getWorkCenter());
item.setProcessName(r.getProcessName());
item.setProcessDescription(r.getProcessDescription());
item.setProcessControl(r.getProcessControl());
item.setActivityDuration(r.getActivityDuration());
item.setActivityUnit(r.getActivityUnit());
item.setXuStartTime(r.getXuStartTime());
item.setXuEndTime(r.getXuEndTime());
// 生成唯一键用于去重
String routeKey = base.getRouteDescription() + "-" + base.getMaterialCode() + "-" + (r.getProcessNo() != null ? r.getProcessNo() : "");
if (!routeKeySet.contains(routeKey)) {
routes.add(item);
routeKeySet.add(routeKey);
}
});
} else {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
item.setXuStartTime(base.getXuStartTime());
item.setXuEndTime(base.getXuEndTime());
// 保留Excel读取的BOM字段防止组焊件数据丢失
item.setRawMaterialCode(base.getRawMaterialCode());
item.setRawMaterialName(base.getRawMaterialName());
item.setBomMaterial(base.getBomMaterial());
item.setBomDanZhong(base.getBomDanZhong());
item.setDiscUsage(base.getDiscUsage());
item.setBomUnit(base.getBomUnit());
// 生成唯一键用于去重
String routeKey = base.getRouteDescription() + "-" + base.getMaterialCode() + "-" + (base.getProcessNo() != null ? base.getProcessNo() : "");
if (!routeKeySet.contains(routeKey)) {
routes.add(item);
routeKeySet.add(routeKey);
}
}
if (bomItems != null && !bomItems.isEmpty()) {
for (MaterialBom b : bomItems) {
// --- 第一步收集这行BOM本身的工艺信息并构建映射原 kingdeeBomRows 逻辑) ---
Map<String, Object> bomMap = new HashMap<>();
bomMap.put("routeDescription", base.getRouteDescription());
bomMap.put("materialCode", base.getMaterialCode());
bomMap.put("materialName", base.getMaterialName());
bomMap.put("material", base.getMaterial());
bomMap.put("discWeight", base.getDiscWeight());
bomMap.put("stateImportance", base.getDiscWeight());
bomMap.put("rawMaterialCode", b.getMaterialCode());
bomMap.put("rawMaterialName", b.getMaterialName());
bomMap.put("bomMaterial", b.getMaterialType());
bomMap.put("bomDanZhong", null);
if ("根".equals(b.getUnit())) {
if (b.getQuantity() != null && b.getQuantity().contains("/")) {
String[] arr = b.getQuantity().split("/");
bomMap.put("discUsage", Double.parseDouble(arr[0]) / Double.parseDouble(arr[1]));
} else {
bomMap.put("discUsage", null);
}
} else if ("mm".equals(b.getUnit())) {
b.setUnit("m");
bomMap.put("discUsage", b.getQuantity());
} else {
bomMap.put("discUsage", b.getQuantity());
}
bomMap.put("bomUnit", b.getUnit());
// 生成唯一键用于去重
String bomKey = base.getRouteDescription() + "-" + base.getMaterialCode() + "-" + b.getMaterialCode();
if (!bomKeySet.contains(bomKey)) {
kingdeeBomRows.add(bomMap);
bomKeySet.add(bomKey);
}
// --- 第二步判断如果是组焊件且需要多行工艺扩展则生成继承父级的对象加入routes ---
// 这里判断该子件是否为组焊件(您可根据实际业务逻辑调整判断条件,例如物料类型包含"组焊"或特定前缀)
if (b.getMaterialName() != null && b.getMaterialName().contains("组焊")) {
// 获取组焊件自身的工艺路线
List<ProcessRoute> subRouteGuDing = processRouteService.getProcessRoutesByOrder(processDescription, b.getMaterialCode());
if (subRouteGuDing != null && !subRouteGuDing.isEmpty()) {
// 如果组焊件自身有工艺路线,则根据工艺路线展开多行
subRouteGuDing.forEach(sr -> {
ProcessRoute subItem = new ProcessRoute();
// 继承父级的通用信息
subItem.setRouteDescription(base.getRouteDescription());
subItem.setMaterialCode(base.getMaterialCode());
subItem.setMaterialName(base.getMaterialName());
subItem.setMaterial(base.getMaterial());
subItem.setDiscWeight(base.getDiscWeight());
subItem.setUnitQuantity(base.getUnitQuantity());
subItem.setBatchQuantity(base.getBatchQuantity());
// 设置BOM层级信息
subItem.setRawMaterialCode(b.getMaterialCode());
subItem.setRawMaterialName(b.getMaterialName());
subItem.setBomMaterial(b.getMaterialType());
subItem.setBomDanZhong(null); // 或者从b获取
Object discUsageObj = bomMap.get("discUsage");
subItem.setDiscUsage(discUsageObj != null ? String.valueOf(discUsageObj) : null); // 复用上方计算出的用量
subItem.setBomUnit((String) bomMap.get("bomUnit"));
// 添加组焊件自身的工艺信息
subItem.setProcessNo(sr.getProcessNo());
subItem.setWorkCenter(sr.getWorkCenter());
subItem.setProcessName(sr.getProcessName());
subItem.setProcessDescription(sr.getProcessDescription());
subItem.setProcessControl(sr.getProcessControl());
subItem.setActivityDuration(sr.getActivityDuration());
subItem.setActivityUnit(sr.getActivityUnit());
subItem.setXuStartTime(sr.getXuStartTime());
subItem.setXuEndTime(sr.getXuEndTime());
// 生成唯一键用于去重
String subRouteKey = base.getRouteDescription() + "-" + base.getMaterialCode() + "-sub-" + b.getMaterialCode() + "-" + (sr.getProcessNo() != null ? sr.getProcessNo() : "") + "-" + System.nanoTime();
if (!routeKeySet.contains(subRouteKey)) {
routes.add(subItem);
routeKeySet.add(subRouteKey);
}
});
} else {
// 如果组焊件没有工艺路线,仅生成一行
ProcessRoute subItem = new ProcessRoute();
// 继承父级的通用信息
subItem.setRouteDescription(base.getRouteDescription());
subItem.setMaterialCode(base.getMaterialCode());
subItem.setMaterialName(base.getMaterialName());
subItem.setMaterial(base.getMaterial());
subItem.setDiscWeight(base.getDiscWeight());
subItem.setUnitQuantity(base.getUnitQuantity());
subItem.setBatchQuantity(base.getBatchQuantity());
subItem.setXuStartTime(base.getXuStartTime());
subItem.setXuEndTime(base.getXuEndTime());
// 设置BOM层级信息
subItem.setRawMaterialCode(b.getMaterialCode());
subItem.setRawMaterialName(b.getMaterialName());
subItem.setBomMaterial(b.getMaterialType());
subItem.setBomDanZhong(null); // 或者从b获取
Object discUsageObj = bomMap.get("discUsage");
subItem.setDiscUsage(discUsageObj != null ? String.valueOf(discUsageObj) : null); // 复用上方计算出的用量
subItem.setBomUnit((String) bomMap.get("bomUnit"));
// 组焊件即使没有工艺,也不要覆盖子件自身的编码,让它自己独立成行
// 生成唯一键用于去重 (以BOM的物料编码作为去重标识一部分)
String subRouteKey = base.getRouteDescription() + "-" + base.getMaterialCode() + "-sub-" + b.getMaterialCode() + "-" + System.nanoTime();
if (!routeKeySet.contains(subRouteKey)) {
routes.add(subItem);
routeKeySet.add(subRouteKey);
}
}
}
}
}
}
// 用生成的 routes 替换原始 routeList保持原序展开后的结构用于后续导出
routeList = routes;*/
// 2. 读取原始表数据
List<BomDataVO> rawDataList = readRawDataTable(rawDataFile);
// 3. 数据分类处理
List<VMIDataVO> vmiList = new ArrayList<>(); // 009开头
List<ElecOutDataVO> elecOutList = new ArrayList<>(); // 两个空格和017开头
List<SupProvidDataVO> supplierList = new ArrayList<>(); // 甲供件
List<EVOProductsDataVO> evoProductsList = new ArrayList<>(); // 伊特
List<ProductionOrderVo> processDataList = new ArrayList<>(); // 工艺数据(剩余数据)
// 分类逻辑
for (ProductionOrderVo item : allDataList) {
String materialCode = item.getDrawingNo();
String remark = item.getRemark(); // 使用备注字段
// 009开头的加入VMI表
if (materialCode != null) {
String drawingNo = item.getDrawingNo();
String drawingName = item.getDrawingName();
if (drawingName != null) {
ImMaterial material = imMaterialService.selectByCodeAndName(drawingNo, drawingName);
if (material != null) {
//判断是否是VMI物料
if ("true".equals(material.getClassificationName())) {
VMIDataVO vmiData = convertToVMIDataVO(item);
vmiList.add(vmiData);
continue; // 已分类,跳过后续检查
}
}
}
// 机电件分类条件:物料编码开头空格/特定前缀 或 备注包含"外购"
if (materialCode.startsWith(" ")
|| materialCode.startsWith("009301") || materialCode.startsWith("009999") || materialCode.startsWith("017003") || materialCode.startsWith("017002")
|| materialCode.startsWith("009001") || materialCode.startsWith("009081")
|| (remark != null && remark.contains("外购"))) {
// 过滤安全库存:如果属于安全库存,则进入工艺数据列表
Boolean isSafeStock = safetyStockService.isSafeCode(materialCode.trim());
if (isSafeStock) {
// 属于安全库存,添加到工艺数据列表
processDataList.add(item);
continue;
} else {
// 如果物料编码相同,则合并数量
boolean found = false;
for (ElecOutDataVO existingElec : elecOutList) {
if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingElec.getDrawingNo())) {
// 合并单台数量 (quantity)
Double currentQuantity = existingElec.getQuantity() != null ? existingElec.getQuantity() : 0.0;
Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
existingElec.setQuantity(currentQuantity + itemQuantity);
// 合并本批数量 (batchQuantity)
Integer currentBatch = existingElec.getBatchQuantity() != null ? existingElec.getBatchQuantity() : 0;
Integer itemBatch = 0;
try {
if (item.getBatchQuantity() != null) {
itemBatch = Integer.valueOf(item.getBatchQuantity().toString());
}
} catch (NumberFormatException e) {
// 转换失败忽略
}
existingElec.setBatchQuantity(currentBatch + itemBatch);
found = true;
break;
}
}
if (!found) {
ElecOutDataVO elecData = convertToElecOutDataVO(item);
elecOutList.add(elecData);
}
continue;
}
}
// 备注是甲供件的
if (remark != null && remark.contains("甲供件")) {
SupProvidDataVO supplierData = convertToSupProvidDataVO(item);
supplierList.add(supplierData);
continue; // 已分类,跳过后续检查
}
// 备注是伊特
if (remark != null && remark.contains("伊特")) {
EVOProductsDataVO evoData = convertToEVOProductsDataVO(item);
evoProductsList.add(evoData);
continue; // 已分类,跳过后续检查
}
}
// 直接将剩余的数据添加到工艺数据列表,不做聚合处理
processDataList.add(item);
}
// 使用Excel模板文件
String templatePath = "jpg/生产及工艺计划模版.xlsx";
String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx";
// 准备模板数据
Map<String, Object> staticDataMap = new HashMap<>();
staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo());
staticDataMap.put("productionName", orderPro.getProductionName());
// 准备动态数据映射
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
// 添加生产订单数据
if (!allDataList.isEmpty()) {
List<Map<String, Object>> productionDataList = convertProductionOrderToMapList(allDataList, orderPro.getProductionOrderNo());
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProductionOrder", productionDataList));
}
// 添加工艺数据第七个sheet工艺及生产计划表
if (!processDataList.isEmpty()) {
List<Map<String, Object>> processDataMapList = convertProductionOrderToMapList(processDataList, orderPro.getProductionOrderNo());
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessData", processDataMapList));
}
// 添加VMI数据
if (!vmiList.isEmpty()) {
List<Map<String, Object>> vmiDataList = convertVMIDataToMapList(vmiList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("VMIDataVO", vmiDataList));
}
// 添加电气外购数据
if (!elecOutList.isEmpty()) {
List<Map<String, Object>> elecDataList = convertElecOutDataToMapList(elecOutList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ElecOutDataVO", elecDataList));
}
// 添加BOM数据
if (!rawDataList.isEmpty()) {
List<Map<String, Object>> bomDataList = convertBomDataToMapList(rawDataList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("BomDataVO", bomDataList));
}
// 添加甲供件数据
if (!supplierList.isEmpty()) {
List<Map<String, Object>> supplierDataList = convertSupProvidDataToMapList(supplierList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("SupProvidDataVO", supplierDataList));
}
// 添加伊特产品数据
if (!evoProductsList.isEmpty()) {
List<Map<String, Object>> evoDataList = convertEVOProductsDataToMapList(evoProductsList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList));
}
// 方案A合并工艺与BOM为单一数据集并按物料分组
if (!routeList.isEmpty() || !kingdeeBomRows.isEmpty()) {
List<Map<String, Object>> routeBomDataList = convertRouteBomToMapList(routeList, kingdeeBomRows);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("RouteBomData", routeBomDataList));
}
// 使用模板导出Excel
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, outputPath, staticDataMap, dynamicDataMappingList);
return outputPath;
}
@SaCheckPermission("system:orderPro:downloadZip")
@Log(title = "下载项目DWG", businessType = BusinessType.OTHER)
@GetMapping("/downloadDwg/{id}")
public void downloadDwg(@PathVariable("id") Long id, HttpServletResponse response) {
try {
// 1. 根据ID查询数据校验 quantity
FigureSave figureSave = figureSaveMapper.selectById(id);
ProcessOrderPro orderPro = processOrderProMapper.selectById(figureSave.getPid());
if (orderPro == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "找不到对应数据");
return;
}
// 检查 quantity 字段(假设你的数量字段名是 quantity 或者 unitQuantity 等,这里假设是 getQuantity(),如果不对请调整为对应的 get 方法)
if (orderPro.getQuantity() != null && orderPro.getQuantity().intValue() == 0) {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSONObject.toJSONString(R.fail("当前图纸数量不允许下载")));
return;
}
// 2. 直接调用 service 层原逻辑进行单个下载
R<String> result = iProcessOrderProService.downloadDwg(id);
if (result.getCode() == 200) {
// R.getData() 返回的如果是一个对象或者其他形式确保能被正确转换为String
String dirPath = result.getMsg(); // 注意:你之前在 iProcessOrderProService 里面返回的是 R.ok(dirPath)
if (result.getData() != null) {
dirPath = String.valueOf(result.getData());
} else if (result.getMsg() != null && !result.getMsg().equals("操作成功")) {
dirPath = result.getMsg();
}
if (dirPath == null) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "下载失败: 未获取到文件目录路径");
return;
}
File downloadDir = new File(dirPath);
if (downloadDir.exists() && downloadDir.isDirectory()) {
File[] files = downloadDir.listFiles();
if (files != null && files.length > 0) {
File downloadFile = files[0]; // 假设目前你只想直接下载第一个
// 设置响应头
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(downloadFile.getName(), "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
// 写入响应流
try (FileInputStream fis = new FileInputStream(downloadFile);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int length;
while ((length = fis.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
}
// 这种模式下不删除源文件,或者根据需求决定是否删除
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "目录为空没有找到DWG文件");
}
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件目录不存在");
}
} else {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSONObject.toJSONString(result));
}
} catch (Exception e) {
log.error("下载DWG失败", e);
try {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "下载失败: " + e.getMessage());
} catch (IOException ex) {
log.error("发送错误响应失败", ex);
}
}
}
}