package cn.iocoder.yudao.module.mes.controller.admin.md.item; import cn.hutool.core.collection.CollUtil; import cn.idev.excel.ExcelWriter; import cn.idev.excel.FastExcelFactory; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.handler.ColumnWidthMatchStyleStrategy; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomImportExcelVO; import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomImportRespVO; import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomRespVO; import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; 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.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Tag(name = "管理后台 - MES 产品BOM") @RestController @RequestMapping("/mes/md/product-bom") @Validated public class MesMdProductBomController { @Resource private MesMdProductBomService productBomService; @Resource private MesMdItemService itemService; @Resource private MesMdItemTypeService itemTypeService; @Resource private MesMdUnitMeasureService unitMeasureService; @PostMapping("/create") @Operation(summary = "创建产品BOM") @PreAuthorize("@ss.hasPermission('mes:md-item:create')") public CommonResult createProductBom(@Valid @RequestBody MesMdProductBomSaveReqVO createReqVO) { return success(productBomService.createProductBom(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新产品BOM") @PreAuthorize("@ss.hasPermission('mes:md-item:update')") public CommonResult updateProductBom(@Valid @RequestBody MesMdProductBomSaveReqVO updateReqVO) { productBomService.updateProductBom(updateReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "删除产品BOM") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('mes:md-item:delete')") public CommonResult deleteProductBom(@RequestParam("id") Long id) { productBomService.deleteProductBom(id); return success(true); } @GetMapping("/get") @Operation(summary = "获得产品BOM") @Parameter(name = "id", description = "编号", required = true, example = "1024") public CommonResult getProductBom(@RequestParam("id") Long id) { MesMdProductBomDO productBom = productBomService.getProductBom(id); return success(BeanUtils.toBean(productBom, MesMdProductBomRespVO.class)); } @GetMapping("/page") @Operation(summary = "获得产品BOM分页") public CommonResult> getProductBomPage(@Valid MesMdProductBomPageReqVO pageReqVO) { PageResult pageResult = productBomService.getProductBomPage(pageReqVO); List voList = buildProductBomRespVOList(pageResult.getList()); return success(new PageResult<>(voList, pageResult.getTotal())); } @GetMapping("/list-by-item-id") @Operation(summary = "根据物料产品编号获得产品BOM列表") @Parameter(name = "itemId", description = "物料产品编号", required = true, example = "1") public CommonResult> getProductBomListByItemId( @RequestParam("itemId") Long itemId) { List list = productBomService.getProductBomListByItemId(itemId); return success(buildProductBomRespVOList(list)); } @GetMapping("/get-import-template") @Operation(summary = "获得产品BOM导入模板") @PreAuthorize("@ss.hasPermission('mes:md-item:create')") public void importTemplate(HttpServletResponse response) throws IOException { List list = Arrays.asList( MesMdProductBomImportExcelVO.builder().parentItemCode("BV-2.5").bomItemCode("CU-T1-8") .quantity(new BigDecimal("0.0227")).remark("示例:填写已存在的物料编码").build(), MesMdProductBomImportExcelVO.builder().parentItemCode("BV-2.5").bomItemCode("PVC-JY-70") .quantity(new BigDecimal("0.0103")).remark("示例:同一父项可有多行子项").build() ); // 不能复用 ExcelUtils.write:它会在表头前加 "*" 必填标记,导入时按表头名称匹配会读不到该列 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8("BOM导入模板.xlsx")); ExcelWriter writer = FastExcelFactory.write(response.getOutputStream(), MesMdProductBomImportExcelVO.class) .autoCloseStream(false) .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) .build(); try { writer.write(list, FastExcelFactory.writerSheet("产品BOM").build()); } finally { writer.finish(); writer.close(); } } @PostMapping("/import") @Operation(summary = "导入产品BOM") @Parameters({ @Parameter(name = "file", description = "Excel 文件", required = true), @Parameter(name = "updateSupport", description = "是否更新已存在的父子组合,默认为 false", example = "true") }) @PreAuthorize("@ss.hasPermission('mes:md-item:create')") public CommonResult importExcel( @RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { List list = ExcelUtils.read(file, MesMdProductBomImportExcelVO.class); return success(productBomService.importProductBomList(list, updateSupport)); } // ==================== 拼接 VO ==================== private List buildProductBomRespVOList(List list) { if (CollUtil.isEmpty(list)) { return Collections.emptyList(); } // 1.1 批量获取 BOM 物料信息 Map itemMap = itemService.getItemMap( convertSet(list, MesMdProductBomDO::getBomItemId)); // 1.2 批量获取计量单位信息 Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); // 1.3 批量获取物料分类信息(用于 itemOrProduct) Map itemTypeMap = itemTypeService.getItemTypeMap( convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); // 2. 拼接 VO return BeanUtils.toBean(list, MesMdProductBomRespVO.class, vo -> { MapUtils.findAndThen(itemMap, vo.getBomItemId(), item -> { vo.setBomItemCode(item.getCode()); vo.setBomItemName(item.getName()); vo.setBomItemSpecification(item.getSpecification()); MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(), itemType -> vo.setItemOrProduct(itemType.getItemOrProduct())); }); }); } }