package com.ruoyi.system.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.json.JSONUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.write.metadata.WriteSheet; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.config.DingTalkProperties; 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.domain.entity.SysUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.dingding.util.DingUtil; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.excel.DefaultExcelListener; import com.ruoyi.common.excel.ExcelResult; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.common.utils.FtpUtil; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.SmbUtil; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.domain.*; import com.ruoyi.system.domain.bo.ProcessRouteBo; import com.ruoyi.system.domain.dto.*; import com.ruoyi.system.domain.vo.PcRigidChainVo; import com.ruoyi.system.domain.vo.PlannedProcessVo; import com.ruoyi.system.domain.vo.ProcessRouteVo; import com.ruoyi.system.domain.vo.ProductionOrderVo; import com.ruoyi.system.jdmain.rouplan.Model; import com.ruoyi.system.mapper.BomDetailsMapper; import com.ruoyi.system.mapper.MaterialBomMapper; import com.ruoyi.system.mapper.ProcessOrderProMapper; import com.ruoyi.system.mapper.ProcessRouteMapper; import com.ruoyi.system.runner.JdUtil; import com.ruoyi.system.service.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.io.*; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; /** * 工艺路线 * * @date 2024-10-09 */ @Validated @RequiredArgsConstructor @RestController @RequestMapping("/system/route") @Slf4j public class ProcessRouteController extends BaseController { private final ProcessRouteMapper baseMapper; private final IProcessRouteService iProcessRouteService; private final IBomDetailsService iBomDetailsService; private final ProcessOrderProMapper proMapper; private final IImMaterialService materialService; @Autowired BomDetailsMapper bomDetailsMapper; @Autowired MaterialBomMapper materialBomMapper; @Autowired private DingTalkProperties dingTalkProperties; @Autowired private ISysOssService iSysOssService; @Autowired private IProcessOrderProService processOrderProService; @Autowired private ISysUserService userService; @Autowired private com.ruoyi.common.dingding.robot.RobotGroupService robotGroupService; @Autowired private com.ruoyi.common.dingding.media.MediaService mediaService; private Long generateUniqueParentId(Long originalId) { return originalId + 1000; } @Log(title = "查看BOM上传状态") @SaCheckPermission("system:route:viewGetBomUploadStatus") @PostMapping("/viewGetBomUploadStatus") public R viewGetBomUploadStatus(@RequestParam String rooteProdet) { return iProcessRouteService.viewGetBomUploadStatus(rooteProdet); } /** * 主动更新可用库存 */ @SaCheckPermission("system:route:list") @GetMapping("/list2") public TableDataInfo list2(ProcessRouteBo bo, PageQuery pageQuery) { try { // 查询工艺路线数据 TableDataInfo processRouteVoTableDataInfo = iProcessRouteService.queryPageList2(bo, pageQuery); // 用于存储父子关系的Map,key为"物料编码_物料名称",值为父级ProcessRouteVo Map routeMap = new HashMap<>(); // 存储顶级列表 List topLevelList = new ArrayList<>(); // 获取查询返回的行数据 List rows = processRouteVoTableDataInfo.getRows(); // 遍历所有工艺路线记录 for (ProcessRouteVo processRouteVo : rows) { // 组合父级键值,物料编码 + 物料名称 String parentCodeAndName = String.format("%s_%s", processRouteVo.getMaterialCode(), processRouteVo.getMaterialName()); // 查找是否已存在父节点 ProcessRouteVo parent = routeMap.get(parentCodeAndName); if (parent == null) { // 如果父节点不存在,创建并初始化 parent = new ProcessRouteVo(); parent.setId(generateUniqueParentId(processRouteVo.getId())); parent.setRouteDescription(processRouteVo.getRouteDescription()); // parent.setParentId((Long.valueOf(generateUniqueParentId(processRouteVo.getId())))); parent.setMaterialCode(processRouteVo.getMaterialCode()); parent.setMaterialName(processRouteVo.getMaterialName()); parent.setMaterial(processRouteVo.getMaterial()); parent.setDiscWeight(processRouteVo.getDiscWeight()); parent.setFirstBatchQuantity(processRouteVo.getFirstBatchQuantity()); // 初始化子节点列表 parent.setChildren(new ArrayList<>()); // 将父节点放入Map中 routeMap.put(parentCodeAndName, parent); // 将父节点加入顶级列表 topLevelList.add(parent); } // 创建子节点,并将其添加到父节点的子集 ProcessRouteVo child = createChildVo(processRouteVo, parent.getId(), parent.getMaterialCode(), parent.getMaterialName()); parent.getChildren().add(child); } // 设置返回的rows为顶级节点列表 processRouteVoTableDataInfo.setRows(topLevelList); // 返回构建后的数据 return processRouteVoTableDataInfo; } catch (Exception e) { e.printStackTrace(); return new TableDataInfo<>(); } } /** * 查询工艺路线列表 */ @SaCheckPermission("system:route:list") @GetMapping("/list") public TableDataInfo list(ProcessRouteBo bo, PageQuery pageQuery) { try { // 查询工艺路线数据 TableDataInfo processRouteVoTableDataInfo = iProcessRouteService.queryPageList(bo, pageQuery); // 用于存储父子关系的Map,key为"物料编码_物料名称",值为父级ProcessRouteVo Map routeMap = new HashMap<>(); // 存储顶级列表 List topLevelList = new ArrayList<>(); // 获取查询返回的行数据 List rows = processRouteVoTableDataInfo.getRows(); // 遍历所有工艺路线记录 for (ProcessRouteVo processRouteVo : rows) { // 组合父级键值,物料编码 + 物料名称 String parentCodeAndName = String.format("%s_%s", processRouteVo.getMaterialCode(), processRouteVo.getMaterialName()); // 查找是否已存在父节点 ProcessRouteVo parent = routeMap.get(parentCodeAndName); if (parent == null) { // 如果父节点不存在,创建并初始化 parent = new ProcessRouteVo(); parent.setId(generateUniqueParentId(processRouteVo.getId())); parent.setRouteDescription(processRouteVo.getRouteDescription()); // parent.setParentId((Long.valueOf(generateUniqueParentId(processRouteVo.getId())))); parent.setMaterialCode(processRouteVo.getMaterialCode()); parent.setMaterialName(processRouteVo.getMaterialName()); parent.setMaterial(processRouteVo.getMaterial()); parent.setDiscWeight(processRouteVo.getDiscWeight()); parent.setBatchQuantity(processRouteVo.getBatchQuantity()); parent.setFirstBatchQuantity(processRouteVo.getFirstBatchQuantity()); // 初始化子节点列表 parent.setChildren(new ArrayList<>()); // 将父节点放入Map中 routeMap.put(parentCodeAndName, parent); // 将父节点加入顶级列表 topLevelList.add(parent); } // 创建子节点,并将其添加到父节点的子集 ProcessRouteVo child = createChildVo(processRouteVo, parent.getId(), parent.getMaterialCode(), parent.getMaterialName()); parent.getChildren().add(child); } // 设置返回的rows为顶级节点列表 processRouteVoTableDataInfo.setRows(topLevelList); // 返回构建后的数据 return processRouteVoTableDataInfo; } catch (Exception e) { e.printStackTrace(); return new TableDataInfo<>(); } } /** * 创建子节点的辅助方法 * * @param processRouteVo 原始数据 * @return ProcessRouteVo 子节点 */ private ProcessRouteVo createChildVo(ProcessRouteVo processRouteVo, Long parentId, String materialCode, String materialName) { ProcessRouteVo child = new ProcessRouteVo(); child.setId(processRouteVo.getId()); child.setParentId(parentId); child.setProcessNo(processRouteVo.getProcessNo()); child.setWorkCenter(processRouteVo.getWorkCenter()); child.setProcessName(processRouteVo.getProcessName()); child.setProcessDescription(processRouteVo.getProcessDescription()); child.setProcessControl(processRouteVo.getProcessControl()); child.setActivityDuration(processRouteVo.getActivityDuration()); child.setActivityUnit(processRouteVo.getActivityUnit()); child.setUnitQuantity(processRouteVo.getUnitQuantity()); child.setPlanStartTime(processRouteVo.getPlanStartTime()); child.setPlanEndTime(processRouteVo.getPlanEndTime()); child.setXuStartTime(processRouteVo.getXuStartTime()); child.setXuEndTime(processRouteVo.getXuEndTime()); return child; } /** * 导出工艺路线列表 */ @SaCheckPermission("system:route:export2") @Log(title = "工艺路线", businessType = BusinessType.EXPORT) @PostMapping("/export2") public void export2(ProcessRouteBo bo, HttpServletResponse response) { log.info("获取项目生产数据表:{}", bo); List list = iProcessRouteService.queryList(bo); List bomlist = JdUtil.getPRD_PPBOM(bo.getRouteDescription()); //过滤bomlist 只要009开头的标准件 bomlist = bomlist.stream().filter(bom -> bom.getMaterialCode().startsWith("009")).collect(Collectors.toList()); if (list.isEmpty() && bomlist.isEmpty()) { throw new ServiceException("没有数据"); } try { // 设置响应头 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("工艺路线", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); ServletOutputStream os = response.getOutputStream(); // 创建ExcelWriter try (com.alibaba.excel.ExcelWriter excelWriter = EasyExcel.write(os).autoCloseStream(false) // 防止自动关闭流 .build()) { // 写入工艺路线sheet if (!list.isEmpty()) { WriteSheet writeSheet1 = EasyExcel.writerSheet(0, "工艺路线").head(ProcessRoute.class).build(); excelWriter.write(list, writeSheet1); } // 写入标准件清单sheet if (!bomlist.isEmpty()) { WriteSheet writeSheet2 = EasyExcel.writerSheet(1, "标准件清单").head(MaterialUsageDTO2.class).build(); excelWriter.write(bomlist, writeSheet2); } } } catch (Exception e) { throw new RuntimeException("导出Excel异常: " + e.getMessage(), e); } } @SaCheckPermission("system:route:export") @Log(title = "工艺路线", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(ProcessRouteBo bo, HttpServletResponse response) { log.info("获取项目生产数据表:{}", bo); // 下载Excel模板 SmbUtil.downloadExcelFiles(bo.getRouteDescription()); // 构建Excel文件路径 String ExcelName = "D:\\file\\" + bo.getRouteDescription() + "汇总表.xlsx"; File file = new File(ExcelName); if (!file.exists()) { throw new ServiceException("文件不存在,请确认路径是否正确"); } //读取file的所有的物料编码 try { if (file.exists()) { // 读取Excel的sheet6 从第三行开始 读取到第4列 无数据的跳过 DefaultExcelListener listener = new DefaultExcelListener<>(true); EasyExcel.read(ExcelName, ProcessRoute.class, listener).sheet(6).headRowNumber(3).doRead(); } } catch (Exception e) { throw new RuntimeException(e); } // 查询要写入的数据是否 List list = iProcessRouteService.queryList(bo); try { // 设置响应头 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("工艺路线", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); ServletOutputStream os = response.getOutputStream(); // 使用 EasyExcel 写入已有Excel的第七个sheet(index=6) try (ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(file) // 指定模板文件 .autoCloseStream(true).build()) { // 写入到第七个 sheet(index=6),并命名为“工艺路线” WriteSheet writeSheet = EasyExcel.writerSheet("已有工艺路线").head(ProcessRoute.class).needHead(true).build(); excelWriter.write(list, writeSheet); } os.flush(); } catch (Exception e) { log.error("导出Excel异常", e); throw new RuntimeException("导出Excel异常: " + e.getMessage(), e); } } /** * 获取工艺路线详细信息 * * @param id 主键 */ @SaCheckPermission("system:route:query") @GetMapping("/{id}") public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { return R.ok(iProcessRouteService.queryById(id)); } /** * 新增工艺路线 */ @SaCheckPermission("system:route:add") @Log(title = "工艺路线", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping() public R add(@Validated(AddGroup.class) @RequestBody ProcessRouteBo bo) { return toAjax(iProcessRouteService.insertByBo(bo)); } /** * 导出 * 修改工艺路线 */ @SaCheckPermission("system:route:edit") @Log(title = "工艺路线", businessType = BusinessType.UPDATE) @RepeatSubmit() @PutMapping() public R edit(@Validated(EditGroup.class) @RequestBody ProcessRouteBo bo) { return toAjax(iProcessRouteService.updateByBo(bo)); } /** * 删除工艺路线 * * @param ids 主键串 */ @SaCheckPermission("system:route:remove") @Log(title = "工艺路线", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { return toAjax(iProcessRouteService.deleteWithValidByIds(Arrays.asList(ids), true)); } @Log(title = "生产工艺计划表导入", businessType = BusinessType.IMPORT) @SaCheckPermission("system:route:importRoute") @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R importData(@RequestParam("file") MultipartFile file) throws Exception { String originalFilename = file.getOriginalFilename(); log.info("读取文件名: " + originalFilename); // 读取工艺部分sheet ExcelResult result = ExcelUtil.importExcelSheet6(file.getInputStream(), ProcessRouteVo.class, true); List list1 = result.getList(); // 读取总装部分sheet ExcelResult result1 = ExcelUtil.importExcelSheet1(file.getInputStream(), ProductionOrderVo.class, true); List list = result1.getList(); String productionOrderNo = list1.get(0).getRouteDescription(); List bomDetails = iBomDetailsService.selectByProjectNumber(list1.get(0).getRouteDescription()); List route = iProcessRouteService.selectByProjectNumber(list1.get(0).getRouteDescription()); if (list1.isEmpty()) { return R.fail("项目 " + productionOrderNo + "工艺生产计划表为空,请检查此表或将sheet移动至第七个!"); } if (!bomDetails.isEmpty()) { return R.fail("项目 " + productionOrderNo + "已导入过BOM,请先清空再上传"); } if (!route.isEmpty()) { return R.fail("项目 " + productionOrderNo + "已导入过工艺 ,请先清空再上传"); } if (iProcessRouteService.saveData(list1, list)) { // 保存临时文件用于发送给指定用户 File tempFile = null; try { String tempDirPath = "D:/file/"; File tempDir = new File(tempDirPath); if (!tempDir.exists()) { tempDir.mkdirs(); } tempFile = new File(tempDirPath + System.currentTimeMillis() + "_" + originalFilename); file.transferTo(tempFile); } catch (Exception e) { log.error("保存上传临时文件失败", e); } final File uploadFile = tempFile; // 获取当前登录用户昵称(需要在异步线程前获取) String currentUserNickName = "未知用户"; try { Long userId = LoginHelper.getUserId(); if (userId != null) { SysUser user = userService.selectUserById(userId); if (user != null && StringUtils.isNotEmpty(user.getNickName())) { currentUserNickName = user.getNickName(); } } } catch (Exception e) { log.warn("获取当前登录用户昵称失败", e); } // 异步发送钉钉卡片和文件 String finalNickName = currentUserNickName; CompletableFuture.runAsync(() -> { try { if (uploadFile != null && uploadFile.exists()) { String planUserIds = dingTalkProperties.getPlanUserId(); if (StringUtils.isNotBlank(planUserIds)) { String mediaId = mediaService.uploadMedia("file", uploadFile.getAbsolutePath()); // 支持多人推送,假设多个 userId 以逗号分隔 String[] userIds = planUserIds.split(","); for (String userId : userIds) { String cleanUserId = userId.trim(); if (StringUtils.isNotBlank(cleanUserId)) { try { robotGroupService.sendFileToUser(cleanUserId, mediaId, originalFilename); log.info("上传的工艺计划表已成功发送给用户: {}", cleanUserId); } catch (Exception e) { log.error("发送文件给用户 {} 异常", cleanUserId, e); } } } } else { log.warn("未配置钉钉工艺计划接收人(planUserId),跳过发送文件"); } } } catch (Exception e) { log.error("发送文件给工艺计划接收人异常", e); } finally { if (uploadFile != null && uploadFile.exists()) { uploadFile.delete(); } } try { ProcessOrderPro order = processOrderProService.selectByProjectNumber(productionOrderNo); if (order != null) { // 获取 AccessToken String accessToken = DingUtil.getAccessToken(dingTalkProperties.getAppKey(), dingTalkProperties.getAppSecret()); // 构造卡片数据 Map cardDataMap = new HashMap<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); cardDataMap.put("pro_number", StringUtils.defaultIfEmpty(order.getProductionOrderNo(), "")); cardDataMap.put("createTime", order.getRouteUptime() != null ? sdf.format(new Date()) : ""); cardDataMap.put("title", finalNickName + "提交工艺审核"); cardDataMap.put("lastMessage", "请尽快处理"); cardDataMap.put("status", StringUtils.defaultIfEmpty("待审批", "待审批")); String outTrackId = "audit-card-" + System.currentTimeMillis(); // 调用发送给工艺负责人的方法 createAndDeliverCardToUser DingUtil.createAndDeliverCardToUser( accessToken, dingTalkProperties.getRouteCardTemplateId(), Collections.singletonList(dingTalkProperties.getRouteApprovalId()), outTrackId, cardDataMap, dingTalkProperties.getCallbackRouteKey() ); // 统一存入带 userId 后缀的完整 outTrackId,以便和钉钉回调保持一致 String fullOutTrackId = outTrackId + "_" + dingTalkProperties.getRouteApprovalId(); // 更新数据库中的AuditCardId ProcessOrderPro update = new ProcessOrderPro(); update.setId(order.getId()); update.setUpdateBy("Dingding"); update.setAuditCardId(fullOutTrackId); update.setBomStatus(2L); // 更新审核状态为1(已审核/提交审核) update.setRouteStatus(0L); proMapper.updateById(update); } } catch (Exception e) { log.error("发送钉钉卡片异常", e); } }); return R.ok("上传物料成功"); } else { return R.fail("导入失败"); } } /** * 查询组焊件集合 */ @Log(title = "查询组焊件集合") @SaCheckPermission("system:route:pushGroupWeldments") @PostMapping("/pushGroupWeldments") public List pushGroupWeldments(@RequestBody ProcessRoute processRoute) { return iProcessRouteService.pushGroupWeldments(processRoute); } /** * 查询需要单独生成BOm 的原材料集合 */ @Log(title = "查询需要单独生成BOM的原材料集合") @SaCheckPermission("system:route:getRawBom") @PostMapping("/getRawBom") public List getRawBom(@RequestParam String rooteProdet) { return iProcessRouteService.getRawBom(rooteProdet); } /** * 查询工艺表中所有的需要做工艺的物料 * * @return RequestBody List routeVoList */ public List getProcessRouteList(@RequestParam String rooteProdet) { List list = iProcessRouteService.pushRawMater(rooteProdet); return list; } @Log(title = "查询工艺工序集合") @SaCheckPermission("system:route:getProcessRoute") @PostMapping("/getProcessRoute") public List getProcessRoute(@RequestParam String rooteProdet) { return iProcessRouteService.getProcessRoute(rooteProdet); } @Log(title = "推送工艺工序") @SaCheckPermission("system:route:pushRouteBom") @PostMapping("/pushRouteBom") public R pushRouteBom(@RequestParam String rooteProdet, @RequestParam String groupName) { return iProcessRouteService.pushRouteBom(rooteProdet, groupName); } /** * 查询项目列表 */ @Log(title = "获取所有的项目令号") @SaCheckPermission("system:route:getDistinctProjectCodes") @GetMapping("/getDistinctProjectCodes") public ResponseEntity> getDistinctProjectCodes(String query) { return ResponseEntity.ok(iProcessRouteService.getDistinctProjectCodes(query)); } @Log(title = "获取工序列表") @SaCheckPermission("system:route:getProcessInfoList") @GetMapping("/getProcessInfoList") public ResponseEntity> getProcessInfoList(String query) { return ResponseEntity.ok(iProcessRouteService.getProcessInfoList(query)); } @Log(title = "根据生产令号获取生产编号==》获取计划编号") @SaCheckPermission("system:route:getSelecPlanRouteList") @PostMapping("/getSelecPlanRouteList") public List getSelecPlanRouteList(@RequestParam String rooteProdet) { return iProcessRouteService.getSelecPlanRouteList(rooteProdet); } @Log(title = "生成项目图纸PDF") @SaCheckPermission("system:route:generatePDFs") @GetMapping("/generatePDFs") public void generatePDFs(String rooteProdet, HttpServletResponse response) throws IOException { // 调用服务层方法生成 ZIP 文件并获取其路径 String zipFilePath = iProcessRouteService.generatePDFs(rooteProdet); ProcessOrderPro processOrderPro = proMapper.selectByProjectNumber(rooteProdet); processOrderPro.setBomStatus(5L); proMapper.updateById(processOrderPro); // 读取文件为字节数组 File zipFile = new File(zipFilePath); if (!zipFile.exists()) { throw new FileNotFoundException("ZIP 文件未找到: " + zipFilePath); } FileInputStream fis = new FileInputStream(zipFile); OutputStream outputStreams = response.getOutputStream(); response.setContentType("application/zip"); byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { outputStreams.write(buffer, 0, len); } outputStreams.flush(); fis.close(); outputStreams.close(); } @Log(title = "更新计划时间") @SaCheckPermission("system:route:updateProcessPlan") @PostMapping("/updateProcessPlan") public List updateProcessPlan(@RequestParam String rooteProdet) throws Exception { return iProcessRouteService.updateProcessPlan(rooteProdet); } /** * 更新生产订单的时间 */ @Log(title = "更新生产订单时间") @SaCheckPermission("system:route:updateProcesTime") @PostMapping("/updateProcesTime") public List updateProcesTime(@RequestParam String rooteProdet) throws Exception { return iProcessRouteService.updateProcesTime(rooteProdet); } /** * 保存工艺路线 */ @SaCheckPermission("system:route:addRoute") @Log(title = "保存工艺路线", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping("/addRoute") public R addRoute(@RequestBody List list) { return iProcessRouteService.addRoute(list); } @SaCheckPermission("system:route:deleteRoute") @Log(title = "删除工艺路线", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping("/deleteRoute") public List deleteRoute(@RequestBody ProcessRoute processRoute) { return iProcessRouteService.deleteRoute(processRoute); } @Log(title = "获取材料bom列表") @SaCheckPermission("system:route:getBomInfo") @PostMapping("/getBomInfo") public ResponseEntity> getProcessMaterialList(@RequestParam(value = "materialCode") String materialCode, @RequestParam(value = "materialName") String materialName, @RequestParam(value = "productionOrderNo") String productionOrderNo) { return ResponseEntity.ok(iProcessRouteService.getProcessMaterialList(materialCode, materialName, productionOrderNo)); } @Log(title = "获取金蝶列表") @SaCheckPermission("system:route:getProcessRouteList") @GetMapping("/getProcessRouteList") public ResponseEntity> getProcessRouteList(@RequestParam(value = "materialCode") String materialCode, @RequestParam(value = "materialName") String materialName, @RequestParam(value = "productionOrderNo") String productionOrderNo) { return ResponseEntity.ok(iProcessRouteService.getProcessRouteList(materialCode, materialName, productionOrderNo)); } @Log(title = "导入时间", businessType = BusinessType.IMPORT) @SaCheckPermission("system:route:importDataTime") @PostMapping(value = "/importDataTime", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R importDataTime(@RequestParam("file") MultipartFile file) throws Exception { String originalFilename = file.getOriginalFilename(); log.info("读取文件名: " + originalFilename); ExcelResult result = ExcelUtil.importExcelSheet6(file.getInputStream(), ProcessRouteVo.class, true); List list = result.getList(); List list1 = iProcessRouteService.importDataTime(list); return R.ok("更新成功"); } @Log(title = "导入时间", businessType = BusinessType.IMPORT) @SaCheckPermission("system:route:importDataTime123") @PostMapping(value = "/importDataTime123", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R importDataTime123(@RequestParam("file") MultipartFile file) throws Exception { DefaultExcelListener listener = new DefaultExcelListener<>(true); EasyExcel.read(file.getInputStream(), PcRigidChainVo.class, listener).excelType(ExcelTypeEnum.XLS).sheet(1).headRowNumber(4).doRead(); List list1 = listener.getExcelResult().getList(); for (PcRigidChainVo pcRigidChainVO : list1) { log.info("数据 ===============>: " + JSONUtil.toJsonStr(pcRigidChainVO)); } return R.ok("更新成功"); } @Log(title = "获取金蝶工艺路线") @SaCheckPermission("system:route:getSelectProcessRout1e") @PostMapping("/getSelectProcessRout1e") public List getSelectProcessRoute1(@RequestParam String materilCode) { return iProcessRouteService.getSelectProcessRoute(materilCode); } private void processCombinedDTO(CombinedDTO combinedDTO, List bomDetailsList, List routeList, List materialBoms, String productionOrderNo) { // 处理工序列表 combinedDTO.getProcesses().forEach(process -> { ProcessRoute processRoute = createProcessRoute(process, combinedDTO, productionOrderNo); routeList.add(processRoute); }); // 处理物料清单 combinedDTO.getMaterialUsageDTOList().forEach(materialUsageDTO -> { BomDetails bomDetails = createBomDetails(materialUsageDTO, combinedDTO, productionOrderNo); bomDetailsList.add(bomDetails); }); // 处理材料BOM combinedDTO.getMaterialUsageDTOList().forEach(materialUsageDTO -> { MaterialBom materialBom = creatBomMaterial(materialUsageDTO, combinedDTO, productionOrderNo); materialBoms.add(materialBom); }); } private void processMaterAndRoute(JDMaterialAndRoute materialAndRoute, List bomDetailsList, List routeList, List materialBoms, String productionOrderNo) { // 处理工序列表 materialAndRoute.getPlannedProcessVos().forEach(processRouteDTO -> { ProcessRoute processRoute = createProcessRoute1(processRouteDTO, materialAndRoute, productionOrderNo); routeList.add(processRoute); }); // 处理物料清单 materialAndRoute.getMaterialUseDTOS().forEach(materialUsageDTO -> { BomDetails bomDetails = createBomDetails1(materialUsageDTO, materialAndRoute, productionOrderNo); bomDetailsList.add(bomDetails); }); // 处理材料BOM materialAndRoute.getMaterialUseDTOS().forEach(materialUsageDTO -> { MaterialBom materialBom = creatBomMaterial1(materialUsageDTO, materialAndRoute, productionOrderNo); materialBoms.add(materialBom); }); } private MaterialBom creatBomMaterial1(MaterialUseDTO materialUsageDTO, JDMaterialAndRoute materialAndRoute, String productionOrderNo) { MaterialBom materialBom = new MaterialBom(); materialBom.setProjectNumber(productionOrderNo); materialBom.setParentMaterialCode(materialAndRoute.getMaterialCode()); materialBom.setParentMaterialName(materialAndRoute.getMaterialName()); materialBom.setMaterialCode(materialUsageDTO.getMaterialCode()); materialBom.setMaterialName(materialUsageDTO.getMaterialName()); materialBom.setUnit(materialUsageDTO.getChildUnit()); materialBom.setMaterialType(materialUsageDTO.getCaizhi()); //保留四位小数 materialBom.setQuantity(String.valueOf(BigDecimal.valueOf(materialUsageDTO.getFenzi()).divide(new BigDecimal(materialUsageDTO.getFenmu()), 4, RoundingMode.HALF_UP))); return materialBom; } private BomDetails createBomDetails1(MaterialUseDTO materialUsageDTO, JDMaterialAndRoute materialAndRoute, String productionOrderNo) { BomDetails bomDetails = new BomDetails(); bomDetails.setTotalWeight(productionOrderNo); bomDetails.setFNumber(materialAndRoute.getMaterialCode()); bomDetails.setFName(materialAndRoute.getMaterialName()); bomDetails.setPartNumber(materialUsageDTO.getMaterialCode()); bomDetails.setUnitWeight("是"); bomDetails.setWareHouse(materialUsageDTO.getChildUnit()); //子项分子 bomDetails.setQuantity(String.valueOf(materialUsageDTO.getFenzi())); //子项分母 bomDetails.setDenominator(Double.valueOf(materialUsageDTO.getFenmu())); bomDetails.setName(materialUsageDTO.getMaterialName()); bomDetails.setMaterial(materialUsageDTO.getCaizhi()); return bomDetails; } private ProcessRoute createProcessRoute1(ProcessRouteDTO processRouteDTO, JDMaterialAndRoute materialAndRoute, String productionOrderNo) { ProcessRoute processRoute = new ProcessRoute(); // 设置路线描述为生产订单号 processRoute.setRouteDescription(productionOrderNo); // 设置工序号 processRoute.setProcessNo(processRouteDTO != null ? processRouteDTO.getProcessNo() : null); // 设置工序名称 processRoute.setProcessName(processRouteDTO != null ? processRouteDTO.getProcessName() : null); if (materialAndRoute != null && StringUtils.isNotEmpty(materialAndRoute.getMaterialCode())) { ImMaterial materialByCode = materialService.getMaterialByCode(materialAndRoute.getMaterialCode()); if (materialByCode != null && materialByCode.getSingleWeight() != null) { processRoute.setDiscWeight(Double.valueOf(String.valueOf(materialByCode.getSingleWeight()))); } else { processRoute.setDiscWeight(null); } } else { processRoute.setDiscWeight(null); } processRoute.setMaterial(materialAndRoute != null ? materialAndRoute.getCaizhi() : null); // 设置物料代码 processRoute.setMaterialCode(materialAndRoute != null ? materialAndRoute.getMaterialCode() : null); processRoute.setMaterialName(materialAndRoute != null ? materialAndRoute.getMaterialName() : null); processRoute.setWorkCenter(processRouteDTO != null ? processRouteDTO.getWorkCenter() : null); // 基本时长 processRoute.setActivityDuration(processRouteDTO != null ? processRouteDTO.getActivityDuration() : null); processRoute.setProcessDescription(processRouteDTO != null ? processRouteDTO.getProcessDescription() : null); processRoute.setProcessControl(processRouteDTO != null ? processRouteDTO.getProcessControl() : null); processRoute.setXuStartTime(null); processRoute.setXuEndTime(null); processRoute.setActivityUnit("分"); // 本批数量对应 processRoute.setBatchQuantity(materialAndRoute != null ? materialAndRoute.getBenpi() : null); if (materialAndRoute != null && materialAndRoute.getDantai() != null) { processRoute.setFirstBatchQuantity(Double.valueOf(materialAndRoute.getDantai())); } else { processRoute.setFirstBatchQuantity(null); } List materialUsageDTOList = materialAndRoute != null ? materialAndRoute.getMaterialUseDTOS() : null; if (materialUsageDTOList != null) { for (MaterialUseDTO materialUsageDTO : materialUsageDTOList) { if (materialUsageDTO != null) { processRoute.setUnitQuantity(materialUsageDTO.getFenzi()); processRoute.setBomMaterial(materialUsageDTO.getCaizhi()); processRoute.setRawMaterialCode(materialUsageDTO.getMaterialCode()); processRoute.setRawMaterialName(materialUsageDTO.getMaterialName()); processRoute.setBomUnit(materialUsageDTO.getChildUnit()); if ("根".equals(materialUsageDTO.getChildUnit())) { if (materialUsageDTO.getFenmu() != null) { processRoute.setDiscUsage(String.valueOf(Double.valueOf(materialUsageDTO.getFenmu()))); } else { processRoute.setDiscUsage(null); } } else { if (materialUsageDTO.getFenzi() != null && materialUsageDTO.getFenmu() != null && materialUsageDTO.getFenmu() != 0) { processRoute.setDiscUsage(String.valueOf(materialUsageDTO.getFenzi() / materialUsageDTO.getFenmu())); } else { processRoute.setDiscUsage(null); } } processRoute.setMaterial(materialUsageDTO.getCaizhi()); } else { processRoute.setUnitQuantity(null); processRoute.setBomMaterial(null); processRoute.setRawMaterialCode(null); processRoute.setRawMaterialName(null); processRoute.setBomUnit(null); processRoute.setDiscUsage(null); processRoute.setMaterial(null); } } } return processRoute; } @Log(title = "生成金蝶标准工艺") @SaCheckPermission("system:route:getKindeeExcel") @GetMapping("/getKindeeExcel") public ResponseEntity getKindeeExcel(String rooteProdet) throws IOException { List planRouteList = iProcessRouteService.getSelecPlanRouteList(rooteProdet); List bomDetailsList = new ArrayList<>(); List routeList = new ArrayList<>(); List materialBoms = new ArrayList<>(); // 将数据写入excel 中 for (CombinedDTO combinedDTO : planRouteList) { processCombinedDTO(combinedDTO, bomDetailsList, routeList, materialBoms, rooteProdet); } // 批量插入数据库 try { bomDetailsMapper.insertBatch(bomDetailsList); baseMapper.insertBatch(routeList); materialBomMapper.insertBatch(materialBoms); return ResponseEntity.ok("保存成功"); } catch (Exception e) { // 处理异常并返回失败信息 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("保存失败: " + e.getMessage()); } } private ProcessRoute createProcessRoute(PlannedProcessVo process, CombinedDTO combinedDTO, String productionOrderNo) { ProcessRoute processRoute = new ProcessRoute(); // 设置路线描述为生产订单号 processRoute.setRouteDescription(productionOrderNo); // 设置工序号 processRoute.setProcessNo(process.getFOperNumber()); // 设置工序名称 processRoute.setProcessName(process.getFProcessName()); String materialCode = combinedDTO.getMaterialCode(); try { List singleWeightList = iProcessRouteService.getSingleWeght(materialCode); if (singleWeightList != null && !singleWeightList.isEmpty()) { processRoute.setDiscWeight(singleWeightList.get(0).getDiscWeight()); } } catch (Exception e) { // 记录日志或采取其他措施 log.error("Error fetching single weight for material code: " + materialCode, e); } // 设置物料代码 processRoute.setMaterialCode(combinedDTO.getMaterialCode()); processRoute.setMaterialName(combinedDTO.getMaterialName()); Double fOperQty = process.getFOperQty(); long l = fOperQty.longValue(); processRoute.setWorkCenter(process.getFWorkCenterName()); // 基本时长 processRoute.setActivityDuration(process.getFActivity1BaseQty()); processRoute.setProcessDescription(process.getFOperDescription()); processRoute.setProcessControl(process.getFOptCtrlCodeIFName()); processRoute.setXuStartTime(process.getFSeqPlanStartTime()); processRoute.setXuEndTime(process.getFSeqPlanFinishTime()); processRoute.setActivityUnit("分"); // 本批数量对应 processRoute.setBatchQuantity(process.getFMOQty()); List materialUsageDTOList = combinedDTO.getMaterialUsageDTOList(); for (MaterialUsageDTO materialUsageDTO : materialUsageDTOList) { processRoute.setUnitQuantity(materialUsageDTO.getFNumerator()); processRoute.setBomMaterial(materialUsageDTO.getChildMaterial()); processRoute.setRawMaterialCode(materialUsageDTO.getMaterialCode()); processRoute.setRawMaterialName(materialUsageDTO.getMaterialName()); processRoute.setBomUnit(materialUsageDTO.getUnit()); if (materialUsageDTO.getUnit().equals("根")) { processRoute.setDiscUsage(String.valueOf(materialUsageDTO.getFDenominator())); } else { processRoute.setDiscUsage(String.valueOf(materialUsageDTO.getFNumerator() / materialUsageDTO.getFDenominator())); } processRoute.setMaterial(materialUsageDTO.getChildMaterial()); } return processRoute; } private BomDetails createBomDetails(MaterialUsageDTO materialUsageDTO, CombinedDTO combinedDTO, String productionOrderNo) { BomDetails bomDetails = new BomDetails(); bomDetails.setTotalWeight(productionOrderNo); bomDetails.setFNumber(combinedDTO.getMaterialCode()); bomDetails.setFName(combinedDTO.getMaterialName()); bomDetails.setPartNumber(materialUsageDTO.getMaterialCode()); bomDetails.setUnitWeight("是"); bomDetails.setWareHouse(materialUsageDTO.getUnit()); //子项分子 bomDetails.setQuantity(String.valueOf(materialUsageDTO.getFNumerator())); //子项分母 bomDetails.setDenominator(materialUsageDTO.getFDenominator()); bomDetails.setName(materialUsageDTO.getMaterialName()); if (materialUsageDTO.getItemType().equals("1")) { bomDetails.setStats("外购"); } else { bomDetails.setStats("自制"); } bomDetails.setMaterial(materialUsageDTO.getChildMaterial()); return bomDetails; } private MaterialBom creatBomMaterial(MaterialUsageDTO materialUsageDTO, CombinedDTO combinedDTO, String productionOrderNo) { MaterialBom materialBom = new MaterialBom(); materialBom.setProjectNumber(productionOrderNo); materialBom.setParentMaterialCode(combinedDTO.getMaterialCode()); materialBom.setParentMaterialName(combinedDTO.getMaterialName()); materialBom.setMaterialCode(materialUsageDTO.getMaterialCode()); materialBom.setMaterialName(materialUsageDTO.getMaterialName()); materialBom.setUnit(materialUsageDTO.getUnit()); materialBom.setMaterialType(materialUsageDTO.getItemType()); materialBom.setQuantity(String.valueOf(BigDecimal.valueOf(materialUsageDTO.getFNumerator()))); return materialBom; } /** * 导出工艺路线列表 */ @SaCheckPermission("system:route:getAllRouteAndUse") @Log(title = "获取全部工艺路线和物料清单", businessType = BusinessType.OTHER) @PostMapping("/getAllRouteAndUse") public void getAllRouteAndUse(@RequestParam("rooteProdet") String rooteProdet) { log.info("获取项目生产数据表:{}", rooteProdet); // 下载Excel模板 (切换为FTP方式) // SmbUtil.downloadExcelFiles(rooteProdet); String ftpHost = "192.168.5.18"; String ftpUser = "admin"; String ftpPass = "hbyt2025"; int ftpPort = 21; String localDir = "D:\\file"; // 假设远程目录结构与SMB一致,为 /2026/{rooteProdet} String remoteDir = "/2026/" + rooteProdet; R ftpResult = FtpUtil.downloadFtpDirectoryFiles(ftpHost, ftpUser, ftpPass, ftpPort, remoteDir, localDir); if (R.isError(ftpResult)) { log.error("FTP下载失败: {}", ftpResult.getMsg()); } else { log.info("FTP下载结果: {}", ftpResult.getMsg()); } // 构建Excel文件路径 String ExcelName = "D:\\file\\" + rooteProdet + "汇总表.xlsx"; File file = new File(ExcelName); if (!file.exists()) { throw new ServiceException("文件不存在,请确认路径是否正确"); } //读取file的所有的物料编码 try { if (file.exists()) { // 读取Excel的sheet6 从第三行开始 读取到第4列 无数据的跳过 DefaultExcelListener listener = new DefaultExcelListener<>(true); EasyExcel.read(ExcelName, ProcessRouteGetDTO.class, listener).sheet(6).headRowNumber(3).doRead(); List list = listener.getExcelResult().getList(); List list1 = iProcessRouteService.getProcessRouteGD(list, rooteProdet); List bomDetailsList = new ArrayList<>(); List routeList = new ArrayList<>(); List materialBoms = new ArrayList<>(); for (JDMaterialAndRoute materialAndRoute : list1) { processMaterAndRoute(materialAndRoute, bomDetailsList, routeList, materialBoms, rooteProdet); } bomDetailsMapper.insertBatch(bomDetailsList); baseMapper.insertBatch(routeList); materialBomMapper.insertBatch(materialBoms); } } catch (Exception e) { throw new RuntimeException(e); } } /** * 更新生产订单仓库字段 */ @SaCheckPermission("system:route:updateProductionOrders") @Log(title = "更新生产订单仓库", businessType = BusinessType.OTHER) @PostMapping("/updateProductionOrders") public R updateProductionOrders(@RequestParam("rooteProdet") String rooteProdet, @RequestParam("cangKuNum") String cangKuNum) throws Exception { //判断此项目是否有 List list = iProcessRouteService.updateProductionOrders(rooteProdet, cangKuNum); return R.ok(list); } /** * 更新采购申请入库仓库仓库 */ @SaCheckPermission("system:route:updateProductionOrders") @Log(title = "更新采购申请单仓库", businessType = BusinessType.OTHER) @PostMapping("/updateCgOrders") public R updateCgOrders(@RequestParam("rooteProdet") String rooteProdet, @RequestParam("cangKuNum") String cangKuNum) throws Exception { //判断此项目是否有 List list = iProcessRouteService.updateCgOrders(rooteProdet, cangKuNum); return R.ok(list); } }