package cn.iocoder.yudao.module.mes.controller.admin.pro.pallet; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; 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.collection.MapUtils; 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.bagcode.vo.MesProBagCodeRespVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletBatchCreateReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletRespVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletTraceRespVO; import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO; import cn.iocoder.yudao.module.mes.framework.qrcode.MesProQrLabelBuilder; import cn.iocoder.yudao.module.mes.framework.qrcode.QrCodeImageUtils; import cn.iocoder.yudao.module.mes.framework.qrcode.QrLabelInfo; import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; import cn.iocoder.yudao.module.mes.service.pro.bagcode.MesProBagCodeService; import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService; import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; 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 java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_PALLET_NOT_EXISTS; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_EXPORT_TOO_MANY; @Tag(name = "管理后台 - MES 托盘码") @RestController @RequestMapping("/mes/pro/pallet") @Validated public class MesProPalletController { @Resource private MesProPalletService palletService; @Resource private MesProBatchService batchService; @Resource private MesProBagCodeService bagCodeService; @Resource private MesMdmItemService mdmItemService; @Resource private AdminUserApi adminUserApi; @PostMapping("/batch-create") @Operation(summary = "批量生成托盘码") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:create')") public CommonResult> batchCreatePallet(@Valid @RequestBody MesProPalletBatchCreateReqVO createReqVO) { return success(palletService.batchCreatePallet(createReqVO)); } @DeleteMapping("/delete") @Operation(summary = "删除托盘码") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:delete')") public CommonResult deletePallet(@RequestParam("id") Long id) { palletService.deletePallet(id); return success(true); } @GetMapping("/get") @Operation(summary = "获得托盘码") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:query')") public CommonResult getPallet(@RequestParam("id") Long id) { MesProPalletDO pallet = palletService.getPallet(id); return success(BeanUtils.toBean(pallet, MesProPalletRespVO.class)); } @GetMapping("/get-by-code") @Operation(summary = "扫码追溯:根据托盘码(二维码内容)反查批次、品种、责任人及袋码列表") @Parameter(name = "code", description = "托盘码(二维码内容)", required = true, example = "PC20260818L01001-P01") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:query')") public CommonResult getPalletByCode(@RequestParam("code") String code) { MesProPalletDO pallet = palletService.getPalletByCode(code); if (pallet == null) { throw exception(PRO_PALLET_NOT_EXISTS); } return success(buildPalletTraceRespVO(pallet)); } @GetMapping("/page") @Operation(summary = "获得托盘码分页") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:query')") public CommonResult> getPalletPage(@Valid MesProPalletPageReqVO pageReqVO) { PageResult pageResult = palletService.getPalletPage(pageReqVO); return success(BeanUtils.toBean(pageResult, MesProPalletRespVO.class)); } @GetMapping("/simple-list") @Operation(summary = "获得批次的托盘码列表(供下拉选择)") @Parameter(name = "batchId", description = "批次编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:query')") public CommonResult> getPalletSimpleList(@RequestParam("batchId") Long batchId) { List list = palletService.getPalletListByBatchId(batchId); return success(BeanUtils.toBean(list, MesProPalletRespVO.class)); } @GetMapping("/export-excel") @Operation(summary = "导出托盘码 Excel") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:export')") @ApiAccessLog(operateType = EXPORT) public void exportPalletExcel(@Valid MesProPalletPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); List list = palletService.getPalletPage(pageReqVO).getList(); List voList = BeanUtils.toBean(list, MesProPalletRespVO.class); ExcelUtils.write(response, "托盘码.xls", "数据", MesProPalletRespVO.class, voList); } @GetMapping("/export-qr") @Operation(summary = "批量导出某批次的托盘码二维码图片 ZIP(图片叠加关键信息文字)") @Parameter(name = "batchId", description = "生产批次编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('mes:pro-pallet:export')") @ApiAccessLog(operateType = EXPORT) public void exportPalletQr(@RequestParam("batchId") Long batchId, HttpServletResponse response) throws IOException { List list = palletService.getPalletListByBatchId(batchId); if (CollUtil.isEmpty(list)) { throw exception(PRO_PALLET_NOT_EXISTS); } if (list.size() > QrCodeImageUtils.MAX_QR_EXPORT) { throw exception(PRO_QR_EXPORT_TOO_MANY); } QrCodeImageUtils.writeZip(response, "托盘码二维码-" + batchId, buildPalletQrLabels(list)); } // ==================== 拼接 VO ==================== private MesProPalletTraceRespVO buildPalletTraceRespVO(MesProPalletDO pallet) { MesProPalletTraceRespVO respVO = BeanUtils.toBean(pallet, MesProPalletTraceRespVO.class); // 批次信息 MesProBatchDO batch = batchService.getBatch(pallet.getBatchId()); if (batch != null) { respVO.setBatchStatus(batch.getStatus()) .setProduceDate(batch.getProduceDate()) .setLineCode(batch.getLineCode()) .setLineName(batch.getLineName()) .setOwnerUserId(batch.getOwnerUserId()) .setItemId(batch.getItemId()); // 责任人 if (batch.getOwnerUserId() != null) { AdminUserRespDTO user = adminUserApi.getUser(batch.getOwnerUserId()); if (user != null) { respVO.setOwnerUserName(user.getNickname()); } } // 品种信息 if (batch.getItemId() != null) { MesMdmItemDO item = mdmItemService.getItem(batch.getItemId()); if (item != null) { respVO.setItemCode(item.getCode()) .setItemName(item.getName()) .setItemSpecification(item.getSpecification()); } } } // 该托盘绑定的袋码列表 respVO.setBags(buildBagCodeRespVOList(bagCodeService.getBagCodeListByPalletId(pallet.getId()))); return respVO; } private List buildBagCodeRespVOList(List list) { if (CollUtil.isEmpty(list)) { return Collections.emptyList(); } // 获得批次的产线信息,拼接袋码的产线编码/名称 Map batchMap = convertMap( batchService.getBatchList(convertSet(list, MesProBagCodeDO::getBatchId)), MesProBatchDO::getId); return BeanUtils.toBean(list, MesProBagCodeRespVO.class, vo -> MapUtils.findAndThen(batchMap, vo.getBatchId(), batch -> vo.setLineCode(batch.getLineCode()).setLineName(batch.getLineName()))); } private List buildPalletQrLabels(List list) { // 获得关联数据(批次、品种、责任人) Map batchMap = convertMap( batchService.getBatchList(convertSet(list, MesProPalletDO::getBatchId)), MesProBatchDO::getId); Map itemMap = mdmItemService.getItemMap( convertSet(batchMap.values(), MesProBatchDO::getItemId)); Map userMap = adminUserApi.getUserMap( convertSet(batchMap.values(), MesProBatchDO::getOwnerUserId)); // 构建标签 List labels = new ArrayList<>(list.size()); for (MesProPalletDO pallet : list) { labels.add(MesProQrLabelBuilder.buildPalletLabel( pallet, batchMap.get(pallet.getBatchId()), itemMap, userMap)); } return labels; } }