evoToK3Cloud/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java

1122 lines
50 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.SimpleDateFormat;
import java.util.*;
import com.alibaba.excel.EasyExcel;
import com.ruoyi.common.excel.DefaultExcelListener;
import com.ruoyi.common.exception.ServiceException;
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.bo.FigureSaveBo;
import com.ruoyi.system.domain.dto.ProcessRouteExcelDTO;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.domain.vo.BomDataVO;
import com.ruoyi.system.mapper.ProcessOrderProMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.service.impl.ProductionOrderServiceImpl;
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;
/**
* 项目令号
*
* @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 iSafetyStockService;
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:list")
@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) {
return toAjax(iProcessOrderProService.insertByBo(bo));
}
/**
* 修改项目令号
*/
@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: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: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:plan:add")
@Log(title = "排产计划", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/addProduct")
public R<Void> addProduct(@Validated(AddGroup.class) @RequestBody FigureSaveBo bo, @RequestBody ProcessOrderProBo orderPro) {
iProcessOrderProService.addProduct(bo, orderPro);
return R.ok();
}
@SaCheckPermission("system:plan:add")
@Log(title = "执行出图", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/executDrawing")
public R<Void> executDrawing(@RequestBody ProcessOrderProBo orderPro) {
String s = iProcessOrderProService.executDrawing(orderPro);
return R.ok(s);
}
/**
* 上传dwg图纸
*
* @param id
* @param filePath
* @return
*/
@PostMapping("/uploadDwg")
@ResponseBody
public R<Void> uploadContractPDF(@RequestParam("id") Integer id, @RequestParam("file") MultipartFile filePath) {
String originalFilename = filePath.getOriginalFilename();
if (StringUtils.isEmpty(originalFilename)) {
return R.fail("获取文件名称错误!!");
}
//校验文件后缀 jpg jpeg pdf 格式的文件不允许上传
String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
if (!"dwg".equals(suffix)) {
return R.fail("禁止非法文件上传!!");
}
String reslut = iProcessOrderProService.uploadContractPDF(id, originalFilename, filePath);
return R.ok(reslut);
}
/**
* 下载PDF并生成zip包
*/
@SaCheckPermission("system:processOrderPro:uploadPDF")
@Log(title = "上传PDF", businessType = BusinessType.UPDATE)
@GetMapping("/uploadPDF")
public void uploadPDF(@RequestParam Long id, HttpServletResponse response) {
try {
// 调用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()));
// 写入文件流
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:processOrderPro: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:geMRPResults")
@Log(title = "获取MRP复核结果", businessType = BusinessType.OTHER)
@PostMapping("/getMRPResults/{id}")
public R<List<MrpResultCheck>> geMRPResults(@PathVariable Long id) {
return iMrpResultCheckService.getMRPResults(id);
}
@SaCheckPermission("system:route: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);
List<ProcessRoute> routeList = readExcelPOIRoute(excelName);
// 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 = iSafetyStockService.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 = "D:/java/excel-template/生产及工艺计划模版.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<ProcessRouteExcelDTO> excelDTOList = iProcessOrderProService.getRouteAndBomDetail(routeList,processDataList,orderPro);
excelDTOList.sort(Comparator.comparing(
ProcessRouteExcelDTO::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(
ProcessRouteExcelDTO::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) {
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 = 2; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
XSSFRow row = sheet.getRow(rowIndex);
if (row == null) {
continue;
}
ProcessRoute vo = new ProcessRoute();
// 根据列索引读取数据,保留原始空格
vo.setMaterialCode(getCellValueAsString(row.getCell(0))); // 图号
vo.setMaterialName(getCellValueAsString(row.getCell(1))); // 名称
vo.setMaterial(getCellValueAsString(row.getCell(2))); // 数量
vo.setDiscWeight(getCellValueAsDouble(row.getCell(3))); // 单重
vo.setBatchQuantity(getCellValueAsLong(row.getCell(18))); // 批次数量
vo.setUnitQuantity(getCellValueAsDouble(row.getCell(17))); // 批次数量
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;
}
/**
* 读取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());
map.put("drawingNo", orderPro.getDrawingNo());
map.put("mainProducts", orderPro.getDrawingName());
map.put("mainProductsName", orderPro.getDrawingName());
mapList.add(map);
}
return mapList;
}
/**
* 使用POI直接读取Excel文件保留前后空格
*/
private List<ProductionOrderVo> readExcelWithPOI(String excelPath) {
List<ProductionOrderVo> resultList = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(excelPath);
XSSFWorkbook workbook = new XSSFWorkbook(fis)) {
XSSFSheet sheet = workbook.getSheetAt(0); // 读取第一个sheet
// 从第3行开始读取headRowNumber=2所以从第3行开始
for (int rowIndex = 2; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
XSSFRow row = sheet.getRow(rowIndex);
if (row == null) {
continue;
}
ProductionOrderVo vo = new ProductionOrderVo();
// 根据列索引读取数据,保留原始空格
vo.setId(getCellValueAsLong(row.getCell(0)));
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成功共{}条记录", 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;
}
}
/**
* 获取单元格的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<ProcessRouteExcelDTO> routeDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (ProcessRouteExcelDTO 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("rawMaterialCode", item.getRawMaterialCode()); // 材料BOM物料编码
map.put("rawMaterialName", item.getRawMaterialName()); // 材料BOM物料名称
map.put("bomMaterial", item.getBomMaterial()); // BOM材质
map.put("bomDanZhong", item.getBomDanZhong()); // 材料单重KG
map.put("discUsage", item.getDiscUsage()); // 用量
map.put("bomUnit", item.getBomUnit()); // 单位
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;
}
}