package cn.iocoder.yudao.module.mes.controller.admin.pro.route; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.MesProRouteImportExcelVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.MesProRouteImportRespVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.MesProRouteCompleteImportWorkbook; import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.MesProRoutePageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.MesProRouteRespVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.MesProRouteSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO; import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteService; import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteCompleteImportService; import cn.idev.excel.ExcelWriter; import cn.idev.excel.FastExcelFactory; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - MES 工艺路线") @RestController @RequestMapping("/mes/pro/route") @Validated public class MesProRouteController { @Resource private MesProRouteService routeService; @Resource private MesProRouteCompleteImportService completeImportService; @PostMapping("/create") @Operation(summary = "创建工艺路线") @PreAuthorize("@ss.hasPermission('mes:pro-route:create')") public CommonResult createRoute(@Valid @RequestBody MesProRouteSaveReqVO createReqVO) { return success(routeService.createRoute(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新工艺路线") @PreAuthorize("@ss.hasPermission('mes:pro-route:update')") public CommonResult updateRoute(@Valid @RequestBody MesProRouteSaveReqVO updateReqVO) { routeService.updateRoute(updateReqVO); return success(true); } @PutMapping("/update-status") @Operation(summary = "更新工艺路线状态") @Parameters({ @Parameter(name = "id", description = "编号", required = true), @Parameter(name = "status", description = "状态", required = true) }) @PreAuthorize("@ss.hasPermission('mes:pro-route:update')") public CommonResult updateRouteStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) { routeService.updateRouteStatus(id, status); return success(true); } @DeleteMapping("/delete") @Operation(summary = "删除工艺路线") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('mes:pro-route:delete')") public CommonResult deleteRoute(@RequestParam("id") Long id) { routeService.deleteRoute(id); return success(true); } @GetMapping("/get") @Operation(summary = "获得工艺路线") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('mes:pro-route:query')") public CommonResult getRoute(@RequestParam("id") Long id) { MesProRouteDO route = routeService.getRoute(id); return success(BeanUtils.toBean(route, MesProRouteRespVO.class)); } @GetMapping("/page") @Operation(summary = "获得工艺路线分页") @PreAuthorize("@ss.hasPermission('mes:pro-route:query')") public CommonResult> getRoutePage(@Valid MesProRoutePageReqVO pageReqVO) { PageResult pageResult = routeService.getRoutePage(pageReqVO); return success(BeanUtils.toBean(pageResult, MesProRouteRespVO.class)); } @GetMapping("/simple-list") @Operation(summary = "获得工艺路线精简列表", description = "只包含被开启的工艺路线,主要用于前端的下拉选项") public CommonResult> getRouteSimpleList() { List list = routeService.getRouteListByStatus(CommonStatusEnum.ENABLE.getStatus()); return success(convertList(list, route -> new MesProRouteRespVO() .setId(route.getId()).setName(route.getName()).setCode(route.getCode()))); } @GetMapping("/export-excel") @Operation(summary = "导出工艺路线 Excel") @PreAuthorize("@ss.hasPermission('mes:pro-route:export')") @ApiAccessLog(operateType = EXPORT) public void exportRouteExcel(@Valid MesProRoutePageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); List list = routeService.getRoutePage(pageReqVO).getList(); List data = BeanUtils.toBean(list, MesProRouteRespVO.class); ExcelUtils.write(response, "工艺路线.xls", "数据", MesProRouteRespVO.class, data); } @GetMapping("/get-import-template") @Operation(summary = "获得工艺路线导入模板") @PreAuthorize("@ss.hasPermission('mes:pro-route:import')") public void importTemplate(HttpServletResponse response) throws IOException { // 手动创建导出 demo List list = Collections.singletonList( MesProRouteImportExcelVO.builder() .code("ROUTE001").name("示例工艺路线").description("").remark("").build() ); // 输出 ExcelUtils.write(response, "工艺路线导入模板.xls", "工艺路线列表", MesProRouteImportExcelVO.class, list); } @PostMapping("/import") @Operation(summary = "导入工艺路线") @Parameters({ @Parameter(name = "file", description = "Excel 文件", required = true), @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") }) @PreAuthorize("@ss.hasPermission('mes:pro-route:import')") public CommonResult importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { List list = ExcelUtils.read(file, MesProRouteImportExcelVO.class); return success(routeService.importRouteList(list, updateSupport)); } @GetMapping("/get-complete-import-template") @Operation(summary = "获得完整工艺路线批量导入模板") @PreAuthorize("@ss.hasPermission('mes:pro-route:import')") public void completeImportTemplate(HttpServletResponse response) throws IOException { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8("完整工艺路线导入模板.xlsx")); ExcelWriter writer = FastExcelFactory.write(response.getOutputStream()).autoCloseStream(false).build(); try { writer.write(Collections.emptyList(), FastExcelFactory.writerSheet(0, "路线") .head(MesProRouteCompleteImportWorkbook.RouteRow.class).build()); writer.write(Collections.emptyList(), FastExcelFactory.writerSheet(1, "产品") .head(MesProRouteCompleteImportWorkbook.ProductRow.class).build()); writer.write(Collections.emptyList(), FastExcelFactory.writerSheet(2, "工序") .head(MesProRouteCompleteImportWorkbook.ProcessRow.class).build()); writer.write(Collections.emptyList(), FastExcelFactory.writerSheet(3, "工序产出") .head(MesProRouteCompleteImportWorkbook.OutputRow.class).build()); writer.write(Collections.emptyList(), FastExcelFactory.writerSheet(4, "工序投料") .head(MesProRouteCompleteImportWorkbook.InputRow.class).build()); writer.write(List.of( new MesProRouteCompleteImportWorkbook.GuideRow("路线", "每行一条路线;路线编码唯一。完整导入仅新增,已有编码会报错,导入后默认停用。"), new MesProRouteCompleteImportWorkbook.GuideRow("产品", "路线编码与路线表一致;每条路线至少一个产品。物料、仓库、库区、库位填写已有业务编码;时间单位填 MINUTE/HOUR/DAY。"), new MesProRouteCompleteImportWorkbook.GuideRow("工序", "每条路线至少一道工序;工序编码须已存在,排序唯一。布尔字段填是或否;关系填 0=开始-开始、1=结束-结束、2=开始-结束、3=结束-开始。"), new MesProRouteCompleteImportWorkbook.GuideRow("工序产出", "按路线编码和工序编码关联;归属产品编码留空表示多产品通用。末道工序应配置全部成品。"), new MesProRouteCompleteImportWorkbook.GuideRow("工序投料", "按路线、工序和归属产品编码关联;投料物料须已在该产品 BOM 中。") ), FastExcelFactory.writerSheet(5, "填写说明") .head(MesProRouteCompleteImportWorkbook.GuideRow.class).build()); } finally { writer.finish(); } } @PostMapping("/import-complete") @Operation(summary = "批量导入完整工艺路线(多工作表)") @PreAuthorize("@ss.hasPermission('mes:pro-route:import')") public CommonResult importComplete(@RequestParam("file") MultipartFile file) throws IOException { MesProRouteCompleteImportWorkbook workbook = new MesProRouteCompleteImportWorkbook(); workbook.setRoutes(readSheet(file, 0, MesProRouteCompleteImportWorkbook.RouteRow.class)); workbook.setProducts(readSheet(file, 1, MesProRouteCompleteImportWorkbook.ProductRow.class)); workbook.setProcesses(readSheet(file, 2, MesProRouteCompleteImportWorkbook.ProcessRow.class)); workbook.setOutputs(readSheet(file, 3, MesProRouteCompleteImportWorkbook.OutputRow.class)); workbook.setInputs(readSheet(file, 4, MesProRouteCompleteImportWorkbook.InputRow.class)); return success(completeImportService.importRoutes(workbook)); } private List readSheet(MultipartFile file, int index, Class type) throws IOException { try (InputStream input = file.getInputStream()) { return FastExcelFactory.read(input, type, null).autoCloseStream(false).sheet(index).doReadSync(); } } }