| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodePageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeRawGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeRespVO; |
| | |
| | | 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.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.framework.qrexport.MesProQrExportProperties; |
| | | 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.qrexport.MesProQrLabelAssembler; |
| | | 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 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 java.util.Set; |
| | | |
| | | 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.apilog.core.enums.OperateTypeEnum.EXPORT; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_BAG_CODE_NOT_EXISTS; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_EXPORT_PARAMS_INVALID; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_EXPORT_TOO_MANY; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_EXPORT_TOO_MANY_FOR_SYNC; |
| | | |
| | | @Tag(name = "管理后台 - MES 袋码赋码(一袋一码)") |
| | | @RestController |
| | |
| | | private AdminUserApi adminUserApi; |
| | | @Resource |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | | private MesProQrLabelAssembler labelAssembler; |
| | | @Resource |
| | | private MesProQrExportProperties qrExportProperties; |
| | | |
| | | @PostMapping("/generate") |
| | | @Operation(summary = "生成袋码数据包(一袋一码),累计达到阈值时自动生成托盘码") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:create')") |
| | | public CommonResult<MesProBagCodeGenerateRespVO> generateBagCodes(@Valid @RequestBody MesProBagCodeGenerateReqVO generateReqVO) { |
| | | return success(bagCodeService.generateBagCodes(generateReqVO)); |
| | | } |
| | | |
| | | @PostMapping("/raw-generate") |
| | | @Operation(summary = "生成原始袋码(仅选品种与袋码数量,不关联计量单位类型、不生成托盘)") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:create')") |
| | | public CommonResult<MesProBagCodeGenerateRespVO> generateRawBagCodes( |
| | | @Valid @RequestBody MesProBagCodeRawGenerateReqVO rawGenerateReqVO) { |
| | | return success(bagCodeService.generateRawBagCodes(rawGenerateReqVO)); |
| | | } |
| | | |
| | | @PostMapping("/replace") |
| | |
| | | } |
| | | |
| | | @GetMapping("/get-by-code") |
| | | @Operation(summary = "扫码追溯:根据袋码(二维码内容)反查批次、产线、责任人等信息") |
| | | @Parameter(name = "code", description = "袋码(二维码内容)", required = true, example = "PC20260818L01001-0001") |
| | | @Operation(summary = "内部扫码查询:根据追溯码或业务码反查袋、批次、产线信息") |
| | | @Parameter(name = "code", description = "单元识别代码(国标:不超过 20 个字符,数字或字母数字组合)", |
| | | required = true, example = "0286267849370923") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:query')") |
| | | public CommonResult<MesProBagCodeTraceRespVO> getBagCodeByCode(@RequestParam("code") String code) { |
| | | MesProBagCodeDO bagCode = bagCodeService.getBagCodeByCode(code); |
| | | MesProBagCodeDO bagCode = bagCodeService.getBagCodeByScanCode(code); |
| | | if (bagCode == null) { |
| | | throw exception(PRO_BAG_CODE_NOT_EXISTS); |
| | | } |
| | |
| | | HttpServletResponse response) throws IOException { |
| | | List<MesProBagCodeDO> list; |
| | | String zipName; |
| | | // 只导出可印刷的袋码:已作废袋码的标签不得再印刷(贴到产品上会被扫码提示"已作废,谨防假冒") |
| | | if (StrUtil.isNotEmpty(uuid)) { |
| | | list = bagCodeService.getBagCodeListByUuid(uuid); |
| | | list = bagCodeService.getPrintableBagCodeListByUuid(uuid); |
| | | zipName = "袋码二维码-" + uuid; |
| | | } else if (batchId != null) { |
| | | list = bagCodeService.getBagCodeListByBatchId(batchId); |
| | | list = bagCodeService.getPrintableBagCodeListByBatchId(batchId); |
| | | zipName = "袋码二维码-" + batchId; |
| | | } else { |
| | | throw exception(PRO_QR_EXPORT_PARAMS_INVALID); |
| | |
| | | if (CollUtil.isEmpty(list)) { |
| | | throw exception(PRO_BAG_CODE_NOT_EXISTS); |
| | | } |
| | | if (list.size() > QrCodeImageUtils.MAX_QR_EXPORT) { |
| | | throw exception(PRO_QR_EXPORT_TOO_MANY); |
| | | } |
| | | QrCodeImageUtils.writeZip(response, zipName, buildBagCodeQrLabels(list)); |
| | | assertSyncExportAllowed(list.size()); |
| | | QrCodeImageUtils.writeZip(response, zipName, labelAssembler.buildBagCodeLabels(list)); |
| | | } |
| | | |
| | | // ==================== 拼接 VO ==================== |
| | | |
| | | @PostMapping("/generate-business-code") |
| | | @Operation(summary = "补生成已有袋码的出入库业务码(已有码值不变)") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:create')") |
| | | public CommonResult<Integer> generateBusinessCodes(@Valid @RequestBody |
| | | cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagBusinessCodeGenerateReqVO reqVO) { |
| | | return success(bagCodeService.generateBusinessCodes(reqVO.getIds())); |
| | | } |
| | | |
| | | @GetMapping("/export-business-qr") |
| | | @Operation(summary = "导出出入库业务码二维码 ZIP(二维码仅编码业务码值)") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:export')") |
| | | @ApiAccessLog(operateType = EXPORT) |
| | | public void exportBusinessQr(@RequestParam(value = "uuid", required = false) String uuid, |
| | | @RequestParam(value = "batchId", required = false) Long batchId, |
| | | HttpServletResponse response) throws IOException { |
| | | List<MesProBagCodeDO> list; |
| | | if (StrUtil.isNotBlank(uuid)) list = bagCodeService.getPrintableBagCodeListByUuid(uuid); |
| | | else if (batchId != null) list = bagCodeService.getPrintableBagCodeListByBatchId(batchId); |
| | | else throw exception(PRO_QR_EXPORT_PARAMS_INVALID); |
| | | if (CollUtil.isEmpty(list)) throw exception(PRO_BAG_CODE_NOT_EXISTS); |
| | | assertSyncExportAllowed(list.size()); |
| | | QrCodeImageUtils.writeZip(response, "袋码业务二维码-" + (StrUtil.isNotBlank(uuid) ? uuid : batchId), |
| | | labelAssembler.buildBagBusinessLabels(list)); |
| | | } |
| | | |
| | | private List<MesProBagCodeRespVO> buildBagCodeRespVOList(List<MesProBagCodeDO> list) { |
| | | if (CollUtil.isEmpty(list)) { |
| | |
| | | .setProduceDate(batch.getProduceDate()) |
| | | .setLineCode(batch.getLineCode()) |
| | | .setLineName(batch.getLineName()) |
| | | .setOwnerUserId(batch.getOwnerUserId()) |
| | | .setItemId(batch.getItemId()); |
| | | .setOwnerUserId(batch.getOwnerUserId()); |
| | | // 责任人 |
| | | if (batch.getOwnerUserId() != null) { |
| | | AdminUserRespDTO user = adminUserApi.getUser(batch.getOwnerUserId()); |
| | |
| | | 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()); |
| | | } |
| | | } |
| | | // 品种信息:优先取袋码上的品种(数据包生成时绑定),历史袋码回退批次品种 |
| | | Long itemId = bagCode.getItemId() != null ? bagCode.getItemId() |
| | | : (batch == null ? null : batch.getItemId()); |
| | | if (itemId != null) { |
| | | MesMdmItemDO item = mdmItemService.getItem(itemId); |
| | | if (item != null) { |
| | | respVO.setItemId(itemId) |
| | | .setItemCode(item.getCode()) |
| | | .setItemName(item.getName()) |
| | | .setItemSpecification(item.getSpecification()); |
| | | } |
| | | } |
| | | return respVO; |
| | | } |
| | | |
| | | /** |
| | | * 构建袋码二维码标签列表(二维码编码纯码值,图片叠加关键信息文字) |
| | | * 同步导出只承接小批量 |
| | | * <p> |
| | | * 数量超过分界线时必须走后台导出任务:同步响应会随张数线性变长(上万张可达数分钟、响应体上 GB), |
| | | * 必然被网关或浏览器截断,用户看到的将是「下载失败」而不是可操作的提示。 |
| | | */ |
| | | private List<QrLabelInfo> buildBagCodeQrLabels(List<MesProBagCodeDO> list) { |
| | | // 1. 获得关联数据(批次、品种、责任人) |
| | | Map<Long, MesProBatchDO> batchMap = convertMap( |
| | | batchService.getBatchList(convertSet(list, MesProBagCodeDO::getBatchId)), MesProBatchDO::getId); |
| | | Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap( |
| | | convertSet(batchMap.values(), MesProBatchDO::getItemId)); |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| | | convertSet(batchMap.values(), MesProBatchDO::getOwnerUserId)); |
| | | // 2. 构建标签 |
| | | List<QrLabelInfo> labels = new ArrayList<>(list.size()); |
| | | for (MesProBagCodeDO bagCode : list) { |
| | | labels.add(MesProQrLabelBuilder.buildBagCodeLabel( |
| | | bagCode, batchMap.get(bagCode.getBatchId()), itemMap, userMap)); |
| | | private void assertSyncExportAllowed(int count) { |
| | | if (count > qrExportProperties.getSyncThreshold()) { |
| | | throw exception(PRO_QR_EXPORT_TOO_MANY_FOR_SYNC, count, qrExportProperties.getSyncThreshold()); |
| | | } |
| | | return labels; |
| | | } |
| | | |
| | | } |