From 975fe5248cc1f3d999f4d660fc331570110c4968 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期四, 08 十月 2026 13:38:49 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_新疆_塔河种业' into dev_新疆_塔河种业
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java | 12
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletService.java | 7
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRespVO.java | 14
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java | 21
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemSaveReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/MesWmTransactionController.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java | 39
yudao-server/src/main/resources/application.yaml | 6
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java | 33
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java | 9
docs/mes_bag_code_package_refactor_integration.md | 96
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java | 5
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java | 50
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java | 82
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java | 20
sql/mysql/mes_qc_seed_quality_record_menu.sql | 14
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java | 33
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java | 4
yudao-server/src/main/resources/static/trace.html | 850 +++++---
yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/item/MesMdItemApiImpl.java | 16
sql/mysql/mes_wm_qualified_warehouse.sql | 85
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java | 93
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java | 30
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java | 8
img/ChatGPT Image 2026年9月30日 18_10_01.png | 0
docs/sql/pro_batch_processing_team.sql | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateRespVO.java | 14
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java | 29
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java | 15
yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml | 40
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java | 19
yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java | 87
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java | 3
img/8fbfd97ac926a2dfd7e3bc2577aee946.jpg | 0
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java | 22
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java | 61
docs/sales_notice_to_product_sales.md | 14
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java | 25
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java | 40
docs/scan_in_multi_type_inbound.md | 80
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletPreGenerateReqVO.java | 4
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java | 13
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java | 12
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java | 9
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java | 9
yudao-server/src/main/resources/application-local.yaml | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java | 165 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java | 17
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateReqVO.java | 15
docs/seed_flow_trace_integration.md | 53
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java | 10
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java | 7
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java | 16
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java | 7
docs/mes_bag_code_package_refactor_requirements.md | 142 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java | 32
docs/batch_trace_refactor_integration.md | 102
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java | 58
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchPageReqVO.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java | 101
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java | 7
yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java | 30
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java | 7
sql/mysql/mes_wm_product_sales_add_columns.sql | 12
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java | 6
docs/sql/trace_platform_01_schema.sql | 79
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java | 22
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java | 59
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java | 84
sql/mysql/mes_pro_scan_event_scan_type.sql | 14
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodePageReqVO.java | 3
img/0d9430aac760f2a00123f8f4f9b8eae0.jpg | 0
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java | 38
docs/mes_wm_material_stock_bag_api.md | 69
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRawGenerateReqVO.java | 24
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java | 128 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java | 20
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java | 18
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java | 65
docs/mdm_unit_measure_type_integration.md | 66
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java | 50
yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java | 37
yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/item/dto/MesMdItemSyncReqDTO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletRespVO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java | 44
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java | 37
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java | 7
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java | 86
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/MesProPalletController.java | 8
docs/h5_trace_unbound_batch_integration.md | 118 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchFlowRespVO.java | 40
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java | 218 +
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java | 55
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java | 57
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java | 59
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java | 239 ++
docs/mes_pro_batch_processing_team_integration.md | 66
sql/mysql/sp_clean_business_data.sql | 435 ++++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 17
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletBatchCreateReqVO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java | 21
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java | 22
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java | 52
yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml | 39
yudao-module-mdm-api/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java | 11
.gitignore | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java | 4
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java | 48
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java | 7
yudao-server/src/main/resources/application-thzy.yaml | 13
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/trace/MesProTraceResolveController.java | 53
docs/mdm_item_remove_category_purchase_price_integration.md | 87
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java | 31
yudao-server/src/main/resources/application-test.yaml | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/batch/MesProBatchDO.java | 17
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java | 11
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java | 22
docs/h5_trace_item_unit_integration.md | 65
docs/seed_quality_bag_granularity.md | 88
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java | 4
sql/mysql/mes_wm_material_stock_bag.sql | 31
sql/mysql/wls_sales_outbound_menu_extract.sql | 25
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java | 19
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java | 18
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java | 11
docs/bagcode_home_dashboard_integration.md | 83
img/tahe_seed_logo.png | 0
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java | 18
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java | 16
sql/mysql/mes_wm_transaction_bag_code.sql | 17
/dev/null | 41
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java | 2
docs/wm_transaction_query.md | 50
sql/mysql/mes_pro_bag_code_qc_status.sql | 13
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java | 3
171 files changed, 5,072 insertions(+), 1,163 deletions(-)
diff --git a/.gitignore b/.gitignore
index a140560..bb4d06c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,4 +57,6 @@
### Claude Code ###
.claude/settings.local.json
.claude/worktrees/
-.claude/scheduled_tasks.json
\ No newline at end of file
+.claude/scheduled_tasks.json
+
+.export_tmp/
\ No newline at end of file
diff --git a/docs/bagcode_home_dashboard_integration.md b/docs/bagcode_home_dashboard_integration.md
new file mode 100644
index 0000000..bb11421
--- /dev/null
+++ b/docs/bagcode_home_dashboard_integration.md
@@ -0,0 +1,83 @@
+# 涓�琚嬩竴鐮侀椤垫敼鐗�(鍏ㄩ摼璺┚椹惰埍) 鈥� 鍓嶇鑱旇皟鏂规
+
+## 鑳屾櫙
+
+灏� `/bagcode-home` 棣栭〉浠�"鍩虹鏁版嵁 + 涓�琚嬩竴鐮佺敓浜�"鐨勫眬閮ㄧ粺璁¢〉,閲嶆瀯涓鸿鐩�**瀹屾暣浠峰�奸摼**鐨勯┚椹惰埍:鍝佺 鈫� 浜х嚎/鎵规 鈫� 琚嬬爜/鎵樼洏 鈫� 閿�鍞嚭搴� 鈫� 娴侀�氭壂鐮� 鈫� 闃茬獪婧簮,骞朵覆鑱斾粨鍌ㄥ簱瀛樸�佽川閲忛璀︺�佸揩鎹峰叆鍙c�傛暣浣撹瑙夊榻愮櫥褰曢〉鐨�**鍐滀笟缈犵豢鐜荤拑**椋庢牸銆�
+
+## 娑夊強椤甸潰
+
+- 棣栭〉(椹鹃┒鑸�):`src/views/dashboard/bagCodeHome/index.vue` 鈥斺�� 鍏ㄩ摼璺噸鏋�
+- 鍏宠仈璺宠浆椤甸潰:鍩虹鏁版嵁銆佷竴琚嬩竴鐮佺敓浜с�佸嚭搴撴祦閫氥�侀槻浼槻绐滆揣銆佹函婧愬垎鏋愩�佷粨鍌ㄧ墿娴併�佽川閲忕鐞� 涓嬬殑鍚勪笟鍔¢〉
+
+## 鎺ュ彛鍙樻洿
+
+### 1. 鎵╁睍姹囨�绘帴鍙�(杩斿洖鏂板瀛楁)
+
+`GET /mes/bag-code-home-statistics/summary`
+
+鏂板鍝嶅簲瀛楁(鍧� `Long`,鏃犻粯璁ゅ�兼椂杩斿洖 0):
+
+| 瀛楁 | 璇存槑 | 鏁版嵁鏉ユ簮琛� |
+|------|------|-----------|
+| `salesNoticeCount` | 鍙戣揣閫氱煡鍗曟暟 | `mes_wm_sales_notice` |
+| `productSalesCount` | 閿�鍞嚭搴撳崟鏁� | `mes_wm_product_sales` |
+| `returnSalesCount` | 閿�鍞��璐у崟鏁� | `mes_wm_return_sales` |
+| `stockWarningPendingCount` | 鏈鐞嗗簱瀛橀璀︽暟(`status=10`) | `mes_wm_stock_warning` |
+| `ncrPendingCount` | 寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁�(`status=0`) | `mes_qc_ncr` |
+
+鍘熸湁瀛楁(`mdmItemCount/mesItemCount/itemTypeCount/unitMeasureCount/lineCount/batchCount/bagCodeCount/palletCount/batchStatusList/bagCodeStatusList`)淇濇寔涓嶅彉銆�
+
+### 2. 澶嶇敤宸叉湁缁熻鎺ュ彛(鏃犻渶鏀瑰姩)
+
+| 鎺ュ彛 | 鐢ㄩ�� | 鍓嶇 API |
+|------|------|---------|
+| `GET /mes/trace-cross-region/summary` | 绐滆揣棰勮姹囨��(`total/pending/handled/falseAlarm/crossProvince/crossCity`) | `api/mes/trace-cross-region`(鏂板) |
+| `GET /mes/trace-consumer-scan/summary` | 绱鎵爜/鎴愬姛/澶辫触/娑夊強鎵规 | 宸叉湁 |
+| `GET /mes/trace-consumer-scan/distribution?groupBy=province` | 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯� | 宸叉湁 |
+
+## 鍓嶇淇敼鐐�
+
+### 1. 棣栭〉缁撴瀯(index.vue)
+
+| 鍖哄潡 | 缁勪欢 | 鏁版嵁 |
+|------|------|------|
+| 涓氬姟鍏ㄩ摼璺� | `modules/business-flow.vue` | summary + 鎵爜鎬绘暟 + 绐滆揣鎬绘暟 |
+| 鍏ㄩ摼璺� KPI 鎬昏(8 鍗�) | `modules/kpi-cards.vue` | summary + 鎵爜鎬绘暟 |
+| 琚嬬爜鐢熸垚瓒嬪娍 | `modules/trend-chart.vue`(澶嶇敤) | `summary/trend` |
+| 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯� | `modules/scan-region-chart.vue`(鏂板) | `distribution/groupBy=province` |
+| 鎵规鐘舵�佸垎甯� / 琚嬬爜鐘舵�佸垎甯� | `batch-status-chart.vue` / `bag-code-status-chart.vue`(澶嶇敤) | summary 鐘舵�佸垪琛� |
+| 寰呭姙涓庨璀� | `modules/alert-panel.vue`(鏂板) | summary + 绐滆揣姹囨�� |
+| 鍒嗙粍蹇嵎鍏ュ彛 | `modules/shortcuts.vue`(閲嶅啓涓哄垎缁�) | 闈欐�佽矾鐢遍厤缃� |
+
+### 2. 鏂板/鍒犻櫎鏂囦欢
+
+- 鏂板:`api/mes/trace-cross-region/index.ts`
+- 鏂板:棣栭〉 `modules/business-flow.vue`銆乣kpi-cards.vue`銆乣scan-region-chart.vue`銆乣alert-panel.vue`
+- 閲嶅啓:棣栭〉 `index.vue`銆乣modules/shortcuts.vue`
+- 鏇存柊:`api/mes/bag-code-home/index.ts`(Summary 鍔� 5 瀛楁)銆乣data.ts`銆乣chart-options.ts`
+- 鍒犻櫎:`modules/basic-cards.vue`銆乣modules/bag-code-cards.vue`(涓嶅啀浣跨敤)
+
+### 3. 鏍峰紡涓婚
+
+- 棣栭〉鍐呭鍖虹粺涓�"鍐滀笟缈犵豢鐜荤拑"涓婚:娴呰壊缈犵豢娓愬彉鑳屾櫙(鏃犺儗鏅浘)銆佺櫧鑹茬(鐮傜幓鐠冨崱鐗囥�佽杽鑽风櫧/澧ㄧ豢鏂囧瓧銆�
+- 鍥捐〃缁熶竴缈犵豢涓昏壊(`#10b981`)骞堕�傞厤娴呭簳鏂囧瓧鑹层��
+- 涓婚鏍峰紡闆嗕腑鍦� `index.vue` 鐨勯潪 scoped `<style>` 涓�(`.agri-dashboard` 瀹瑰櫒涓轰綔鐢ㄥ煙),鍚勫崱鐗囩粍浠朵娇鐢ㄥ搴旂幓鐠冪被銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鍝佺鎬绘暟 | KPI + 涓氬姟閾捐矾 | 鐐规寜璺宠浆 `MdmItem` |
+| 鐢熶骇鎵规 | KPI + 涓氬姟閾捐矾 | 璺宠浆 `MesProBatch` |
+| 琚嬬爜 / 鎵樼洏鐮� | KPI + 涓氬姟閾捐矾 | 璺宠浆 `MesProBagCode` / `MesProPallet` |
+| 閿�鍞嚭搴撳崟鏁� | KPI + 涓氬姟閾捐矾 | 璺宠浆 `MesWmProductSales` |
+| 绱鎵爜 | KPI + 涓氬姟閾捐矾 | 鏉ヨ嚜 `trace-consumer-scan/summary`,璺宠浆 `MesConsumerScanStatistics` |
+| 绐滆揣棰勮鎬绘暟 | 涓氬姟閾捐矾(闃茬獪/婧簮) | 鏉ヨ嚜 `trace-cross-region/summary`,璺宠浆 `MesTraceCrossRegion` |
+| 搴撳瓨棰勮(鏈鐞�) | KPI + 寰呭姙棰勮 | 璺宠浆 `MesWmStockWarning` |
+| 寰呰瘎瀹′笉鍚堟牸 | KPI + 寰呭姙棰勮 | 璺宠浆 `MesQcNcr` |
+
+## 娉ㄦ剰浜嬮」
+
+- 鏂板鐨� 5 涓眹鎬诲瓧娈甸渶瑕�**鍚庣閲嶆柊缂栬瘧骞堕噸鍚�**鍚庢墠浼氳繑鍥�;閲嶅惎鍓嶅墠绔凡鍋� `?? 0` 鍏滃簳,鐩稿叧鍗$墖/鑺傜偣鏄剧ず 0,涓嶅奖鍝嶅叾瀹冩暟鎹��
+- 璺敱璺宠浆浣跨敤**璺敱 name**(宸蹭笌鑿滃崟 `component_name` 瀵归綈),鏈姞杞界殑鑿滃崟娌跨敤 `message.warning('褰撳墠鑿滃崟灏氭湭鍔犺浇...')` 鍏滃簳銆�
+- 娑堣垂鑰呮壂鐮�/绐滆揣鏃犵粡绾害瀛楁,浠呮敮鎸佺渷/甯傛枃鏈垎甯冨浘,涓嶆敮鎸佸湴鍥惧潗鏍囥��
diff --git a/docs/batch_trace_refactor_integration.md b/docs/batch_trace_refactor_integration.md
new file mode 100644
index 0000000..85f11b5
--- /dev/null
+++ b/docs/batch_trace_refactor_integration.md
@@ -0,0 +1,102 @@
+# 鎵规杩芥函缁熶竴鑱氬悎鎺ュ彛 - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- MES 鈫� 璐ㄦ 鈫� 鎵规杩芥函锛坄/qc/batch-trace`锛�
+- 鎵规杩芥函璇︽儏
+- 鎵规鐮併�佹墭鐩樼爜銆佽鐮佹壂鐮佽拷婧叆鍙�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. 鍦ㄦ壒娆¤拷婧垪琛ㄨ緭鍏ョ敓浜ф壒娆$爜銆佷复鏃舵壒娆$爜銆佽鐮佹垨鎵樼洏鐮併��
+2. 椤甸潰璋冪敤缁熶竴璇︽儏鎺ュ彛锛屽悗绔皢鍏ュ彛鐮佽В鏋愬埌鐢熶骇鎵规锛屽苟鑱氬悎鐢熶骇銆佽川妫�銆佷粨鍌ㄣ�侀攢鍞拰闃蹭吉淇℃伅銆�
+3. 璇︽儏椤典互鐢熶骇鎵规涓烘牴灞曠ず鍏ㄩ摼璺暟鎹紱琚嬬爜鍜屾墭鐩樹俊鎭潵鑷敓浜ц祴鐮佹暟鎹紝浠撳偍涓庨攢鍞俊鎭潵鑷粨鍌ㄤ笟鍔℃暟鎹��
+4. 鍓嶅悜杩芥函灞曠ず褰撳墠鎵规浜у嚭鐨勪笅娓告壒娆★紱鍚庡悜杩芥函灞曠ず褰撳墠鎵规娑堣�楃殑涓婃父鎵规銆�
+5. 鏃堕棿绾裤�侀樁娈佃鍥惧拰鍐崇瓥鎽樿鍧囦娇鐢ㄥ悓涓�娆¤仛鍚堝搷搴旓紝閬垮厤鎵撳紑璇︽儏鍚庨噸澶嶈姹傚涓棫鎺ュ彛銆�
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|---|---|---|
+| GET | `/mes/trace/batch/detail` | 鏌ヨ缁熶竴鎵规杩芥函璇︽儏 |
+
+### 璇锋眰鍙傛暟
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `code` | String | 鏄� | 鐢熶骇鎵规鐮併�佷复鏃舵壒娆$爜銆佽鐮佹垨鎵樼洏鐮� |
+
+绀轰緥锛歚code=BAG-202608280001`
+
+### 鍝嶅簲涓昏瀛楁
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `sourceType` | String | 鍏ュ彛绫诲瀷锛歚BAG`銆乣PALLET`銆乣BATCH` |
+| `requestCode` | String | 鍘熷杈撳叆鐮� |
+| `itemCode` / `itemName` | String | 鍝佺缂栫爜銆佸悕绉� |
+| `itemSpecification` | String | 鍝佺瑙勬牸 |
+| `batchCode` / `tempCode` | String | 姝e紡鎵规鍙枫�佷复鏃舵壒娆$爜 |
+| `batchStatusName` | String | 鎵规鐘舵�佸悕绉� |
+| `produceDate` | DateTime | 鐢熶骇鏃ユ湡 |
+| `lineCode` / `lineName` | String | 浜х嚎缂栫爜銆佸悕绉� |
+| `ownerUserName` | String | 鐢熶骇璐d换浜� |
+| `planQuantity` | Decimal | 璁″垝鏁伴噺 |
+| `bagQuantity` / `palletQuantity` | Integer | 琚嬬爜鏁伴噺銆佹墭鐩樻暟閲� |
+| `workers` | Array | 鐢熶骇浜哄憳 |
+| `pallets` | Array | 鎵樼洏鎽樿 |
+| `bagTotal` / `bags` | Long / Array | 琚嬬爜鎬绘暟鍙婃渶澶� 100 鏉℃槑缁� |
+| `inbound` | Object | 鏈�鏂板叆搴撲簨浠� |
+| `quality` | Object | 绉嶅瓙璐ㄩ噺妫�楠屼笌鎸囨爣 |
+| `antiFake` | Object | 褰撳墠杩芥函鐮佹壂鐮佹鏁般�侀娆″拰鏈�杩戞壂鐮佹椂闂� |
+| `purchaseSources` | Array | 閲囪喘鏉ユ簮銆佷緵搴斿晢鍜� IQC 淇℃伅 |
+| `salesTargets` | Array | 閿�鍞嚭搴撱�佸鎴峰拰 OQC 淇℃伅 |
+| `processTraces` | Array | 宸ュ簭鎶曞叆銆佷骇鍑烘祦杞俊鎭� |
+
+### 鍝嶅簲绀轰緥
+
+```json
+{
+ "code": 0,
+ "data": {
+ "sourceType": "BAG",
+ "requestCode": "BAG-202608280001",
+ "batchCode": "B20260828001",
+ "itemName": "绀轰緥鍝佺",
+ "batchStatusName": "宸插畬鎴�",
+ "workers": [],
+ "pallets": [],
+ "bags": [],
+ "purchaseSources": [],
+ "salesTargets": [],
+ "processTraces": []
+ }
+}
+```
+
+## 椤甸潰灞曠ず瑙勫垯
+
+| 瑙嗗浘 | 灞曠ず鍐呭 |
+|---|---|
+| 闃舵鎬昏 | 鏉ユ簮銆佺敓浜с�佽川妫�銆佽祴鐮併�佸叆搴撱�侀攢鍞�佹秷璐广�侀槻浼叓涓樁娈电殑鐘舵�佸拰鏁伴噺 |
+| 鍏ㄩ摼璺椂闂寸嚎 | 鎸夋椂闂村睍绀洪噰璐�佺敓浜с�佽川妫�銆佽祴鐮併�佸叆搴撱�佸嚭搴撳拰鎵爜浜嬩欢锛涘紓甯哥姸鎬佷紭鍏堥珮浜� |
+| 娴佸姩鍥捐氨 | 浠ユ壒娆°�佸伐搴忋�佷粨搴撱�佹墭鐩樸�佽鐮併�侀攢鍞崟鍜屽鎴蜂负鑺傜偣锛涢粯璁ゅ睍绀烘壒娆$骇鍏崇郴 |
+| 鍐崇瓥鍒嗘瀽 | 灞曠ず璐ㄩ噺缁撹銆佸簱瀛樻暟閲忋�侀攢鍞幓鍚戙�侀槻浼壂鐮佹鏁板拰绐滆揣椋庨櫓 |
+| 閲囪喘鏉ユ簮 | 灞曠ず閲囪喘鍏ュ簱銆佷緵搴斿晢銆侀噰璐鍗曘�両QC 鍗曞彿鍙婃楠岀粨璁� |
+| 閿�鍞幓鍚� | 灞曠ず閿�鍞嚭搴撱�佸鎴枫�侀攢鍞鍗曘�丱QC 鍗曞彿鍙婅川閲忕姸鎬� |
+| 宸ュ簭娴佽浆 | `IN` 鏄剧ず涓烘姇鍏ワ紝`OUT` 鏄剧ず涓轰骇鍑� |
+
+## 涓氬姟瑙勫垯
+
+- 杈撳叆琚嬬爜鎴栨墭鐩樼爜鏃讹紝璇︽儏浠嶄互鍏舵墍灞炵敓浜ф壒娆′负鏍硅繘琛岃仛鍚堛��
+- 褰撳墠鎺ュ彛杩斿洖鐨勮鐮佹槑缁嗘渶澶� 100 鏉★紝`bagTotal` 鐢ㄤ簬灞曠ず瀹屾暣鏁伴噺锛涘ぇ鎵规涓嶅緱鎸夋槑缁嗘暟閲忓垽鏂�婚噺銆�
+- 绌烘暟缁勮〃绀鸿涓氬姟闃舵鏆傛棤璁板綍锛沗quality`銆乣inbound`銆乣antiFake` 涓虹┖琛ㄧず鏆傛棤瀵瑰簲淇℃伅銆�
+- 闃蹭吉鎵爜缁熻浠呯敤浜庡睍绀猴紝涓嶈兘鏇夸唬璐ㄩ噺妫�楠岀粨璁烘垨鍑哄簱鐘舵�併��
+- 瀹㈡埛銆佷緵搴斿晢銆佹搷浣滀汉绛夊悕绉板簲浠ユ帴鍙h繑鍥炲�间负鍑嗭紝涓嶅湪鍓嶇閲嶅鏌ヨ鏃ф壒娆℃帴鍙c��
+
+## 娉ㄦ剰浜嬮」
+
+- 绠$悊绔帴鍙i渶瑕佹壒娆¤拷婧煡璇㈡潈闄愶細`mes:trace-batch:query`銆�
+- 鏃х殑 `/mes/wm/batch/*` 鎺ュ彛缁х画渚涗粨鍌ㄦ壒娆¢〉闈娇鐢紝鎵规杩芥函椤甸潰鍒囨崲鍚庝笉搴斿啀骞惰璇锋眰鏃х殑浜斾釜璇︽儏鎺ュ彛銆�
+- 鍚庣画鎵╁睍鏃堕棿绾垮拰鍥捐氨鏃讹紝寤鸿鍚庣澧炲姞鍒嗛〉涓庤妭鐐瑰眰绾у弬鏁帮紝閬垮厤涓�娆℃�у姞杞藉叏閮ㄨ鐮併��
+- 灞曠ず娑堣垂鑰呮壂鐮佷俊鎭椂涓嶅緱灞曠ず IP 鍦板潃鍜� User-Agent 鍘熸枃銆�
\ No newline at end of file
diff --git a/docs/h5_trace_item_unit_integration.md b/docs/h5_trace_item_unit_integration.md
new file mode 100644
index 0000000..7684fb0
--- /dev/null
+++ b/docs/h5_trace_item_unit_integration.md
@@ -0,0 +1,65 @@
+# H5 婧簮銆屽搧绉嶄俊鎭甫璁¢噺鍗曚綅銆�- 鍓嶇鑱旇皟璇存槑
+
+## 鑳屾櫙
+
+H5 鎵爜婧簮椤碉紙`mes.trace-base-url` 鎸囧悜鐨� `trace.html`锛夈�岃拷婧煡璇€�嶅尯鍧楃殑鍝佺淇℃伅闇�瑕佸甫涓婅閲忓崟浣嶃��
+
+鍝佺涓昏閲忓崟浣嶅瓨鍌ㄥ湪 `mdm_item.unit_measure_id`锛堝崟浣嶇紪鍙凤級锛岄〉闈㈤渶瑕佺殑鍗曚綅鍚嶇О鐢卞悗绔�氳繃
+`MdmUnitMeasureApi.getUnitMeasure(id)` 瑙f瀽鍚庨殢鍝嶅簲杩斿洖锛屽墠绔笉闇�瑕佸啀鍗曠嫭璇锋眰鍗曚綅鎺ュ彛銆�
+
+鍚屾椂鎸夐渶姹傜簿绠�銆岃拷婧煡璇€�嶅尯鍧楋細鍘绘帀銆岃矗浠讳汉銆嶃�岃川妫�缁撹銆嶄袱琛岋紙杩欎袱椤规暟鎹湪鎶樺彔鐨勩�岃川妫�淇℃伅銆嶅尯鍧椾腑浠嶇劧鍙煡锛屾湭涓㈠け锛夈��
+
+## 娑夊強鎺ュ彛
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /public/mes/trace/query?code={杩芥函鐮亇 | H5 婧簮鏌ヨ锛堝厤鐧诲綍锛夛紝鍝嶅簲鍝佺鍖哄潡鏂板 `itemUnitMeasureName` |
+
+**鍝嶅簲鏂板瀛楁锛堝搧绉嶄俊鎭尯鍧楋紝浣嶄簬 `itemSpecification` 涔嬪悗锛夛細**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| itemUnitMeasureName | String | 鍝佺涓昏閲忓崟浣嶅悕绉帮紙濡� `48鍗冨厠`锛夛紱鐗╂枡鏈厤缃崟浣嶆椂杩斿洖 `null` |
+
+**鍝嶅簲绀轰緥锛堝搧绉嶇浉鍏崇墖娈碉級锛�**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "itemCode": "ITEM_20260917002",
+ "itemName": "娴嬭瘯",
+ "itemSpecification": "涓�绾�",
+ "itemUnitMeasureName": "48鍗冨厠"
+ }
+}
+```
+
+## 椤甸潰灞曠ず瑙勫垯
+
+銆岃拷婧煡璇€�嶅尯鍧楀瓧娈甸『搴忥細
+
+| 瀛楁 | 鍙栧�� | 璇存槑 |
+|------|------|------|
+| 鍝佺鍚嶇О | `itemName` + `itemSpecification` | 涓よ�呬互绌烘牸鎷兼帴锛屼负绌虹殑涓嶅弬涓庢嫾鎺� |
+| 璁¢噺鍗曚綅 | `itemUnitMeasureName` | 鏈厤缃崟浣嶆椂灞曠ず `-` |
+| 鐢熶骇缁忚惀鑰� | 椤甸潰甯搁噺 `COMPANY_NAME` | 闈欐�佷俊鎭� |
+| 鍗曞厓璇嗗埆浠g爜 | `requestCode` 鈫� `batchCode` 鈫� `tempCode` 渚濇鍥為�� | 鈥� |
+| 杩芥函缃戝潃 | 椤甸潰甯搁噺 `TRACE_URL` | 澶栫綉璁块棶鍦板潃锛屼笌鍖呰/浜岀淮鐮佸嵃鍒朵竴鑷� |
+| 杩芥函绫诲瀷 | `sourceType` | 琚嬬爜 / 鎵樼洏鐮� / 鎵规鐮� |
+| 鎵规鍙� | `batchCode` | 鈥� |
+| 鐢熶骇鏃ユ湡 | `produceDate` | 鈥� |
+| 浜х嚎 | `lineName`锛屼负绌哄洖閫� `lineCode` | 鈥� |
+
+**鏈绉婚櫎鐨勫睍绀洪」锛�**
+
+| 瀛楁 | 鍘熷睍绀轰綅缃� | 璇存槑 |
+|------|-----------|------|
+| 璐d换浜� | 杩芥函鏌ヨ鍖哄潡 | 宸茬Щ闄わ紝`ownerUserName` 瀛楁浠嶅湪鍝嶅簲涓� |
+| 璐ㄦ缁撹 | 杩芥函鏌ヨ鍖哄潡 | 宸茬Щ闄わ紝璐ㄦ缁撹浠嶅湪鍝嶅簲 `quality.resultName` 涓紝鍙湪鎶樺彔鐨勩�岃川妫�淇℃伅銆嶅尯鍧楁煡鐪� |
+
+## 娉ㄦ剰浜嬮」
+
+- `itemUnitMeasureName` 鍙栫殑鏄崟浣�**鍚嶇О**锛坄mdm_unit_measure.name`锛夛紝涓嶆槸鍗曚綅绫诲瀷锛坄type`锛屽 48鍗冨厠/100鍗冨厠/鍚級銆傜墿鏂欐湭閰嶇疆涓昏閲忓崟浣嶆椂璇ュ瓧娈典负 `null`锛岄〉闈㈠睍绀� `-`銆�
+- 鍗曚綅鍚嶇О涓虹┖瀛楃涓叉椂鍚庣缁熶竴杞垚 `null` 杩斿洖銆�
+- 璇ュ瓧娈典负绾睍绀哄瓧娈碉紝鍘嗗彶鏁版嵁鏃犻渶澶勭悊锛涙帴鍙e叾浣欏瓧娈典笌缁撴瀯淇濇寔涓嶅彉锛屽悜鍚庡吋瀹广��
diff --git a/docs/h5_trace_unbound_batch_integration.md b/docs/h5_trace_unbound_batch_integration.md
new file mode 100644
index 0000000..bbda6cb
--- /dev/null
+++ b/docs/h5_trace_unbound_batch_integration.md
@@ -0,0 +1,118 @@
+# H5 婧簮銆屾湭缁戝畾鎵规涔熷彲鎵爜銆�- 鍓嶇鑱旇皟璇存槑
+
+## 鑳屾櫙
+
+琚嬬爜 / 鎵樼洏鐮佸湪鐢熸垚鍚庛�佸綍鍏ョ敓浜ф壒娆″墠锛屾槸涓�涓�屽凡鍗板埗銆佹湭鎶曚骇銆嶇殑涓棿鎬併�傛鍓嶈鐘舵�佷笅璋冪敤婧簮鏌ヨ鎺ュ彛浼氱洿鎺ヨ繑鍥為敊璇爜 `1040760000`锛堟湭鏌ヨ鍒拌杩芥函鐮侊級锛屾秷璐硅�呮壂鍒拌繖绫诲寘瑁呮椂鏃犳硶鏌ョ湅浠讳綍淇℃伅銆�
+
+鏈璋冩暣锛�**鏈粦瀹氭壒娆$殑琚嬬爜 / 鎵樼洏鐮佸悓鏍峰彲浠ユ壂鐮佹垚鍔�**锛屾帴鍙f甯歌繑鍥炶鐮佸搴旂殑**鍝佺淇℃伅**锛屽苟鏂板 `batchBound` 瀛楁鏍囪瘑鎵规鏄惁宸插綍鍏ワ紝鐢卞墠绔彁绀恒�屽皻鏈粦瀹氭壒娆°�嶃�傝拷婧爜鏈韩涓嶅瓨鍦ㄦ椂锛岃涓轰笉鍙橈紝浠嶈繑鍥� `1040760000`銆�
+
+## 娑夊強鎺ュ彛
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /public/mes/trace/query?code={杩芥函鐮亇 | H5 婧簮鏌ヨ锛堝厤鐧诲綍锛� |
+
+## 鍝嶅簲鏂板瀛楁
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| batchBound | Boolean | 鏄惁宸插綍鍏ョ敓浜ф壒娆°�俙true` 宸茬粦瀹氾紙鎵规鍖哄潡瀛楁姝e父杩斿洖锛夛紱`false` 鏈粦瀹氾紝姝ゆ椂**浠�** `itemCode` / `itemName` / `itemSpecification` / `itemUnitMeasureName`銆乣sourceType`銆乣requestCode`銆乣antiFake`銆乣timeline`銆乣decision` 鏈夊�硷紝鍏朵綑鎵规鐩稿叧瀛楁鍏ㄩ儴涓� `null` |
+
+**瀛楁浣嶇疆锛�** `requestCode` 涔嬪悗锛宍itemCode` 涔嬪墠銆�
+
+## 鍙樻洿鍓嶅悗瀵规瘮
+
+| 鍦烘櫙 | 鍙樻洿鍓� | 鍙樻洿鍚� |
+|------|--------|--------|
+| 琚嬬爜宸茬敓鎴愩�佹湭褰曞叆鎵规 | `code=1040760000`锛宍data=null`锛屾棤娉曞睍绀轰换浣曚俊鎭� | `code=0`锛宍batchBound=false`锛岃繑鍥炲搧绉嶄俊鎭紝鍓嶇鎻愮ず鏈粦瀹氭壒娆� |
+| 鎵樼洏宸茬敓鎴愩�佹湭褰曞叆鎵规 | 鍚屼笂 | 鍚屼笂锛屽搧绉嶅彇鎵樼洏鍐�**浠讳竴琚嬬爜**鐨勫搧绉� |
+| 杩芥函鐮佷笉瀛樺湪 | `code=1040760000` | 涓嶅彉 |
+
+## 鍝嶅簲绀轰緥锛堟湭缁戝畾鎵规锛�
+
+```json
+{
+ "code": 0,
+ "data": {
+ "sourceType": "BAG",
+ "requestCode": "BAG-00000153",
+ "batchBound": false,
+ "itemCode": "ITEM_20260917003",
+ "itemName": "鍚�",
+ "itemSpecification": null,
+ "itemUnitMeasureName": "鍚ㄨ瀛�",
+ "batchCode": null,
+ "tempCode": null,
+ "batchStatus": null,
+ "batchStatusName": null,
+ "produceDate": null,
+ "lineCode": null,
+ "lineName": null,
+ "ownerUserId": null,
+ "ownerUserName": null,
+ "planQuantity": null,
+ "bagQuantity": null,
+ "palletQuantity": null,
+ "inboundTime": null,
+ "remark": null,
+ "workers": null,
+ "palletCount": null,
+ "pallets": null,
+ "bagTotal": null,
+ "bags": null,
+ "inbound": null,
+ "quality": null,
+ "antiFake": {
+ "scanCount": 0,
+ "firstScanTime": null,
+ "lastScanTime": null
+ },
+ "purchaseSources": null,
+ "salesTargets": null,
+ "seedFlows": null,
+ "processTraces": null,
+ "timeline": [],
+ "decision": {
+ "qualityRisk": false,
+ "inboundQuantity": null,
+ "salesTargetCount": 0,
+ "consumerScanCount": 0,
+ "riskLevel": "NORMAL"
+ }
+ }
+}
+```
+
+## 椤甸潰灞曠ず瑙勫垯
+
+### 杩芥函鏌ヨ鍖哄潡
+
+| 瀛楁 | 缁戝畾鎵规锛坄batchBound=true`锛� | 鏈粦瀹氭壒娆★紙`batchBound=false`锛� |
+|------|------------------------------|--------------------------------|
+| 鍝佺鍚嶇О | `itemName` + `itemSpecification` 绌烘牸鎷兼帴 | 鍚屽乏 |
+| 璁¢噺鍗曚綅 | `itemUnitMeasureName` | 鍚屽乏 |
+| 鐢熶骇缁忚惀鑰� | 椤甸潰甯搁噺 `COMPANY_NAME` | 鍚屽乏 |
+| 鍗曞厓璇嗗埆浠g爜 | `requestCode` 鈫� `batchCode` 鈫� `tempCode` 渚濇鍥為�� | `requestCode` |
+| 杩芥函缃戝潃 | 椤甸潰甯搁噺 `TRACE_URL` | 鍚屽乏 |
+| 杩芥函绫诲瀷 | `sourceType` | 鍚屽乏 |
+| 鎵规鍙� | `batchCode` | **涓嶅睍绀�**锛屾浛鎹负鎻愮ず鏂囨 |
+| 鐢熶骇鏃ユ湡 | `produceDate` | **涓嶅睍绀�** |
+| 浜х嚎 | `lineName`锛屼负绌哄洖閫� `lineCode` | **涓嶅睍绀�** |
+
+**鏈粦瀹氭壒娆℃椂鐨勬彁绀烘枃妗堬紙鏇夸唬鎵规鍙� / 鐢熶骇鏃ユ湡 / 浜х嚎涓夎锛夛細**
+
+> 璇ヨ拷婧爜灏氭湭褰曞叆鐢熶骇鎵规锛屾壒娆″彿銆佺敓浜ф棩鏈熴�佷骇绾跨瓑淇℃伅寰呭畬鍠勶紱褰撳墠灞曠ず璇ョ爜瀵瑰簲鐨勫搧绉嶄俊鎭��
+
+### 闃蹭吉鏌ヨ鍖哄潡
+
+- `batchCode` 鏈夊�兼椂锛宍瀵瑰簲鎵规` 琛屽睍绀烘壒娆″彿銆�
+- `batchCode` 涓虹┖锛堝嵆鏈粦瀹氭壒娆★級鏃讹紝`瀵瑰簲鎵规` 琛屽睍绀恒�屽皻鏈粦瀹氭壒娆°�嶏紝骞朵互寮卞寲 / 璀︾ず鏍峰紡鍖哄垎锛岄伩鍏嶈璇涓恒�屾棤鏁版嵁銆嶃��
+
+## 娉ㄦ剰浜嬮」
+
+- `batchBound` 鏄�**鍞竴**鍒ゆ柇鎵规鏄惁宸插綍鍏ョ殑瀛楁锛屽墠绔笉瑕佺敤 `batchCode == null` 鎺ㄦ柇锛堝巻鍙叉暟鎹腑鍚屾牱瀛樺湪鎵规鍙蜂负绌轰絾鎵规宸茬粦瀹氱殑杈圭晫鎯呭喌锛夈��
+- 鏈粦瀹氭壒娆℃椂锛宍bags` / `pallets` / `workers` / `quality` 绛夊尯鍧楀潎涓� `null`锛堜笉鏄┖鏁扮粍锛夛紝鍓嶇娓叉煋鍓嶉渶鍒ょ┖銆�
+- 鏈粦瀹氭壒娆$殑鎵爜**鍚屾牱浼�**璁″叆闃蹭吉鏌ヨ娆℃暟锛坄antiFake.scanCount`锛変笌娑堣垂鑰呮壂鐮佷簨浠讹紝閫昏緫涓庢甯告壂鐮佷竴鑷淬��
+- 鎵樼洏鐨勫搧绉嶅彇銆屾墭鐩樺唴浠讳竴琚嬬爜銆嶇殑鍝佺銆傜悊璁轰笂鍚屼竴鎵樼洏鐨勮鐮佸搧绉嶄竴鑷达紱鑻ュ嚭鐜颁笉涓�鑷达紙鏁版嵁寮傚父锛夛紝灞曠ず鐨勫搧绉嶅彲鑳戒笌瀹為檯涓嶇锛屽睘鍙帴鍙楃殑闄嶇骇琛ㄧ幇銆�
+- 杩芥函鐮佹湰韬笉瀛樺湪鏃朵粛杩斿洖 `code=1040760000`锛屽墠绔部鐢ㄥ師鏈夐敊璇彁绀猴紝涓嶉渶瑕佹敼鍔ㄣ��
+- 鏈涓�**鏀惧**鏍¢獙锛屼笉褰卞搷宸茬粦瀹氭壒娆$殑鍘嗗彶鏁版嵁锛屾帴鍙e悜鍚庡吋瀹广��
diff --git a/docs/mdm_item_remove_category_purchase_price_integration.md b/docs/mdm_item_remove_category_purchase_price_integration.md
new file mode 100644
index 0000000..428cf14
--- /dev/null
+++ b/docs/mdm_item_remove_category_purchase_price_integration.md
@@ -0,0 +1,87 @@
+# 鍝佺绠$悊鍘绘帀銆屽搧绉嶅垎绫汇�嶃�岄噰璐环銆� - 鍓嶇鑱旇皟鏂规
+
+## 鑳屾櫙
+
+鍩虹鏁版嵁-鍝佺绠$悊涓嶅啀缁存姢銆屽搧绉嶅垎绫汇�嶅拰銆岄噰璐环銆嶄袱涓瓧娈碉細
+
+- 鏁版嵁搴撳垪 `mdm_item.category_id`銆乣mdm_item.purchase_price` 淇濈暀锛堝巻鍙叉暟鎹笉鍒狅級锛屼絾鎺ュ彛灞備笉鍐嶆帴鏀跺拰杩斿洖銆�
+- MDM鈫扢ES 鍚屾涓嶅啀浼犲搧绉嶅垎绫伙紝鍚屾鐢熸垚鐨� MES 鐗╂枡銆岀墿鏂欏垎绫汇�嶄负绌猴紝鍙湪 MES 鐗╂枡浜у搧椤甸潰鎵嬪伐琛ュ~銆�
+- MES鈫扢DM 鍙嶅悜鍚屾锛圡ES 鐗╂枡鍕鹃�夈�屽悓姝ュ埌 MDM銆嶅洖鍐欏垎绫伙級淇濇寔涓嶅彉銆�
+
+## API 鍙樺寲
+
+| 鏂规硶 | 璺緞 | 鍙樺寲 |
+|------|------|------|
+| POST | /mdm/item/create | 璇锋眰浣撲笉鍐嶆帴鏀� `categoryId`銆乣purchasePrice`锛堜紶鍏ュ皢琚拷鐣ワ級 |
+| PUT | /mdm/item/update | 鍚屼笂 |
+| GET | /mdm/item/get | 鍝嶅簲涓嶅啀杩斿洖 `categoryId`銆乣categoryName`銆乣purchasePrice` |
+| GET | /mdm/item/page | 鍝嶅簲涓嶅啀杩斿洖涓婅堪涓夊瓧娈碉紱涓嶅啀鏀寔 `categoryId` 鏌ヨ鍙傛暟 |
+| GET | /mdm/item/simple-list | 鍝嶅簲涓嶅啀杩斿洖涓婅堪涓夊瓧娈� |
+| GET | /mdm/item/list-by-ids | 鍝嶅簲涓嶅啀杩斿洖涓婅堪涓夊瓧娈� |
+
+**鍝嶅簲绀轰緥锛堣妭閫夛級锛�**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "list": [
+ {
+ "id": 1,
+ "code": "PZ0001",
+ "name": "姘寸ɑ鍝佺A",
+ "specification": "500g/琚�",
+ "unitMeasureId": 2,
+ "unitMeasureName": "琚�",
+ "salesPrice": 15.00,
+ "syncedMes": true
+ }
+ ],
+ "total": 1
+ }
+}
+```
+
+## 鍓嶇淇敼鐐癸紙鏈壒宸插悓姝ヤ慨鏀癸紝渚涘墠绔洟闃熷鏍革級
+
+### 1. 鍝佺绠$悊椤甸潰锛坰rc/views/basicData/mdm/锛�
+
+| 鏂囦欢 | 淇敼鍐呭 |
+|------|----------|
+| data.ts | 鍒犻櫎琛ㄥ崟銆屽搧绉嶅垎绫汇�峊reeSelect銆併�岄噰璐环銆岻nputNumber锛涘垹闄ゅ垪琛ㄣ�屽搧绉嶅垎绫汇�嶃�岄噰璐环銆嶅垪锛涘垹闄� `buildCategoryTree` 鍙� MES 鐗╂枡鍒嗙被鎺ュ彛 import |
+| index.vue | 鍒犻櫎鍒嗙被鍒楄〃缂撳瓨銆佸垎绫诲悕绉�/棰滆壊宸ュ叿鍑芥暟銆乣#categoryName` 鎻掓Ы鍙婂垎绫诲姞杞介�昏緫 |
+| modules/form.vue | 鍒犻櫎鎵撳紑琛ㄥ崟鏃跺姞杞藉垎绫绘爲鐨勯�昏緫 |
+| components/data.ts | 鍝佺閫夋嫨寮圭獥鍒犻櫎銆屽搧绉嶅垎绫汇�嶆悳绱㈤」涓庡垪 |
+| components/select-dialog.vue | 鍒犻櫎鍒嗙被缂撳瓨銆佸悕绉�/棰滆壊鍑芥暟銆乣#categoryId` 鎻掓Ы鍙婂垎绫诲姞杞介�昏緫 |
+
+### 2. API 绫诲瀷锛坰rc/api/mdm/item/index.ts锛�
+
+- `MdmItemApi.Item` 鍒犻櫎 `categoryId`銆乣categoryName`銆乣purchasePrice`銆�
+- `MdmItemApi.PageParams` 鍒犻櫎 `categoryId`銆�
+
+### 3. 渚濊禆閲囪喘浠疯嚜鍔ㄧ畻浠风殑鍗曟嵁椤碉紙琛屼负鍙樺寲锛岄噸鐐瑰鏍革級
+
+鍝佺涓嶅啀鏈夐噰璐环锛屼互涓嬩袱澶勯�夊搧鍚庛�屽崟浠枫�嶄笉鍐嶈嚜鍔ㄥ甫鍏ワ紝鏀逛负榛樿 0銆佺敱鐢ㄦ埛鎵嬪伐濉啓锛�
+
+| 鏂囦欢 | 淇敼鍐呭 |
+|------|----------|
+| src/views/erp/purchase/order/modules/item-form.vue | 閫夋嫨鍝佺鍚� `productPrice` 涓嶅啀鍙栭噰璐环锛岀疆 0 鎵嬪伐濉啓 |
+| src/views/erp/purchase/request/modules/item-form.vue | 鍚屼笂 |
+
+鍏朵綑鍗曟嵁锛堥攢鍞�佸簱瀛樼瓑锛変娇鐢ㄧ殑鏄� ERP 浜у搧锛坄erp_product`锛夎嚜韬环鏍兼垨閿�鍞环锛屼笉鍙楀奖鍝嶃��
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 鏂板/缂栬緫鍝佺 | 鏃犲垎绫汇�佹棤閲囪喘浠峰瓧娈碉紱淇濆瓨鎺ュ彛蹇界暐杩欎袱涓叆鍙� |
+| 缂栬緫鍘嗗彶鍝佺 | 鍘嗗彶宸插~鐨勫垎绫�/閲囪喘浠峰湪鏇存柊鏃朵笉浼氳娓呯┖锛堜粎涓嶅啀鍥炴樉锛夛紝涔熶笉浼氳瑕嗙洊 |
+| 鍝佺鍚屾鍒� MES | 鐢熸垚鐨� MES 鐗╂枡浜у搧銆岀墿鏂欏垎绫汇�嶄负绌猴紱MES 鐗╂枡浜у搧椤甸潰浠嶅彲鎵嬪伐琛ュ~鍒嗙被 |
+| MES 鐗╂枡鍕鹃�夊悓姝ュ埌 MDM | 鍒嗙被鍥炲啓 `mdm_item.category_id` 淇濇寔鍘熼�昏緫锛堝搧绉嶇鐞嗛〉闈笉灞曠ず璇ュ�硷級 |
+| 鍝佺鍒嗙被绠$悊妯″潡 | 涓嶆敼鍔紝鍒嗙被鏁版嵁浠嶄緵 MES 鐗╂枡鍒嗙被绛夊満鏅娇鐢� |
+
+## 娉ㄦ剰浜嬮」
+
+- 閿�鍞环銆佹垚鏈环鏈笅绾匡紝琛ㄥ崟涓庡垪琛ㄤ繚鎸佸師鏍枫��
+- 鍒楄〃鍒犻櫎涓ゅ垪鍚庡垪瀹借嚜琛屽井璋冦��
+- 鍝佺閫夋嫨寮圭獥锛圡dmItemSelect/MdmItemSelectDialog锛夎閲囪喘銆佸簱瀛樼瓑澶氬涓氬姟椤靛鐢紝鍒犻櫎鍒嗙被鍒楀悗璇峰洖褰掗獙璇侀�夊搧甯﹀叆锛堢紪鐮�/鍚嶇О/鍗曚綅/鏉$爜锛夋槸鍚︽甯搞��
diff --git a/docs/mdm_unit_measure_type_integration.md b/docs/mdm_unit_measure_type_integration.md
new file mode 100644
index 0000000..fc0cc1c
--- /dev/null
+++ b/docs/mdm_unit_measure_type_integration.md
@@ -0,0 +1,66 @@
+# MDM 璁¢噺鍗曚綅鏂板銆岀被鍨嬨�嶅瓧娈� - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- 鍩虹鏁版嵁 > MDM > 璁¢噺鍗曚綅锛堝垪琛ㄣ�佹柊澧�/缂栬緫寮圭獥锛�
+
+## API
+
+鎺ュ彛璺緞涓嶅彉锛屼粎璇锋眰/鍝嶅簲浣撴柊澧� `type` 瀛楁銆�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /mdm/unit/create | 鍒涘缓璁¢噺鍗曚綅锛堣姹備綋鏂板 type锛� |
+| PUT | /mdm/unit/update | 鏇存柊璁¢噺鍗曚綅锛堣姹備綋鏂板 type锛� |
+| GET | /mdm/unit/get | 鑾峰緱璁¢噺鍗曚綅锛堝搷搴旀柊澧� type锛� |
+| GET | /mdm/unit/page | 鑾峰緱璁¢噺鍗曚綅鍒嗛〉锛堝搷搴旀柊澧� type锛� |
+| GET | /mdm/unit/list | 鑾峰緱璁¢噺鍗曚綅鍒楄〃锛堝搷搴旀柊澧� type锛� |
+
+**璇锋眰鍙傛暟锛堟柊澧烇級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| type | String | 鏄� | 绫诲瀷锛屽崟閫夛紝鍙�夊�煎浐瀹氫负锛歚48鍗冨厠`銆乣100鍗冨厠`銆乣鍚╜锛堜笁閫変竴锛岀洿鎺ュ瓨鏂囨湰锛涘悗绔� `@NotBlank` 鏍¢獙锛� |
+
+**鍝嶅簲瀛楁锛堟柊澧烇級锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| type | String | 绫诲瀷锛屽巻鍙叉暟鎹负 null |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "id": 1,
+ "code": "BAG",
+ "name": "琚�",
+ "type": "48鍗冨厠",
+ "status": 0
+ }
+}
+```
+
+## 鍓嶇淇敼鐐硅鏄庯紙宸查殢鏈鍚庣鏀瑰姩涓�骞跺畬鎴愶紝渚涙牳瀵癸級
+
+| 浣嶇疆 | 瑕佹眰 |
+|------|------|
+| 鏂板/缂栬緫寮圭獥琛ㄥ崟 | 澧炲姞銆岀被鍨嬨�嶄笅鎷夐�夋嫨锛岄�夐」鍥哄畾涓夐」锛�48鍗冨厠 / 100鍗冨厠 / 鍚紝鍗曢�夈�佸繀濉� |
+| 鍒楄〃琛ㄦ牸 | 澧炲姞銆岀被鍨嬨�嶅垪灞曠ず锛岀┖鍊兼樉绀轰负 `-` |
+| 鏌ヨ琛ㄥ崟 | 鏆備笉鎻愪緵绫诲瀷绛涢�夛紙鍚庣鍒嗛〉鎺ュ彛鏈姞璇ヨ繃婊ゆ潯浠讹級 |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 瀛橀噺鏁版嵁 | 鑰佽褰� `type` 涓虹┖锛屽垪琛ㄥ睍绀� `-`锛涚紪杈戣�佽褰曟椂蹇呴』琛ラ�夌被鍨嬪悗鎵嶈兘淇濆瓨锛堝悗绔己鏍¢獙锛� |
+| 閫夐」鏉ユ簮 | 閫夐」涓哄墠绔啓姝讳笁椤规枃鏈紝涓嶅缓鏁版嵁瀛楀吀锛涙彁浜ょ殑 value 鍗充腑鏂囨枃鏈湰韬� |
+| 鍚庣鏍¢獙 | `@NotBlank` 蹇呭~鏍¢獙锛涘彇鍊艰寖鍥翠笉闄愬埗锛屽墠绔笅鎷夐渶淇濊瘉鍙細鎻愪氦涓変釜鍥哄畾鍊� |
+
+## 娉ㄦ剰浜嬮」
+
+- `type` 涓烘枃鏈瓧娈碉紙VARCHAR(20)锛夛紝淇濆瓨鏃朵紶涓枃鍘熸枃锛屼笉瑕佷紶缂栫爜鎴栨暟瀛椼��
+- 璇ュ瓧娈靛繀濉紝涓虹┖鏃舵帴鍙h繑鍥炲弬鏁版牎楠岄敊璇�岀被鍨嬩笉鑳戒负绌恒�嶃��
+- 璁¢噺鍗曚綅琚墿鏂欏紩鐢ㄥ悗浠嶅彲淇敼绫诲瀷锛屾棤绾ц仈闄愬埗銆�
diff --git a/docs/mes_bag_code_package_refactor_integration.md b/docs/mes_bag_code_package_refactor_integration.md
new file mode 100644
index 0000000..a24ef59
--- /dev/null
+++ b/docs/mes_bag_code_package_refactor_integration.md
@@ -0,0 +1,96 @@
+# 涓�琚嬩竴鐮佺敓浜ч�昏緫鏀归�� - 鍓嶇鑱旇皟鏂规
+
+> 閰嶅闇�姹傛柟妗堬細`docs/mes_bag_code_package_refactor_requirements.md`銆傛湰鏂规瑕嗙洊鎺ュ彛鍙樻洿涓庨〉闈㈡暟鎹甫鍏ワ紝鍓嶇涓讳綋鏀瑰姩宸查殢鏈鏀归�犲悓姝ュ畬鎴愶紝渚涜仈璋冨洖褰掍娇鐢ㄣ��
+
+## 娑夊強椤甸潰
+
+- 璧嬬爜绠$悊锛堣鐮侊級锛氱敓鎴愭暟鎹寘寮圭獥銆佺敓鎴愬師濮嬭鐮佸脊绐椼�佽鐮佸垪琛ㄣ�佸綍鍏ユ壒娆°�佺粦瀹氭墭鐩樸�佽拷婧脊绐�
+- 鐢熶骇鎵规锛氭柊澧�/缂栬緫/琛ュ綍琛ㄥ崟锛堟柊澧炪�岀粦瀹氭墭鐩樸�嶅閫夛級銆佸垪琛ㄣ�佹悳绱㈠尯
+- 鎵樼洏绠$悊锛氶鐢熸垚寮圭獥銆佸垪琛ㄣ�佺粦瀹氭壒娆″脊绐�
+- 鍏叡 H5 婧簮椤点�佹壂鐮佽拷婧脊绐楋紙鍥炲綊锛�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. 鐢熸垚鏁版嵁鍖咃細閫夊搧绉� 鈫� 鍓嶇鎸夊搧绉嶄富璁¢噺鍗曚綅绫诲瀷鑱斿姩锛堟煡 `/mdm/item/get` 鍙� `unitMeasureId`锛屽啀鏌� `/mdm/unit/get?id=` 鍙� `type`锛夛細
+ - `48鍗冨厠`/`100鍗冨厠` 鈫� 杈撳叆**鎵樼洏鏁�**锛岄瑙堛�屾瘡鎵� N 琚� 脳 鎵樼洏鏁� = 琚嬬爜鏁般��
+ - `鍚╜ 鈫� 杈撳叆**琚嬬爜鏁�**锛堟棤鎵樼洏锛�
+ - 绫诲瀷鏈厤缃� 鈫� 鎻愮ず鍓嶅線銆岃閲忓崟浣嶃�嶇淮鎶わ紝鎻愪氦鏃跺悗绔篃浼氬厹搴曟姤閿�
+2. 鐢熸垚缁撴灉锛氬悓涓� uuid 琚嬬爜缁� + 鑷姩鐢熸垚鐨勪复鏃舵墭鐩橈紙PL-搴忓彿锛夛紝琚嬬爜宸插甫鍝佺銆佸凡缁戞墭鐩樸��
+3. 褰曞叆鎵规锛氬嬀閫夎鐮� 鈫� 閫夌敓浜ф壒娆°�傚悗绔骇鑱旓細涓存椂鎵樼洏鍗囨寮忕爜锛堟壒娆″彿-P搴忓彿锛夊苟缁戞壒娆°�佸洖鍐欒鐮佸啑浣欐墭鐩樼爜銆傛贩鍝佺浼氳鎷︽埅銆�
+4. 鎵规涓嶅啀褰曞叆/灞曠ず鍝佺锛涘搧绉嶄俊鎭叏閮ㄧ敱琚嬬爜鏁版嵁鍖呮惡甯︺��
+5. 鏂板/琛ュ綍/缂栬緫鎵规鏃跺潎鍙�夈�岀粦瀹氭墭鐩樸�嶏紙澶氶�夈�侀潪蹇呭~锛屾暟鎹簮 `GET /mes/pro/pallet/unbound-list`锛屽睍绀轰复鏃舵墭鐩樼爜+宸茶琚嬫暟锛夛細鍕鹃�夊悗鎵规鐘舵�佺洿鎺ヤ负**鐢熶骇涓�**锛屽悗绔悓浜嬪姟澶嶇敤鎵樼洏缁戝畾鎵规閫昏緫锛堟墭鐩樺崌姝e紡鐮併�佹墭鐩樹笅琚嬬爜绾ц仈褰曞叆锛夛紝浠讳竴鏍¢獙澶辫触鏁翠綋鍥炴粴锛涚紪杈戞椂浠呴渶鍕鹃�夋湰娆℃柊澧炵殑鎵樼洏锛堝凡缁戝畾鎵樼洏涓嶅湪涓嬫媺涓�佷笉鍙В缁戯級銆�
+
+## API
+
+| 鏂规硶 | 璺緞 | 鍙樻洿 |
+|------|------|------|
+| POST | /mes/pro/bag-code/generate | 璇锋眰/鍝嶅簲缁撴瀯鍙樻洿锛堣涓嬶級 |
+| POST | /mes/pro/bag-code/raw-generate | **鏂板**锛氱敓鎴愬師濮嬭鐮侊紝璇锋眰 `{ itemId, count, remark? }`锛涗粎鎸夋暟閲忕敓鎴愩�佷笉鎹㈢畻璁¢噺鍗曚綅绫诲瀷銆佷笉鐢熸垚鎵樼洏锛涘搷搴旂粨鏋勫悓 generate锛坄type/perPallet` 涓虹┖銆乣palletIds` 绌烘暟缁勶級 |
+| PUT | /mes/pro/bag-code/bind-batch | 璺緞涓嶅彉锛涙柊澧炲搧绉嶄竴鑷存牎楠屻�佹墭鐩樼骇鑱旂粦瀹氾紱宸插鍑哄嵃鍒凤紙PRINTED锛夎鐮佷篃鍏佽褰曞叆鎵规 |
+| PUT | /mes/pro/pallet/bind-batch | 璺緞涓嶅彉锛涙墭鐩樼粦瀹氭壒娆℃椂锛屾墭鐩樹笅鏈粦鎵规鐨勮鐮佽嚜鍔ㄧ骇鑱斿綍鍏ュ悓涓�鎵规锛堝搧绉嶄竴鑷存牎楠屻�佸洖鍐欐壒娆¤鏁帮級 |
+| DELETE | /mes/pro/bag-code/delete-by-uuid | 璺緞涓嶅彉锛涚骇鑱斿垹闄ゆ湰缁勮嚜鍔ㄧ敓鎴愭墭鐩� |
+| POST | /mes/pro/bag-code/replace | 涓嶅彉锛涙柊琚嬬爜鑷姩缁ф壙鍘熷搧绉� |
+| GET | /mes/pro/bag-code/page銆乴ist-by-uuid銆乬et-by-code | 鍝嶅簲鏂板鍝佺瀛楁锛沺age 鏂板鍙�夋煡璇㈠弬鏁� `itemId`锛堝搧绉嶏紝绛夊�煎尮閰嶏紱瀵煎嚭 Excel 鍚屽彛寰勶級 |
+| POST | /mes/pro/pallet/batch-create銆乸re-generate | 璇锋眰鍘绘帀 capacity |
+| GET | /mes/pro/pallet/page | 鍝嶅簲鍘绘帀 capacity锛屼繚鐣� autoGenerated |
+| POST/PUT | /mes/pro/batch/create銆乽pdate銆乫ill-info | 璇锋眰鍘绘帀 itemId锛涗笁鑰呭潎鏂板鍙�� `palletIds`锛堢粦瀹氭椂鎵规杩涘叆鐢熶骇涓級 |
+| GET | /mes/pro/pallet/unbound-list | **鏂板**锛氭湭缁戝畾鎵规鐨勪复鏃舵墭鐩樺垪琛紙鏉冮檺 mes:pro-pallet:query锛夛紝渚涙壒娆℃柊澧�/琛ュ綍缁戝畾鎵樼洏涓嬫媺 |
+| GET | /mes/pro/batch/page銆乬et銆乻imple-list | 鍝嶅簲鍘绘帀 itemId/itemCode/itemName/itemSpecification |
+
+**鐢熸垚鏁版嵁鍖呰姹傚弬鏁帮細**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| itemId | Long | 鏄� | 鍝佺缂栧彿 |
+| palletCount | Integer | 鏉′欢蹇呭~ | 鎵樼洏鏁帮紙绫诲瀷=N鍗冨厠锛� |
+| bagCount | Integer | 鏉′欢蹇呭~ | 琚嬬爜鏁帮紙绫诲瀷=鍚級 |
+| remark | String | 鍚� | 澶囨敞 |
+
+**鐢熸垚鏁版嵁鍖呭搷搴旂ず渚嬶細**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "uuid": "鐢熸垚缁刄UID",
+ "type": "48鍗冨厠",
+ "perPallet": 48,
+ "totalCount": 96,
+ "palletIds": [101, 102]
+ }
+}
+```
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鍝佺缂栫爜/鍚嶇О锛坕temCode/itemName锛� | 琚嬬爜鍒楄〃銆佽拷婧�佸鍑� Excel | 鐢熸垚鏃剁粦瀹氬湪琚嬬爜涓� |
+| autoGenerated | 鎵樼洏鍒楄〃銆岃嚜鍔ㄧ敓鎴愩�峊ag | 鏁版嵁鍖呰嚜鍔ㄥ垱寤虹殑鎵樼洏鏍囪瘑 |
+| 鍝佺锛堟壒娆¢〉锛� | 涓嶅啀灞曠ず | 琛ㄥ崟/鍒楄〃/鎼滅储鍧囧凡绉婚櫎 |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 绫诲瀷=N鍗冨厠 鐢熸垚 | 琚嬬爜鏁� = N 脳 鎵樼洏鏁帮紝鑷姩寤� N 涓墭鐩樺苟鍧囧垎缁戝畾 |
+| 绫诲瀷=鍚� 鐢熸垚 | 鏃犳墭鐩橈紝琚嬬爜浠呯粦鎵规 |
+| 鐢熸垚鍘熷琚嬬爜 | 浠呴渶鍝佺+鏁伴噺锛涜鐮佸甫鍝佺銆佷笉缁戞壒娆�/鎵樼洏锛屽悗缁綍鍏ユ壒娆°�佺粦鎵樼洏銆佸鍑哄嵃鍒枫�佸垹闄ょ粍涓庢暟鎹寘琚嬬爜瀹屽叏涓�鑷达紱涓嶆牎楠屽搧绉嶈閲忓崟浣嶇被鍨� |
+| 褰曞叆鎵规娣峰搧绉� | 鎶ラ敊銆屽綍鍏ユ壒娆$殑琚嬬爜蹇呴』灞炰簬鍚屼竴鍝佺銆嶏紙涓庢壒娆″凡鏈夎鐮佷竴骞舵牎楠岋級 |
+| 鎵樼洏缁戝畾鎵规 | 鎵樼洏涓嬫湭缁戞壒娆$殑琚嬬爜锛堝凡鐢熸垚/宸插鍑哄嵃鍒凤級鑷姩闅忔墭鐩樺綍鍏ュ悓涓�鎵规锛岃鐮佸啑浣欐墭鐩樼爜鍚屾鏇存柊涓烘寮忕爜 |
+| 鎵规鏂板/琛ュ綍/缂栬緫缁戝畾鎵樼洏 | palletIds 闈炵┖鏃舵壒娆$姸鎬佺洿鎺ョ疆銆岀敓浜т腑銆嶏紝鍚屼簨鍔″鐢ㄦ墭鐩樼粦瀹氭壒娆¢�昏緫锛堟寮忕爜+琚嬬爜绾ц仈+鍝佺涓�鑷存牎楠岋級锛屽け璐ユ暣浣撳洖婊氾紱鏂板/琛ュ綍鏈嬀閫夊垯缁存寔鑽夌锛涚紪杈戝彇娑堝嬀閫変笉鍥為��鐘舵�併�佸凡缁戝畾鎵樼洏涓嶅彲瑙g粦 |
+| 缁戞墭鐩樺閲� | 鏃犱笂闄愶紝鑷姩鎵樼洏鍙户缁墜鍔ㄧ粦鍏� |
+| 鍒犻櫎鏁版嵁鍖� | 缁勫唴鎵樼洏宸茬粦鎵规鎴栨湁姝e紡鐮佸垯涓嶅彲鍒狅紝鍚﹀垯绾ц仈鍒犺嚜鍔ㄦ墭鐩� |
+| 杩芥函鍝佺 | 浼樺厛琚嬬爜鍝佺锛涘巻鍙茶鐮佸洖閫�鎵规鍝佺锛堝叕鍏� H5 鍚屾鏀寔锛� |
+| 鎵规鍙� | PC + yyyyMMdd + 浜х嚎缂栫爜 + 娴佹按鍙凤紙涓嶅啀鍚搧绉嶇紪鐮侊級 |
+
+## 娉ㄦ剰浜嬮」
+
+- `generate` 鏃у弬鏁� `count` 宸插簾寮冿紝鍙紶 `palletCount` 鎴� `bagCount`锛堟寜鍝佺绫诲瀷浜岄�変竴锛夈��
+- 鎵规 `itemId` 鐩稿叧瀛楁宸蹭粠鎺ュ彛绉婚櫎锛屽嬁鍐嶅紩鐢紙鎵规杩芥函瑙嗗浘 `get-by-code` 鐨勫搧绉嶅瓧娈典繚鐣欙紝鍙兘涓虹┖=鏂版壒娆★級銆�
+- 鎵樼洏杩芥函瑙嗗浘锛圥alletTrace/qr-trace-modal锛変粛杩斿洖 `capacity` 渚涘巻鍙叉暟鎹睍绀猴紝鏂版墭鐩樹负绌恒��
+- 鑰佹暟鎹紙鍘嗗彶绌虹櫧琚嬬爜锛夊搧绉嶄负绌哄睘姝e父锛岃拷婧蛋鎵规鍥為��銆�
+- `palletIds` 鍦� create/update/fill-info 鍧囩敓鏁堬紱涓嬫媺姣忔鎵撳紑寮圭獥閲嶆柊鎷夊彇 `unbound-list`锛岃嫢鎻愪氦鏃舵墍閫夋墭鐩樺凡琚粬浜虹粦瀹氾紝鍚庣鏁翠綋鎶ラ敊鍥炴粴锛堟湰娆℃壒娆℃搷浣滀笉鐢熸晥锛夛紝鎻愮ず鐢ㄦ埛鍒锋柊閲嶈瘯銆�
+- 琚嬬爜鍒嗛〉锛坄/page`锛夊悗绔凡鏀逛负**鍒涘缓鏃堕棿鍊掑簭**锛堝悓绉掑唴鎸夌紪鍙峰�掑簭锛夛紝鍓嶇鏃犻渶鍐嶄紶鎺掑簭鍙傛暟锛涘鍑� Excel 鍚屽彛寰勩��
+- 鍘熷琚嬬爜涓庢暟鎹寘琚嬬爜鍚岃〃鍚岃鍒欙紙uuid 鎴愮粍銆佸彲鏁寸粍鍒犻櫎锛夛紝鍒楄〃椤甸�氳繃鐢熸垚缁� UUID 鍖哄垎鏉ユ簮銆�
+- 鍒楄〃鎼滅储鍖烘柊澧炪�屽搧绉嶃�嶆潯浠讹紙澶嶇敤 `MdmItemSelect`锛屽彲娓呯┖锛夛紝浼� `itemId` 绛夊�艰繃婊わ紱瀵煎嚭 Excel 鎼哄甫鍚屼竴鏌ヨ鏉′欢鍚屽彛寰勭敓鏁堛�傚巻鍙茬┖鐧借鐮佸搧绉嶄负绌猴紝鎸夊搧绉嶇瓫閫変笉浼氬懡涓��
diff --git a/docs/mes_bag_code_package_refactor_requirements.md b/docs/mes_bag_code_package_refactor_requirements.md
new file mode 100644
index 0000000..5eb73e6
--- /dev/null
+++ b/docs/mes_bag_code_package_refactor_requirements.md
@@ -0,0 +1,142 @@
+# 涓�琚嬩竴鐮佺敓浜ч�昏緫鏀归�� - 闇�姹傛柟妗�
+
+> 鐘舵�侊細宸茬‘璁ゅ苟瀹屾垚瀹炴柦锛�2026-09-17锛夈�傚喅绛栫偣瀹氱瑙佹枃鏈��6. 纭缁撹銆嶃��
+
+## 1. 闇�姹傝儗鏅�
+
+涓�琚嬩竴鐮佺殑鐢熶骇閫昏緫璋冩暣锛�
+
+- 鎵规鐢熶骇绠$悊**涓嶅啀缁戝畾鍝佺**锛屽搧绉嶄笅娌夊埌銆岃祴鐮佺鐞嗐�嶇殑鏁版嵁鍖呬笂銆�
+- 鐢熸垚鏁版嵁鍖呮椂閫夋嫨**鍝佺**骞惰緭鍏�**鎵樼洏鏁�**锛岀郴缁熸寜鍝佺涓昏閲忓崟浣嶇殑銆岀被鍨嬨�嶈嚜鍔ㄨ绠楄鐮佹暟閲忓苟鐢熸垚琚嬬爜銆�
+- 鎸夋墭鐩樻暟**鑷姩鐢熸垚鎵樼洏骞惰嚜鍔ㄧ粦瀹�**琚嬬爜锛涙墭鐩樹笉鍐嶉渶瑕併�屽彲瑁呰鏁般�嶃��
+- 鍝佺涓恒�屽惃銆嶆椂鏃犳墭鐩橈細鏀逛负鐩存帴杈撳叆**琚嬬爜鏁�**锛岃鐮佸彧缁戠敓浜ф壒娆°�佷笉缁戞墭鐩樼爜銆�
+
+## 2. 鐜扮姸瑕佺偣
+
+| 瀵硅薄 | 鐜扮姸 |
+|------|------|
+| 鏁版嵁鍖呯敓鎴� | `POST /mes/pro/bag-code/generate` 浠呬紶 `count`锛岀敓鎴愮┖鐧借鐮侊紙鏃犲搧绉�/鎵规/鎵樼洏锛� |
+| 鎵规 | `mes_pro_batch.itemId` 缁戝畾鍝佺锛涙壒娆″彿 = PC + 鏃ユ湡 + 浜х嚎缂栫爜 + 鍝佺缂栫爜 + 娴佹按鍙� |
+| 鎵樼洏 | 鎵嬪姩鍒涘缓锛堟壒閲忕敓鎴�/棰勭敓鎴愶級锛屽垱寤烘椂濉� `capacity 鍙琚嬫暟`锛涜鐮佹墜鍔ㄧ粦鎵樼洏骞舵牎楠屽閲� |
+| 鍝佺鈫掑崟浣� | `mdm_item.unitMeasureId 鈫� mdm_unit_measure.type`锛堢被鍨嬮�夐」锛�48鍗冨厠/100鍗冨厠/鍚紝鏈宸插姞锛� |
+| 杩芥函 | 鎵爜杩芥函鐨勫搧绉嶄俊鎭彇鑷壒娆� `batch.itemId` |
+
+## 3. 鏀归�犳柟妗�
+
+### 3.1 鐢熸垚鏁版嵁鍖咃紙璧嬬爜绠$悊锛屾牳蹇冩敼鍔級
+
+**鎹㈢畻瑙勫垯**锛堝悗绔绠楋紝涓嶄俊浠诲墠绔紶鍊硷級锛�
+
+| 鍝佺涓诲崟浣嶇被鍨� | 杈撳叆 | 鐢熸垚缁撴灉 |
+|------|------|------|
+| 48鍗冨厠 | 鎵樼洏鏁� P | 琚嬬爜 48 脳 P 涓紱鑷姩鐢熸垚 P 涓墭鐩橈紝姣忔墭缁戝畾 48 涓鐮� |
+| 100鍗冨厠 | 鎵樼洏鏁� P | 琚嬬爜 100 脳 P 涓紱鑷姩鐢熸垚 P 涓墭鐩橈紝姣忔墭缁戝畾 100 涓鐮� |
+| 鍚� | 琚嬬爜鏁� N | 琚嬬爜 N 涓紱涓嶇敓鎴愭墭鐩橈紝琚嬬爜涓嶇粦鎵樼洏 |
+| 绫诲瀷涓虹┖/鏃犳硶瑙f瀽 | - | 鎶ラ敊锛氬搧绉嶄富璁¢噺鍗曚綅鏈厤缃被鍨嬶紙48鍗冨厠/100鍗冨厠/鍚級 |
+
+**鎺ュ彛鍙樻洿** `POST /mes/pro/bag-code/generate`锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| itemId | Long | 鏄� | 鍝佺锛坢dm_item 缂栧彿锛� |
+| palletCount | Integer | 鏉′欢蹇呭~ | 鎵樼洏鏁帮紙绫诲瀷涓� N鍗冨厠 鏃跺繀濉級 |
+| bagCount | Integer | 鏉′欢蹇呭~ | 琚嬬爜鏁帮紙绫诲瀷涓� 鍚� 鏃跺繀濉級 |
+| remark | String | 鍚� | 澶囨敞 |
+
+鍝嶅簲鏂板锛歚uuid銆乼ype銆乸erPallet锛堟瘡鎵樿鏁帮級銆乼otalCount锛堢敓鎴愯鐮佹暟锛夈�乸alletIds锛堣嚜鍔ㄧ敓鎴愮殑鎵樼洏锛塦銆�
+
+**浜嬪姟閫昏緫**锛氫竴娆$敓鎴� = 鍚屼竴 uuid 鐨勮鐮佺粍 + 鍚屾壒鑷姩鐢熸垚鐨勬墭鐩橈紱鎵樼洏鍏堜互**涓存椂鐮侊紙PL-搴忓彿锛�**钀藉簱骞跺畬鎴愯鐮佺粦瀹氾紝姝e紡鎵樼洏鐮佸湪銆屽綍鍏ユ壒娆°�嶆椂鐢熸垚銆�
+
+**鐢熸垚鏁版嵁鍖呭脊绐楋紙鍓嶇锛�**锛氶�夋嫨鍝佺锛堟部鐢ㄥ搧绉嶉�夋嫨缁勪欢锛夆啋 璇诲彇璇ュ搧绉嶄富鍗曚綅绫诲瀷锛堝墠绔煡 `mdm_unit_measure`锛岀被鍨嬩负绌虹粰鎻愮ず锛夆啋 鎸夌被鍨嬪垏鎹㈣緭鍏ャ�屾墭鐩樻暟銆嶆垨銆岃鐮佹暟銆嶁啋 瀹炴椂棰勮"灏嗙敓鎴� 琚嬬爜 X 涓� / 鎵樼洏 Y 涓�"銆�
+
+### 3.2 褰曞叆鎵规锛堜繚鎸佸悗褰曞叆锛屾墿灞曠骇鑱旓級
+
+`PUT /mes/pro/bag-code/bind-batch` 娴佺▼涓嶅彉锛屾柊澧炵骇鑱旓細
+
+1. 琚嬬爜缁戝畾鎵规锛堢幇鐘讹級銆�
+2. 璇ョ粍琚嬬爜鎵�缁戝畾鐨勪复鏃舵墭鐩樿嚜鍔ㄧ粦瀹氬悓涓�鎵规锛屽苟鍒嗛厤姝e紡鎵樼洏鐮� `鎵规鍙�-P搴忓彿`锛屽洖鍐欐壒娆℃墭鐩樻暟銆�
+3. 鏂板鏍¢獙锛氬悓涓�鏁版嵁鍖咃紙鍚屾壒缁戝畾琚嬬爜锛夊搧绉嶅繀椤讳竴鑷达紙鐢熸垚鏃跺ぉ鐒朵竴鑷达紝闃叉墜鍔ㄦ贩閫夛級銆�
+
+### 3.3 琚嬬爜鏁版嵁妯″瀷
+
+`mes_pro_bag_code` 鏂板锛歚item_id`銆乣item_code`銆乣item_name`锛堝啑浣欙級銆�
+
+- 鍒楄〃/鏌ヨ锛氭樉绀哄搧绉嶅垪锛堢紪鐮�/鍚嶇О鍙绱㈡湰鏈熶笉鍋氾紝浠呭睍绀猴級銆�
+- 鍒犻櫎鏁版嵁鍖咃紙delete-by-uuid锛夛細绾ц仈鍒犻櫎鏈粍**鑷姩鐢熸垚**鐨勬墭鐩橈紙鍓嶆彁浠嶆槸鍏ㄩ儴鏈粦鎵规锛涘凡褰曟壒娆$淮鎸佺幇鐘朵笉鍙垹锛夈��
+- 琚嬬爜涓嶅己鍒舵墭鐩橈細`pallet_id` 淇濇寔鍙┖锛堝惃绫诲瀷锛夈��
+
+### 3.4 鎵规鐢熶骇绠$悊
+
+- **鍘绘帀鍝佺瀛楁**锛氬垱寤�/缂栬緫琛ㄥ崟銆佸垪琛ㄥ垪銆佹煡璇㈡潯浠躲�丼ave/Resp/Page VO 鍧囩Щ闄� `itemId`锛汥O 涓庢暟鎹簱鍒� `mes_pro_batch.item_id` 淇濈暀锛堝巻鍙叉暟鎹�佽拷婧洖閫�鐢級锛屾敞閲婃爣璁�"宸插簾寮�"銆�
+- **鎵规鍙疯鍒欐敼涓�** `PC + yyyyMMdd + 浜х嚎缂栫爜 + 娴佹按鍙穈锛坄generateBatchCode` 涓嶅啀鎷煎搧绉嶇紪鐮侊紱鑷姩缂栫爜瑙勫垯閰嶇疆鏃犻渶鏀癸級銆�
+- 缂栬緫鎵规涓嶅啀鍥犲搧绉嶅彉鍖栭噸鏂扮敓鎴愭壒娆″彿銆�
+
+### 3.5 鎵樼洏绠$悊
+
+- 鎵归噺鐢熸垚/棰勭敓鎴愭帴鍙e幓鎺� `capacity` 鍏ュ弬锛涜〃鍗曞幓鎺夈�屽彲瑁呰鏁般�嶅瓧娈碉紱鍒楄〃鍘绘帀璇ュ垪銆侱B 鍒椾繚鐣欏吋瀹瑰巻鍙层��
+- 琚嬬爜鎵嬪姩缁戞墭鐩樺幓鎺夊閲忔牎楠岋紙`capacity` 鍒ょ┖閫昏緫澶╃劧璺宠繃锛屽垹闄ょ浉鍏虫牎楠屼唬鐮侊級銆�
+- 鎵樼洏鍒楄〃涓鸿嚜鍔ㄧ敓鎴愭墭鐩樻墦鏍囪瘑锛堝鐢� `auto_generated` 瀛楁 = true锛夈��
+
+### 3.6 杩芥函/鎵爜/鐪嬫澘锛堝洖褰掗」锛�
+
+- 琚嬬爜杩芥函锛坄/get-by-code`銆乀raceRespVO锛夛細鍝佺鏀逛负**浼樺厛鍙栬鐮� item_id锛屽巻鍙茶鐮佸洖閫�鎵规 itemId**銆�
+- 鎵规杩芥函瑙嗗浘锛圡esProBatchTraceRespVO锛夛細淇濈暀鍝佺杩斿洖浣嗗彲鑳戒负绌猴紙鍘嗗彶鎵规鏈夊�硷級銆�
+- 鎵爜鍏ュ簱銆侀攢鍞嚭搴撱�佽鐮侀椤电湅鏉匡細涓嶇洿鎺ヤ緷璧栨壒娆″搧绉嶇殑閫昏緫涓嶅姩锛屾秹鍙婂鍥炲綊楠岃瘉銆�
+
+## 4. 鏁版嵁搴撳彉鏇达紙mom-thzy锛�
+
+```sql
+ALTER TABLE mes_pro_bag_code ADD COLUMN item_id BIGINT NULL COMMENT '鍝佺锛堢墿鏂欙級缂栧彿' AFTER pallet_code;
+ALTER TABLE mes_pro_bag_code ADD COLUMN item_code VARCHAR(64) NULL COMMENT '鍝佺缂栫爜锛堝啑浣欙級' AFTER item_id;
+ALTER TABLE mes_pro_bag_code ADD COLUMN item_name VARCHAR(255) NULL COMMENT '鍝佺鍚嶇О锛堝啑浣欙級' AFTER item_code;
+-- mes_pro_batch.item_id 淇濈暀涓嶅垹锛孞ava 娉ㄩ噴鏍囪搴熷純
+```
+
+## 5. 鍓嶅悗绔敼鍔ㄦ竻鍗�
+
+| 灞� | 鏂囦欢 | 鏀瑰姩 |
+|----|------|------|
+| DB | mes_pro_bag_code | +item_id/item_code/item_name |
+| 鍚庣 | MesProBagCodeGenerateReqVO/RespVO銆丼erviceImpl | 鏂板弬鏁般�佺被鍨嬫崲绠椼�佽嚜鍔ㄥ缓鎵樼洏銆佷簨鍔� |
+| 鍚庣 | MesProBagCodeDO/RespVO/Mapper | +鍝佺瀛楁 |
+| 鍚庣 | bind-batch 娴佺▼ | 绾ц仈鎵樼洏缁戞壒娆°�佸搧绉嶄竴鑷存�ф牎楠� |
+| 鍚庣 | MesProBatchServiceImpl/VO | 鍘诲搧绉嶃�佹壒娆″彿瑙勫垯銆佺紪杈戦�昏緫 |
+| 鍚庣 | MesProPalletServiceImpl/VO | 鍘� capacity 鍏ュ弬涓庢牎楠� |
+| 鍚庣 | delete-by-uuid | 绾ц仈鍒犺嚜鍔ㄦ墭鐩� |
+| 鍚庣 | 杩芥函 VO | 鍝佺浼樺厛琚嬬爜銆佸洖閫�鎵规 |
+| 鍓嶇 | pro/bagCode generate-form | 鍝佺+鎵樼洏鏁�/琚嬬爜鏁拌〃鍗� |
+| 鍓嶇 | pro/bagCode 鍒楄〃 | +鍝佺鍒� |
+| 鍓嶇 | pro/batch form/list/search | 绉婚櫎鍝佺 |
+| 鍓嶇 | pro/pallet form/list | 绉婚櫎鍙琚嬫暟 |
+
+## 6. 纭缁撹锛堝畾绋匡級
+
+1. **娣峰搧绉�**锛氳銆備竴娆� bind-batch 鍕鹃�夌殑琚嬬爜鍝佺蹇呴』涓�鑷达紝鍚﹀垯鎶ラ敊銆屽綍鍏ユ壒娆$殑琚嬬爜蹇呴』灞炰簬鍚屼竴鍝佺銆嶏紙鍘嗗彶绌虹櫧琚嬬爜涓嶅弬涓庢牎楠岋級銆�
+2. **鑷姩鎵樼洏鍙惁鍐嶆墜鍔ㄥ缁�**锛氭棤瀹归噺涓婇檺锛岃婊″悗浠嶅彲缁х画鎵嬪姩缁戝叆琚嬬爜銆�
+3. **鎵规鍒楄〃鍘嗗彶鏁版嵁**锛氳�佹壒娆� itemId 鐩存帴涓嶅睍绀哄嵆鍙紝鏃犳暟鎹縼绉伙紱杩芥函瑙嗗浘淇濈暀鎵规鍝佺鍋氬巻鍙插洖閫�銆�
+4. **娴佺▼涓庢壒娆″彿**锛氫繚鎸併�屽厛鐢熸垚鏁版嵁鍖呫�佸悗褰曞叆鎵规銆嶏紱鎵规鍙疯鍒欐敼涓� `PC + yyyyMMdd + 浜х嚎缂栫爜 + 娴佹按鍙穈銆�
+
+## 7. 瀹炴柦璁板綍锛�2026-09-17锛�
+
+- DB锛坢om-thzy锛夛細`mes_pro_bag_code` 鏂板 `item_id/item_code/item_name`锛沗mdm_unit_measure.type`锛�48鍗冨厠/100鍗冨厠/鍚級锛沗mes_pro_batch.item_id` 淇濈暀鏍囧簾寮冦��
+- 鍚庣锛歚generate` 閲嶅啓锛堢被鍨嬫崲绠�+鑷姩涓存椂鎵樼洏锛夈�乣bind-batch` 绾ц仈鎵樼洏姝e紡鐮�+鍝佺涓�鑷存牎楠屻�乣delete-by-uuid` 绾ц仈鍒犺嚜鍔ㄦ墭鐩樸�乣replace` 缁ф壙鍝佺銆佹墭鐩樺垱寤哄幓 `capacity` 鍏ュ弬銆佽鐮佺粦鎵樼洏鍘诲閲忔牎楠屻�佹壒娆� VO/Service 鍘诲搧绉嶃�佹壒娆″彿鍗曚骇绾胯绱犮�佽鐮�/鍏叡杩芥函涓庝簩缁寸爜鏍囩鍝佺銆岃鐮佷紭鍏堛�佹壒娆″洖閫�銆嶃��
+- 鍓嶇锛氳鐮佺敓鎴愬脊绐楋紙鍝佺+鎵樼洏鏁�/琚嬬爜鏁板姩鎬�+棰勮锛夈�佸垪琛ㄥ搧绉嶅垪锛涙壒娆¤〃鍗�/鍒楄〃/鎼滅储鍘诲搧绉嶏紱鎵樼洏琛ㄥ崟/鍒楄〃鍘诲彲瑁呰鏁般�佸垪琛ㄥ姞銆岃嚜鍔ㄧ敓鎴愩�嶆爣璇嗐�佺粦鎵樼洏涓嬫媺鍘诲閲忔彁绀恒��
+- 缂栬瘧锛歚mvn compile -pl yudao-module-mes -am -q` 閫氳繃銆�
+
+## 8. 琛ュ厖闇�姹傦細鎵规鎿嶄綔缁戝畾鎵樼洏锛�2026-09-17锛�
+
+- 鎵规鏂板/琛ュ綍/缂栬緫鍧囧彲閫夈�岀粦瀹氭墭鐩樸�嶏紙澶氶�夈�侀潪蹇呭~锛夛細鍕鹃�夊悗鎵规鐘舵�佺洿鎺ョ疆**鐢熶骇涓�**锛屽悓浜嬪姟澶嶇敤鎵樼洏缁戝畾鎵规閫昏緫锛堟寮忔墭鐩樼爜銆佹墭鐩樹笅琚嬬爜绾ц仈褰曞叆銆佸搧绉嶄竴鑷存牎楠岋級锛屼换涓�姝ュけ璐ユ暣浣撳洖婊氥��
+- 缂栬緫鏃朵粎浼犳湰娆℃柊澧炲嬀閫夌殑鎵樼洏锛涘凡缁戝畾鎵樼洏涓嶅湪涓嬫媺涓紙unbound-list 宸茶繃婊わ級锛屼笉鏀寔瑙g粦锛屾湭鍕鹃�変笉鏀圭姸鎬併�佷笉鎴柇鍥為��銆�
+- 鏂版帴鍙� `GET /mes/pro/pallet/unbound-list`锛歜atch_id 涓虹┖銆佹棤姝e紡鎵樼洏鐮佷笖鏈綔搴熺殑涓存椂鎵樼洏銆�
+- 鍓嶇鑱旇皟缁嗗垯瑙� `docs/mes_bag_code_package_refactor_integration.md`銆�
+
+## 9. 琛ュ厖闇�姹傦細鍘熷琚嬬爜涓庡垪琛ㄦ帓搴忥紙2026-09-17锛�
+
+- 鏂板 `POST /mes/pro/bag-code/raw-generate`锛氫粎閫夊搧绉�+琚嬬爜鏁伴噺鍗崇敓鎴愬搴旀暟閲忚鐮侊紙甯﹀搧绉嶅啑浣欍�乽uid 鎴愮粍锛夛紝**涓嶆牎楠岃閲忓崟浣嶇被鍨嬨�佷笉鐢熸垚鎵樼洏**锛涘悗缁綍鍏ユ壒娆�/缁戞墭鐩�/鍗板埛/鍒犻櫎涓庢暟鎹寘琚嬬爜涓�鑷淬�傝祴鐮佺鐞嗛〉宸ュ叿鏍忓姞銆岀敓鎴愬師濮嬭鐮併�嶅脊绐楀叆鍙c��
+- 琚嬬爜鍒嗛〉鏌ヨ鏀逛负鎸�**鍒涘缓鏃堕棿鍊掑簭**锛堝悓绉掓寜缂栧彿鍊掑簭锛夛紝鍘熴�岃搴忓彿鍗囧簭銆嶅簾寮冦��
+- 缂栬瘧 `mvn compile -pl yudao-module-mes -am -q` 閫氳繃銆佸墠绔被鍨嬫鏌ユ敼鍔ㄦ枃浠堕浂閿欒銆�
+
+## 10. 琛ュ厖闇�姹傦細琚嬬爜鍒楄〃鍝佺鏌ヨ锛�2026-09-17锛�
+
+- 璧嬬爜绠$悊鍒楄〃鎼滅储鍖烘柊澧炪�屽搧绉嶃�嶆潯浠讹紙澶嶇敤 `MdmItemSelect` 閫夋嫨缁勪欢锛夛紝鎸� `mes_pro_bag_code.item_id` 绛夊�艰繃婊わ紱鍒嗛〉涓庡鍑� Excel 鍚屽彛寰勭敓鏁堛��
+- 鍘嗗彶绌虹櫧琚嬬爜 `item_id` 涓虹┖锛岄�夋嫨鍝佺鍚庝笉浼氬懡涓紙灞炴甯革級銆偮�3.3 鍘熴�岀紪鐮�/鍚嶇О鍙绱㈡湰鏈熶笉鍋氾紝浠呭睍绀恒�嶅氨姝ゅ崌绾т负鎸夊搧绉嶇紪鍙锋绱€��
diff --git a/docs/mes_pro_batch_processing_team_integration.md b/docs/mes_pro_batch_processing_team_integration.md
new file mode 100644
index 0000000..d689fa1
--- /dev/null
+++ b/docs/mes_pro_batch_processing_team_integration.md
@@ -0,0 +1,66 @@
+# 鎵规鐢熶骇绠$悊锛氶殣钘忎骇绾跨紪鐮併�佸瓧娈垫敼鍚嶃�佹柊澧炲姞宸ョ彮缁� - 鍓嶇鑱旇皟鏂规
+
+## 鑳屾櫙
+
+鎵规鐢熶骇绠$悊椤甸潰锛�/mes/pro/batch锛夎皟鏁达細
+
+- 闅愯棌銆屼骇绾跨紪鐮併�嶏紙鍒楄〃鍒椼�佹悳绱㈤」銆丒xcel 瀵煎嚭鍧囦笉鍐嶅睍绀猴紱鎺ュ彛浠嶈繑鍥� `lineCode`锛夈��
+- 銆屼骇绾垮悕绉般�嶅睍绀烘枃妗堢粺涓�鏀逛负銆屽姞宸ュ崟浣嶃�嶏紙鏁版嵁浠嶄负 `lineName`锛屾潵婧愪骇绾夸富鏁版嵁锛夈��
+- 銆岃鍒掓暟閲忋�嶅睍绀烘枃妗堟敼涓恒�屽姞宸ユ暟閲忋�嶏紙鏁版嵁浠嶄负 `planQuantity`锛�2026-09-17 鐢便�屼环鏍兼暟閲忋�嶅啀娆℃洿鍚嶏級銆�
+- 鏂板銆屽姞宸ョ彮缁勩�嶅瓧娈碉紝鎵嬪伐濉啓鏂囨湰锛屾渶闀� 64 瀛楃锛屼綅缃湪銆屽姞宸ュ崟浣嶃�嶄箣鍚庛��
+
+## API 鍙樺寲
+
+| 鏂规硶 | 璺緞 | 鍙樺寲 |
+|------|------|------|
+| POST | /mes/pro/batch/create | 璇锋眰浣撴柊澧� `processingTeam`锛堝彲閫夛級 |
+| PUT | /mes/pro/batch/update | 鍚屼笂 |
+| PUT | /mes/pro/batch/fill-info | 鍚屼笂锛堜复鏃舵壒娆¤ˉ褰曪級 |
+| GET | /mes/pro/batch/get | 鍝嶅簲鏂板 `processingTeam` |
+| GET | /mes/pro/batch/page | 鍝嶅簲鏂板 `processingTeam`锛涙柊澧炴煡璇㈠弬鏁� `processingTeam`锛堟ā绯婂尮閰嶏級 |
+
+**瀛楁璇存槑锛�**
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| processingTeam | String(64) | 鍚� | 鍔犲伐鐝粍锛屾墜宸ュ~鍐欙紝涓嶉�変骇绾夸篃鍙~ |
+
+**鍝嶅簲绀轰緥锛堣妭閫夛級锛�**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "list": [
+ {
+ "id": 1,
+ "code": "PC20260917L01NY001",
+ "lineName": "鍖呰涓�绾�",
+ "processingTeam": "涓�鍙峰姞宸ョ彮缁�",
+ "planQuantity": 1000,
+ "ownerUserName": "寮犱笁"
+ }
+ ],
+ "total": 1
+ }
+}
+```
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 鏂板/琛ュ綍/缂栬緫鎵规 | 銆屽姞宸ョ彮缁勩�嶄负鍙�夋枃鏈緭鍏ワ紱缂栬緫鏃朵笉浼犱笉浼氭竻绌哄巻鍙插�� |
+| 鍔犲伐鍗曚綅 | 浠嶇敱閫夋嫨浜х嚎锛坄lineId`锛夊洖濉� `lineName`锛屼粎灞曠ず鏂囨鍙樺寲 |
+| 鍔犲伐鏁伴噺 | 浠呭睍绀烘枃妗堝彉鍖栵紝瀛楁涓庢牎楠岄�昏緫涓嶅彉 |
+| 浜х嚎缂栫爜 | 鎺ュ彛淇濈暀 `lineCode`锛堟壂鐮併�佹壒娆″彿鐢熸垚绛変粛渚濊禆锛夛紝椤甸潰涓庡鍑洪殣钘� |
+| 瀵煎嚭 Excel | 鍒楀悓姝ュ彉鍖栵細鍘绘帀銆屼骇绾跨紪鐮併�嶏紝銆屼骇绾垮悕绉扳啋鍔犲伐鍗曚綅銆嶏紝鏂板銆屽姞宸ョ彮缁勩�嶏紝銆岃鍒掓暟閲忊啋鍔犲伐鏁伴噺銆� |
+
+## 鏁版嵁搴撳彉鏇�
+
+`mes_pro_batch` 鏂板鍒� `processing_team VARCHAR(64) NULL COMMENT '鍔犲伐鐝粍'`锛堣剼鏈細`docs/sql/pro_batch_processing_team.sql`锛夈��
+
+## 娉ㄦ剰浜嬮」
+
+- 鎵爜杩芥函寮圭獥锛坬r-trace-modal锛夈�佹壒娆¤拷婧〉锛坬c/batchtrace锛夋湰娆℃湭瑕佹眰璋冩暣锛屼粛灞曠ず浜х嚎缂栫爜/鍚嶇О涓庤鍒掓暟閲忔枃妗堬紝濡傞渶缁熶竴鍙﹁澶勭悊銆�
+- 鏈壒鍚庣宸插悓姝ヤ慨鏀瑰墠绔� `src/views/mes/pro/batch/`锛堝垪銆佹悳绱㈣〃鍗曘�佺紪杈戣〃鍗曪級涓� `src/api/mes/pro/batch/index.ts` 绫诲瀷锛屼緵鍓嶇鍥㈤槦澶嶆牳銆�
diff --git a/docs/mes_wm_material_stock_bag_api.md b/docs/mes_wm_material_stock_bag_api.md
new file mode 100644
index 0000000..bbda426
--- /dev/null
+++ b/docs/mes_wm_material_stock_bag_api.md
@@ -0,0 +1,69 @@
+# 搴撳瓨琚嬬爜鏄庣粏鑱旇皟鏂规
+
+## 涓氬姟娴佺▼
+
+绉嶅瓙璐ㄦ浠ヨ鐮佹彁浜ゃ�傝川妫�鍚堟牸鏃讹紝鏆傚瓨搴撳瓨姹囨�绘暟閲忓噺灏� 1锛屽悎鏍煎簱瀛樻眹鎬绘暟閲忓鍔� 1锛屽悓鏃惰琚嬬爜鏄庣粏杩佺Щ鍒板悎鏍间粨锛涜川妫�涓嶅悎鏍兼椂锛屾殏瀛樺簱瀛樻眹鎬绘暟閲忓噺灏� 1锛岃鐮佹槑缁嗘爣璁颁负鎶ュ簾銆傚叾浠栬鐮佷笉鍙楀奖鍝嶃��
+
+搴撳瓨鍙拌处缁х画鎸夌墿鏂欍�佹壒娆°�佷粨搴撱�佸簱鍖恒�佸簱浣嶅拰渚涘簲鍟嗘眹鎬伙紱琚嬬爜鏄庣粏鐢ㄤ簬璁板綍姣忎釜琚嬬爜鐨勫叿浣撶姸鎬佸拰浣嶇疆銆�
+
+## 琚嬬爜鏄庣粏鐢熷懡鍛ㄦ湡锛堢粺涓�鏈嶅姟鎵樼锛�
+
+鎵�鏈夊甫琚嬬爜鐨勫簱瀛樺彉鍔ㄧ粺涓�閫氳繃搴撳瓨浜嬪姟鏈嶅姟鍦ㄥ悓涓�浜嬪姟鍐呭悓姝ョ淮鎶� **姹囨�诲簱瀛� + 琚嬬爜鏄庣粏 + 搴撳瓨娴佹按** 涓夎�呬竴鑷达紝鍚勪笟鍔″叆鍙f棤闇�鍚勮嚜瀹炵幇琚嬬爜閫昏緫銆傜敓鍛藉懆鏈燂細
+
+| 闃舵 | 鍔ㄤ綔 | 琚嬬爜鏄庣粏鍙樺寲 |
+|------|------|--------------|
+| 鍗曡鎵爜鍏ュ簱 | 鐢熶骇鎵爜鍏ュ簱锛堟壂鐮佺被鍨� BAG锛� | 寤虹珛娲诲姩鏄庣粏锛堟殏瀛樺簱锛� |
+| 绉嶅瓙璐ㄦ鍚堟牸 | 鏆傚瓨鍑哄簱 + 鍚堟牸鍏ュ簱 | 鏄庣粏鐢辨殏瀛樺簱杩佺Щ鍒板悎鏍煎簱 |
+| 绉嶅瓙璐ㄦ涓嶅悎鏍� | 鏆傚瓨鍑哄簱 | 鏄庣粏鎶ュ簾 |
+| 閿�鍞嚭搴撳畬鎴� | 鍑哄簱鎵e噺 | 鏄庣粏缃负宸插嚭搴� |
+| 鏁翠綅绉诲簱 | 璋冩嫧绉诲嚭 + 绉诲叆 | 鏄庣粏浣嶇疆杩佺Щ鍒扮洰鏍囧簱浣� |
+
+璇存槑锛�
+- 鎵樼洏锛圥ALLET锛�/鎵规锛圔ATCH锛夋暣鎵瑰叆搴撱�侀噰璐�/鏉傞」/閫�璐х瓑鎸夎鎸夋暟閲忓叆搴撶殑鍑哄叆鍙o紝涓烘壒閲忔眹鎬伙紝涓嶉�愯寤虹珛鏄庣粏锛涜繖浜涜鐮佸湪棣栨绉嶅瓙璐ㄦ鏃堕�氳繃鎸夋壒娆″畾浣嶆殏瀛樺簱瀛樿ˉ寤烘槑缁嗐��
+- 浜嬪姟娴佹按 DTO 澧炲姞 `bagCodeId`/`bagCode` 瀛楁锛涘嚭搴�/绉诲叆鎸夎鐮佽嚜鍔ㄦ洿鏂拌鐮佹槑缁嗐��
+- 姣忕瑪甯﹁鐮佺殑鍏ュ簱銆佸嚭搴撱�佺Щ搴撱�佽川妫�閮戒細鐢熸垚瀵瑰簲鐨� `mes_wm_transaction` 娴佹按骞跺洖濉鐮侊紝渚夸簬鍦ㄥ簱瀛樻祦姘撮〉闈㈡寜琚嬬爜绛涢�夎拷婧��
+
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/mes/wm/material-stock/page` | 搴撳瓨姹囨�诲垎椤碉紝鍝嶅簲澧炲姞琚嬬爜缁熻瀛楁 |
+| GET | `/mes/wm/material-stock/bag-details` | 鏌ヨ鎸囧畾搴撳瓨姹囨�昏褰曚笅鐨勫湪搴撹鐮佹槑缁� |
+| GET | `/mes/wm/transaction/page` | 搴撳瓨浜嬪姟娴佹按锛屾敮鎸� `bagCode` 绛涢�夊苟杩斿洖琚嬬爜 |
+
+### 琚嬬爜鏄庣粏鏌ヨ
+
+璇锋眰鍙傛暟锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| materialStockId | Long | 鏄� | 搴撳瓨姹囨�昏褰� ID |
+| bagCode | String | 鍚� | 琚嬬爜妯$硦鏌ヨ |
+| pageNo | Integer | 鏄� | 椤电爜 |
+| pageSize | Integer | 鏄� | 姣忛〉鏉℃暟 |
+
+鍝嶅簲瀛楁鍖呮嫭 `bagCode`銆乣batchCode`銆乣stockState`銆乣status`銆乣quantity`銆乣warehouseId`銆乣locationId`銆乣areaId`銆乣inboundTime` 鍜� `outboundTime`銆�
+
+搴撳瓨姹囨�诲垎椤靛搷搴旀柊澧烇細
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| bagCount | Long | 褰撳墠鍦ㄥ簱琚嬬爜鏄庣粏鏁伴噺 |
+| bagDetailSupported | Boolean | 鏄惁瀛樺湪琚嬬爜鏄庣粏锛涘巻鍙叉棤娉曡繕鍘熻鐮佺殑搴撳瓨涓� false |
+
+## 鍓嶇璋冪敤鏃跺簭
+
+1. 璋冪敤搴撳瓨鍙拌处鍒嗛〉鎺ュ彛鑾峰彇姹囨�昏褰曘��
+2. 瀵� `bagDetailSupported=true` 鐨勮褰曟樉绀衡�滄煡鐪嬭鐮佲�濄��
+3. 鐐瑰嚮鍚庤皟鐢� `/mes/wm/material-stock/bag-details`锛屼紶鍏ュ綋鍓嶈 `id` 浣滀负 `materialStockId`銆�
+4. 琚嬬爜鏄庣粏涓殑 `bagCode` 鍙户缁皟鐢ㄦ壒娆�/琚嬬爜杩芥函鎺ュ彛鏌ョ湅璐ㄦ鍜岀敓浜т俊鎭��
+5. 搴撳瓨娴佹按椤甸潰浣跨敤 `bagCode` 绛涢�夋椂锛屽睍绀鸿川妫�杩佺Щ浜х敓鐨勮鐮佺骇娴佹按銆�
+
+## 涓氬姟瑙勫垯
+
+- 鍚屼竴琚嬬爜鍙兘瀛樺湪涓�鏉″簱瀛樿鐮佹槑缁嗐��
+- 璐ㄦ鎸夊疄闄呰鐮佸畾浣嶆殏瀛樺簱瀛橈紝涓嶆寜鎵规闅忔満鎵e噺銆�
+- 鎶ュ簾琚嬬爜涓嶈鍏ュ湪搴撴槑缁嗘煡璇紝浣嗕繚鐣欐槑缁嗚褰曠敤浜庤拷婧��
+- 鏃犳硶浠庡巻鍙叉眹鎬诲簱瀛樿繕鍘熻鐮佹椂锛屼笉浼�犺鐮佹槑缁嗐��
+- SQL 鑴氭湰涓嶅寘鍚� `tenant_id` 瀛楁銆�
diff --git a/docs/sales_notice_to_product_sales.md b/docs/sales_notice_to_product_sales.md
index ff668cf..1eca419 100644
--- a/docs/sales_notice_to_product_sales.md
+++ b/docs/sales_notice_to_product_sales.md
@@ -101,6 +101,20 @@
**娉ㄦ剰锛�** 鎷h揣鏄庣粏闇�瑕佹墜鍔ㄦ坊鍔�
+## 鍙戣揣閫氱煡琛岀墿鏂欐牎楠�
+
+鏂板鎴栦慨鏀瑰彂璐ч�氱煡琛屾椂锛岀墿鏂欏繀椤诲叧鑱旀壒娆★紝涓旇鐗╂枡鎵规蹇呴』瀛樺湪姝e紡搴撳簱瀛樸�傛寮忓簱鎸囧簱瀛樼姸鎬佷负鍚堟牸搴擄紙`stockState = 20`锛夌殑搴撳瓨璁板綍銆�
+
+| 鏍¢獙椤� | 瑙勫垯 |
+|--------|------|
+| 鐗╂枡 | 蹇呴』瀛樺湪涓斿惎鐢� |
+| 鎵规 | `batchId` 鎴� `batchCode` 蹇呴』鑳藉尮閰嶆湁鏁堟壒娆★紝涓旀壒娆″睘浜庢墍閫夌墿鏂� |
+| 姝e紡搴撳瓨 | 浠呯粺璁″悎鏍煎簱搴撳瓨锛屼笉缁熻鏆傚瓨搴撳簱瀛� |
+| 鏁伴噺 | 鍚屼竴鐗╂枡銆佹壒娆$殑鍚堟牸搴撳簱瀛樺悎璁″繀椤讳笉灏戜簬鍙戣揣鏁伴噺 |
+| 搴撳瓨鍙樻洿 | 淇濆瓨鍙戣揣閫氱煡琛屾椂涓嶆墸鍑忋�佷笉棰勫崰搴撳瓨锛屽疄闄呭嚭搴撴椂鍐嶆鏍¢獙 |
+
+搴撳瓨涓嶈冻鏃讹紝鍓嶇搴旂洿鎺ュ睍绀哄悗绔繑鍥炵殑鈥滃簱瀛樻暟閲忎笉瓒斥�濅笟鍔℃彁绀猴紝骞朵繚鐣欑敤鎴峰~鍐欑殑琛ㄥ崟鍐呭銆�
+
## 瀛楁鏄犲皠琛�
### 涓昏〃瀛楁鏄犲皠
diff --git a/docs/scan_in_multi_type_inbound.md b/docs/scan_in_multi_type_inbound.md
new file mode 100644
index 0000000..283635c
--- /dev/null
+++ b/docs/scan_in_multi_type_inbound.md
@@ -0,0 +1,80 @@
+# 鐢熶骇绾挎壂鐮佸叆搴擄細鏀寔琚嬬爜/鎵樼洏鐮�/鎵规鐮� + 鍘绘帀璁惧缂栫爜 - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- 鐢熶骇绾挎壂鐮佸叆搴擄紙`src/views/mes/pro/scan-in/index.vue`锛�
+
+## 涓氬姟鍙樻洿
+
+1. **鍘绘帀璁惧缂栫爜**锛氭壂鐮佸叆搴撲笉鍐嶅綍鍏�/灞曠ず璁惧缂栫爜锛屾帴鍙� `deviceCode` 鏀逛负闈炲繀濉紝鍓嶇涓嶅啀浼犮��
+2. **浜х嚎銆佸簱鍖恒�佸簱浣嶆敼涓轰笅鎷夐�夋嫨**锛氭暟鎹簮涓虹幇鏈夌簿绠�鍒楄〃鎺ュ彛锛屼笉鍐嶆墜濉紪鍙枫��
+3. **绛夊緟鎵爜鍖哄鍔�"鎵爜绫诲瀷"閫夋嫨**锛氳鐮� / 鎵樼洏鐮� / 鎵规鐮佷笁閫変竴锛屾壂鐮佹闅忕被鍨嬫彁浜ゅ搴旂爜鍊笺��
+
+## API
+
+### 涓绘帴鍙o細杩芥函鐮佹壂鐮佸叆搴�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /mes/pro/scan-in/inbound | 杩芥函鐮佹壂鐮佸叆搴擄紙琚嬬爜/鎵樼洏鐮�/鎵规鐮侊級 |
+
+**璇锋眰鍙傛暟锛堟湰娆″彉鏇达級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 鍙樻洿 | 璇存槑 |
+|------|------|------|------|------|
+| scanType | String | 鍚� | 鏂板 | 鎵爜绫诲瀷锛歚BAG` 琚嬬爜 / `PALLET` 鎵樼洏鐮� / `BATCH` 鎵规鐮侊紝涓嶄紶榛樿 `BAG` |
+| deviceCode | String | 鍚� | 鏀逛负闈炲繀濉� | 璁惧缂栫爜锛屽墠绔笉鍐嶄紶 |
+| bagCode | String | 鏄� | 璇箟鎵╁睍 | 鎵爜鍐呭锛氳鐮�/鎵樼洏鐮�/鎵规鐮佺殑鐮佸�硷紙鍚复鏃剁爜锛� |
+| eventId | String | 鏄� | - | 浜嬩欢鍙凤紙寤鸿鐢� `{scanType}-{鏃堕棿鎴硙` 淇濊瘉鍞竴锛� |
+| quantity | Number | 鏄� | - | 琚嬬爜鍦烘櫙浼� 1锛涙墭鐩�/鎵规鍦烘櫙鍚庣蹇界暐璇ュ�硷紝鎸夊凡瑁呰鏁�/鎵规琚嬫暟璁$畻 |
+| lineCode | String | 鍚� | - | 浜х嚎缂栫爜锛堝墠绔笅鎷夐�夋嫨锛� |
+| locationId | Long | 鏄� | - | WIP 鏆傚瓨搴撳尯缂栧彿锛堝墠绔笅鎷夐�夋嫨锛� |
+| areaId | Long | 鏄� | - | WIP 鏆傚瓨搴撲綅缂栧彿锛堝墠绔笅鎷夐�夋嫨锛� |
+
+**鍝嶅簲鏂板瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| scanType | String | 鏈鎵爜绫诲瀷锛圔AG/PALLET/BATCH锛� |
+
+**鍏ュ簱鏁伴噺鍙e緞锛�**
+
+| scanType | 鏁伴噺 | 璇存槑 |
+|----------|------|------|
+| BAG | 鍓嶇浼� 1 | 鍗曡鍏ュ簱 |
+| PALLET | 鎵樼洏宸茶琚嬫暟 `bag_count` | 鏁存墭涓�娆℃�у叆鏆傚瓨搴� |
+| BATCH | 鎵规琚嬫暟 `bag_quantity` | 鏁存壒涓�娆℃�у叆鏆傚瓨搴� |
+
+**鍏ュ簱鍘婚噸锛�** 琚嬬爜銆佹墭鐩樼爜銆佹壒娆$爜鍧囦互鍚勮嚜 `inbound_event_id` 鍒ゆ柇鏄惁宸插叆搴擄紝閲嶅鎵爜杩斿洖瀵瑰簲"宸插叆搴�"閿欒鐮侊紝涓嶄細閲嶅鍐欏叆搴撳瓨浜嬪姟銆�
+
+### 涓嬫媺鏁版嵁婧愶紙澶嶇敤鐜版湁鎺ュ彛锛屾棤鏂板锛�
+
+| 鐢ㄩ�� | 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|------|
+| 浜х嚎 | GET | /mes/pro/line/simple-list | 杩斿洖鍚敤浜х嚎 `{id, code, name}` |
+| 搴撳尯 | GET | /mes/wm/warehouse-location/simple-list | 杩斿洖搴撳尯 `{id, code, name}`锛涢�夊簱鍖哄悗鑱斿姩鍔犺浇鍏朵笅搴撲綅 |
+| 搴撲綅 | GET | /mes/wm/warehouse-area/simple-list?locationId= | 杩斿洖搴撲綅 `{id, code, name}` |
+
+## 鏁版嵁甯﹀叆璇存槑
+
+- 浜х嚎/搴撳尯/搴撲綅锛氫笅鎷夐�夋嫨锛岄〉闈� `onMounted` 涓�娆℃�у姞杞戒骇绾裤�佸簱鍖猴紱閫夋嫨搴撳尯鍚庢寜 `locationId` 鑱斿姩鍔犺浇搴撲綅銆�
+- 鎵爜鎻愪氦锛歚locationId`銆乣areaId`銆乣scanType`銆乣bagCode` 涓�骞跺甫鍏ュ叆搴撴帴鍙o紱浜х嚎 `lineCode` 鏈夊�兼墠浼犮��
+- 浜嬩欢鍒楄〃/鐪嬫澘锛氫互 `scanType` 鍖哄垎杩芥函鐮佺被鍨嬪睍绀猴紙鍘嗗彶鏃犵被鍨嬬殑鏁版嵁榛樿鏄剧ず"琚嬬爜"锛夈��
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鎵爜绫诲瀷 | 绛夊緟鎵爜鍖轰笅鎷� | 涓夐�変竴锛氳鐮�/鎵樼洏鐮�/鎵规鐮� |
+| 鐢熶骇浜х嚎 | 鎵爜鍗¢厤缃尯 + 鐘舵�佸崱 | 涓嬫媺閫夋嫨锛屽彲娓呯┖ |
+| WIP 鏆傚瓨搴撳尯/搴撲綅 | 鎵爜鍗¢厤缃尯 + 鐘舵�佸崱 | 涓嬫媺閫夋嫨锛屽簱浣嶉殢搴撳尯鑱斿姩绂佺敤/鍚敤 |
+| 鏈�杩戝叆搴撹拷婧爜 | 缁熻鍗� | 灞曠ず鏈�鏂颁竴鏉℃壂鐮佸唴瀹� |
+| 杩芥函鐮�/绫诲瀷/浜х嚎 | 鏈�杩戞壂鐮佷簨浠惰〃 | 琛ㄦ牸鏂板"绫诲瀷"鍒楋紝鍘�"璁惧/浜х嚎"鍒楁敼涓�"浜х嚎" |
+| 鏈�杩戞壂鐮佺被鍨� | 鐘舵�佸崱 | 灞曠ず鏈�鏂颁簨浠舵壂鐮佺被鍨� |
+
+## 娉ㄦ剰浜嬮」
+
+1. 鍚庣闇�**鎵ц SQL 鑴氭湰** `sql/mysql/mes_pro_scan_event_scan_type.sql`锛坄mes_pro_scan_event` 澧炲姞 `scan_type` 鍒楋紝`mes_pro_pallet` 澧炲姞 `inbound_event_id`/`inbound_time` 鍒楋級锛屽啀**閲嶆柊缂栬瘧骞堕噸鍚�**銆�
+2. 閲嶅惎鍓嶆棫鎺ュ彛浼氬拷鐣� `scanType`锛堟寜琚嬬爜澶勭悊锛夛紝鎵樼洏/鎵规鐮佹壂鐮佷細杩斿洖"琚嬬爜涓嶅瓨鍦�"锛涘墠绔被鍨嬩笅鎷夌収甯稿彲閫夛紝鍔熻兘闄嶇骇涓轰粎琚嬬爜銆�
+3. 浜х嚎/搴撳尯/搴撲綅涓嬫媺鑻ユ帴鍙� 404锛堝悗绔湭閲嶅惎锛夛紝涓嬫媺涓虹┖锛岄渶鍏堜繚闅滃悗绔彲鐢ㄣ��
+4. 鎵樼洏銆佹壒娆℃暣鎵�/鏁存壒鍏ュ簱浼氬悓姝ユ妸鍏朵笅鏈叆搴撹鐮佹爣璁颁负宸插叆搴擄紝閬垮厤鍚庣画鍗曡鎵爜閲嶅鍏ュ簱銆�
diff --git a/docs/seed_flow_trace_integration.md b/docs/seed_flow_trace_integration.md
new file mode 100644
index 0000000..ff9ecd5
--- /dev/null
+++ b/docs/seed_flow_trace_integration.md
@@ -0,0 +1,53 @@
+# 绉嶅瓙娴佸悜淇℃伅锛堥攢鍞嚭搴撳嚭鍏ュ簱娴佹按锛� - H5 婧簮鑱旇皟璇存槑
+
+## 鑳屾櫙
+
+H5 鎵爜婧簮椤碉紙`mes.trace-base-url` 鎸囧悜鐨� `trace.html`锛夋柊澧炪�岀瀛愭祦鍚戜俊鎭�嶅尯鍧楋細
+鎸�**鎵规鍏ㄦ祦姘�**灞曠ず璇ユ壒娆$殑鍏ュ簱涓庡嚭搴撹褰曪紙鏁版嵁婧愪负閿�鍞嚭搴� `/sales-outbound/product-sales` 妯″潡瀵瑰簲鐨勫簱瀛樹簨鍔★級銆�
+
+鍚屾椂淇鏃㈡湁銆岄攢鍞幓鍚戙�嶆暟鎹摼璺細绉嶅瓙閿�鍞嚭搴撴寜琚嬬爜/鎵樼洏鎵爜鎷h揣鏃讹紝鎵规鍙峰彧鍐欏叆鍑哄簱**鏄庣粏琛�**
+锛坄mes_wm_product_sales_detail.batch_code`锛夛紝鍘熸煡璇㈠彧鍖归厤鍑哄簱**琛岃〃**鎵规鍙凤紝瀵艰嚧婧簮姘歌繙鏌ヤ笉鍒伴攢鍞嚭搴撲俊鎭��
+
+## 娑夊強鎺ュ彛
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /public/mes/trace/query?code={杩芥函鐮亇 | H5 婧簮鏌ヨ锛堝厤鐧诲綍锛夛紝鍝嶅簲鏂板 `seedFlows` 鍖哄潡 |
+
+**鍝嶅簲鏂板瀛楁 `seedFlows`锛堟壒娆″嚭鍏ュ簱娴佹按锛屾寜浜嬪姟鏃堕棿鍗囧簭锛夛細**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| type | Integer | 浜嬪姟鏂瑰悜锛�1-鍏ュ簱 2-鍑哄簱 |
+| bizType | Integer | 涓氬姟绫诲瀷锛�118-鐢熶骇鍏ュ簱銆�119-閿�鍞嚭搴撱��124-浜у搧浜у嚭銆�120-閿�鍞��璐у叆搴撶瓑锛岃 MesBizTypeConstants锛� |
+| bizCode | String | 鏉ユ簮涓氬姟鍗曞彿锛堝閿�鍞嚭搴撳崟鍙� SL_xxx锛� |
+| quantity | BigDecimal | 鍙樺姩鏁伴噺锛堝嚭搴撲负璐熸暟锛屽睍绀烘椂鍙栫粷瀵瑰�硷級 |
+| transactionTime | LocalDateTime | 浜嬪姟鍙戠敓鏃堕棿 |
+| warehouseName | String | 浠撳簱鍚嶇О |
+| locationName | String | 搴撳尯鍚嶇О |
+| areaName | String | 搴撲綅鍚嶇О |
+| clientName | String | 瀹㈡埛鍚嶇О锛堜粎閿�鍞嚭搴撴祦姘村甫鍑猴紝鏉ヨ嚜鍑哄簱鍗曞揩鐓э級 |
+
+**`salesTargets` 瀛楁鍙樺寲锛堝悓鎺ュ彛锛屽悜鍚庡吋瀹癸級锛�**
+
+- 鏌ヨ鍙e緞鎵╁睍锛氭壒娆″彿闄ゅ尮閰嶅嚭搴撹澶栵紝鍚屾椂鎸夊嚭搴撴槑缁嗚仛鍚堝尮閰嶏紙鎺掗櫎宸插彇娑堝崟鎹級銆�
+- 鏂板濉厖 `clientName`锛堝鎴峰悕绉板揩鐓э級銆乣clientCode` 涓嶅彉锛涙鍓嶆亽涓� null銆�
+
+## H5 椤甸潰灞曠ず瑙勫垯
+
+| 鍖哄潡 | 灞曠ず鏉′欢 | 鍒� |
+|------|----------|----|
+| 绉嶅瓙娴佸悜淇℃伅 | `seedFlows` 闈炵┖锛堜紭鍏堬級 | 鏂瑰悜锛堝叆搴�/鍑哄簱寰芥爣锛夈�佷笟鍔°�佹潵婧愬崟鍙枫�佸鎴枫�佹暟閲忋�佹椂闂淬�佷粨搴�/搴撳尯 |
+| 绉嶅瓙娴佸悜淇℃伅锛堝洖閫�锛� | `seedFlows` 涓虹┖浣� `salesTargets` 闈炵┖ | 閿�鍞嚭搴撳崟銆佸鎴枫�佹暟閲忋�佹棩鏈� |
+
+## 閮ㄧ讲娉ㄦ剰浜嬮」
+
+1. `trace.html` 涓� `yudao-server` 闈欐�佽祫婧愶紙`src/main/resources/static/trace.html`锛夛紝闇�**閲嶆柊鎵撳寘鍙戝竷鍚庣**锛�
+ 鑻ョ敓浜� nginx 鐨� `/prod/trace.html`锛堝 `http://47.97.181.254:9008/prod/trace.html`锛夋槸鐙珛鎷疯礉閮ㄧ讲鐨勶紝闇�鍚屾鏇挎崲璇ユ枃浠躲��
+2. 閿�鍞嚭搴撴祦姘寸殑瀹㈡埛鍚嶇О鍙� `mes_wm_product_sales.client_name` 蹇収瀛楁锛岃姹傜幆澧冨簱鍖呭惈璇ュ垪锛�
+ 缁忔帓鏌� `mom-thzy` 搴撳凡鏈夛紝**`mom-xgdl` 搴撶己澶� `client_name` / `outbound_time` / `outbound_user_id` 鍒�**锛堣惤鍚庝簬浠g爜锛夛紝浣跨敤 local 鐜鏃堕渶鍏堣ˉ鍒椼��
+3. 鍘嗗彶鍑哄簱鍗曚笉浼氳ˉ鐢熸垚娴佹按锛屼粎鏂板嚭搴撳彲鐪嬪埌瀹屾暣鍏�+鍑鸿褰曪紱鏃犳祦姘存椂鍥為��灞曠ず閿�鍞嚭搴撳崟銆�
+
+## 楠岃瘉鏁版嵁锛坢om-thzy锛�
+
+鎵规 `PC20260819twoITEM_001`锛氬叆搴� 100锛堜骇鍝佷骇鍑猴紝铏氭嫙绾胯竟浠撳簱锛夆啋 鍑哄簱 1锛堥攢鍞嚭搴� SL_20260901002锛屾垚鍝佸悎鏍煎簱锛屽崡閫氬鎴凤級銆�
diff --git a/docs/seed_quality_bag_granularity.md b/docs/seed_quality_bag_granularity.md
new file mode 100644
index 0000000..c6c0bc3
--- /dev/null
+++ b/docs/seed_quality_bag_granularity.md
@@ -0,0 +1,88 @@
+# 绉嶅瓙璐ㄦ鎸夎鐮佺矑搴︽祦杞簱瀛� - 鍓嶇鑱旇皟鏂规
+
+## 鑳屾櫙
+
+绉嶅瓙璐ㄦ鍘熼�昏緫锛氳川妫�鍚堟牸鍚�**鏁存壒**灏嗕粨搴撴壒娆″簱瀛樹粠鏆傚瓨搴�(10)杞负鍚堟牸搴�(20)锛屼竴琚嬪悎鏍煎嵆鏁存壒鏀捐锛岄绮掑害杩囩矖銆�
+
+鏈鏀归�犱负**鎸夎鐮佺矑搴�**锛氳川妫�鍙拡瀵硅鎵殑閭d竴琚嬶紝鍚堟牸浠呭皢璇ヨ瀵瑰簲搴撳瓨浠庢殏瀛樺簱杞叆鍚堟牸搴擄紝鍚屾壒娆″叾浠栬淇濇寔鏆傚瓨搴撳緟妫�锛涘悓鏃剁粰姣忚鎵撲笂璐ㄦ鏍囪锛坄qc_status`锛夛紝閿�鍞嚭搴撴壂琚嬬爜/鎵樼洏鏃舵牎楠屽凡璐ㄦ鍚堟牸鎵嶅厑璁稿嚭搴撱��
+
+## 娑夊強椤甸潰
+
+- 璐ㄩ噺绠$悊-绉嶅瓙璐ㄦ锛堟彁浜よ川妫�琛ㄥ崟锛�
+- 閿�鍞嚭搴�-鎵爜鎷h揣锛堟壂琚嬬爜/鎵樼洏锛�
+- 搴撳瓨鍙拌处锛坄mes_wm_material_stock` 鍒嗛〉锛氬悓鎵规鍙兘鍚屾椂鍑虹幇鏆傚瓨搴撲笌鍚堟牸搴撲袱鏉¤褰曪紝鐘舵�佸垪宸叉寜瀛楀吀灞曠ず鏂囧瓧锛�
+
+## API
+
+鏈**鏃犳柊澧�/淇敼鎺ュ彛**锛屽潎涓烘棦鏈夋帴鍙g殑鏍¢獙璇箟涓庢暟鎹祦杞彉鍖栥��
+
+### 1. 鎻愪氦绉嶅瓙璐ㄦ
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/mes/qc/seed-quality/submit` | 鎻愪氦绉嶅瓙璐ㄦ锛堟寜琚嬬爜锛� |
+
+**璇锋眰鍙傛暟锛堜笉鍙橈級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鏄� | 琚嬬爜锛堟壂鐮佸唴瀹癸級锛�**蹇呴』涓烘湁鏁堣鐮�** |
+| batchCode | String | 鍚� | 鐢熶骇鎵规鍙凤紙鍏煎棰勭暀锛� |
+| indicators | Array | 鏄� | 鍥涢」鎸囨爣锛坧urity/cleanliness/germination_rate/moisture锛� |
+| reason | String | 鍚� | 澶囨敞 |
+
+**鍝嶅簲锛堜笉鍙橈級锛�** `{ "code": 0, "data": 璐ㄦ璁板綍ID }`
+
+### 2. 鎵爜鎷h揣
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/mes/wm/product-sales/scan` | 鎵爜鎷h揣锛堣鐮�/鎵樼洏锛� |
+
+**璇锋眰鍙傛暟锛堜笉鍙橈級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| salesId | Long | 鏄� | 閿�鍞嚭搴撳崟ID |
+| scanContent | String | 鏄� | 琚嬬爜鎴栨墭鐩樼爜 |
+| quantity | BigDecimal | 鍚� | 鍑哄簱鏁伴噺锛堢己鐪佺敤琛屾暟閲忥級 |
+
+**鍝嶅簲锛堜笉鍙橈級锛�** 娌跨敤 `MesWmProductSalesScanRespVO`锛宍availableQuantity`/`outboundQuantity` 鍧囧熀浜�**鍚堟牸搴�**搴撳瓨璁$畻銆�
+
+## 涓氬姟瑙勫垯鍙樺寲
+
+| 鍦烘櫙 | 鍘熻涓� | 鏂拌涓� |
+|------|--------|--------|
+| 绉嶅瓙璐ㄦ鎻愪氦闈炶鐮� | 鍏煎鎵规鐮佹彁浜� | 鎶ラ敊銆屾湭瑙f瀽鍒版湁鏁堣鐮侊紝绉嶅瓙璐ㄦ蹇呴』浠ヨ鐮佹彁浜ゃ�� |
+| 璐ㄦ鍚堟牸 | 鏁存壒鏆傚瓨搴撯啋鍚堟牸搴� | 浠呰琚嬶細鏆傚瓨搴� -1銆佸悎鏍煎簱 +1锛堝悓鎵规鍏朵粬琚嬩粛涓烘殏瀛樺簱锛夛紱琚嬬爜 qc_status=20 |
+| 璐ㄦ涓嶅悎鏍� | 鏃犲簱瀛樺彉鍖� | 璇ヨ浠庢殏瀛樺簱瀛樻竻闄わ紙鎶ュ簾锛夛紱琚嬬爜 qc_status=30 |
+| 閿�鍞嚭搴撴壂琚嬬爜 | 涓嶆牎楠岃川妫� | qc_status 蹇呴』涓� 20锛屽惁鍒欐姤銆岃琚嬬爜鏈川妫�鍚堟牸锛岀姝㈠嚭搴撱�� |
+| 閿�鍞嚭搴撴壂鎵樼洏 | 涓嶆牎楠岃川妫� | 鎵樼洏涓嬫墍鏈夎鐮� qc_status 蹇呴』涓� 20锛屽惁鍒欐姤銆屾墭鐩樹笅瀛樺湪鏈川妫�琚嬬爜锛岀姝㈡暣鎵樺嚭搴撱�� |
+| 閿�鍞嚭搴撻�夊簱瀛� | 鍙兘閫変腑鏆傚瓨搴撹褰� | 浠呬粠鍚堟牸搴�(20)璁板綍涓�夋暟閲忚冻澶熺殑 |
+
+## 搴撳瓨璇箟璇存槑
+
+鍚屼竴娆★紙鍏ュ簱浠嶆寜鎵规鑱氬悎锛夎川妫�鍚堟牸鍚庯紝鍚屾壒娆� `mes_wm_material_stock` 浼氬悓鏃跺瓨鍦ㄤ袱鏉¤褰曪細
+
+| 璁板綍 | stock_state | 鍚箟 | 鏄惁鍙嚭搴� |
+|------|-------------|------|-----------|
+| 鏆傚瓨搴� | 10 | 璇ユ壒娆℃湭璐ㄦ鐨勫墿浣欒鏁� | 鍚� |
+| 鍚堟牸搴� | 20 | 宸茶川妫�鍚堟牸銆佸彲閿�鍞殑琚嬫暟 | 鏄� |
+
+绀轰緥锛氭壒娆″叆搴� 3 琚嬶紙quantity=3銆佹殏瀛樺簱锛夈�傝川妫�鍚堟牸 1 琚嬪悗 鈫� 鏆傚瓨搴� quantity=2 + 鍚堟牸搴� quantity=1銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 璐ㄦ鐘舵�侊紙qc_status锛� | 绉嶅瓙璐ㄦ鎻愪氦缁撴灉鍙嶉 | 鍓嶇鏃犻渶灞曠ず锛屽悗绔湪绗簩娆℃彁浜ゅ悓涓�琚嬬爜鏃舵姤銆岃琚嬬爜宸茶川妫�锛岀姝㈤噸澶嶆彁浜ゃ�� |
+| 搴撳瓨鐘舵�� | 搴撳瓨鍙拌处鍒楄〃 | 鍚屼竴鐗╂枡/鎵规鍙兘鍑虹幇涓ゆ潯涓嶅悓鐘舵�佽褰曪紝鍧囦负姝e父鐜拌薄 |
+| 鍙嚭搴撴暟閲� | 鎵爜鎷h揣缁撴灉 | 浠� `availableQuantity` 涓哄噯锛屽彧鍙嶆槧鍚堟牸搴撳簱瀛� |
+
+## 娉ㄦ剰浜嬮」
+
+1. **绉嶅瓙璐ㄦ鎻愪氦蹇呴』浼犺鐮�**锛歚code` 瀛楁鐜板湪蹇呴』鏄郴缁熶腑瀛樺湪鐨勬湁鏁堣鐮侊紱浠呬紶鎵规鍙蜂笉鍐嶈鎺ュ彈銆�
+2. **璐ㄦ鎴愬姛鍚庡簱瀛樻�绘暟涓嶅彉**锛氭殏瀛樺簱 -1 涓庡悎鏍煎簱 +1 鍚屾鍙戠敓锛岀墿鏂欏湪搴撴�绘暟瀹堟亽锛屽彧鏄粠"寰呮"鍙樹负"鍙敭"銆�
+3. **鍚屾壒娆″弻鐘舵�佸苟瀛�**锛氭殏瀛樺簱涓庡悎鏍煎簱璁板綍鍚屾椂瀛樺湪鏄鏈熻涓猴紝鍓嶇鍦ㄥ簱瀛樺彴璐︺�佸嚭搴撻�夊簱瀛樻椂搴旇兘鎺ュ彈鍚屼竴鐗╂枡/鎵规鍑虹幇澶氳銆�
+4. **鍑哄簱鏁伴噺鎻愮ず**锛氳嫢鏌愭壒娆′粎閮ㄥ垎琚嬭川妫�鍚堟牸锛屾壂鐮佹嫞璐у彲鍑哄簱鏁伴噺鍙寘鍚悎鏍艰锛屽墠绔彁绀哄簲浠ユ帴鍙h繑鍥炵殑 `availableQuantity` 涓哄噯銆�
+5. **涓嶅悎鏍艰鎶ュ簾**锛氳川妫�涓嶅悎鏍肩殑琚嬩細浠庢殏瀛樺簱瀛樹腑鎵i櫎锛屼笖璇ヨ鐮� qc_status=30锛岀姝㈠嚭搴撱��
diff --git a/docs/sql/pro_batch_processing_team.sql b/docs/sql/pro_batch_processing_team.sql
new file mode 100644
index 0000000..0ecc824
--- /dev/null
+++ b/docs/sql/pro_batch_processing_team.sql
@@ -0,0 +1,3 @@
+-- 鎵规鐢熶骇绠$悊锛氭柊澧炪�屽姞宸ョ彮缁勩�嶅瓧娈�
+-- 鎵ц搴擄細mom-thzy锛坙ocal锛�
+ALTER TABLE mes_pro_batch ADD COLUMN processing_team VARCHAR(64) NULL COMMENT '鍔犲伐鐝粍锛堟墜宸ュ~鍐欙級' AFTER line_name;
diff --git a/docs/sql/trace_platform_01_schema.sql b/docs/sql/trace_platform_01_schema.sql
new file mode 100644
index 0000000..b4bd50f
--- /dev/null
+++ b/docs/sql/trace_platform_01_schema.sql
@@ -0,0 +1,79 @@
+-- 鎵规杩芥函鏁版嵁妯″瀷琛ュ己
+-- 璇存槑锛氬瓧娈靛厛鍏佽涓虹┖锛屽巻鍙叉暟鎹洖濉畬鎴愬悗鍐嶈瘎浼版槸鍚︽敹绱х害鏉熴��
+-- 娉ㄦ剰锛氶」鐩笉浣跨敤 tenant_id锛涙墽琛屽墠璇风‘璁ゅ瓧娈靛拰绱㈠紩涓嶅瓨鍦ㄣ��
+
+ALTER TABLE mes_wm_batch
+ ADD COLUMN pro_batch_id BIGINT NULL COMMENT '瀵瑰簲鐢熶骇鎵规ID' AFTER id;
+ALTER TABLE mes_wm_batch
+ ADD INDEX idx_mes_wm_batch_pro_batch_id (pro_batch_id);
+
+ALTER TABLE mes_wm_sn
+ ADD COLUMN pro_batch_id BIGINT NULL COMMENT '鐢熶骇鎵规ID' AFTER id;
+ALTER TABLE mes_wm_sn
+ ADD COLUMN bag_code_id BIGINT NULL COMMENT '琚嬬爜ID' AFTER pro_batch_id;
+ALTER TABLE mes_wm_sn
+ ADD COLUMN pallet_id BIGINT NULL COMMENT '鎵樼洏ID' AFTER bag_code_id;
+ALTER TABLE mes_wm_sn
+ ADD COLUMN sales_id BIGINT NULL COMMENT '閿�鍞嚭搴撳崟ID' AFTER pallet_id;
+ALTER TABLE mes_wm_sn
+ ADD INDEX idx_mes_wm_sn_pro_batch_id (pro_batch_id);
+ALTER TABLE mes_wm_sn
+ ADD INDEX idx_mes_wm_sn_bag_code_id (bag_code_id);
+
+ALTER TABLE mes_qc_seed_quality
+ ADD COLUMN batch_id BIGINT NULL COMMENT '鐢熶骇鎵规ID' AFTER item_id;
+ALTER TABLE mes_qc_seed_quality
+ ADD INDEX idx_mes_qc_seed_quality_batch_id (batch_id);
+
+CREATE TABLE mes_trace_event (
+ id BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ event_no VARCHAR(64) NOT NULL COMMENT '浜嬩欢缂栧彿',
+ event_type VARCHAR(32) NOT NULL COMMENT '浜嬩欢绫诲瀷',
+ event_category VARCHAR(32) NULL COMMENT '浜嬩欢鍒嗙被',
+ event_time DATETIME NOT NULL COMMENT '浜嬩欢鏃堕棿',
+ pro_batch_id BIGINT NULL COMMENT '鐢熶骇鎵规ID',
+ wm_batch_id BIGINT NULL COMMENT '浠撳偍鎵规ID',
+ bag_code_id BIGINT NULL COMMENT '琚嬬爜ID',
+ pallet_id BIGINT NULL COMMENT '鎵樼洏ID',
+ sn_id BIGINT NULL COMMENT 'SN ID',
+ item_id BIGINT NULL COMMENT '鐗╂枡ID',
+ biz_type VARCHAR(32) NULL COMMENT '涓氬姟绫诲瀷',
+ biz_id BIGINT NULL COMMENT '涓氬姟ID',
+ biz_code VARCHAR(100) NULL COMMENT '涓氬姟缂栫爜',
+ biz_line_id BIGINT NULL COMMENT '涓氬姟鏄庣粏ID',
+ from_node_type VARCHAR(32) NULL COMMENT '鏉ユ簮鑺傜偣绫诲瀷',
+ from_node_id BIGINT NULL COMMENT '鏉ユ簮鑺傜偣ID',
+ from_node_code VARCHAR(100) NULL COMMENT '鏉ユ簮鑺傜偣缂栫爜',
+ to_node_type VARCHAR(32) NULL COMMENT '鐩爣鑺傜偣绫诲瀷',
+ to_node_id BIGINT NULL COMMENT '鐩爣鑺傜偣ID',
+ to_node_code VARCHAR(100) NULL COMMENT '鐩爣鑺傜偣缂栫爜',
+ quantity DECIMAL(18, 6) NULL COMMENT '鏁伴噺',
+ warehouse_id BIGINT NULL COMMENT '浠撳簱ID',
+ location_id BIGINT NULL COMMENT '搴撳尯ID',
+ area_id BIGINT NULL COMMENT '搴撲綅ID',
+ line_id BIGINT NULL COMMENT '浜х嚎ID',
+ work_order_id BIGINT NULL COMMENT '宸ュ崟ID',
+ process_id BIGINT NULL COMMENT '宸ュ簭ID',
+ sales_id BIGINT NULL COMMENT '閿�鍞嚭搴撳崟ID',
+ quality_id BIGINT NULL COMMENT '璐ㄦ璁板綍ID',
+ operator_id BIGINT NULL COMMENT '鎿嶄綔浜篒D',
+ payload_json JSON NULL COMMENT '浜嬩欢鎵╁睍鏁版嵁',
+ content_hash VARCHAR(64) NULL COMMENT '浜嬩欢鍐呭SHA-256鎽樿',
+ prev_hash VARCHAR(64) NULL COMMENT '鍓嶄竴浜嬩欢鎽樿',
+ creator VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ updater VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ deleted BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (id),
+ UNIQUE KEY uk_mes_trace_event_no (event_no),
+ KEY idx_mes_trace_event_batch_time (pro_batch_id, event_time),
+ KEY idx_mes_trace_event_biz (biz_type, biz_id, biz_line_id),
+ KEY idx_mes_trace_event_nodes (from_node_id, to_node_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES缁熶竴杩芥函浜嬩欢';
+
+-- 鍘嗗彶鏁版嵁鍥炲~绀轰緥锛岀‘璁ゆ暟鎹川閲忓悗鎵ц锛�
+-- UPDATE mes_wm_batch w JOIN mes_pro_batch p ON p.code = w.code AND p.deleted = b'0'
+-- SET w.pro_batch_id = p.id WHERE w.pro_batch_id IS NULL AND w.deleted = b'0';
+-- UPDATE mes_qc_seed_quality q JOIN mes_pro_batch p ON p.code = q.batch_code AND p.deleted = b'0'
+-- SET q.batch_id = p.id WHERE q.batch_id IS NULL AND q.deleted = b'0';
diff --git a/docs/wm_transaction_query.md b/docs/wm_transaction_query.md
index 33b616f..c48c2b9 100644
--- a/docs/wm_transaction_query.md
+++ b/docs/wm_transaction_query.md
@@ -9,6 +9,7 @@
| 鏂规硶 | 璺緞 | 璇存槑 |
|------|------|------|
| GET | /mes/wm/transaction/page | 鍒嗛〉鏌ヨ搴撳瓨浜嬪姟娴佹按 |
+| GET | /mes/pro/batch/get-by-code | 鐐瑰嚮鎵规鍙锋煡璇㈢敓浜ф壒娆°�佹墭鐩樺強琚嬬爜淇℃伅 |
### 璇锋眰鍙傛暟
@@ -23,10 +24,37 @@
| bizType | Integer | 鍚� | 涓氬姟绫诲瀷 |
| bizCode | String | 鍚� | 涓氬姟鍗曞彿锛屾ā绯婂尮閰� |
| materialStockId | Long | 鍚� | 搴撳瓨璁板綍ID |
+| bagCode | String | 鍚� | 琚嬬爜锛屾ā绯婂尮閰嶏紙璐ㄦ銆侀攢鍞嚭搴撶瓑琚嬬爜绾ф祦姘达級 |
| startTime | String | 鍚� | 寮�濮嬫椂闂达紙鏍煎紡锛歽yyy-MM-dd HH:mm:ss锛� |
| endTime | String | 鍚� | 缁撴潫鏃堕棿锛堟牸寮忥細yyyy-MM-dd HH:mm:ss锛� |
| pageNo | Integer | 鏄� | 椤电爜锛岄粯璁�1 |
| pageSize | Integer | 鏄� | 姣忛〉鏉℃暟锛岄粯璁�10 |
+
+### 鎵规杩芥函鏌ヨ
+
+鐐瑰嚮娴佹按鍒楄〃涓殑鎵规鍙锋椂锛屼娇鐢ㄥ綋鍓嶈鐨� `batchCode` 璋冪敤浠ヤ笅鎺ュ彛锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鏄� | 鎵规鍙锋垨鎵规浜岀淮鐮佸唴瀹� |
+
+璇锋眰绀轰緥锛歚GET /mes/pro/batch/get-by-code?code={batchCode}`
+
+鎺ュ彛杩斿洖鐨勯噸鐐瑰瓧娈碉細
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| id | Long | 鐢熶骇鎵规ID |
+| code | String | 姝e紡鎵规鍙� |
+| tempCode | String | 涓存椂鎵规鐮� |
+| itemCode | String | 鐗╂枡缂栫爜 |
+| itemName | String | 鐗╂枡鍚嶇О |
+| workers | Array | 鎵规浜哄憳閰嶇疆 |
+| pallets | Array | 鎵规涓嬬殑鎵樼洏鍒楄〃 |
+| bagTotal | Integer | 琚嬬爜鎬绘暟 |
+| bags | Array | 鎵规涓嬬殑琚嬬爜鍒楄〃 |
+
+璇ユ帴鍙e悓鏃舵敮鎸佹寮忔壒娆″彿鍜屼复鏃舵壒娆$爜銆傝嫢鎵规鍙蜂负绌猴紝涓嶆樉绀虹偣鍑诲叆鍙o紱鑻ユ煡璇笉鍒扮敓浜ф壒娆★紝鎸夋帴鍙h繑鍥炵殑涓氬姟閿欒鎻愮ず鐢ㄦ埛銆�
### 鍝嶅簲瀛楁
@@ -44,6 +72,8 @@
| quantity | BigDecimal | 鍙樺姩鏁伴噺锛堟鏁�=鍏ュ簱锛岃礋鏁�=鍑哄簱锛� |
| batchId | Long | 鎵规ID |
| batchCode | String | 鎵规鍙� |
+| bagCodeId | Long | 琚嬬爜ID锛堣鐮佺骇娴佹按闈炵┖锛� |
+| bagCode | String | 琚嬬爜锛堣鐮佺骇娴佹按闈炵┖锛屽璐ㄦ銆侀攢鍞嚭搴撱�佺Щ搴擄級 |
| warehouseId | Long | 浠撳簱ID |
| warehouseName | String | 浠撳簱鍚嶇О |
| locationId | Long | 搴撳尯ID |
@@ -111,6 +141,24 @@
| 121 | 澶栧崗鍙戞枡 | 澶栧崗鍙戞枡 |
| 122 | 澶栧崗鍏ュ簱 | 澶栧崗鍏ュ簱 |
+## 璋冪敤鏃跺簭
+
+1. 杩涘叆搴撳瓨浜嬪姟娴佹按椤甸潰鏃讹紝璋冪敤 `/mes/wm/transaction/page` 鑾峰彇娴佹按鍒楄〃銆�
+2. 鍒楄〃涓睍绀� `batchCode`锛涙壒娆″彿闈炵┖鏃跺厑璁哥偣鍑汇��
+3. 鐐瑰嚮鎵规鍙峰悗锛屽皢褰撳墠琛岀殑 `batchCode` 浣滀负 `code` 璋冪敤 `/mes/pro/batch/get-by-code`銆�
+4. 鏍规嵁杩斿洖缁撴灉灞曠ず鐢熶骇鎵规淇℃伅銆佹墭鐩樺垪琛ㄥ拰琚嬬爜鍒楄〃锛沗bagTotal` 鐢ㄤ簬鏄剧ず琚嬬爜鎬绘暟锛宍bags` 鐢ㄤ簬灞曠ず琚嬬爜鏄庣粏銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| batchCode | 搴撳瓨娴佹按鍒楄〃 | 鎵规鍙烽潪绌烘椂浣滀负鍙偣鍑诲叆鍙� |
+| code | 鎵规璇︽儏 | 姝e紡鎵规鍙� |
+| tempCode | 鎵规璇︽儏 | 涓存椂鎵规鐮侊紝鏈夊�兼椂灞曠ず |
+| bagTotal | 鎵规璇︽儏 | 灞曠ず璇ユ壒娆¤鐮佹�绘暟 |
+| bags[].code | 鎵规璇︽儏 | 灞曠ず琚嬬爜鏄庣粏 |
+| pallets | 鎵规璇︽儏 | 灞曠ず璇ユ壒娆″叧鑱旂殑鎵樼洏淇℃伅 |
+
## 鎼滅储鏉′欢
| 鏉′欢瀛楁 | 缁勪欢绫诲瀷 | 璇存槑 |
@@ -140,6 +188,7 @@
| 搴撳尯 | locationName | 100 | - |
| 搴撲綅 | areaName | 100 | - |
| 浜嬪姟鏃堕棿 | transactionTime | 160 | 鏍煎紡锛歽yyy-MM-dd HH:mm:ss |
+| 琚嬬爜 | bagCode | 150 | 琚嬬爜绾ф祦姘寸殑琚嬬爜锛涙壒娆�/琚嬬爜鍙户缁拷婧� |
## 涓氬姟瑙勫垯璇存槑
@@ -150,6 +199,7 @@
| 鏁伴噺鏄剧ず | quantity > 0 鏄剧ず缁胯壊锛宷uantity < 0 鏄剧ず绾㈣壊 |
| 绫诲瀷鏍囩 | 鍏ュ簱鏄剧ず缁胯壊 success 鏍囩锛屽嚭搴撴樉绀虹孩鑹� danger 鏍囩 |
| 涓氬姟鍗曞彿璺宠浆 | 鐐瑰嚮 bizCode 鍙烦杞埌瀵瑰簲涓氬姟鍗曟嵁璇︽儏椤� |
+| 琚嬬爜绛涢�� | 浼� bagCode 鍙煡鐪嬫寚瀹氳鐮佺殑瀹屾暣娴佽浆锛堣川妫�鏆傚瓨鍑哄簱/鍚堟牸鍏ュ簱/閿�鍞嚭搴撶瓑锛� |
## 鏉冮檺閰嶇疆
diff --git a/img/0d9430aac760f2a00123f8f4f9b8eae0.jpg b/img/0d9430aac760f2a00123f8f4f9b8eae0.jpg
new file mode 100644
index 0000000..590b461
--- /dev/null
+++ b/img/0d9430aac760f2a00123f8f4f9b8eae0.jpg
Binary files differ
diff --git a/img/8fbfd97ac926a2dfd7e3bc2577aee946.jpg b/img/8fbfd97ac926a2dfd7e3bc2577aee946.jpg
new file mode 100644
index 0000000..0fdd7df
--- /dev/null
+++ b/img/8fbfd97ac926a2dfd7e3bc2577aee946.jpg
Binary files differ
diff --git "a/img/ChatGPT Image 2026\345\271\2649\346\234\21030\346\227\245 18_10_01.png" "b/img/ChatGPT Image 2026\345\271\2649\346\234\21030\346\227\245 18_10_01.png"
new file mode 100644
index 0000000..cc34fbf
--- /dev/null
+++ "b/img/ChatGPT Image 2026\345\271\2649\346\234\21030\346\227\245 18_10_01.png"
Binary files differ
diff --git a/img/tahe_seed_logo.png b/img/tahe_seed_logo.png
new file mode 100644
index 0000000..bb820c7
--- /dev/null
+++ b/img/tahe_seed_logo.png
Binary files differ
diff --git a/sql/mysql/mes_pro_bag_code_qc_status.sql b/sql/mysql/mes_pro_bag_code_qc_status.sql
new file mode 100644
index 0000000..54e3fe4
--- /dev/null
+++ b/sql/mysql/mes_pro_bag_code_qc_status.sql
@@ -0,0 +1,13 @@
+-- =========================================
+-- 琚嬬爜璐ㄦ鐘舵�侊細鏀寔绉嶅瓙璐ㄦ鎸夎鐮佺矑搴︽祦杞簱瀛�
+-- qc_status锛�10 鏈川妫� / 20 璐ㄦ鍚堟牸 / 30 璐ㄦ涓嶅悎鏍�
+-- 鏂板鍒楃敤浜庤褰曟瘡琚嬬殑璐ㄦ缁撴灉锛岄攢鍞嚭搴撴壂琚嬬爜鏃舵牎楠岃琚嬪凡璐ㄦ鍚堟牸銆�
+-- =========================================
+
+ALTER TABLE `mes_pro_bag_code`
+ ADD COLUMN `qc_status` TINYINT NOT NULL DEFAULT 10 COMMENT '璐ㄦ鐘舵�侊紙10鏈川妫� 20璐ㄦ鍚堟牸 30璐ㄦ涓嶅悎鏍硷級' AFTER `status`;
+
+-- 鍥炲~瀛橀噺鏁版嵁锛氭寜宸叉湁绉嶅瓙璐ㄦ璁板綍鍚屾琚嬬爜璐ㄦ鐘舵��
+UPDATE `mes_pro_bag_code` b
+ JOIN `mes_qc_seed_quality` q ON b.code = q.code AND b.deleted = 0
+SET b.qc_status = IF(q.result = 1, 20, 30), b.update_time = NOW();
diff --git a/sql/mysql/mes_pro_scan_event_scan_type.sql b/sql/mysql/mes_pro_scan_event_scan_type.sql
new file mode 100644
index 0000000..cf2b728
--- /dev/null
+++ b/sql/mysql/mes_pro_scan_event_scan_type.sql
@@ -0,0 +1,14 @@
+-- 鐢熶骇绾挎壂鐮佸叆搴擄細鏀寔琚嬬爜/鎵樼洏鐮�/鎵规鐮佷笁绉嶆壂鐮佺被鍨嬶紝骞跺幓鎺夎澶囩紪鐮佸繀濉�
+-- 璇存槑锛�
+-- 1. mes_pro_scan_event 澧炲姞 scan_type 鍒楋紝鏍囪鎵爜绫诲瀷锛圔AG 琚嬬爜 / PALLET 鎵樼洏鐮� / BATCH 鎵规鐮侊級锛屽巻鍙茶鐮佹暟鎹洖濉� BAG
+-- 2. mes_pro_pallet 澧炲姞鍏ュ簱鏍囪鍒楋紙鎵樼洏鍘熷厛鏃犲叆搴撴爣璁板瓧娈碉紝鏁存墭鍏ュ簱闇�鍘婚噸锛岄槻姝㈠悓涓�鎵樼洏閲嶅鎵爜鍏ュ簱锛�
+
+ALTER TABLE mes_pro_scan_event ADD COLUMN scan_type VARCHAR(16) NULL COMMENT '鎵爜绫诲瀷锛圔AG琚嬬爜/PALLET鎵樼洏鐮�/BATCH鎵规鐮侊級' AFTER bag_code;
+
+-- 璁惧缂栫爜涓嶅啀蹇呭~锛堝墠绔幓鎺夎澶囩紪鐮侊紝鍘嗗彶鍒椾繚鎸佸吋瀹癸級
+ALTER TABLE mes_pro_scan_event MODIFY COLUMN device_code VARCHAR(64) NULL DEFAULT NULL COMMENT '璁惧缂栫爜锛堜笉鍐嶅繀濉級';
+
+ALTER TABLE mes_pro_pallet ADD COLUMN inbound_event_id BIGINT NULL COMMENT '鏈�杩戝叆搴撴壂鐮佷簨浠剁紪鍙�' AFTER bag_count;
+ALTER TABLE mes_pro_pallet ADD COLUMN inbound_time DATETIME NULL COMMENT '鏈�杩戝叆搴撴椂闂�' AFTER inbound_event_id;
+
+UPDATE mes_pro_scan_event SET scan_type = 'BAG' WHERE scan_type IS NULL;
diff --git a/sql/mysql/mes_qc_seed_quality_record_menu.sql b/sql/mysql/mes_qc_seed_quality_record_menu.sql
new file mode 100644
index 0000000..11bd3f2
--- /dev/null
+++ b/sql/mysql/mes_qc_seed_quality_record_menu.sql
@@ -0,0 +1,14 @@
+-- =============================================
+-- 绉嶅瓙璐ㄦ璁板綍鐙珛鑿滃崟
+-- 灏嗚川妫�璁板綍浠庛�岀瀛愯川妫�銆嶉〉(鎻愪氦+璁板綍鍚堜竴)鎷嗗嚭锛岀嫭绔嬫垚鑿滃崟椤甸潰
+-- 璇存槑锛�
+-- 1. 绉嶅瓙璐ㄦ鎻愪氦椤碉細seed-quality -> mes/qc/seedQuality/index锛堜粎鎻愪氦锛�
+-- 2. 璐ㄦ璁板綍椤碉細seed-quality-record -> mes/qc/seedQuality/record锛堜粎璁板綍鏌ヨ锛�
+-- 鎸傚湪銆岃川閲忕鐞嗐��(5500) 鐩綍涓嬶紱骞傜瓑锛屽彲閲嶅鎵ц锛涙棤绉熸埛瀛楁銆�
+-- =============================================
+
+INSERT INTO system_menu
+(id, name, parent_id, type, sort, status, path, icon, component, component_name, permission, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT 1065224, '璐ㄦ璁板綍', 5500, 2, 95, 0, 'seed-quality-record', 'ep:list', 'mes/qc/seedQuality/record', 'MesQcSeedQualityRecord', '', b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE id = 1065224 AND deleted = b'0');
diff --git a/sql/mysql/mes_wm_material_stock_bag.sql b/sql/mysql/mes_wm_material_stock_bag.sql
new file mode 100644
index 0000000..e659a95
--- /dev/null
+++ b/sql/mysql/mes_wm_material_stock_bag.sql
@@ -0,0 +1,31 @@
+CREATE TABLE mes_wm_material_stock_bag (
+ id BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ material_stock_id BIGINT NOT NULL COMMENT '搴撳瓨姹囨�昏褰旾D',
+ bag_code_id BIGINT NOT NULL COMMENT '鐢熶骇琚嬬爜ID',
+ bag_code VARCHAR(64) NOT NULL COMMENT '琚嬬爜',
+ item_id BIGINT NOT NULL COMMENT '鐗╂枡ID',
+ batch_id BIGINT NULL COMMENT '浠撳簱鎵规ID',
+ batch_code VARCHAR(64) NULL COMMENT '鎵规鍙�',
+ vendor_id BIGINT NULL COMMENT '渚涘簲鍟咺D',
+ warehouse_id BIGINT NOT NULL COMMENT '浠撳簱ID',
+ location_id BIGINT NULL COMMENT '搴撳尯ID',
+ area_id BIGINT NULL COMMENT '搴撲綅ID',
+ stock_state TINYINT NOT NULL COMMENT '搴撳瓨鐘舵�侊細10鏆傚瓨锛�20鍚堟牸锛�30宸插嚭搴擄紝40鎶ュ簾',
+ status TINYINT NOT NULL DEFAULT 1 COMMENT '鏄庣粏鐘舵�侊細1鍦ㄥ簱锛�2宸插嚭搴擄紝3宸叉姤搴�',
+ quantity DECIMAL(18, 6) NOT NULL DEFAULT 1 COMMENT '琚嬬爜搴撳瓨鏁伴噺',
+ frozen BIT NOT NULL DEFAULT 0 COMMENT '鏄惁鍐荤粨',
+ last_transaction_id BIGINT NULL COMMENT '鏈�杩戝簱瀛樹簨鍔D',
+ inbound_time DATETIME NULL COMMENT '鍏ュ簱鏃堕棿',
+ outbound_time DATETIME NULL COMMENT '鍑哄簱鏃堕棿',
+ creator VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ updater VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ deleted BIT NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (id),
+ UNIQUE KEY uk_bag_code (bag_code),
+ KEY idx_material_stock (material_stock_id),
+ KEY idx_batch_state (batch_id, stock_state, status),
+ KEY idx_location_state (warehouse_id, location_id, area_id, stock_state, status),
+ KEY idx_bag_code_id (bag_code_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES搴撳瓨琚嬬爜鏄庣粏';
diff --git a/sql/mysql/mes_wm_product_sales_add_columns.sql b/sql/mysql/mes_wm_product_sales_add_columns.sql
new file mode 100644
index 0000000..04f072d
--- /dev/null
+++ b/sql/mysql/mes_wm_product_sales_add_columns.sql
@@ -0,0 +1,12 @@
+-- MES 閿�鍞嚭搴撳崟琛ㄧ粨鏋勪慨鏀�
+-- 鏍规嵁 MesWmProductSalesDO 琛ュ厖缂哄け瀛楁
+-- 璇存槑锛氫慨澶嶆煡璇㈡姤閿� Unknown column 'client_name'锛屽悓鏃惰ˉ鍏� outbound_time銆乷utbound_user_id
+
+-- 1. 缁忛攢鍟嗗悕绉板揩鐓�
+ALTER TABLE mes_wm_product_sales ADD COLUMN client_name VARCHAR(128) DEFAULT NULL COMMENT '缁忛攢鍟嗗悕绉板揩鐓�' AFTER client_id;
+
+-- 2. 瀹為檯鍑哄簱鏃堕棿
+ALTER TABLE mes_wm_product_sales ADD COLUMN outbound_time DATETIME DEFAULT NULL COMMENT '瀹為檯鍑哄簱鏃堕棿';
+
+-- 3. 鎵ц鍑哄簱鎿嶄綔浜篒D
+ALTER TABLE mes_wm_product_sales ADD COLUMN outbound_user_id BIGINT DEFAULT NULL COMMENT '鎵ц鍑哄簱鎿嶄綔浜篒D';
\ No newline at end of file
diff --git a/sql/mysql/mes_wm_qualified_warehouse.sql b/sql/mysql/mes_wm_qualified_warehouse.sql
new file mode 100644
index 0000000..29379d1
--- /dev/null
+++ b/sql/mysql/mes_wm_qualified_warehouse.sql
@@ -0,0 +1,85 @@
+-- =====================================================================
+-- 鏂板缓鍚堟牸浠撳簱 + 浠撳簱绫诲瀷 + 璐ㄦ鍏ュ悎鏍煎簱鏀归��
+--
+-- 1) mes_wm_warehouse 澧炲姞 type 瀛楁锛�10 鏆傚瓨搴� / 20 鍚堟牸搴擄級
+-- 2) 鐜版湁浠撳簱鍒嗙被锛氳櫄鎷熺嚎杈逛粨搴�=10锛堟殏瀛樺簱锛夛紝浜у搧搴�/鐗╂枡搴�=20锛堝悎鏍煎簱锛�
+-- 3) 鏂板缓"鎴愬搧鍚堟牸搴�"(type=20) + 涓�涓簱鍖� + 涓�涓簱浣�
+-- 4) 铏氭嫙浠撳簱涓� stock_state=20 鐨勫悎鏍煎簱瀛樿縼绉诲埌鏂板悎鏍煎簱
+--
+-- 璇存槑锛氭湰鑴氭湰骞傜瓑锛屽彲閲嶅鎵ц锛涙棤绉熸埛瀛楁銆�
+-- =====================================================================
+
+-- 1) 澧炲姞浠撳簱绫诲瀷瀛楁锛圡ySQL 涓嶆敮鎸� ALTER ADD COLUMN IF NOT EXISTS锛屽厛鏌ュ瓨鍦ㄦ�э級
+SET @type_exists = (
+ SELECT COUNT(*)
+ FROM information_schema.columns
+ WHERE table_schema = DATABASE()
+ AND table_name = 'mes_wm_warehouse'
+ AND column_name = 'type'
+);
+SET @type_sql = IF(
+ @type_exists = 0,
+ 'ALTER TABLE mes_wm_warehouse ADD COLUMN type tinyint NOT NULL DEFAULT 10 COMMENT ''浠撳簱绫诲瀷锛�10鏆傚瓨搴擄紝20鍚堟牸搴�'' AFTER frozen',
+ 'SELECT 1'
+);
+PREPARE type_stmt FROM @type_sql;
+EXECUTE type_stmt;
+DEALLOCATE PREPARE type_stmt;
+
+-- 2) 鐜版湁浠撳簱鍒嗙被
+UPDATE mes_wm_warehouse SET type = 10 WHERE code = 'WIP_VIRTUAL_WAREHOUSE' AND deleted = 0;
+UPDATE mes_wm_warehouse SET type = 20 WHERE code IN ('1212', 'WHS000001') AND deleted = 0;
+
+-- 3) 鏂板缓"鎴愬搧鍚堟牸搴�"锛坱ype=20锛�
+SET @wh_exists = (
+ SELECT COUNT(*) FROM mes_wm_warehouse WHERE code = 'FG_QUALIFIED_WH' AND deleted = 0
+);
+INSERT INTO mes_wm_warehouse (code, name, frozen, type, remark)
+SELECT 'FG_QUALIFIED_WH', '鎴愬搧鍚堟牸搴�', 0, 20, '璐ㄦ鍚堟牸鐩存帴鍏ュ簱鐨勭洰鏍囦粨搴擄紙type=20 鍚堟牸搴擄級'
+WHERE @wh_exists = 0;
+SET @wh_id = (SELECT id FROM mes_wm_warehouse WHERE code = 'FG_QUALIFIED_WH' AND deleted = 0 LIMIT 1);
+
+-- 鏂板缓"鎴愬搧鍚堟牸搴撳尯"
+SET @loc_exists = (
+ SELECT COUNT(*) FROM mes_wm_warehouse_location WHERE code = 'FG_QUALIFIED_WH_LOC' AND deleted = 0
+);
+INSERT INTO mes_wm_warehouse_location (code, name, warehouse_id, frozen, remark)
+SELECT 'FG_QUALIFIED_WH_LOC', '鎴愬搧鍚堟牸搴撳尯', @wh_id, 0, '璐ㄦ鍚堟牸鍏ュ簱榛樿搴撳尯'
+WHERE @loc_exists = 0;
+SET @loc_id = (SELECT id FROM mes_wm_warehouse_location WHERE code = 'FG_QUALIFIED_WH_LOC' AND deleted = 0 LIMIT 1);
+
+-- 鏂板缓"鎴愬搧鍚堟牸搴撲綅"
+SET @area_exists = (
+ SELECT COUNT(*) FROM mes_wm_warehouse_area WHERE code = 'FG_QUALIFIED_WH_AREA' AND deleted = 0
+);
+INSERT INTO mes_wm_warehouse_area (code, name, location_id, frozen, remark)
+SELECT 'FG_QUALIFIED_WH_AREA', '鎴愬搧鍚堟牸搴撲綅', @loc_id, 0, '璐ㄦ鍚堟牸鍏ュ簱榛樿搴撲綅'
+WHERE @area_exists = 0;
+SET @area_id = (SELECT id FROM mes_wm_warehouse_area WHERE code = 'FG_QUALIFIED_WH_AREA' AND deleted = 0 LIMIT 1);
+
+-- 4) 杩佺Щ铏氭嫙浠撳簱鍚堟牸搴撳瓨鍒版柊鍚堟牸搴�
+-- 4.1 鑻ユ柊鍚堟牸搴撳凡瀛樺湪鍚� (item_id, batch_id, vendor_id) 鐨� state=20 璁板綍锛屽厛鏁伴噺绱姞鍚堝苟
+UPDATE mes_wm_material_stock t
+JOIN mes_wm_material_stock s
+ ON s.warehouse_id = 3 AND s.stock_state = 20 AND s.deleted = 0
+ AND t.warehouse_id = @wh_id AND t.stock_state = 20 AND t.deleted = 0
+ AND t.item_id = s.item_id
+ AND IFNULL(t.batch_id, 0) = IFNULL(s.batch_id, 0)
+ AND IFNULL(t.vendor_id, 0) = IFNULL(s.vendor_id, 0)
+SET t.quantity = t.quantity + s.quantity,
+ t.reserved_quantity = t.reserved_quantity + s.reserved_quantity,
+ t.frozen_quantity = t.frozen_quantity + s.frozen_quantity;
+
+-- 4.2 鍒犻櫎宸插悎骞跺埌鏂板悎鏍煎簱鐨勬簮璁板綍锛堣櫄鎷熶粨搴撲腑锛�
+DELETE s FROM mes_wm_material_stock s
+JOIN mes_wm_material_stock t
+ ON s.warehouse_id = 3 AND s.stock_state = 20 AND s.deleted = 0
+ AND t.warehouse_id = @wh_id AND t.stock_state = 20 AND t.deleted = 0
+ AND t.item_id = s.item_id
+ AND IFNULL(t.batch_id, 0) = IFNULL(s.batch_id, 0)
+ AND IFNULL(t.vendor_id, 0) = IFNULL(s.vendor_id, 0);
+
+-- 4.3 鍏朵綑鍚堟牸搴撳瓨鐩存帴鏀逛粨搴�/搴撳尯/搴撲綅
+UPDATE mes_wm_material_stock
+SET warehouse_id = @wh_id, location_id = @loc_id, area_id = @area_id
+WHERE warehouse_id = 3 AND stock_state = 20 AND deleted = 0;
diff --git a/sql/mysql/mes_wm_transaction_bag_code.sql b/sql/mysql/mes_wm_transaction_bag_code.sql
new file mode 100644
index 0000000..4b974c9
--- /dev/null
+++ b/sql/mysql/mes_wm_transaction_bag_code.sql
@@ -0,0 +1,17 @@
+SET @exists_bag_code_id = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND column_name = 'bag_code_id');
+SET @sql_bag_code_id = IF(@exists_bag_code_id = 0, 'ALTER TABLE mes_wm_transaction ADD COLUMN bag_code_id BIGINT NULL COMMENT ''鐢熶骇琚嬬爜ID'' AFTER material_stock_id', 'SELECT 1');
+PREPARE stmt FROM @sql_bag_code_id;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @exists_bag_code = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND column_name = 'bag_code');
+SET @sql_bag_code = IF(@exists_bag_code = 0, 'ALTER TABLE mes_wm_transaction ADD COLUMN bag_code VARCHAR(64) NULL COMMENT ''琚嬬爜'' AFTER bag_code_id', 'SELECT 1');
+PREPARE stmt FROM @sql_bag_code;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @exists_bag_code_index = (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND index_name = 'idx_bag_code');
+SET @sql_bag_code_index = IF(@exists_bag_code_index = 0, 'ALTER TABLE mes_wm_transaction ADD KEY idx_bag_code (bag_code)', 'SELECT 1');
+PREPARE stmt FROM @sql_bag_code_index;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/sql/mysql/sp_clean_business_data.sql b/sql/mysql/sp_clean_business_data.sql
new file mode 100644
index 0000000..7fe5cc2
--- /dev/null
+++ b/sql/mysql/sp_clean_business_data.sql
@@ -0,0 +1,435 @@
+-- ============================================================
+-- 涓氬姟鏁版嵁娓呯悊瀛樺偍杩囩▼锛堢洰鏍囧簱锛歮om-thzy锛�
+--
+-- 鐢ㄩ�旓細娓呯┖鍚勪笟鍔℃ā鍧楃殑娴佹按/浜嬪姟鏁版嵁锛屼繚鐣欑敤鎴枫�佽鑹层�佽彍鍗曘��
+-- 瀛楀吀銆佹祦绋嬪畾涔夈�佸熀纭�閰嶇疆涓庝富鏁版嵁妗f銆�
+--
+-- 娉ㄦ剰锛�
+-- 1. TRUNCATE 涓� DDL 闅愬紡鎻愪氦锛屾棤娉曞洖婊氾紝鎵ц鍓嶈鍏堝浠姐��
+-- 2. 鎵ц鏂瑰紡锛歮ysql -uroot -p mom-thzy < sp_clean_business_data.sql
+-- 鎴栧湪瀹㈡埛绔腑鏁翠綋鎵ц鏈剼鏈紙鍚� DELIMITER锛夈��
+-- 3. 鎵ц娓呯悊锛欳ALL sp_clean_business_data();
+-- ============================================================
+
+DROP PROCEDURE IF EXISTS `sp_clean_business_data`;
+
+DELIMITER $$
+
+CREATE DEFINER=`root`@`%` PROCEDURE `sp_clean_business_data`()
+BEGIN
+ SET FOREIGN_KEY_CHECKS = 0;
+
+ -- ============================================================
+ -- 1. 绯荤粺杩愯鏁版嵁锛堟棩蹇� / Token / 楠岃瘉鐮� / 绔欏唴淇� / 绀句氦缁戝畾锛�
+ -- ============================================================
+ TRUNCATE TABLE system_login_log;
+ TRUNCATE TABLE system_operate_log;
+ TRUNCATE TABLE system_notify_message;
+ TRUNCATE TABLE system_oauth2_access_token;
+ TRUNCATE TABLE system_oauth2_refresh_token;
+ TRUNCATE TABLE system_oauth2_code;
+ TRUNCATE TABLE system_oauth2_approve;
+ TRUNCATE TABLE system_sms_code;
+ TRUNCATE TABLE system_sms_log;
+ TRUNCATE TABLE system_mail_log;
+ TRUNCATE TABLE system_social_user;
+ TRUNCATE TABLE system_social_user_bind;
+ TRUNCATE TABLE infra_api_access_log;
+ TRUNCATE TABLE infra_api_error_log;
+ TRUNCATE TABLE infra_job_log;
+
+ -- 鍒犻櫎涓庢湰椤圭洰鏃犲叧鐨勬鏋惰嚜甯﹀畾鏃朵换鍔★紙pay/mall/iot/demo锛夛紝
+ -- 淇濈暀鏃ュ織娓呯悊涓変欢濂楋細accessLogCleanJob / errorLogCleanJob / jobLogCleanJob
+ DELETE FROM infra_job
+ WHERE handler_name IN (
+ 'payNotifyJob', 'payOrderSyncJob', 'payOrderExpireJob',
+ 'payRefundSyncJob', 'payTransferSyncJob',
+ 'tradeOrderAutoCancelJob', 'tradeOrderAutoReceiveJob', 'tradeOrderAutoCommentJob',
+ 'brokerageRecordUnfreezeJob', 'combinationRecordExpireJob',
+ 'couponExpireJob', 'productStatisticsJob',
+ 'iotDeviceOfflineCheckJob', 'iotOtaUpgradeJob',
+ 'demoJob'
+ );
+
+ -- Quartz 璋冨害杩愯鏃舵暟鎹紙qrtz_locks 淇濈暀閿佽锛屾竻绌轰細瀵艰嚧璋冨害鍣ㄥ姞閿佹姤閿欙級
+ -- 娓呯悊鍚庡闇�鎭㈠淇濈暀浠诲姟鐨勮皟搴︽敞鍐岋紝鍦ㄣ�愬熀纭�璁炬柦-瀹氭椂浠诲姟銆戦〉闈㈢偣"鍚屾"鎴栬皟鐢�
+ -- POST /admin-api/infra/job/sync 浠� infra_job 閲嶅缓瑙﹀彂鍣�
+ TRUNCATE TABLE qrtz_blob_triggers;
+ TRUNCATE TABLE qrtz_calendars;
+ TRUNCATE TABLE qrtz_cron_triggers;
+ TRUNCATE TABLE qrtz_fired_triggers;
+ TRUNCATE TABLE qrtz_job_details;
+ TRUNCATE TABLE qrtz_paused_trigger_grps;
+ TRUNCATE TABLE qrtz_scheduler_state;
+ TRUNCATE TABLE qrtz_simple_triggers;
+ TRUNCATE TABLE qrtz_simprop_triggers;
+ TRUNCATE TABLE qrtz_triggers;
+
+ -- ============================================================
+ -- 2. 鏂囦欢涓庨檮浠�
+ -- ============================================================
+ TRUNCATE TABLE system_storage_attachment;
+ TRUNCATE TABLE system_storage_blob;
+ TRUNCATE TABLE storage_attachment;
+ TRUNCATE TABLE storage_blob;
+ TRUNCATE TABLE infra_file;
+ TRUNCATE TABLE infra_file_content;
+
+ -- ============================================================
+ -- 3. BPM 娴佺▼瀹炰緥涓庡鎵瑰巻鍙�
+ -- 淇濈暀锛氭祦绋嬪畾涔�/琛ㄥ崟/鍒嗙被/琛ㄨ揪寮�/鐩戝惉鍣�/鐢ㄦ埛缁�/涓氬姟闄勪欢閰嶇疆
+ -- 淇濈暀锛歛ct_re_* / act_ge_* / act_id_* / act_procdef_info锛堝畾涔変笌閮ㄧ讲璧勬簮锛�
+ -- ============================================================
+ TRUNCATE TABLE bpm_oa_leave;
+ TRUNCATE TABLE bpm_process_instance_copy;
+ TRUNCATE TABLE act_hi_procinst;
+ TRUNCATE TABLE act_hi_taskinst;
+ TRUNCATE TABLE act_hi_actinst;
+ TRUNCATE TABLE act_hi_varinst;
+ TRUNCATE TABLE act_hi_identitylink;
+ TRUNCATE TABLE act_hi_comment;
+ TRUNCATE TABLE act_hi_detail;
+ TRUNCATE TABLE act_hi_attachment;
+ TRUNCATE TABLE act_hi_entitylink;
+ TRUNCATE TABLE act_hi_tsk_log;
+ TRUNCATE TABLE act_ru_task;
+ TRUNCATE TABLE act_ru_execution;
+ TRUNCATE TABLE act_ru_actinst;
+ TRUNCATE TABLE act_ru_variable;
+ TRUNCATE TABLE act_ru_identitylink;
+ TRUNCATE TABLE act_ru_job;
+ TRUNCATE TABLE act_ru_timer_job;
+ TRUNCATE TABLE act_ru_deadletter_job;
+ TRUNCATE TABLE act_ru_suspended_job;
+ TRUNCATE TABLE act_ru_external_job;
+ TRUNCATE TABLE act_ru_history_job;
+ TRUNCATE TABLE act_ru_event_subscr;
+ TRUNCATE TABLE act_ru_entitylink;
+ TRUNCATE TABLE act_evt_log;
+ -- Flowable 鎵规杩愯鏃讹紙multi-instance 鎵瑰鐞嗭紝鍘熻剼鏈仐婕忥級
+ TRUNCATE TABLE flw_ru_batch;
+ TRUNCATE TABLE flw_ru_batch_part;
+
+ -- ============================================================
+ -- 4. MES 鐢熶骇妯″潡 鈥� 涓氬姟鏁版嵁
+ -- 淇濈暀锛歮es_pro_process / mes_pro_route*锛堝伐鑹轰笌璺嚎瀹氫箟锛�
+ -- ============================================================
+ TRUNCATE TABLE mes_pro_work_order_param_record_detail;
+ TRUNCATE TABLE mes_pro_work_order_param_record;
+ TRUNCATE TABLE mes_pro_work_order_process;
+ TRUNCATE TABLE mes_pro_work_order_bom;
+ TRUNCATE TABLE mes_pro_work_order;
+ TRUNCATE TABLE mes_pro_task_issue;
+ TRUNCATE TABLE mes_pro_task;
+ TRUNCATE TABLE mes_pro_task_pause_record; -- 鐢熶骇浠诲姟鍋滃伐璁板綍锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mes_pro_feedback;
+ TRUNCATE TABLE mes_pro_mps_merge_item;
+ TRUNCATE TABLE mes_pro_mps;
+ TRUNCATE TABLE mes_pro_card_process;
+ TRUNCATE TABLE mes_pro_card;
+ TRUNCATE TABLE mes_pro_work_record_log;
+ TRUNCATE TABLE mes_pro_work_record;
+ TRUNCATE TABLE mes_pro_andon_record;
+ TRUNCATE TABLE mes_pro_scan_event; -- 琚嬬爜鎵爜鍏ュ簱浜嬩欢锛堝師鑴氭湰閬楁紡锛�
+
+ -- ============================================================
+ -- 5. MES 浠撳偍妯″潡 鈥� 涓氬姟鏁版嵁
+ -- 淇濈暀锛歮es_wm_warehouse / _area / _location / _barcode_config锛堜粨鍌ㄩ厤缃級
+ -- ============================================================
+ TRUNCATE TABLE mes_wm_transaction;
+ TRUNCATE TABLE mes_wm_stock_reserve;
+ TRUNCATE TABLE mes_wm_material_stock;
+ TRUNCATE TABLE mes_wm_material_stock_bag; -- 搴撳瓨琚嬬爜鏄庣粏锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mes_wm_stock_warning; -- 搴撳瓨棰勮璁板綍锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mes_wm_sn;
+ TRUNCATE TABLE mes_wm_batch;
+ TRUNCATE TABLE mes_wm_barcode;
+ TRUNCATE TABLE mes_wm_stock_taking_task_result;
+ TRUNCATE TABLE mes_wm_stock_taking_task_line;
+ TRUNCATE TABLE mes_wm_stock_taking_task;
+ TRUNCATE TABLE mes_wm_stock_taking_plan_param;
+ TRUNCATE TABLE mes_wm_stock_taking_plan;
+ TRUNCATE TABLE mes_wm_package_line;
+ TRUNCATE TABLE mes_wm_package;
+ TRUNCATE TABLE mes_wm_item_receipt_detail;
+ TRUNCATE TABLE mes_wm_item_receipt_line;
+ TRUNCATE TABLE mes_wm_item_receipt;
+ TRUNCATE TABLE mes_wm_item_consume_detail;
+ TRUNCATE TABLE mes_wm_item_consume_line;
+ TRUNCATE TABLE mes_wm_item_consume;
+ TRUNCATE TABLE mes_wm_product_produce_detail;
+ TRUNCATE TABLE mes_wm_product_produce_line;
+ TRUNCATE TABLE mes_wm_product_produce;
+ TRUNCATE TABLE mes_wm_product_issue_detail;
+ TRUNCATE TABLE mes_wm_product_issue_line;
+ TRUNCATE TABLE mes_wm_product_issue;
+ TRUNCATE TABLE mes_wm_product_receipt_detail;
+ TRUNCATE TABLE mes_wm_product_receipt_line;
+ TRUNCATE TABLE mes_wm_product_receipt;
+ TRUNCATE TABLE mes_wm_product_sales_detail;
+ TRUNCATE TABLE mes_wm_product_sales_line;
+ TRUNCATE TABLE mes_wm_product_sales;
+ TRUNCATE TABLE mes_wm_misc_receipt_detail;
+ TRUNCATE TABLE mes_wm_misc_receipt_line;
+ TRUNCATE TABLE mes_wm_misc_receipt;
+ TRUNCATE TABLE mes_wm_misc_issue_detail;
+ TRUNCATE TABLE mes_wm_misc_issue_line;
+ TRUNCATE TABLE mes_wm_misc_issue;
+ TRUNCATE TABLE mes_wm_outsource_receipt_detail;
+ TRUNCATE TABLE mes_wm_outsource_receipt_line;
+ TRUNCATE TABLE mes_wm_outsource_receipt;
+ TRUNCATE TABLE mes_wm_outsource_issue_detail;
+ TRUNCATE TABLE mes_wm_outsource_issue_line;
+ TRUNCATE TABLE mes_wm_outsource_issue;
+ TRUNCATE TABLE mes_wm_return_vendor_detail;
+ TRUNCATE TABLE mes_wm_return_vendor_line;
+ TRUNCATE TABLE mes_wm_return_vendor;
+ TRUNCATE TABLE mes_wm_return_issue_detail;
+ TRUNCATE TABLE mes_wm_return_issue_line;
+ TRUNCATE TABLE mes_wm_return_issue;
+ TRUNCATE TABLE mes_wm_return_sales_detail;
+ TRUNCATE TABLE mes_wm_return_sales_line;
+ TRUNCATE TABLE mes_wm_return_sales;
+ TRUNCATE TABLE mes_wm_sales_notice_line;
+ TRUNCATE TABLE mes_wm_sales_notice;
+ TRUNCATE TABLE mes_wm_transfer_detail;
+ TRUNCATE TABLE mes_wm_transfer_line;
+ TRUNCATE TABLE mes_wm_transfer;
+ TRUNCATE TABLE mes_wm_arrival_notice_line;
+ TRUNCATE TABLE mes_wm_arrival_notice;
+
+ -- ============================================================
+ -- 6. MES 璐ㄦ妯″潡 鈥� 涓氬姟鏁版嵁
+ -- 淇濈暀锛歮es_qc_template(_indicator/_item) / _indicator / _defect锛堣川妫�閰嶇疆涓庡瓧鍏革級
+ -- ============================================================
+ TRUNCATE TABLE mes_qc_indicator_result_detail;
+ TRUNCATE TABLE mes_qc_indicator_result;
+ TRUNCATE TABLE mes_qc_defect_record;
+ TRUNCATE TABLE mes_qc_ncr;
+ TRUNCATE TABLE mes_qc_iqc_line;
+ TRUNCATE TABLE mes_qc_iqc;
+ TRUNCATE TABLE mes_qc_ipqc_line;
+ TRUNCATE TABLE mes_qc_ipqc;
+ TRUNCATE TABLE mes_qc_oqc_line;
+ TRUNCATE TABLE mes_qc_oqc;
+ TRUNCATE TABLE mes_qc_rqc_line;
+ TRUNCATE TABLE mes_qc_rqc;
+ -- 绉嶅瓙璐ㄦ璁板綍锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mes_qc_seed_quality_indicator;
+ TRUNCATE TABLE mes_qc_seed_quality_source;
+ TRUNCATE TABLE mes_qc_seed_quality;
+
+ -- ============================================================
+ -- 7. MES 杩芥函妯″潡 鈥� 浜嬩欢涓庨璀﹁褰曪紙鍘熻剼鏈仐婕忥級
+ -- 淇濈暀锛歮es_trace_anti_config锛堥槻浼獪閰嶇疆锛�
+ -- ============================================================
+ TRUNCATE TABLE mes_trace_consumer_scan_event;
+ TRUNCATE TABLE mes_trace_cross_region_warning;
+ TRUNCATE TABLE mes_trace_integrity_record;
+ TRUNCATE TABLE mes_trace_event;
+
+ -- ============================================================
+ -- 8. MES 璁惧妯″潡 鈥� 鐐规/淇濆吇/缁翠慨/璁¢噺妫�娴嬭褰�
+ -- 淇濈暀锛歮es_dv_machinery(_type) / _check_plan* / _subject / _metering锛堝彴璐︿笌璁″垝锛�
+ -- ============================================================
+ TRUNCATE TABLE mes_dv_check_record_line;
+ TRUNCATE TABLE mes_dv_check_record;
+ TRUNCATE TABLE mes_dv_mainten_record_line;
+ TRUNCATE TABLE mes_dv_mainten_record;
+ TRUNCATE TABLE mes_dv_repair_line;
+ TRUNCATE TABLE mes_dv_repair;
+ TRUNCATE TABLE mes_dv_metering_check;
+
+ -- ============================================================
+ -- 9. MES 宸ヨ壓/璁捐妯″潡 鈥� 涓氬姟鏁版嵁锛堢紪鐮佺敓鎴愯褰曚负娴佹按鏁版嵁锛�
+ -- 淇濈暀锛歮es_pd_process_param(_template/_detail)锛堝伐鑹哄弬鏁板畾涔夛級
+ -- / mes_md_auto_code_rule / _part锛堢紪鐮佽鍒欙級
+ -- ============================================================
+ TRUNCATE TABLE mes_pd_archive;
+ TRUNCATE TABLE mes_pd_document_audit;
+ TRUNCATE TABLE mes_pd_document;
+ TRUNCATE TABLE mes_pd_project;
+ TRUNCATE TABLE mes_md_auto_code_record;
+
+ -- ============================================================
+ -- 10. CRM 妯″潡 鈥� 涓氬姟鏁版嵁
+ -- 淇濈暀锛歝rm_customer / crm_contact / crm_business_status(_type)
+ -- / crm_contract_config / crm_customer_limit_config / crm_customer_pool_config
+ -- ============================================================
+ TRUNCATE TABLE crm_receivable_plan;
+ TRUNCATE TABLE crm_receivable;
+ TRUNCATE TABLE crm_contract_product;
+ TRUNCATE TABLE crm_contract;
+ TRUNCATE TABLE crm_sale_quotation_product;
+ TRUNCATE TABLE crm_sale_quotation;
+ TRUNCATE TABLE crm_business_product;
+ TRUNCATE TABLE crm_contact_business;
+ TRUNCATE TABLE crm_business;
+ TRUNCATE TABLE crm_clue;
+ TRUNCATE TABLE crm_follow_up_record;
+ TRUNCATE TABLE crm_invoice;
+ TRUNCATE TABLE crm_sales_target;
+ TRUNCATE TABLE crm_permission;
+
+ -- ============================================================
+ -- 11. 鍞悗妯″潡 鈥� 涓氬姟鏁版嵁
+ -- ============================================================
+ TRUNCATE TABLE after_sale_return_item;
+ TRUNCATE TABLE after_sale_return;
+ TRUNCATE TABLE after_sale_ticket_item;
+ TRUNCATE TABLE after_sale_ticket;
+ TRUNCATE TABLE after_sale_repair;
+ TRUNCATE TABLE after_sale_permission;
+
+ -- ============================================================
+ -- 12. ERP 妯″潡 鈥� 涓氬姟鏁版嵁
+ -- 淇濈暀锛歟rp_supplier / erp_account
+ -- ============================================================
+ TRUNCATE TABLE erp_finance_payment_item;
+ TRUNCATE TABLE erp_finance_payment;
+ TRUNCATE TABLE erp_finance_receipt_item;
+ TRUNCATE TABLE erp_finance_receipt;
+ TRUNCATE TABLE erp_purchase_order_items;
+ TRUNCATE TABLE erp_purchase_order;
+ TRUNCATE TABLE erp_purchase_request_items;
+ TRUNCATE TABLE erp_purchase_request;
+ TRUNCATE TABLE erp_sale_order_items;
+ TRUNCATE TABLE erp_sale_order;
+ TRUNCATE TABLE erp_purchase_invoice;
+
+ -- ============================================================
+ -- 13. SRM 妯″潡 鈥� 涓氬姟鏁版嵁
+ -- 淇濈暀锛歴rm_supplier / srm_supplier_contact / srm_supplier_category
+ -- / srm_tender_config
+ -- ============================================================
+ TRUNCATE TABLE srm_bid_award;
+ TRUNCATE TABLE srm_bid_evaluation;
+ TRUNCATE TABLE srm_bid_open;
+ TRUNCATE TABLE srm_tender_bid;
+ TRUNCATE TABLE srm_tender_material;
+ TRUNCATE TABLE srm_tender_project;
+ TRUNCATE TABLE srm_delivery_plan;
+ TRUNCATE TABLE srm_purchase_collaboration;
+ TRUNCATE TABLE srm_supplier_quote;
+ TRUNCATE TABLE srm_supplier_evaluation;
+ TRUNCATE TABLE srm_supplier_certificate;
+ TRUNCATE TABLE srm_supplier_apply;
+
+ -- ============================================================
+ -- 14. HRM 妯″潡 鈥� 涓氬姟鏁版嵁
+ -- 淇濈暀锛歨rm_employee 鍙婃。妗堝瓙琛紙鏁欒偛/宸ヤ綔缁忓巻/绱ф�ヨ仈绯讳汉/
+ -- 绀句繚鍏Н閲�/钖叕妗f/鍚堝悓锛夈�佽�冨嫟鑺傚亣鏃�/瑙勫垯銆佽鍋囩被鍨嬮厤缃��
+ -- 钖叕缁撴瀯銆佺ぞ淇濆叕绉噾鏂规銆佷釜绋庣◣鐜囬厤缃�
+ -- ============================================================
+ TRUNCATE TABLE hrm_salary_payment_detail;
+ TRUNCATE TABLE hrm_salary_payment;
+ TRUNCATE TABLE hrm_salary_calculation;
+ TRUNCATE TABLE hrm_attendance_summary;
+ TRUNCATE TABLE hrm_attendance_record;
+ TRUNCATE TABLE hrm_attendance_exception;
+ TRUNCATE TABLE hrm_leave_application;
+ TRUNCATE TABLE hrm_resignation_application;
+ TRUNCATE TABLE hrm_transfer_application;
+
+ -- ============================================================
+ -- 15. AI 妯″潡 鈥� 瀵硅瘽涓庣敓鎴愬唴瀹�
+ -- 淇濈暀锛歛i_api_key / ai_model / ai_tool / ai_chat_role
+ -- / ai_knowledge(_document/_segment) / ai_workflow
+ -- ============================================================
+ TRUNCATE TABLE ai_chat_message;
+ TRUNCATE TABLE ai_chat_conversation;
+ TRUNCATE TABLE ai_image;
+ TRUNCATE TABLE ai_mind_map;
+ TRUNCATE TABLE ai_music;
+ TRUNCATE TABLE ai_write;
+
+ -- ============================================================
+ -- 16. IM 妯″潡 鈥� 浼氳瘽涓庢秷鎭�
+ -- 淇濈暀锛歩m_sensitive_word / im_face_pack / im_face_pack_item
+ -- ============================================================
+ TRUNCATE TABLE im_group_message_receipt;
+ TRUNCATE TABLE im_group_message;
+ TRUNCATE TABLE im_private_message;
+ TRUNCATE TABLE im_message_file;
+ TRUNCATE TABLE im_group_request;
+ TRUNCATE TABLE im_group_member;
+ TRUNCATE TABLE im_group;
+ TRUNCATE TABLE im_friend_request;
+ TRUNCATE TABLE im_friend;
+ TRUNCATE TABLE im_conversation_read;
+ TRUNCATE TABLE im_conversation;
+ TRUNCATE TABLE im_channel_message;
+ TRUNCATE TABLE im_channel_material;
+ TRUNCATE TABLE im_channel;
+ TRUNCATE TABLE im_rtc_participant;
+ TRUNCATE TABLE im_rtc_call;
+ TRUNCATE TABLE im_user_online;
+ TRUNCATE TABLE im_face_user_item;
+
+ -- ============================================================
+ -- 17. OA 宸茶/鎸囧畾浜哄叧鑱旓紙淇濈暀閫氱煡鍏憡鍐呭 oa_notice / system_notice锛�
+ -- ============================================================
+ TRUNCATE TABLE oa_notice_read;
+ TRUNCATE TABLE oa_notice_user;
+
+ -- ============================================================
+ -- 18. 绀轰緥鏁版嵁
+ -- ============================================================
+ TRUNCATE TABLE yudao_demo01_contact;
+ TRUNCATE TABLE yudao_demo02_category;
+ TRUNCATE TABLE yudao_demo03_course;
+ TRUNCATE TABLE yudao_demo03_grade;
+ TRUNCATE TABLE yudao_demo03_student;
+
+ -- ============================================================
+ -- 19. 鍩虹鏁版嵁涓庝竴琚嬩竴鐮佺鐞�
+ -- 鍩虹鏁版嵁锛氱墿鏂欑鐞� / 鐗╂枡鍒嗙被 / 璁¢噺鍗曚綅 / 鍝佺墝 / SKU
+ -- 涓�琚嬩竴鐮侊細浜х嚎缁存姢 / 鎵规鐢熶骇绠$悊 / 璧嬬爜绠$悊 / 鎵樼洏鐮佺鐞�
+ -- 鍝佺鏁版嵁婧愶細mes_md_item锛堜笌 mdm_item 鍚屾锛屾壒娆�/琚嬬爜閫夊搧绉嶄娇鐢級
+ -- 淇濈暀锛歮es_md_vendor锛堜緵搴斿晢锛屼笌 erp_supplier 绛栫暐涓�鑷达級
+ -- / mdm_warehouse锛堜粨搴擄紝涓� mes_wm_warehouse 绛栫暐涓�鑷达級
+ -- / mes_md_workshop / mes_md_workstation*锛堣溅闂村伐浣滅珯閰嶇疆锛�
+ -- ============================================================
+ -- 涓�琚嬩竴鐮侊細鍏堟竻寮曠敤鎵规鐨勬槑缁嗭紝鍐嶆竻鎵规涓庝骇绾�
+ TRUNCATE TABLE mes_pro_batch_worker;
+ TRUNCATE TABLE mes_pro_bag_code_replace; -- 琚嬬爜鏇挎崲璁板綍锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mes_pro_bag_code;
+ TRUNCATE TABLE mes_pro_pallet;
+ TRUNCATE TABLE mes_pro_batch;
+ TRUNCATE TABLE mes_pro_line;
+ -- 鍝佺鏁版嵁婧愶紙MES 鐗╂枡浜у搧鍏宠仈閰嶇疆锛�
+ TRUNCATE TABLE mes_md_product_bom;
+ TRUNCATE TABLE mes_md_product_sop;
+ TRUNCATE TABLE mes_md_product_sip;
+ TRUNCATE TABLE mes_md_item_batch_config;
+ TRUNCATE TABLE mes_md_unit_measure; -- MES 璁¢噺鍗曚綅锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mes_md_item;
+ -- 鍩虹鏁版嵁锛圡DM 鐗╂枡涓绘暟鎹� / 鍒嗙被 / 璁¢噺鍗曚綅 / 鍝佺墝 / SKU锛�
+ TRUNCATE TABLE mdm_item_batch_config;
+ TRUNCATE TABLE mdm_item_sku; -- 鐗╂枡 SKU锛坢dm_item 瀛愯〃锛屽師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mdm_item;
+ TRUNCATE TABLE mdm_item_category; -- 鐗╂枡鍒嗙被锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mdm_brand; -- 鍝佺墝锛堝師鑴氭湰閬楁紡锛�
+ TRUNCATE TABLE mes_md_item_type;
+ TRUNCATE TABLE mdm_unit_measure;
+ -- 鐗╂枡杩佺Щ鏄犲皠琛細濡傛竻鐞嗗悗闇�浠� ERP 閲嶆柊杩佺Щ鐗╂枡锛岃鏀惧紑涓嬮潰涓�琛�
+ -- TRUNCATE TABLE mdm_item_migration_map;
+
+ SET FOREIGN_KEY_CHECKS = 1;
+
+ -- ============================================================
+ -- 娓呯悊缁撴灉鏍¢獙锛堜唬琛ㄨ〃琛屾暟搴斿叏閮ㄤ负 0锛�
+ -- ============================================================
+ SELECT
+ (SELECT COUNT(*) FROM mes_pro_work_order) AS work_order_cnt,
+ (SELECT COUNT(*) FROM mes_wm_material_stock) AS stock_cnt,
+ (SELECT COUNT(*) FROM mes_qc_iqc) AS iqc_cnt,
+ (SELECT COUNT(*) FROM crm_contract) AS contract_cnt,
+ (SELECT COUNT(*) FROM erp_sale_order) AS sale_order_cnt,
+ (SELECT COUNT(*) FROM mdm_item) AS mdm_item_cnt,
+ (SELECT COUNT(*) FROM system_operate_log) AS operate_log_cnt;
+
+ SELECT '涓氬姟鏁版嵁娓呯悊瀹屾垚' AS result;
+END $$
+
+DELIMITER ;
diff --git a/sql/mysql/wls_sales_outbound_menu_extract.sql b/sql/mysql/wls_sales_outbound_menu_extract.sql
new file mode 100644
index 0000000..6df47c8
--- /dev/null
+++ b/sql/mysql/wls_sales_outbound_menu_extract.sql
@@ -0,0 +1,25 @@
+-- =============================================
+-- 鍑哄簱娴侀�氱鐞嗚彍鍗曟彁鍙栬剼鏈�
+-- 灏�"閿�鍞粨搴�"(602479) 鎻愬彇涓轰竴绾ц彍鍗�"鍑哄簱娴侀�氱鐞�"
+-- 鍘熺粨鏋勶細浠撳偍鐗╂祦(5780) -> 閿�鍞粨搴�(602479) -> 鍙戣揣閫氱煡/閿�鍞嚭搴�/閿�鍞��璐�
+-- =============================================
+
+-- 1. 鎻愬彇涓轰竴绾ц彍鍗�
+-- 璇存槑锛氶《绾�"钀ラ攢绠$悊"(2617) 宸插崰鐢� path=sale锛屾晠鏀圭敤 sales-outbound 閬垮厤璺敱鍐茬獊
+UPDATE system_menu SET
+ parent_id = 0,
+ name = '鍑哄簱娴侀�氱鐞�',
+ path = 'sales-outbound',
+ sort = 10 -- 鏀惧湪浠撳偍鐗╂祦(sort=9)涔嬪悗
+WHERE id = 602479 AND deleted = b'0';
+
+-- =============================================
+-- 璇存槑锛�
+-- 1. 瀛愯彍鍗�(鍙戣揣閫氱煡 5867 / 閿�鍞嚭搴� 5970 / 閿�鍞��璐� 5847) 鏃犻渶鏀瑰姩锛�
+-- 鍓嶇鍔ㄦ�佽矾鐢变細鑷姩鎷兼帴涓� /sales-outbound/sales-notice 绛夎矾寰�
+-- 2. 椤剁骇鐩綍鑿滃崟鐢卞墠绔嚜鍔ㄦ覆鏌撲负 BasicLayout锛宑omponent 瀛楁鏃犻渶濉啓
+-- 3. 濡傞渶鎭㈠锛屾墽琛屼互涓嬪弽鍚戣剼鏈細
+-- =============================================
+
+-- 鍙嶅悜鑴氭湰锛堝闇�鎭㈠锛夛細
+-- UPDATE system_menu SET parent_id = 5780, name = '閿�鍞粨搴�', path = 'sale', sort = 5 WHERE id = 602479;
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java
new file mode 100644
index 0000000..e19d041
--- /dev/null
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.framework.common.util.number;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 涓氬姟缂栫爜锛堝崟鎹彿 / 涓绘暟鎹紪鐮侊級鐢熸垚鐨勫叕鍏辩害瀹氥��
+ *
+ * <p>闇�姹傦細绯荤粺涓墍鏈夎嚜鍔ㄧ敓鎴愮殑涓氬姟缂栫爜缁熶竴涓恒��16 浣嶇函鏁板瓧銆嶏紝涓�**闅忔満鐢熸垚銆佷笉浣跨敤鑷/椤哄簭**锛�
+ * 鍚屾椂淇濊瘉鍏ㄧ郴缁熷敮涓�锛堜换鎰忎袱鏉$紪鐮侀兘涓嶉噸澶嶏級銆�
+ *
+ * <p>瀹炵幇绾﹀畾锛�
+ * <ul>
+ * <li>缂栫爜 = 闅忔満 16 浣嶆暟瀛楋紙鑼冨洿 0 ~ 10^16-1锛屽乏渚цˉ '0'锛夛紱</li>
+ * <li>鍞竴鎬х敱 Redis 闆嗗悎 {@link #USED_SET_KEY} 鏌ラ噸淇濊瘉锛氶殢鏈虹敓鎴愬悗鍐欏叆闆嗗悎锛�
+ * 鍐欐垚鍔燂紙杩斿洖 1锛夎鏄庢病鐢ㄨ繃鎵嶉噰鐢紝鍚﹀垯閲嶈瘯锛�</li>
+ * <li>鍚勭敓鎴愮偣锛氳 {@link #randomCode()} 涓� {@link #MAX_RETRY}銆�</li>
+ * </ul>
+ *
+ * <p>娉ㄦ剰锛歊edis 闆嗗悎涓㈠け鍚庯紝鍘嗗彶缂栫爜鍙兘琚噸鏂伴殢鏈哄懡涓紱搴旂敤鍚姩鏃朵細灏嗗簱鍐呭凡鏈夌紪鐮�
+ * 閲嶆柊杞藉叆闆嗗悎锛堣 yudao-server 鐨勫惎鍔ㄥ厹搴曪級銆�
+ */
+public class BizNoUtils {
+
+ /**
+ * 宸蹭娇鐢ㄤ笟鍔$紪鐮佺殑 Redis 闆嗗悎 KEY锛岀敤浜庨殢鏈虹紪鐮佹煡閲嶏紝淇濊瘉鍏ㄧ郴缁熷敮涓�銆�
+ */
+ public static final String USED_SET_KEY = "biz:code:used";
+
+ /**
+ * 涓氬姟缂栫爜鐨勬�婚暱搴︼細16 浣�
+ */
+ public static final int CODE_LENGTH = 16;
+
+ /**
+ * 闅忔満缂栫爜鐨勭┖闂翠笂闄愶紙涓嶅惈锛夛細10^16
+ */
+ private static final long CODE_SPACE = 10_000_000_000_000_000L;
+
+ /**
+ * 鐢熸垚闅忔満缂栫爜鏃剁殑鏈�澶ч噸璇曟鏁帮紙鍛戒腑宸茬敤缂栫爜鏃堕噸璇曪級
+ */
+ public static final int MAX_RETRY = 10;
+
+ /**
+ * 鐢熸垚涓�涓殢鏈� 16 浣嶇函鏁板瓧缂栫爜锛堝乏渚цˉ '0'锛夛紝**涓嶅仛鏌ラ噸**銆�
+ *
+ * <p>璋冪敤鏂归渶鑷鐢� {@link #USED_SET_KEY} 鏌ラ噸锛屽懡涓垯閲嶈瘯銆�
+ *
+ * @return 闅忔満 16 浣嶇函鏁板瓧缂栫爜
+ */
+ public static String randomCode() {
+ return String.format("%0" + CODE_LENGTH + "d", ThreadLocalRandom.current().nextLong(CODE_SPACE));
+ }
+
+}
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java
index 856c862..a07d9c0 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java
@@ -1,14 +1,9 @@
package cn.iocoder.yudao.module.aftersales.dal.redis.no;
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateUtil;
-import cn.iocoder.yudao.module.aftersales.dal.redis.RedisKeyConstants;
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
-
-import java.time.Duration;
-import java.time.LocalDateTime;
/**
* 鍞悗妯″潡鍗曞彿 Redis DAO
@@ -30,17 +25,24 @@
private StringRedisTemplate stringRedisTemplate;
/**
- * 鐢熸垚搴忓彿锛屼娇鐢ㄥ綋鍓嶆棩鏈燂紝鏍煎紡涓� {PREFIX} + yyyyMMdd + 6 浣嶈嚜澧�
+ * 鐢熸垚 16 浣嶇函鏁板瓧涓氬姟缂栫爜锛堝叏绯荤粺鍞竴锛夈��
*
- * @param prefix 鍓嶇紑
- * @return 搴忓彿
+ * <p>涓哄吋瀹规棦鏈夎皟鐢ㄦ柟锛屼繚鐣� {@code prefix} 鍏ュ弬锛屼絾涓嶅啀鍙備笌缂栫爜鎷兼帴銆�
+ *
+ * @param prefix 鍗曟嵁绫诲瀷鍓嶇紑锛堝凡涓嶅啀鍙備笌缂栫爜鎷兼帴锛�
+ * @return 16 浣嶇函鏁板瓧缂栫爜
*/
public String generate(String prefix) {
- String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
- String key = RedisKeyConstants.NO + noPrefix;
- Long no = stringRedisTemplate.opsForValue().increment(key);
- stringRedisTemplate.expire(key, Duration.ofDays(1L));
- return noPrefix + String.format("%06d", no);
+ // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
+ // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+ String code = BizNoUtils.randomCode();
+ Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+ if (added != null && added > 0) {
+ return code;
+ }
+ }
+ throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
}
}
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java
index ed5fcd6..e820f5d 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java
@@ -130,8 +130,6 @@
MesWmReturnSalesCreateReqDTO mesReqDTO = new MesWmReturnSalesCreateReqDTO();
mesReqDTO.setCode(returnDO.getNo());
mesReqDTO.setName("鍞悗閫�璐�-" + returnDO.getNo());
- mesReqDTO.setSaleOrderId(returnDO.getSaleOrderId());
- mesReqDTO.setSalesOrderCode(ticket != null ? ticket.getSaleOrderNo() : null);
mesReqDTO.setClientId(returnDO.getCustomerId());
mesReqDTO.setReturnDate(LocalDate.now());
mesReqDTO.setReturnReason(returnDO.getReturnReason());
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
index 2a14f51..1fe6485 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
@@ -1,16 +1,10 @@
package cn.iocoder.yudao.module.bpm.dal.redis;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
-
-import java.time.Duration;
-import java.time.LocalDateTime;
-
-import static cn.hutool.core.date.DatePattern.*;
/**
* BPM 娴佺▼ Id 缂栫爜鐨� Redis DAO
@@ -24,38 +18,24 @@
private StringRedisTemplate stringRedisTemplate;
/**
- * 鐢熸垚搴忓彿锛屼娇鐢ㄥ畾涔夌殑 processIdRule 瑙勫垯鐢熸垚
+ * 鐢熸垚 16 浣嶇函鏁板瓧涓氬姟缂栫爜锛堝叏绯荤粺鍞竴锛夈��
*
- * @param processIdRule 瑙勫垯
- * @return 搴忓彿
+ * <p>涓哄吋瀹规棦鏈夎皟鐢ㄦ柟锛屼繚鐣� {@code processIdRule} 鍏ュ弬锛屼絾涓嶅啀鍙備笌缂栫爜鎷兼帴銆�
+ *
+ * @param processIdRule 娴佺▼ Id 瑙勫垯锛堝凡涓嶅啀鍙備笌缂栫爜鎷兼帴锛�
+ * @return 16 浣嶇函鏁板瓧缂栫爜
*/
public String generate(BpmModelMetaInfoVO.ProcessIdRule processIdRule) {
- // 鐢熸垚鏃ユ湡鍓嶇紑
- String infix = "";
- switch (processIdRule.getInfix()) {
- case "DAY":
- infix = DateUtil.format(LocalDateTime.now(), PURE_DATE_PATTERN);
- break;
- case "HOUR":
- infix = DateUtil.format(LocalDateTime.now(), PURE_DATE_PATTERN + "HH");
- break;
- case "MINUTE":
- infix = DateUtil.format(LocalDateTime.now(), PURE_DATE_PATTERN + "HHmm");
- break;
- case "SECOND":
- infix = DateUtil.format(LocalDateTime.now(), PURE_DATETIME_PATTERN);
- break;
+ // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
+ // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+ String code = BizNoUtils.randomCode();
+ Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+ if (added != null && added > 0) {
+ return code;
+ }
}
-
- // 鐢熸垚搴忓彿
- String noPrefix = processIdRule.getPrefix() + infix + processIdRule.getPostfix();
- String key = RedisKeyConstants.BPM_PROCESS_ID + noPrefix;
- Long no = stringRedisTemplate.opsForValue().increment(key);
- if (StrUtil.isEmpty(infix)) {
- // 鐗规畩锛氭病鏈夊墠缂�锛屽垯涓嶈兘杩囨湡锛屼笉鑳芥瘡娆¢兘鏄粠 0 寮�濮嬨�傚彲瑙� https://t.zsxq.com/MU1E2 璁ㄨ
- stringRedisTemplate.expire(key, Duration.ofDays(1L));
- }
- return noPrefix + String.format("%0" + processIdRule.getLength() + "d", no);
+ throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
}
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
index 7303e0c..2978c75 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
@@ -1,14 +1,9 @@
package cn.iocoder.yudao.module.crm.dal.redis.no;
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateUtil;
-import cn.iocoder.yudao.module.crm.dal.redis.RedisKeyConstants;
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
-
-import java.time.Duration;
-import java.time.LocalDateTime;
/**
@@ -43,20 +38,24 @@
private StringRedisTemplate stringRedisTemplate;
/**
- * 鐢熸垚搴忓彿锛屼娇鐢ㄥ綋鍓嶆棩鏈燂紝鏍煎紡涓� {PREFIX} + yyyyMMdd + 6 浣嶈嚜澧�
- * 渚嬪璇达細QTRK 202109 000001 锛堟病鏈変腑闂寸┖鏍硷級
+ * 鐢熸垚 16 浣嶇函鏁板瓧涓氬姟缂栫爜锛堝叏绯荤粺鍞竴锛夈��
*
- * @param prefix 鍓嶇紑
- * @return 搴忓彿
+ * <p>涓哄吋瀹规棦鏈夎皟鐢ㄦ柟锛屼繚鐣� {@code prefix} 鍏ュ弬锛屼絾涓嶅啀鍙備笌缂栫爜鎷兼帴銆�
+ *
+ * @param prefix 鍗曟嵁绫诲瀷鍓嶇紑锛堝凡涓嶅啀鍙備笌缂栫爜鎷兼帴锛�
+ * @return 16 浣嶇函鏁板瓧缂栫爜
*/
public String generate(String prefix) {
- // 閫掑搴忓彿
- String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
- String key = RedisKeyConstants.NO + noPrefix;
- Long no = stringRedisTemplate.opsForValue().increment(key);
- // 璁剧疆杩囨湡鏃堕棿
- stringRedisTemplate.expire(key, Duration.ofDays(1L));
- return noPrefix + String.format("%06d", no);
+ // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
+ // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+ String code = BizNoUtils.randomCode();
+ Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+ if (added != null && added > 0) {
+ return code;
+ }
+ }
+ throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
}
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
index 3cacd73..43748cd 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
@@ -21,9 +21,6 @@
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
-import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi;
-import cn.iocoder.yudao.module.mes.api.productsales.MesWmProductSalesLineApi;
-import cn.iocoder.yudao.module.mes.api.salesnotice.MesWmSalesNoticeApi;
import cn.iocoder.yudao.module.mes.api.wms.MesWmStockApi;
import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -63,12 +60,6 @@
private MdmItemApi mdmItemApi;
@Resource
private AdminUserApi adminUserApi;
- @Resource
- private MesWmSalesNoticeApi salesNoticeApi;
- @Resource
- private MesWmProductSalesLineApi productSalesLineApi;
- @Resource
- private MesProMpsApi mpsApi;
@Resource
private StorageAttachmentApi storageAttachmentApi;
@Resource
@@ -155,14 +146,11 @@
// 2. 鎵归噺鏌ヨ鍏宠仈鏁版嵁
Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(
convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId));
- Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds(
- convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId));
Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap(
convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId));
// 3. 杞崲璁㈠崟椤�
List<ErpSaleOrderRespVO.Item> itemVOList = BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> {
item.setStockCount(mesWmStockApi.getStockQuantity(item.getProductId()));
- item.setBatchCode(batchCodeMap.get(item.getId()));
MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem ->
item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode())
.setProductSpecification(mdmItem.getSpecification()));
@@ -213,54 +201,13 @@
// 1.4 绠$悊鍛樹俊鎭�
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(pageResult.getList(), saleOrder -> Long.parseLong(saleOrder.getCreator())));
- // 1.5 鍙戣揣閫氱煡鍗曚俊鎭�
- Map<Long, Boolean> salesNoticeMap = salesNoticeApi.checkSalesNoticeBySaleOrderIds(
- convertSet(pageResult.getList(), ErpSaleOrderDO::getId));
- // 1.6 鍑哄簱鎵瑰彿
- Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds(
- convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId));
- // 1.7 璁¢噺鍗曚綅
+ // 1.5 璁¢噺鍗曚綅
Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap(
convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId));
- // 1.8 妫�鏌ユ槸鍚﹀彲浠ョ敓鎴愬彂璐ч�氱煡鍗曪紙闇�瑕佺敓浜х殑鏄庣粏瀵瑰簲鐨� MPS 鏄惁宸插畬鎴愶級
- // 绛涢�夊嚭闇�瑕佺敓浜х殑鏄庣粏ID
- List<Long> needProductionItemIds = saleOrderItemList.stream()
- .filter(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1)
- .map(ErpSaleOrderItemDO::getId)
- .toList();
- Map<Long, Boolean> canCreateSalesNoticeMap = new java.util.HashMap<>();
- if (!needProductionItemIds.isEmpty()) {
- // 鎸夎鍗曞垎缁勬槑缁咺D
- Map<Long, List<Long>> orderItemIdsMap = new java.util.HashMap<>();
- for (ErpSaleOrderItemDO item : saleOrderItemList) {
- orderItemIdsMap.computeIfAbsent(item.getOrderId(), k -> new java.util.ArrayList<>())
- .add(item.getId());
- }
- // 妫�鏌ユ瘡涓鍗�
- for (Map.Entry<Long, List<Long>> entry : orderItemIdsMap.entrySet()) {
- List<Long> itemIds = entry.getValue().stream()
- .filter(id -> {
- ErpSaleOrderItemDO item = saleOrderItemList.stream()
- .filter(i -> i.getId().equals(id))
- .findFirst().orElse(null);
- return item != null && item.getNeedProduction() != null && item.getNeedProduction() == 1;
- }
- ).toList();
- if (itemIds.isEmpty()) {
- canCreateSalesNoticeMap.put(entry.getKey(), true);
- } else {
- canCreateSalesNoticeMap.put(entry.getKey(), mpsApi.checkCanCreateSalesNotice(itemIds));
- }
- }
- } else {
- // 娌℃湁闇�瑕佺敓浜х殑鏄庣粏锛岄兘鍙互鐢熸垚鍙戣揣閫氱煡鍗�
- pageResult.getList().forEach(order -> canCreateSalesNoticeMap.put(order.getId(), true));
- }
// 2. 寮�濮嬫嫾鎺�
return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> {
saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class,
item -> {
- item.setBatchCode(batchCodeMap.get(item.getId()));
MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem ->
item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode())
.setProductSpecification(mdmItem.getSpecification()));
@@ -270,10 +217,6 @@
saleOrder.setProductNames(CollUtil.join(saleOrder.getItems(), "锛�", ErpSaleOrderRespVO.Item::getProductName));
MapUtils.findAndThen(customerMap, saleOrder.getCustomerId(), supplier -> saleOrder.setCustomerName(supplier.getName()));
MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.setCreatorName(user.getNickname()));
- // 璁剧疆鏄惁宸茬敓鎴愬彂璐ч�氱煡鍗�
- saleOrder.setHasSalesNotice(salesNoticeMap.getOrDefault(saleOrder.getId(), false));
- // 璁剧疆鏄惁鍙互鐢熸垚鍙戣揣閫氱煡鍗曪細宸茬敓鎴愬彂璐ч�氱煡鍗曟椂涓嶆樉绀烘寜閽�
- saleOrder.setCanCreateSalesNotice(!saleOrder.getHasSalesNotice() && canCreateSalesNoticeMap.getOrDefault(saleOrder.getId(), true));
// 璁剧疆鏄惁鏈夐渶瑕佺敓浜х殑鏄庣粏
boolean hasNeedProduction = saleOrder.getItems().stream()
.anyMatch(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1);
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
index dd38717..73e35e7 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
@@ -104,18 +104,10 @@
@Schema(description = "鍑哄簱鐘舵��", example = "0")
private Integer outStatus;
- // ========== 鍙戣揣閫氱煡 ==========
-
- @Schema(description = "鏄惁宸茬敓鎴愬彂璐ч�氱煡鍗�", example = "false")
- private Boolean hasSalesNotice;
-
- @Schema(description = "鏄惁鍙互鐢熸垚鍙戣揣閫氱煡鍗曪紙鏈夐渶瑕佺敓浜т笖鏈畬鎴愮殑鏄庣粏鏃朵负 false锛�", example = "true")
- private Boolean canCreateSalesNotice;
+ // ========== 鐢熶骇鍏宠仈 ==========
@Schema(description = "鏄惁鏈夐渶瑕佺敓浜х殑鏄庣粏锛�0=鍚� 1=鏄級", example = "1")
private Integer needProduction;
-
- // ========== 鐢熶骇鍏宠仈 ==========
@Schema(description = "鐢熶骇鐘舵�侊細0-鏈畬鎴愶紝1-宸插畬鎴�", example = "1")
private Integer productionStatus;
@@ -163,11 +155,6 @@
@Schema(description = "鍏宠仈鐨� MPS 缂栧彿", example = "1024")
private Long mpsId;
-
- // ========== 鍑哄簱鎵瑰彿 ==========
-
- @Schema(description = "鍑哄簱鎵瑰彿", example = "B2026001銆丅2026002")
- private String batchCode;
// ========== 鍏宠仈瀛楁 ==========
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
index bdce48c..965f8be 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
@@ -1,14 +1,9 @@
package cn.iocoder.yudao.module.erp.dal.redis.no;
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateUtil;
-import cn.iocoder.yudao.module.erp.dal.redis.RedisKeyConstants;
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
-
-import java.time.Duration;
-import java.time.LocalDateTime;
/**
@@ -52,20 +47,24 @@
private StringRedisTemplate stringRedisTemplate;
/**
- * 鐢熸垚搴忓彿锛屼娇鐢ㄥ綋鍓嶆棩鏈燂紝鏍煎紡涓� {PREFIX} + yyyyMMdd + 6 浣嶈嚜澧�
- * 渚嬪璇达細CGDD 202109 000001 锛堟病鏈変腑闂寸┖鏍硷級
+ * 鐢熸垚 16 浣嶇函鏁板瓧涓氬姟缂栫爜锛堝叏绯荤粺鍞竴锛夈��
*
- * @param prefix 鍓嶇紑
- * @return 搴忓彿
+ * <p>涓哄吋瀹规棦鏈夎皟鐢ㄦ柟锛屼繚鐣� {@code prefix} 鍏ュ弬锛屼絾涓嶅啀鍙備笌缂栫爜鎷兼帴銆�
+ *
+ * @param prefix 鍗曟嵁绫诲瀷鍓嶇紑锛堝凡涓嶅啀鍙備笌缂栫爜鎷兼帴锛�
+ * @return 16 浣嶇函鏁板瓧缂栫爜
*/
public String generate(String prefix) {
- // 閫掑搴忓彿
- String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
- String key = RedisKeyConstants.NO + noPrefix;
- Long no = stringRedisTemplate.opsForValue().increment(key);
- // 璁剧疆杩囨湡鏃堕棿
- stringRedisTemplate.expire(key, Duration.ofDays(1L));
- return noPrefix + String.format("%06d", no);
+ // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
+ // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+ String code = BizNoUtils.randomCode();
+ Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+ if (added != null && added > 0) {
+ return code;
+ }
+ }
+ throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
}
}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java
index 44009fd..a934a53 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java
@@ -1,13 +1,9 @@
package cn.iocoder.yudao.module.hrm.dal.redis;
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateUtil;
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
-
-import java.time.Duration;
-import java.time.LocalDateTime;
/**
* HRM 缂栧彿鐢熸垚鐨� Redis DAO
@@ -131,19 +127,23 @@
}
/**
- * 鐢熸垚缂栧彿
+ * 鐢熸垚 16 浣嶇函鏁板瓧涓氬姟缂栫爜锛堝叏绯荤粺鍞竴锛夈��
*
- * @param prefix 鍓嶇紑
- * @param digits 浣嶆暟
- * @return 缂栧彿
+ * <p>涓哄吋瀹规棦鏈夎皟鐢ㄦ柟锛屼繚鐣欏叆鍙傦紝浣嗕笉鍐嶅弬涓庣紪鐮佹嫾鎺ャ��
+ *
+ * @return 16 浣嶇函鏁板瓧缂栫爜
*/
public String generate(String prefix, int digits) {
- String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
- String key = HrmRedisKeyConstants.NO + noPrefix;
- Long no = stringRedisTemplate.opsForValue().increment(key);
- // 璁剧疆杩囨湡鏃堕棿 1 澶�
- stringRedisTemplate.expire(key, Duration.ofDays(1L));
- return noPrefix + String.format("%0" + digits + "d", no);
+ // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
+ // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+ String code = BizNoUtils.randomCode();
+ Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+ if (added != null && added > 0) {
+ return code;
+ }
+ }
+ throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
}
}
diff --git a/yudao-module-mdm-api/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java b/yudao-module-mdm-api/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java
index a9144f6..297ddb4 100644
--- a/yudao-module-mdm-api/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java
+++ b/yudao-module-mdm-api/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java
@@ -18,6 +18,9 @@
@Schema(description = "鍗曚綅鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "涓�")
private String name;
+ @Schema(description = "绫诲瀷锛�48鍗冨厠/100鍗冨厠/鍚級", example = "48鍗冨厠")
+ private String type;
+
@Schema(description = "鏄惁涓诲崟浣�", example = "true")
private Boolean primaryFlag;
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
index 664126c..77bc2c9 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
@@ -8,12 +8,10 @@
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemStatusUpdateReqVO;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSyncUpdateReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService;
-import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService;
import cn.iocoder.yudao.module.mdm.service.item.MdmItemBatchConfigService;
import cn.iocoder.yudao.module.mdm.service.item.MdmItemService;
import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService;
@@ -47,8 +45,6 @@
@Resource
private MesMdItemApi mesMdItemApi;
- @Resource
- private MdmItemCategoryService itemCategoryService;
@Resource
private MdmUnitMeasureService unitMeasureService;
@Resource
@@ -129,9 +125,6 @@
@PreAuthorize("@ss.hasPermission('mdm:item:query')")
public CommonResult<PageResult<MdmItemRespVO>> getItemPage(@Valid MdmItemPageReqVO pageReqVO) {
PageResult<MdmItemDO> pageResult = itemService.getItemPage(pageReqVO);
- // 鍏宠仈鏌ヨ鍒嗙被鍚嶇О
- Map<Long, MdmItemCategoryDO> categoryMap = itemCategoryService.getItemCategoryMap(
- convertSet(pageResult.getList(), MdmItemDO::getCategoryId));
// 鍏宠仈鏌ヨ璁¢噺鍗曚綅鍚嶇О
Map<Long, MdmUnitMeasureDO> unitMap = unitMeasureService.getUnitMeasureMap(
convertSet(pageResult.getList(), MdmItemDO::getUnitMeasureId));
@@ -158,11 +151,6 @@
.collect(Collectors.toMap(MesWmWarehouseRespDTO::getId, w -> w));
// 璧嬪��
respList.forEach(resp -> {
- // 鍒嗙被鍚嶇О
- MdmItemCategoryDO category = categoryMap.get(resp.getCategoryId());
- if (category != null) {
- resp.setCategoryName(category.getName());
- }
MdmUnitMeasureDO unit = unitMap.get(resp.getUnitMeasureId());
if (unit != null) {
resp.setUnitMeasureName(unit.getName());
@@ -215,13 +203,6 @@
* 濉厖鐗╂枡鍝嶅簲 VO 鐨勫叧鑱斿悕绉帮紙鍒嗙被銆佷富鍗曚綅銆佽緟鍗曚綅銆佷粨搴撳悕绉帮級
*/
private void enrichItemRespVO(MdmItemRespVO resp) {
- // 鍒嗙被鍚嶇О
- if (resp.getCategoryId() != null) {
- MdmItemCategoryDO category = itemCategoryService.getItemCategory(resp.getCategoryId());
- if (category != null) {
- resp.setCategoryName(category.getName());
- }
- }
// 涓诲崟浣嶅悕绉�
if (resp.getUnitMeasureId() != null) {
MdmUnitMeasureDO unit = unitMeasureService.getUnitMeasure(resp.getUnitMeasureId());
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java
index 93e87b5..174f5dd 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java
@@ -23,9 +23,6 @@
@Schema(description = "鐗╂枡鏉$爜", example = "12345678")
private String barCode;
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", example = "1")
- private Long categoryId;
-
@Schema(description = "鐗╂枡绫诲瀷", example = "1")
private Integer itemType;
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java
index b9709d3..a718008 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java
@@ -25,12 +25,6 @@
@Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
private String specification;
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long categoryId;
-
- @Schema(description = "鐗╂枡鍒嗙被鍚嶇О", example = "浜旈噾閰嶄欢")
- private String categoryName;
-
@Schema(description = "璁¢噺鍗曚綅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long unitMeasureId;
@@ -75,9 +69,6 @@
@Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer status;
-
- @Schema(description = "閲囪喘浠锋牸", example = "10.00")
- private BigDecimal purchasePrice;
@Schema(description = "閿�鍞环鏍�", example = "15.00")
private BigDecimal salesPrice;
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java
index de0c38d..fd76583 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java
@@ -24,9 +24,6 @@
@Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
private String specification;
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿锛堝叧鑱� MES 鐗╂枡鍒嗙被 mes_md_item_type锛�", example = "1")
- private Long categoryId;
-
@Schema(description = "璁¢噺鍗曚綅缂栧彿", example = "1")
private Long unitMeasureId;
@@ -53,9 +50,6 @@
@Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer status;
-
- @Schema(description = "閲囪喘浠锋牸", example = "10.00")
- private BigDecimal purchasePrice;
@Schema(description = "閿�鍞环鏍�", example = "15.00")
private BigDecimal salesPrice;
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java
index 0d9455c..509f0f9 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.mdm.controller.admin.unit.vo;
import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.math.BigDecimal;
@@ -18,6 +19,10 @@
@Schema(description = "鍗曚綅鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "涓�")
private String name;
+ @Schema(description = "绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "48鍗冨厠")
+ @NotBlank(message = "绫诲瀷涓嶈兘涓虹┖")
+ private String type;
+
@Schema(description = "鏄惁涓诲崟浣�", example = "true")
private Boolean primaryFlag;
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java
index 7663696..3cb2d2c 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java
@@ -40,6 +40,13 @@
private String name;
/**
+ * 绫诲瀷
+ *
+ * 鍙�夊�硷細48鍗冨厠銆�100鍗冨厠銆佸惃
+ */
+ private String type;
+
+ /**
* 鏄惁涓诲崟浣�
*/
private Boolean primaryFlag;
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
index 138b8e0..3176e2f 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
@@ -2,28 +2,20 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemBatchConfigMapper;
import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService;
-import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService;
import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService;
import cn.iocoder.yudao.module.mes.api.item.MesMdItemApi;
-import cn.iocoder.yudao.module.mes.api.item.MesMdItemTypeApi;
import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO;
-import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -33,7 +25,6 @@
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
/**
@@ -49,8 +40,6 @@
private MdmItemMapper itemMapper;
@Resource
- private MdmItemCategoryService itemCategoryService;
- @Resource
private MdmUnitMeasureService unitMeasureService;
@Resource
private MdmBrandService brandService;
@@ -60,9 +49,6 @@
private MesMdItemApi mesMdItemApi;
@Resource
private MdmItemBatchConfigMapper itemBatchConfigMapper;
-
- @Resource
- private MesMdItemTypeApi mesMdItemTypeApi;
@Override
@@ -115,10 +101,9 @@
}
/**
- * 鍚屾鐗╂枡鍒� MES锛堝崟浣�/鍒嗙被鎸� code 鏄犲皠锛�
+ * 鍚屾鐗╂枡鍒� MES锛堝崟浣嶆寜 code 鏄犲皠锛�
*
- * MDM 鐨� unitMeasureId/categoryId 涓� MES 鐨� unitMeasureId/itemTypeId 鍒嗗睘涓ゅ涓绘暟鎹紝
- * 杩欓噷鍏堝湪 MDM 渚цВ鏋愬嚭 code锛屽啀浜ょ敱 MesMdItemApi 鍦� MES 渚цВ鏋愪负瀵瑰簲 id銆�
+ * 鍝佺绠$悊宸插幓鎺夈�屽搧绉嶅垎绫汇�嶅瓧娈碉紝鍚屾涓嶅啀浼犻�� MES 鐗╂枡鍒嗙被锛坕tem_type_id 鐣欑┖锛屽彲鍦� MES 渚цˉ濉級銆�
* 鍚屾澶辫触灏嗘姏鍑哄紓甯革紝瑙﹀彂澶栧眰 @Transactional 鏁翠綋鍥炴粴锛圡DM 鎿嶄綔涓�骞跺洖婊氾級銆�
*/
private void syncItemToMes(MdmItemSaveReqVO reqVO) {
@@ -131,12 +116,6 @@
}
unitCode = unitMeasure.getCode();
}
- // 瑙f瀽鍒嗙被 id -> code锛堜娇鐢� MDM 鏈湴鍒嗙被鏈嶅姟锛�
- String itemTypeCode = null;
- if (reqVO.getCategoryId() != null) {
- CommonResult<MesMdItemTypeRespDTO> itemType = mesMdItemTypeApi.getItemType(reqVO.getCategoryId());
- itemTypeCode = itemType.getData().getCode();
- }
// 缁勮鍚屾 DTO
MesMdItemSyncReqDTO syncReqDTO = new MesMdItemSyncReqDTO();
syncReqDTO.setCode(reqVO.getCode());
@@ -144,7 +123,6 @@
syncReqDTO.setName(reqVO.getName());
syncReqDTO.setSpecification(reqVO.getSpecification());
syncReqDTO.setUnitCode(unitCode);
- syncReqDTO.setItemTypeCode(itemTypeCode);
syncReqDTO.setSafeStockFlag(Boolean.TRUE); // 淇濈暀 MDM 鐨� minStock/maxStock锛岄伩鍏嶈 MES 娓呴浂
syncReqDTO.setMinStock(reqVO.getMinStock());
syncReqDTO.setMaxStock(reqVO.getMaxStock());
@@ -274,17 +252,6 @@
}
}
- private void validateCategoryExists(Long categoryId) {
- if (categoryId == null) {
- return;
- }
- // 浣跨敤 MDM 鏈湴鍒嗙被鏈嶅姟鏍¢獙
- MdmItemCategoryDO category = itemCategoryService.getItemCategory(categoryId);
- if (category == null) {
- throw exception(MDM_ITEM_CATEGORY_NOT_EXISTS);
- }
- }
-
private void validateUnitMeasureExists(Long unitMeasureId) {
if (unitMeasureService.getUnitMeasure(unitMeasureId) == null) {
throw exception(MDM_UNIT_MEASURE_NOT_EXISTS);
@@ -328,17 +295,8 @@
@Override
public PageResult<MdmItemDO> getItemPage(MdmItemPageReqVO pageReqVO) {
- // 鏌ユ壘鏃讹紝濡傛灉鏌ユ壘鏌愪釜鍒嗙被缂栧彿锛屽垯鍖呭惈瀹冪殑瀛愬垎绫�
- Set<Long> categoryIds = null;
- if (pageReqVO.getCategoryId() != null) {
- categoryIds = new HashSet<>();
- categoryIds.add(pageReqVO.getCategoryId());
- List<cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO> children =
- itemCategoryService.getItemCategoryChildrenList(pageReqVO.getCategoryId());
- categoryIds.addAll(convertSet(children, cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO::getId));
- }
// 鍒嗛〉鏌ヨ
- return itemMapper.selectPage(pageReqVO, categoryIds);
+ return itemMapper.selectPage(pageReqVO, (Collection<Long>) null);
}
@Override
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/item/dto/MesMdItemSyncReqDTO.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/item/dto/MesMdItemSyncReqDTO.java
index 1910fb0..2512f86 100644
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/item/dto/MesMdItemSyncReqDTO.java
+++ b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/item/dto/MesMdItemSyncReqDTO.java
@@ -21,9 +21,6 @@
@Schema(description = "璁¢噺鍗曚綅缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "PCS")
private String unitCode;
- @Schema(description = "鐗╂枡鍒嗙被缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "TYPE001")
- private String itemTypeCode;
-
@Schema(description = "鏄惁鍚敤瀹夊叏搴撳瓨", example = "false")
private Boolean safeStockFlag;
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApi.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApi.java
deleted file mode 100644
index 42d7636..0000000
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApi.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.productsales;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * MES 閿�鍞嚭搴撳崟琛� API 鎺ュ彛
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-public interface MesWmProductSalesLineApi {
-
- /**
- * 鏍规嵁閿�鍞鍗曟槑缁� ID 鍒楄〃鏌ヨ鍑哄簱鎵瑰彿
- *
- * @param saleOrderItemIds 閿�鍞鍗曟槑缁� ID 鍒楄〃
- * @return Map<閿�鍞鍗曟槑缁咺D, 鎵瑰彿涓茶仈瀛楃涓�>
- */
- Map<Long, String> getBatchCodesBySaleOrderItemIds(Collection<Long> saleOrderItemIds);
-
-}
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java
index ce7e494..bdc8482 100644
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java
+++ b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java
@@ -20,12 +20,6 @@
@Schema(description = "閫�璐у崟鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍞悗閫�璐�")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long clientId;
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApi.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApi.java
deleted file mode 100644
index b6c5825..0000000
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApi.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.salesnotice;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * MES 鍙戣揣閫氱煡鍗� API 鎺ュ彛
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-public interface MesWmSalesNoticeApi {
-
- /**
- * 鏍规嵁閿�鍞鍗� ID 鍒楄〃妫�鏌ユ槸鍚﹀凡鐢熸垚鍙戣揣閫氱煡鍗�
- *
- * @param saleOrderIds 閿�鍞鍗� ID 鍒楄〃
- * @return Map<閿�鍞鍗旾D, 鏄惁宸茬敓鎴愬彂璐ч�氱煡鍗�>
- */
- Map<Long, Boolean> checkSalesNoticeBySaleOrderIds(Collection<Long> saleOrderIds);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/item/MesMdItemApiImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/item/MesMdItemApiImpl.java
index 3376239..437a08f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/item/MesMdItemApiImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/item/MesMdItemApiImpl.java
@@ -5,12 +5,10 @@
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.batchconfig.MesMdItemBatchConfigSaveReqVO;
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.unitmeasure.MesMdUnitMeasureDO;
import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemMapper;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService;
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.unitmeasure.MesMdUnitMeasureService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -27,7 +25,7 @@
* MES 鐗╂枡浜у搧 API 瀹炵幇绫�
*
* 渚� MDM 绛夋ā鍧楀悓姝ョ墿鏂欎富鏁版嵁鍒� MES 浣跨敤銆�
- * 鍗曚綅銆佸垎绫绘寜 code 鍦� MES 渚цВ鏋愪负瀵瑰簲 id銆�
+ * 鍗曚綅鎸� code 鍦� MES 渚цВ鏋愪负瀵瑰簲 id銆�
*
* @author 瓒呯骇绠$悊鍛�
*/
@@ -40,8 +38,6 @@
private MesMdItemService itemService;
@Resource
private MesMdItemMapper itemMapper;
- @Resource
- private MesMdItemTypeService itemTypeService;
@Resource
private MesMdUnitMeasureService unitMeasureService;
@Resource
@@ -92,7 +88,9 @@
}
/**
- * 灏嗗悓姝� DTO 杞崲涓� MES 鐗╂枡浜у搧 SaveReqVO锛屽苟鎸� code 瑙f瀽鍗曚綅/鍒嗙被 id
+ * 灏嗗悓姝� DTO 杞崲涓� MES 鐗╂枡浜у搧 SaveReqVO锛屽苟鎸� code 瑙f瀽鍗曚綅 id
+ *
+ * MDM 鍝佺绠$悊宸插幓鎺夈�屽搧绉嶅垎绫汇�嶏紝鍚屾涓嶅啀璁剧疆鐗╂枡鍒嗙被锛坕tem_type_id 鐣欑┖锛屽彲鍦� MES 渚ф墜宸ヨˉ濉級
*/
private MesMdItemSaveReqVO buildSaveReqVO(MesMdItemSyncReqDTO syncReqDTO) {
// 瑙f瀽璁¢噺鍗曚綅 code -> id
@@ -100,15 +98,9 @@
if (unitMeasure == null) {
throw exception(MD_UNIT_MEASURE_NOT_EXISTS);
}
- // 瑙f瀽鐗╂枡鍒嗙被 code -> id
- MesMdItemTypeDO itemType = itemTypeService.getItemTypeByCode(syncReqDTO.getItemTypeCode());
- if (itemType == null) {
- throw exception(MD_ITEM_TYPE_NOT_EXISTS);
- }
// 缁勮锛坈ode/name/specification/safeStockFlag/minStock/maxStock/highValue/batchFlag/remark 鍚屽悕鎷疯礉锛�
MesMdItemSaveReqVO saveReqVO = BeanUtils.toBean(syncReqDTO, MesMdItemSaveReqVO.class);
saveReqVO.setUnitMeasureId(unitMeasure.getId());
- saveReqVO.setItemTypeId(itemType.getId());
return saveReqVO;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApiImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApiImpl.java
deleted file mode 100644
index 005e87e..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApiImpl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.productsales;
-
-import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * MES 閿�鍞嚭搴撳崟琛� API 瀹炵幇绫�
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-@Service
-@Validated
-public class MesWmProductSalesLineApiImpl implements MesWmProductSalesLineApi {
-
- @Resource
- private MesWmProductSalesLineMapper productSalesLineMapper;
-
- @Override
- public Map<Long, String> getBatchCodesBySaleOrderItemIds(Collection<Long> saleOrderItemIds) {
- return productSalesLineMapper.selectBatchCodesBySaleOrderItemIds(saleOrderItemIds);
- }
-
-}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApiImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApiImpl.java
deleted file mode 100644
index 943fb7b..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApiImpl.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.salesnotice;
-
-import cn.iocoder.yudao.module.mes.dal.mysql.wm.salesnotice.MesWmSalesNoticeMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * MES 鍙戣揣閫氱煡鍗� API 瀹炵幇绫�
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-@Service
-@Validated
-public class MesWmSalesNoticeApiImpl implements MesWmSalesNoticeApi {
-
- @Resource
- private MesWmSalesNoticeMapper salesNoticeMapper;
-
- @Override
- public Map<Long, Boolean> checkSalesNoticeBySaleOrderIds(Collection<Long> saleOrderIds) {
- if (saleOrderIds == null || saleOrderIds.isEmpty()) {
- return Collections.emptyMap();
- }
- // 鏌ヨ宸插瓨鍦ㄧ殑閿�鍞鍗� ID
- List<Long> existingSaleOrderIds = salesNoticeMapper.selectExistingSaleOrderIds(saleOrderIds);
- // 鏋勫缓杩斿洖缁撴灉
- Map<Long, Boolean> result = new HashMap<>();
- for (Long saleOrderId : saleOrderIds) {
- result.put(saleOrderId, existingSaleOrderIds.contains(saleOrderId));
- }
- return result;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java
index cf6c323..4bb5491 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java
@@ -37,6 +37,25 @@
@Schema(description = "鎵樼洏鐮佹�绘暟", requiredMode = Schema.RequiredMode.REQUIRED, example = "800")
private Long palletCount;
+ // ========== 鍑哄簱娴侀�� ==========
+
+ @Schema(description = "鍙戣揣閫氱煡鍗曟暟锛坢es_wm_sales_notice锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ private Long salesNoticeCount;
+
+ @Schema(description = "閿�鍞嚭搴撳崟鏁帮紙mes_wm_product_sales锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ private Long productSalesCount;
+
+ @Schema(description = "閿�鍞��璐у崟鏁帮紙mes_wm_return_sales锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ private Long returnSalesCount;
+
+ // ========== 浠撳偍棰勮 / 璐ㄩ噺 ==========
+
+ @Schema(description = "鏈鐞嗗簱瀛橀璀︽暟锛坢es_wm_stock_warning.status=10锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
+ private Long stockWarningPendingCount;
+
+ @Schema(description = "寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁帮紙mes_qc_ncr.status=0锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ private Long ncrPendingCount;
+
// ========== 鐘舵�佸垎甯� ==========
@Schema(description = "鎵规鐘舵�佸垎甯�")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemSaveReqVO.java
index 6de4a79..756f55e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemSaveReqVO.java
@@ -29,8 +29,7 @@
@NotNull(message = "璁¢噺鍗曚綅涓嶈兘涓虹┖")
private Long unitMeasureId;
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- @NotNull(message = "鐗╂枡鍒嗙被缂栧彿涓嶈兘涓虹┖")
+ @Schema(description = "鐗╂枡鍒嗙被缂栧彿", example = "1")
private Long itemTypeId;
@Schema(description = "鏄惁鍚敤瀹夊叏搴撳瓨", example = "false")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java
index fa1455f..8e6ca6e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/MesProBagCodeController.java
@@ -14,6 +14,7 @@
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;
@@ -77,6 +78,14 @@
@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")
@@ -242,8 +251,7 @@
.setProduceDate(batch.getProduceDate())
.setLineCode(batch.getLineCode())
.setLineName(batch.getLineName())
- .setOwnerUserId(batch.getOwnerUserId())
- .setItemId(batch.getItemId());
+ .setOwnerUserId(batch.getOwnerUserId());
// 璐d换浜�
if (batch.getOwnerUserId() != null) {
AdminUserRespDTO user = adminUserApi.getUser(batch.getOwnerUserId());
@@ -251,14 +259,17 @@
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;
@@ -268,11 +279,12 @@
* 鏋勫缓琚嬬爜浜岀淮鐮佹爣绛惧垪琛紙浜岀淮鐮佺紪鐮佺函鐮佸�硷紝鍥剧墖鍙犲姞鍏抽敭淇℃伅鏂囧瓧锛�
*/
private List<QrLabelInfo> buildBagCodeQrLabels(List<MesProBagCodeDO> list) {
- // 1. 鑾峰緱鍏宠仈鏁版嵁锛堟壒娆°�佸搧绉嶃�佽矗浠讳汉锛�
+ // 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));
+ Set<Long> itemIds = convertSet(list, MesProBagCodeDO::getItemId);
+ itemIds.addAll(convertSet(batchMap.values(), MesProBatchDO::getItemId));
+ Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap(itemIds);
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(batchMap.values(), MesProBatchDO::getOwnerUserId));
// 2. 鏋勫缓鏍囩
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateReqVO.java
index 3a708f4..2199316 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateReqVO.java
@@ -9,10 +9,17 @@
@Data
public class MesProBagCodeGenerateReqVO {
- @Schema(description = "鐢熸垚琚嬫暟锛堟湰娆$敓鎴愮殑琚嬬爜鏁伴噺锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
- @NotNull(message = "鐢熸垚琚嬫暟涓嶈兘涓虹┖")
- @Positive(message = "鐢熸垚琚嬫暟蹇呴』澶т簬 0")
- private Integer count;
+ @Schema(description = "鍝佺锛堢墿鏂欙級缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "鍝佺涓嶈兘涓虹┖")
+ private Long itemId;
+
+ @Schema(description = "鎵樼洏鏁帮紙鍝佺涓诲崟浣嶇被鍨嬩负 48鍗冨厠/100鍗冨厠 鏃跺繀濉紝琚嬬爜鏁� = 姣忔墭琚嬫暟 脳 鎵樼洏鏁帮級", example = "5")
+ @Positive(message = "鎵樼洏鏁板繀椤诲ぇ浜� 0")
+ private Integer palletCount;
+
+ @Schema(description = "琚嬬爜鏁帮紙鍝佺涓诲崟浣嶇被鍨嬩负 鍚� 鏃跺繀濉紝涓嶇敓鎴愭墭鐩橈級", example = "100")
+ @Positive(message = "琚嬬爜鏁板繀椤诲ぇ浜� 0")
+ private Integer bagCount;
@Schema(description = "澶囨敞")
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateRespVO.java
index 87f5d35..8d8c484 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeGenerateRespVO.java
@@ -3,10 +3,24 @@
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
+import java.util.List;
+
@Schema(description = "绠$悊鍚庡彴 - MES 琚嬬爜鐢熸垚鍝嶅簲")
@Data
public class MesProBagCodeGenerateRespVO {
@Schema(description = "鐢熸垚缁� UUID")
private String uuid;
+
+ @Schema(description = "鍝佺涓诲崟浣嶇被鍨�", example = "48鍗冨厠")
+ private String type;
+
+ @Schema(description = "姣忔墭鐩樿鏁帮紙绫诲瀷涓� 鍚� 鏃朵负 0锛�", example = "48")
+ private Integer perPallet;
+
+ @Schema(description = "鏈鐢熸垚鐨勮鐮佹�绘暟", example = "240")
+ private Integer totalCount;
+
+ @Schema(description = "鑷姩鐢熸垚鐨勬墭鐩樼紪鍙峰垪琛紙绫诲瀷涓� 鍚� 鏃朵负绌猴級")
+ private List<Long> palletIds;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodePageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodePageReqVO.java
index d8a1fd4..7f2b2ea 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodePageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodePageReqVO.java
@@ -32,6 +32,9 @@
@Schema(description = "缁戝畾鎵樼洏缂栧彿", example = "1024")
private Long palletId;
+ @Schema(description = "鍝佺锛堢墿鏂欙級缂栧彿", example = "1024")
+ private Long itemId;
+
@Schema(description = "鐘舵�侊紙瀛楀吀 mes_pro_bag_code_status锛�", example = "10")
private Integer status;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRawGenerateReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRawGenerateReqVO.java
new file mode 100644
index 0000000..0d18c50
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRawGenerateReqVO.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 鍘熷琚嬬爜鐢熸垚 Request VO锛堜粎鍝佺+鏁伴噺锛屼笉鍏宠仈璁¢噺鍗曚綅绫诲瀷銆佷笉鐢熸垚鎵樼洏锛�")
+@Data
+public class MesProBagCodeRawGenerateReqVO {
+
+ @Schema(description = "鍝佺锛堢墿鏂欙級缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "鍝佺涓嶈兘涓虹┖")
+ private Long itemId;
+
+ @Schema(description = "琚嬬爜鏁伴噺", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+ @NotNull(message = "琚嬬爜鏁伴噺涓嶈兘涓虹┖")
+ @Positive(message = "琚嬬爜鏁伴噺蹇呴』澶т簬 0")
+ private Integer count;
+
+ @Schema(description = "澶囨敞")
+ private String remark;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRespVO.java
index 07be109..68186db 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/bagcode/vo/MesProBagCodeRespVO.java
@@ -58,6 +58,20 @@
@ColumnWidth(30)
private String palletCode;
+ @Schema(description = "鍝佺缂栧彿", example = "1")
+ @ExcelIgnore
+ private Long itemId;
+
+ @Schema(description = "鍝佺缂栫爜")
+ @ExcelProperty("鍝佺缂栫爜")
+ @ColumnWidth(20)
+ private String itemCode;
+
+ @Schema(description = "鍝佺鍚嶇О")
+ @ExcelProperty("鍝佺鍚嶇О")
+ @ColumnWidth(20)
+ private String itemName;
+
@Schema(description = "鐘舵�侊紙瀛楀吀 mes_pro_bag_code_status锛�", example = "10")
@ExcelProperty(value = "鐘舵��", converter = DictConvert.class)
@DictFormat(DictTypeConstants.MES_PRO_BAG_CODE_STATUS)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java
index 6c4830a..05ba023 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/MesProBatchController.java
@@ -213,21 +213,13 @@
if (CollUtil.isEmpty(list)) {
return Collections.emptyList();
}
- // 1. 鑾峰緱鍏宠仈鏁版嵁锛堣矗浠讳汉銆佸搧绉嶇墿鏂欙級
+ // 1. 鑾峰緱鍏宠仈鏁版嵁锛堣矗浠讳汉锛夛紱鍝佺宸蹭笅娌夊埌琚嬬爜鏁版嵁鍖咃紝鎵规鍒楄〃涓嶅啀灞曠ず
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(list, MesProBatchDO::getOwnerUserId));
- Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap(
- convertSet(list, MesProBatchDO::getItemId));
// 2. 鏋勫缓缁撴灉
- return BeanUtils.toBean(list, MesProBatchRespVO.class, vo -> {
- MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user ->
- vo.setOwnerUserName(user.getNickname()));
- MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
- vo.setItemCode(item.getCode());
- vo.setItemName(item.getName());
- vo.setItemSpecification(item.getSpecification());
- });
- });
+ return BeanUtils.toBean(list, MesProBatchRespVO.class, vo ->
+ MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user ->
+ vo.setOwnerUserName(user.getNickname())));
}
private List<MesProBatchWorkerRespVO> buildWorkerRespVOList(List<MesProBatchWorkerDO> workers) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchPageReqVO.java
index 552dd1e..327f26f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchPageReqVO.java
@@ -23,18 +23,18 @@
@Schema(description = "涓存椂鎵规鐮�", example = "PB-00000001")
private String tempCode;
- @Schema(description = "鍝佺锛堜骇鍝佺墿鏂欙級缂栧彿", example = "1")
- private Long itemId;
-
@Schema(description = "浜х嚎缂栧彿", example = "1")
private Long lineId;
@Schema(description = "浜х嚎缂栫爜", example = "L01")
private String lineCode;
- @Schema(description = "浜х嚎鍚嶇О", example = "鍖呰涓�绾�")
+ @Schema(description = "浜х嚎鍚嶇О锛堥〉闈㈠睍绀轰负銆屽姞宸ュ崟浣嶃�嶏級", example = "鍖呰涓�绾�")
private String lineName;
+ @Schema(description = "鍔犲伐鐝粍", example = "涓�鍙峰姞宸ョ彮缁�")
+ private String processingTeam;
+
@Schema(description = "璐d换浜虹敤鎴风紪鍙�", example = "1")
private Long ownerUserId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java
index 8a97fa6..3114c86 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchRespVO.java
@@ -30,41 +30,29 @@
@ExcelIgnore
private String tempCode;
- @Schema(description = "鍝佺锛堜骇鍝佺墿鏂欙級缂栧彿", example = "1")
- @ExcelIgnore
- private Long itemId;
-
- @Schema(description = "鍝佺缂栫爜")
- @ExcelProperty("鍝佺缂栫爜")
- private String itemCode;
-
- @Schema(description = "鍝佺鍚嶇О")
- @ExcelProperty("鍝佺鍚嶇О")
- private String itemName;
-
- @Schema(description = "鍝佺瑙勬牸")
- @ExcelProperty("鍝佺瑙勬牸")
- private String itemSpecification;
-
@Schema(description = "浜х嚎缂栧彿", example = "1")
@ExcelIgnore
private Long lineId;
- @Schema(description = "浜х嚎缂栫爜", example = "L01")
- @ExcelProperty("浜х嚎缂栫爜")
+ @Schema(description = "浜х嚎缂栫爜锛堥〉闈㈠凡闅愯棌锛屼粎鎺ュ彛杩斿洖锛�", example = "L01")
+ @ExcelIgnore
private String lineCode;
- @Schema(description = "浜х嚎鍚嶇О", example = "鍖呰涓�绾�")
- @ExcelProperty("浜х嚎鍚嶇О")
+ @Schema(description = "浜х嚎鍚嶇О锛堥〉闈㈠睍绀轰负銆屽姞宸ュ崟浣嶃�嶏級", example = "鍖呰涓�绾�")
+ @ExcelProperty("鍔犲伐鍗曚綅")
private String lineName;
+
+ @Schema(description = "鍔犲伐鐝粍", example = "涓�鍙峰姞宸ョ彮缁�")
+ @ExcelProperty("鍔犲伐鐝粍")
+ private String processingTeam;
@Schema(description = "鐢熶骇鏃ユ湡")
@ExcelProperty("鐢熶骇鏃ユ湡")
@ColumnWidth(20)
private LocalDateTime produceDate;
- @Schema(description = "璁″垝鏁伴噺", example = "1000")
- @ExcelProperty("璁″垝鏁伴噺")
+ @Schema(description = "鍔犲伐鏁伴噺锛堝師璁″垝鏁伴噺锛岄〉闈㈠睍绀轰负銆屽姞宸ユ暟閲忋�嶏級", example = "1000")
+ @ExcelProperty("鍔犲伐鏁伴噺")
private BigDecimal planQuantity;
@Schema(description = "璐d换浜虹敤鎴风紪鍙�", example = "1")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java
index 6b5cd8d..9985b15 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/batch/vo/MesProBatchSaveReqVO.java
@@ -4,6 +4,7 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -20,20 +21,20 @@
@Schema(description = "缂栧彿", example = "1024")
private Long id;
- @Schema(description = "鍝佺锛堜骇鍝佺墿鏂欙級缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- @NotNull(message = "鍝佺涓嶈兘涓虹┖")
- private Long itemId;
-
- @Schema(description = "浜х嚎缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- @NotNull(message = "浜х嚎涓嶈兘涓虹┖")
+ @Schema(description = "浜х嚎缂栧彿锛堥〉闈㈠睍绀轰负銆屽姞宸ュ崟浣嶃�嶏級", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "鍔犲伐鍗曚綅涓嶈兘涓虹┖")
private Long lineId;
+
+ @Schema(description = "鍔犲伐鐝粍锛堟墜宸ュ~鍐欙級", example = "涓�鍙峰姞宸ョ彮缁�")
+ @Size(max = 64, message = "鍔犲伐鐝粍闀垮害涓嶈兘瓒呰繃 64")
+ private String processingTeam;
@Schema(description = "鐢熶骇鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "鐢熶骇鏃ユ湡涓嶈兘涓虹┖")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime produceDate;
- @Schema(description = "璁″垝鏁伴噺", example = "1000")
+ @Schema(description = "鍔犲伐鏁伴噺锛堝師璁″垝鏁伴噺锛岄〉闈㈠睍绀轰负銆屽姞宸ユ暟閲忋�嶏級", example = "1000")
private BigDecimal planQuantity;
@Schema(description = "璐d换浜虹敤鎴风紪鍙凤紙璐d换钀藉疄鍒颁汉锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -48,6 +49,9 @@
@Valid
private List<Worker> workers;
+ @Schema(description = "缁戝畾鎵樼洏缂栧彿鍒楄〃锛堝彲閫夛紱缁戝畾鏃舵壒娆$洿鎺ヨ繘鍏ョ敓浜т腑锛屾墭鐩樹笅琚嬬爜绾ц仈褰曞叆鏈壒娆★紱鏂板/琛ュ綍/缂栬緫鍧囧彲浼犲叆锛岀紪杈戞椂浠呴渶浼犳湰娆℃柊澧炲嬀閫夌殑鎵樼洏锛�")
+ private List<Long> palletIds;
+
@Schema(description = "鐢熶骇浜哄憳閰嶇疆")
@Data
public static class Worker {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/MesProPalletController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/MesProPalletController.java
index 9139d30..1aba55e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/MesProPalletController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/MesProPalletController.java
@@ -159,6 +159,14 @@
return success(BeanUtils.toBean(list, MesProPalletRespVO.class));
}
+ @GetMapping("/unbound-list")
+ @Operation(summary = "鑾峰緱鏈粦瀹氭壒娆$殑涓存椂鎵樼洏鍒楄〃锛堜緵鎵规鏂板/琛ュ綍缁戝畾鎵樼洏涓嬫媺浣跨敤锛�")
+ @PreAuthorize("@ss.hasPermission('mes:pro-pallet:query')")
+ public CommonResult<List<MesProPalletRespVO>> getUnboundPalletList() {
+ List<MesProPalletDO> list = palletService.getUnboundPalletList();
+ return success(BeanUtils.toBean(list, MesProPalletRespVO.class));
+ }
+
@GetMapping("/export-excel")
@Operation(summary = "瀵煎嚭鎵樼洏鐮� Excel")
@PreAuthorize("@ss.hasPermission('mes:pro-pallet:export')")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletBatchCreateReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletBatchCreateReqVO.java
index 5638401..050a19d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletBatchCreateReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletBatchCreateReqVO.java
@@ -18,10 +18,6 @@
@Positive(message = "鐢熸垚鏁伴噺蹇呴』澶т簬 0")
private Integer count;
- @Schema(description = "鍙琚嬫暟锛堣/鎵樼洏锛�", example = "25")
- @Positive(message = "鍙琚嬫暟蹇呴』澶т簬 0")
- private Integer capacity;
-
@Schema(description = "澶囨敞")
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletPreGenerateReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletPreGenerateReqVO.java
index 8d6b510..65d00a3 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletPreGenerateReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletPreGenerateReqVO.java
@@ -14,10 +14,6 @@
@Positive(message = "鐢熸垚鏁伴噺蹇呴』澶т簬 0")
private Integer count;
- @Schema(description = "鍙琚嬫暟锛堣/鎵樼洏锛�", example = "25")
- @Positive(message = "鍙琚嬫暟蹇呴』澶т簬 0")
- private Integer capacity;
-
@Schema(description = "澶囨敞")
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletRespVO.java
index 15181be..1b78e2f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletRespVO.java
@@ -41,10 +41,6 @@
@ExcelProperty("鎵樼洏搴忓彿")
private Integer palletNo;
- @Schema(description = "鍙琚嬫暟锛堣/鎵樼洏锛�", example = "25")
- @ExcelProperty("鍙琚嬫暟")
- private Integer capacity;
-
@Schema(description = "宸茬粦瀹氳鐮佹暟閲�", example = "10")
@ExcelProperty("宸茶琚嬫暟")
private Integer bagCount;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java
index 4566021..f3dfe25 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java
@@ -23,7 +23,7 @@
@RestController @RequestMapping("/mes/pro/scan-in")
public class MesProScanEventController {
@Resource private MesProScanEventService service;
- @PostMapping("/inbound") @PreAuthorize("@ss.hasPermission('mes:pro-scan-in:inbound')") @Operation(summary = "琚嬬爜鎵爜鍏ュ簱")
+ @PostMapping("/inbound") @PreAuthorize("@ss.hasPermission('mes:pro-scan-in:inbound')") @Operation(summary = "杩芥函鐮佹壂鐮佸叆搴擄紙琚嬬爜/鎵樼洏鐮�/鎵规鐮侊級")
public CommonResult<MesProScanEventRespVO> inbound(@Valid @RequestBody MesProScanEventCreateReqVO req) {
return success(BeanUtils.toBean(service.createInbound(req), MesProScanEventRespVO.class));
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java
index 99ded7b..c6c2565 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java
@@ -8,9 +8,19 @@
@Data
public class MesProScanEventCreateReqVO {
@NotBlank private String eventId;
+ /**
+ * 鎵爜鍐呭锛堣鐮� / 鎵樼洏鐮� / 鎵规鐮佺殑鐮佸�硷紝鍚复鏃剁爜锛�
+ */
@NotBlank private String bagCode;
+ /**
+ * 鎵爜绫诲瀷锛欱AG 琚嬬爜 / PALLET 鎵樼洏鐮� / BATCH 鎵规鐮侊紝榛樿 BAG
+ */
+ private String scanType;
@NotNull @DecimalMin("0.000001") private BigDecimal quantity;
- @NotBlank private String deviceCode;
+ /**
+ * 璁惧缂栫爜锛堜笉鍐嶅繀濉紝浜х嚎鎵爜浠ヤ骇绾�+搴撳尯搴撲綅瀹氫綅锛�
+ */
+ @Size(max = 64) private String deviceCode;
private String lineCode;
@NotNull private Long locationId;
@NotNull private Long areaId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java
index 18ca711..2cfb498 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java
@@ -10,6 +10,7 @@
private Long id;
private String eventId;
private String bagCode;
+ private String scanType;
private String batchCode;
private BigDecimal quantity;
private String deviceCode;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/trace/MesProTraceResolveController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/trace/MesProTraceResolveController.java
new file mode 100644
index 0000000..0061b4b
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/trace/MesProTraceResolveController.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.mes.controller.admin.pro.trace;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+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 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 org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * MES 鎵爜杩芥函 - 缂栫爜绫诲瀷瑙f瀽銆�
+ *
+ * <p>缂栫爜缁熶竴涓恒��16 浣嶇函鏁板瓧銆嶅悗锛屾棤娉曞啀鎸夊墠缂�鍒ゆ柇绫诲瀷锛圔AG-/PL-/PB- 绛夊墠缂�宸插彇娑堬級锛�
+ * 鍓嶇鎵爜鍚庡厛璋冪敤鏈帴鍙f寜缂栫爜鍙嶆煡鍏舵墍灞炵被鍨嬶紝鍐嶈皟鐢ㄥ搴旂被鍨嬬殑杩芥函鎺ュ彛銆�
+ */
+@Tag(name = "绠$悊鍚庡彴 - MES 鎵爜婧簮锛堢被鍨嬭В鏋愶級")
+@RestController
+@RequestMapping("/mes/pro/trace")
+@Validated
+public class MesProTraceResolveController {
+
+ @Resource
+ private MesProBagCodeService bagCodeService;
+ @Resource
+ private MesProPalletService palletService;
+ @Resource
+ private MesProBatchService batchService;
+
+ @GetMapping("/resolve-type")
+ @Operation(summary = "鏍规嵁缂栫爜瑙f瀽婧簮绫诲瀷锛歜ag / pallet / batch锛涘潎涓嶅尮閰嶈繑鍥炵┖")
+ @Parameter(name = "code", description = "缂栫爜锛堜簩缁寸爜鍐呭锛�", required = true)
+ @PreAuthorize("@ss.hasPermission('mes:pro-bag-code:query')")
+ public CommonResult<String> resolveType(@RequestParam("code") String code) {
+ if (bagCodeService.getBagCodeByCode(code) != null) {
+ return success("bag");
+ }
+ if (palletService.getPalletByCode(code) != null) {
+ return success("pallet");
+ }
+ if (batchService.getBatchByCode(code) != null) {
+ return success("batch");
+ }
+ return success(null);
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
index 2d35909..3bbd79e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
@@ -1,6 +1,10 @@
package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
import cn.iocoder.yudao.module.mes.service.qc.seedquality.MesQcSeedQualityService;
import io.swagger.v3.oas.annotations.Operation;
@@ -16,6 +20,13 @@
@RestController @RequestMapping("/mes/qc/seed-quality") @Validated
public class MesQcSeedQualityController {
@Resource private MesQcSeedQualityService service;
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱绉嶅瓙璐ㄦ璁板綍鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:query')")
+ public CommonResult<PageResult<MesQcSeedQualityRespVO>> getQualityPage(@Valid MesQcSeedQualityPageReqVO pageReqVO) {
+ return success(BeanUtils.toBean(service.getQualityPage(pageReqVO), MesQcSeedQualityRespVO.class));
+ }
+
@PostMapping("/submit") @Operation(summary = "鎻愪氦绉嶅瓙璐ㄦ")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:submit')")
public CommonResult<Long> submit(@Valid @RequestBody MesQcSeedQualitySubmitReqVO reqVO) { return success(service.submit(reqVO)); }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java
new file mode 100644
index 0000000..2645d67
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 绉嶅瓙璐ㄦ璁板綍鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MesQcSeedQualityPageReqVO extends PageParam {
+
+ @Schema(description = "璐ㄦ琚嬬爜")
+ private String code;
+
+ @Schema(description = "鐢熶骇鎵规")
+ private String batchCode;
+
+ @Schema(description = "妫�楠岀粨鏋滐細1鍚堟牸 2涓嶅悎鏍�")
+ private Integer result;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java
new file mode 100644
index 0000000..6102954
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 绉嶅瓙璐ㄦ璁板綍 Response VO")
+@Data
+public class MesQcSeedQualityRespVO {
+
+ private Long id;
+ private String code;
+ private Long itemId;
+ private Long batchId;
+ private String batchCode;
+ private Integer result;
+ private String reason;
+ private Long inspectorId;
+ private LocalDateTime inspectedAt;
+ private LocalDateTime createTime;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
index d3b0978..1d8d9d3 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
@@ -9,10 +9,11 @@
@Data
public class MesQcSeedQualitySubmitReqVO {
@NotBlank private String code;
- @NotNull private Long itemId;
private String batchCode;
@NotEmpty @Valid private List<Indicator> indicators;
private String reason;
+ /** 鐩爣鍚堟牸搴撶紪鍙凤紙璐ㄦ鍚堟牸鍚庡叆璇ヤ粨搴擄級锛屽繀椤绘槸浠撳簱绫诲瀷涓哄悎鏍煎簱(20)鐨勪粨搴� */
+ @NotNull private Long qualifiedWarehouseId;
@Data public static class Indicator {
@NotBlank private String code;
@NotNull @DecimalMin("0") private BigDecimal value;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java
new file mode 100644
index 0000000..4ce1163
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.mes.controller.admin.trace.batch;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesProTracePublicRespVO;
+import cn.iocoder.yudao.module.mes.service.trace.MesProTracePublicService;
+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.validation.constraints.NotBlank;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - MES 鎵规杩芥函")
+@RestController
+@RequestMapping("/mes/trace/batch")
+@Validated
+public class MesTraceBatchController {
+
+ @Resource
+ private MesProTracePublicService traceService;
+
+ @GetMapping("/detail")
+ @Operation(summary = "鏌ヨ缁熶竴鎵规杩芥函璇︽儏")
+ @Parameter(name = "code", description = "鎵规鐮併�佷复鏃舵壒娆$爜銆佽鐮佹垨鎵樼洏鐮�", required = true,
+ example = "BAG-202608280001")
+ @PreAuthorize("@ss.hasPermission('mes:trace-batch:query')")
+ public CommonResult<MesProTracePublicRespVO> getBatchTraceDetail(
+ @RequestParam("code") @NotBlank(message = "杩芥函鐮佷笉鑳戒负绌�") String code) {
+ return success(traceService.queryTrace(code));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchFlowRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchFlowRespVO.java
new file mode 100644
index 0000000..ce058b2
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchFlowRespVO.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 鎵规鍑哄叆搴撴祦姘达紙绉嶅瓙娴佸悜锛塕esponse VO")
+@Data
+public class MesWmBatchFlowRespVO {
+
+ @Schema(description = "浜嬪姟绫诲瀷锛�1-鍏ュ簱 2-鍑哄簱", example = "2")
+ private Integer type;
+
+ @Schema(description = "涓氬姟绫诲瀷锛堣 MesBizTypeConstants锛屽 119-閿�鍞嚭搴撱��124-浜у搧浜у嚭锛�", example = "119")
+ private Integer bizType;
+
+ @Schema(description = "鏉ユ簮涓氬姟鍗曞彿", example = "SL_20260901002")
+ private String bizCode;
+
+ @Schema(description = "鏈鍙樺姩鏁伴噺锛堝嚭搴撲负璐熸暟锛�", example = "-1")
+ private BigDecimal quantity;
+
+ @Schema(description = "浜嬪姟鍙戠敓鏃堕棿")
+ private LocalDateTime transactionTime;
+
+ @Schema(description = "浠撳簱鍚嶇О", example = "鎴愬搧鍚堟牸搴�")
+ private String warehouseName;
+
+ @Schema(description = "搴撳尯鍚嶇О", example = "鎴愬搧鍚堟牸搴撳尯")
+ private String locationName;
+
+ @Schema(description = "搴撲綅鍚嶇О", example = "鎴愬搧鍚堟牸搴撲綅")
+ private String areaName;
+
+ @Schema(description = "瀹㈡埛鍚嶇О锛堥攢鍞嚭搴�/閿�鍞��璐ф椂锛�", example = "瀹㈡埛A")
+ private String clientName;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
index 26cb544..6c23287 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
@@ -14,6 +14,9 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagRespVO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmStockSummaryRespVO;
import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO;
@@ -21,6 +24,7 @@
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
@@ -72,6 +76,8 @@
private MesWmWarehouseAreaService areaService;
@Resource
private SrmSupplierApi srmSupplierApi;
+ @Resource
+ private MesWmMaterialStockBagMapper materialStockBagMapper;
@GetMapping("/get")
@Operation(summary = "鑾峰緱搴撳瓨璁板綍")
@@ -92,6 +98,17 @@
@Valid MesWmMaterialStockPageReqVO pageReqVO) {
PageResult<MesWmMaterialStockDO> pageResult = materialStockService.getMaterialStockPage(pageReqVO);
return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/bag-details")
+ @Operation(summary = "鏌ヨ搴撳瓨琚嬬爜鏄庣粏")
+ @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:query')")
+ public CommonResult<PageResult<MesWmMaterialStockBagRespVO>> getMaterialStockBagDetails(
+ @Valid MesWmMaterialStockBagPageReqVO pageReqVO) {
+ PageResult<MesWmMaterialStockBagRespVO> result = new PageResult<>();
+ PageResult<cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO> page =
+ materialStockBagMapper.selectPage(pageReqVO);
+ return success(new PageResult<>(BeanUtils.toBean(page.getList(), MesWmMaterialStockBagRespVO.class), page.getTotal()));
}
@PutMapping("/update-frozen")
@@ -179,6 +196,9 @@
convertSet(list, MesWmMaterialStockDO::getLocationId));
Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
convertSet(list, MesWmMaterialStockDO::getAreaId));
+ Map<Long, Long> bagCountMap = materialStockBagMapper.selectListByMaterialStockIds(
+ convertSet(list, MesWmMaterialStockDO::getId)).stream()
+ .collect(Collectors.groupingBy(MesWmMaterialStockBagDO::getMaterialStockId, Collectors.counting()));
Map<Long, SrmSupplierRespDTO> vendorMap = srmSupplierApi.getSupplierList(
convertSet(list, MesWmMaterialStockDO::getVendorId)).getCheckedData().stream()
.collect(Collectors.toMap(SrmSupplierRespDTO::getId, s -> s));
@@ -197,6 +217,8 @@
area -> vo.setAreaName(area.getName()));
MapUtils.findAndThen(vendorMap, vo.getVendorId(),
vendor -> vo.setVendorName(vendor.getName()));
+ vo.setBagCount(bagCountMap.getOrDefault(vo.getId(), 0L));
+ vo.setBagDetailSupported(bagCountMap.containsKey(vo.getId()));
// 璁$畻鍙敤閲� = 鍦ㄥ簱鏁伴噺 - 鍐荤粨鏁伴噺 - 鍗犵敤閲�
BigDecimal quantity = vo.getQuantity() != null ? vo.getQuantity() : BigDecimal.ZERO;
BigDecimal frozenQty = vo.getFrozenQuantity() != null ? vo.getFrozenQuantity() : BigDecimal.ZERO;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java
new file mode 100644
index 0000000..7b6c868
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Schema(description = "绠$悊鍚庡彴 - 搴撳瓨琚嬬爜鏄庣粏鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MesWmMaterialStockBagPageReqVO extends PageParam {
+
+ @Schema(description = "搴撳瓨姹囨�昏褰旾D", requiredMode = Schema.RequiredMode.REQUIRED)
+ private Long materialStockId;
+
+ @Schema(description = "琚嬬爜")
+ private String bagCode;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java
new file mode 100644
index 0000000..e1b8041
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo;
+
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 搴撳瓨琚嬬爜鏄庣粏 Response VO")
+@Data
+public class MesWmMaterialStockBagRespVO {
+ private Long id;
+ private Long materialStockId;
+ private Long bagCodeId;
+ private String bagCode;
+ private Long itemId;
+ private Long batchId;
+ private String batchCode;
+ private Long warehouseId;
+ private Long locationId;
+ private Long areaId;
+ private Integer stockState;
+ private Integer status;
+ private BigDecimal quantity;
+ private Boolean frozen;
+ private LocalDateTime inboundTime;
+ private LocalDateTime outboundTime;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java
index 8be7fce..cc8d0b6 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java
@@ -12,6 +12,9 @@
@Schema(description = "浠撳簱缂栧彿")
private Long warehouseId;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴擄紝20鍚堟牸搴擄紙鎸夌被鍨嬭繃婊や粨搴擄紝涓� warehouseId 浜岄�変竴锛�", example = "20")
+ private Integer warehouseType;
+
@Schema(description = "搴撳尯缂栧彿")
private Long locationId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java
index 6549016..c4b9862 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java
@@ -39,6 +39,9 @@
@Schema(description = "浠撳簱缂栧彿", example = "1")
private Long warehouseId;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴擄紝20鍚堟牸搴擄紙鎸夌被鍨嬭繃婊や粨搴擄紝涓� warehouseId 浜岄�変竴锛�", example = "20")
+ private Integer warehouseType;
+
@Schema(description = "搴撳尯缂栧彿", example = "1")
private Long locationId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java
index 5cec30c..c3d901e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java
@@ -46,6 +46,12 @@
@ExcelProperty("鎵规鍙�")
private String batchCode;
+ @Schema(description = "褰撳墠琚嬬爜鏁伴噺", example = "10")
+ private Long bagCount;
+
+ @Schema(description = "鏄惁瀛樺湪琚嬬爜鏄庣粏", example = "true")
+ private Boolean bagDetailSupported;
+
@Schema(description = "浠撳簱缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long warehouseId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java
index a3f44a6..885e7fd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java
@@ -42,10 +42,6 @@
@ExcelProperty("鍑哄簱鎿嶄綔浜�")
private String outboundUserName;
- @Schema(description = "閿�鍞鍗曞彿", example = "SO2026030001")
- @ExcelProperty("閿�鍞鍗曞彿")
- private String salesOrderCode;
-
@Schema(description = "鍑哄簱鏃ユ湡")
@ExcelProperty("鍑哄簱鏃ユ湡")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java
index 1c94e13..996c873 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java
@@ -26,9 +26,6 @@
@NotNull(message = "瀹㈡埛涓嶈兘涓虹┖")
private Long clientId;
- @Schema(description = "閿�鍞鍗曞彿", example = "SO2026030001")
- private String salesOrderCode;
-
@Schema(description = "鍑哄簱鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "鍑哄簱鏃ユ湡涓嶈兘涓虹┖")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java
index 1008ffc..f581a93 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java
@@ -26,12 +26,6 @@
@Schema(description = "閫�璐у崟鍚嶇О", example = "閿�鍞��璐�")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", example = "1")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java
index 8d50c3c..dbd8d3f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java
@@ -24,12 +24,6 @@
@Schema(description = "閫�璐у崟鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "閿�鍞��璐�")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java
index b77d34f..a267c62 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java
@@ -27,12 +27,6 @@
@NotBlank(message = "閫�璐у崟鍚嶇О涓嶈兘涓虹┖")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "瀹㈡埛 ID 涓嶈兘涓虹┖")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java
index 2bf826e..17e2662 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java
@@ -111,14 +111,6 @@
return success(true);
}
- @PostMapping("/generate-from-sale-order")
- @Operation(summary = "浠庨攢鍞鍗曠敓鎴愬彂璐ч�氱煡鍗�")
- @PreAuthorize("@ss.hasPermission('mes:wm-sales-notice:create')")
- public CommonResult<Long> generateFromSaleOrder(@RequestBody Map<String, Long> params) {
- Long saleOrderId = params.get("saleOrderId");
- return success(salesNoticeService.generateSalesNoticeFromSaleOrder(saleOrderId));
- }
-
@PostMapping("/generate-product-sales")
@Operation(summary = "浠庡彂璐ч�氱煡鍗曠敓鎴愰攢鍞嚭搴撳崟")
@Parameter(name = "id", description = "鍙戣揣閫氱煡鍗曠紪鍙�", required = true)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java
index f3ce710..80d4881 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java
@@ -18,9 +18,6 @@
@Schema(description = "閫氱煡鍗曞悕绉�", example = "娴嬭瘯鍙戣揣閫氱煡")
private String name;
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String saleOrderCode;
-
@Schema(description = "瀹㈡埛缂栧彿", example = "1")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java
index ad39bbd..53445d2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java
@@ -31,13 +31,6 @@
@ExcelProperty("瀹㈡埛鍚嶇О")
private String clientName;
- @Schema(description = "閿�鍞鍗旾D", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曞彿", example = "SO202603010001")
- @ExcelProperty("閿�鍞鍗曞彿")
- private String saleOrderCode;
-
@Schema(description = "鍙戣揣鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("鍙戣揣鏃ユ湡")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java
index 4ffa6e2..444d3d9 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java
@@ -26,12 +26,6 @@
@NotNull(message = "瀹㈡埛缂栧彿涓嶈兘涓虹┖")
private Long clientId;
- @Schema(description = "閿�鍞鍗旾D", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曞彿", example = "SO202603010001")
- private String saleOrderCode;
-
@Schema(description = "鍙戣揣鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "鍙戣揣鏃ユ湡涓嶈兘涓虹┖")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java
index 93201b1..3a3f837 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java
@@ -16,9 +16,6 @@
@Schema(description = "鍙戣揣閫氱煡鍗曠紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long noticeId;
- @Schema(description = "閿�鍞鍗曟槑缁咺D", example = "1")
- private Long saleOrderItemId;
-
@Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long itemId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java
index 35af7ca..d6ba341 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java
@@ -18,9 +18,6 @@
@NotNull(message = "鍙戣揣閫氱煡鍗曠紪鍙蜂笉鑳戒负绌�")
private Long noticeId;
- @Schema(description = "閿�鍞鍗曟槑缁咺D", example = "1")
- private Long saleOrderItemId;
-
@Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "鐗╂枡缂栧彿涓嶈兘涓虹┖")
private Long itemId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/MesWmTransactionController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/MesWmTransactionController.java
index 10faf64..4f90f4f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/MesWmTransactionController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/MesWmTransactionController.java
@@ -119,6 +119,12 @@
return "鏈煡";
}
switch (bizType) {
+ case MesBizTypeConstants.QC_SEED_QUALITY:
+ return "绉嶅瓙璐ㄦ";
+ case MesBizTypeConstants.WM_ITEM_RECEIPT_CANCEL:
+ return "閲囪喘鍏ュ簱鍙栨秷";
+ case MesBizTypeConstants.WM_STOCK_TAKING:
+ return "鐩樼偣璋冩暣";
case MesBizTypeConstants.WM_STOCK_ADJUST_IN:
return "鑷畾涔夊叆搴�";
case MesBizTypeConstants.WM_STOCK_ADJUST_OUT:
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java
index 0cabd59..20b4b0f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java
@@ -26,6 +26,9 @@
@Schema(description = "鎵规鍙�", example = "BATCH001")
private String batchCode;
+ @Schema(description = "琚嬬爜", example = "BG202608180001")
+ private String bagCode;
+
@Schema(description = "浠撳簱ID", example = "1")
private Long warehouseId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java
index e40218c..3ec6568 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java
@@ -51,6 +51,12 @@
@Schema(description = "鎵规鍙�", example = "BATCH001")
private String batchCode;
+ @Schema(description = "琚嬬爜ID", example = "1")
+ private Long bagCodeId;
+
+ @Schema(description = "琚嬬爜", example = "BG202608180001")
+ private String bagCode;
+
// ========== 搴撳瓨浣嶇疆 ==========
@Schema(description = "浠撳簱ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java
index e6861e3..1b2e826 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java
@@ -21,4 +21,7 @@
@Schema(description = "鏄惁鍐荤粨", example = "false")
private Boolean frozen;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴� 20鍚堟牸搴�", example = "20")
+ private Integer type;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java
index 6c85e3b..10edec2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java
@@ -40,6 +40,10 @@
@ExcelProperty("鏄惁鍐荤粨")
private Boolean frozen;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴� 20鍚堟牸搴�", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ @ExcelProperty("浠撳簱绫诲瀷")
+ private Integer type;
+
@Schema(description = "澶囨敞", example = "澶囨敞")
@ExcelProperty("澶囨敞")
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java
index a05c861..ddfe51e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java
@@ -35,6 +35,10 @@
@NotNull(message = "鏄惁鍐荤粨涓嶈兘涓虹┖")
private Boolean frozen;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴� 20鍚堟牸搴�", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ @NotNull(message = "浠撳簱绫诲瀷涓嶈兘涓虹┖")
+ private Integer type;
+
@Schema(description = "澶囨敞", example = "澶囨敞")
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java
index 6f5d570..7c1e32e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.controller.pub.trace.vo;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
@@ -14,7 +15,7 @@
* H5 鎵爜婧簮 - 鍏ㄧ▼婧簮淇℃伅 Response VO
* <p>
* 浠ャ�屼俊鎭尯鍧椼�嶆ā鍧楀寲缁勭粐锛屾牳蹇冧俊鎭紙鍝佺/鎵规/浜哄憳/璐ㄦ/鍏ュ簱锛夊缁堣繑鍥烇紱
- * 閲囪喘鏉ユ簮銆侀攢鍞幓鍚戙�佸姞宸ユ祦杞负鍙�夋墿灞曞尯鍧楋紙鏈夋暟鎹墠闈炵┖锛夈�傚悗缁柊澧炴暟鎹簮鎸夊悓涓�妯″紡杩藉姞鍖哄潡瀛楁銆�
+ * 閲囪喘鏉ユ簮銆侀攢鍞幓鍚戙�佺瀛愭祦鍚戯紙鎵规鍑哄叆搴撴祦姘达級銆佸姞宸ユ祦杞负鍙�夋墿灞曞尯鍧楋紙鏈夋暟鎹墠闈炵┖锛夈�傚悗缁柊澧炴暟鎹簮鎸夊悓涓�妯″紡杩藉姞鍖哄潡瀛楁銆�
*/
@Schema(description = "H5 鎵爜婧簮 - 鍏ㄧ▼婧簮淇℃伅 Response VO")
@Data
@@ -26,6 +27,9 @@
@Schema(description = "璇锋眰鐨勮拷婧爜锛堝師濮嬫壂鐮佸�硷級", example = "PC20260828twoITEM_001")
private String requestCode;
+ @Schema(description = "鏄惁宸插綍鍏ョ敓浜ф壒娆★紙false 琛ㄧず琚嬬爜/鎵樼洏宸茬敓鎴愪絾灏氭湭褰曞叆鎵规锛屾鏃朵粎杩斿洖鍝佺淇℃伅锛�", example = "true")
+ private Boolean batchBound;
+
// ====== 鍝佺淇℃伅鍖哄潡 ======
@Schema(description = "鍝佺缂栫爜")
private String itemCode;
@@ -35,6 +39,9 @@
@Schema(description = "鍝佺瑙勬牸")
private String itemSpecification;
+
+ @Schema(description = "鍝佺璁¢噺鍗曚綅鍚嶇О", example = "48鍗冨厠")
+ private String itemUnitMeasureName;
// ====== 鐢熶骇鎵规淇℃伅鍖哄潡 ======
@Schema(description = "鎵规鍙�")
@@ -116,9 +123,50 @@
@Schema(description = "閿�鍞幓鍚戯紙鍙�夛級")
private List<MesWmBatchSalesTargetRespVO> salesTargets;
+ @Schema(description = "绉嶅瓙娴佸悜淇℃伅锛堟壒娆″嚭鍏ュ簱娴佹按锛氱敓浜у叆搴� 鈫� 閿�鍞嚭搴撶瓑锛屽彲閫夛級")
+ private List<MesWmBatchFlowRespVO> seedFlows;
+
@Schema(description = "鍔犲伐娴佽浆锛堝彲閫夛級")
private List<MesWmBatchProcessTraceRespVO> processTraces;
+ @Schema(description = "杩芥函鏃堕棿绾�")
+ private List<TimelineVO> timeline;
+
+ @Schema(description = "杩芥函鍐崇瓥鎽樿")
+ private DecisionVO decision;
+
+ @Schema(description = "杩芥函鏃堕棿绾夸簨浠�")
+ @Data
+ public static class TimelineVO {
+ @Schema(description = "闃舵")
+ private String stage;
+ @Schema(description = "浜嬩欢绫诲瀷")
+ private String eventType;
+ @Schema(description = "浜嬩欢鍚嶇О")
+ private String eventName;
+ @Schema(description = "浜嬩欢鏃堕棿")
+ private LocalDateTime eventTime;
+ @Schema(description = "鏁伴噺")
+ private BigDecimal quantity;
+ @Schema(description = "鐘舵��")
+ private String status;
+ }
+
+ @Schema(description = "杩芥函鍐崇瓥鎽樿")
+ @Data
+ public static class DecisionVO {
+ @Schema(description = "璐ㄩ噺鏄惁瀛樺湪椋庨櫓")
+ private Boolean qualityRisk;
+ @Schema(description = "搴撳瓨鍏ュ簱鏁伴噺")
+ private BigDecimal inboundQuantity;
+ @Schema(description = "閿�鍞幓鍚戞暟閲�")
+ private Integer salesTargetCount;
+ @Schema(description = "娑堣垂鑰呮壂鐮佹鏁�")
+ private Long consumerScanCount;
+ @Schema(description = "椋庨櫓绛夌骇")
+ private String riskLevel;
+ }
+
@Schema(description = "鐢熶骇浜哄憳")
@Data
public static class WorkerVO {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java
index 50e4df7..328edb7 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java
@@ -28,7 +28,20 @@
private String batchCode;
private Long palletId;
private String palletCode;
+ /**
+ * 鍝佺锛堢墿鏂欙級缂栧彿锛堢敓鎴愭暟鎹寘鏃堕�夊畾锛屽叧鑱� mdm_item锛�
+ */
+ private Long itemId;
+ /**
+ * 鍝佺缂栫爜锛堝啑浣欙級
+ */
+ private String itemCode;
+ /**
+ * 鍝佺鍚嶇О锛堝啑浣欙級
+ */
+ private String itemName;
private Integer status;
+ private Integer qcStatus;
private LocalDateTime printTime;
private LocalDateTime cancelTime;
private String cancelReason;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/batch/MesProBatchDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/batch/MesProBatchDO.java
index 6bf42be..c9f7f38 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/batch/MesProBatchDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/batch/MesProBatchDO.java
@@ -14,8 +14,9 @@
/**
* MES 鐢熶骇鎵规 DO
* <p>
- * 鎵规鐢熶骇绠$悊锛堜竴琚嬩竴鐮佹ā鍧楋級锛氬叧鑱斿搧绉嶏紙MDM 鐗╂枡锛夈�佷骇绾匡紙浜х嚎缁存姢锛変笌鐢熶骇浜哄憳锛堜汉鍛橀厤缃 {@link MesProBatchWorkerDO}锛夛紝璐d换钀藉疄鍒颁汉銆�
- * 鎵规鍙疯嚜鍔ㄧ敓鎴愶紝缂栫爜瑙勫垯鍖呭惈鏃ユ湡銆佷骇绾跨紪鐮併�佸搧绉嶇紪鐮併�佹祦姘村彿绛夎绱狅紝骞朵笌琚嬬爜锛堜竴琚嬩竴鐮侊級銆佹墭鐩樼爜鑷姩鍏宠仈銆�
+ * 鎵规鐢熶骇绠$悊锛堜竴琚嬩竴鐮佹ā鍧楋級锛氬叧鑱斾骇绾匡紙浜х嚎缁存姢锛変笌鐢熶骇浜哄憳锛堜汉鍛橀厤缃 {@link MesProBatchWorkerDO}锛夛紝璐d换钀藉疄鍒颁汉銆�
+ * 鍝佺宸蹭笅娌夊埌琚嬬爜鏁版嵁鍖咃紙璧嬬爜绠$悊锛夛紝鎵规涓嶅啀缁戝畾鍝佺銆�
+ * 鎵规鍙疯嚜鍔ㄧ敓鎴愶紝缂栫爜瑙勫垯鍖呭惈鏃ユ湡銆佷骇绾跨紪鐮併�佹祦姘村彿绛夎绱狅紝骞朵笌琚嬬爜锛堜竴琚嬩竴鐮侊級銆佹墭鐩樼爜鑷姩鍏宠仈銆�
*
* @author 瓒呯骇绠$悊鍛�
*/
@@ -35,7 +36,7 @@
@TableId
private Long id;
/**
- * 鎵规鍙凤紙鑷姩鐢熸垚锛氬墠缂� + 鏃ユ湡 + 浜х嚎缂栫爜 + 鍝佺缂栫爜 + 娴佹按鍙凤紱琛ュ綍涓氬姟淇℃伅鍚庣敓鎴愶級
+ * 鎵规鍙凤紙鑷姩鐢熸垚锛氬墠缂� + 鏃ユ湡 + 浜х嚎缂栫爜 + 娴佹按鍙凤紱琛ュ綍涓氬姟淇℃伅鍚庣敓鎴愶級
*/
private String code;
/**
@@ -43,9 +44,11 @@
*/
private String tempCode;
/**
- * 鍝佺锛堜骇鍝佺墿鏂欙級缂栧彿
+ * 鍝佺锛堜骇鍝佺墿鏂欙級缂栧彿锛堝凡搴熷純锛�
* <p>
* 鍏宠仈 {@link cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO#getId()}
+ * <p>
+ * 鍝佺宸蹭笅娌夊埌琚嬬爜鏁版嵁鍖咃紙{@code mes_pro_bag_code.item_id}锛夛紝鏂版壒娆′笉鍐嶅啓鍏ワ紱浠呬繚鐣欎緵鍘嗗彶鎵规杩芥函鍥為��
*/
private Long itemId;
/**
@@ -59,10 +62,14 @@
*/
private String lineCode;
/**
- * 浜х嚎鍚嶇О锛堝啑浣欏垪锛岀敱 {@link #lineId} 鍥炲~锛�
+ * 浜х嚎鍚嶇О锛堝啑浣欏垪锛岀敱 {@link #lineId} 鍥炲~锛岄〉闈㈠睍绀轰负銆屽姞宸ュ崟浣嶃�嶏級
*/
private String lineName;
/**
+ * 鍔犲伐鐝粍锛堟墜宸ュ~鍐欙級
+ */
+ private String processingTeam;
+ /**
* 鐢熶骇鏃ユ湡
*/
private LocalDateTime produceDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java
index 43024f1..dfeae62 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java
@@ -62,6 +62,14 @@
*/
private Integer bagCount;
/**
+ * 鏈�杩戝叆搴撴壂鐮佷簨浠剁紪鍙凤紙鏁存墭鎵爜鍏ュ簱鍚庡洖鍐欙紝鐢ㄤ簬闃查噸澶嶅叆搴擄級
+ */
+ private Long inboundEventId;
+ /**
+ * 鏈�杩戝叆搴撴椂闂�
+ */
+ private java.time.LocalDateTime inboundTime;
+ /**
* 鏄惁鑷姩鐢熸垚锛堟寜鏈夋晥琚嬬爜绱闃堝�肩敓鎴愶紝瀹归噺鍥哄畾涓洪槇鍊硷級
*/
private Boolean autoGenerated;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java
index d0be21d..6bf1274 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java
@@ -14,7 +14,14 @@
public class MesProScanEventDO extends BaseDO {
@TableId private Long id;
private String eventId;
+ /**
+ * 鎵爜鍐呭锛堣鐮� / 鎵樼洏鐮� / 鎵规鐮佺殑鐮佸�硷紝鍚复鏃剁爜锛�
+ */
private String bagCode;
+ /**
+ * 鎵爜绫诲瀷锛欱AG 琚嬬爜 / PALLET 鎵樼洏鐮� / BATCH 鎵规鐮�
+ */
+ private String scanType;
private Long bagCodeId;
private Long batchId;
private String batchCode;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
index 0c79b74..1ca77b7 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
@@ -12,6 +12,8 @@
@TableId private Long id;
private String code;
private Long itemId;
+ /** 鐢熶骇鎵规 ID */
+ private Long batchId;
private String batchCode;
private Integer result;
private String reason;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
index ac0e186..3f67ca8 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
@@ -3,6 +3,7 @@
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO;
@@ -34,6 +35,12 @@
@TableId
private Long id;
/**
+ * 瀵瑰簲鐢熶骇鎵规 ID
+ *
+ * 鍏宠仈 {@link MesProBatchDO#getId()}
+ */
+ private Long proBatchId;
+ /**
* 鎵规缂栫爜
*/
private String code;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java
new file mode 100644
index 0000000..fb40f0b
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * MES 搴撳瓨琚嬬爜鏄庣粏 DO
+ */
+@TableName("mes_wm_material_stock_bag")
+@KeySequence("mes_wm_material_stock_bag_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MesWmMaterialStockBagDO extends BaseDO {
+
+ @TableId
+ private Long id;
+ private Long materialStockId;
+ private Long bagCodeId;
+ private String bagCode;
+ private Long itemId;
+ private Long batchId;
+ private String batchCode;
+ private Long vendorId;
+ private Long warehouseId;
+ private Long locationId;
+ private Long areaId;
+ private Integer stockState;
+ private Integer status;
+ private BigDecimal quantity;
+ private Boolean frozen;
+ private Long lastTransactionId;
+ private LocalDateTime inboundTime;
+ private LocalDateTime outboundTime;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java
index d266de7..211f40e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java
@@ -50,14 +50,6 @@
*/
private String clientName;
/**
- * 閿�鍞鍗旾D
- */
- private Long saleOrderId;
- /**
- * 閿�鍞鍗曞彿
- */
- private String salesOrderCode;
- /**
* 鍙戣揣閫氱煡鍗� ID
*
* 鍏宠仈 {@link MesWmSalesNoticeDO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java
index f76011b..29fd0a7 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java
@@ -42,10 +42,6 @@
*/
private Long salesId;
/**
- * 閿�鍞鍗曟槑缁咺D
- */
- private Long saleOrderItemId;
- /**
* 鍙戣揣閫氱煡鍗曡ID
*
* 鍏宠仈 {@link MesWmSalesNoticeLineDO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java
index aa3bb74..d26f69b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java
@@ -39,14 +39,6 @@
*/
private String name;
/**
- * 閿�鍞鍗� ID
- */
- private Long saleOrderId;
- /**
- * 閿�鍞鍗曠紪鍙�
- */
- private String salesOrderCode;
- /**
* 瀹㈡埛 ID
*
* 鍏宠仈 CRM 瀹㈡埛 {@link cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java
index 4c69b80..a6d6c2d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java
@@ -42,14 +42,6 @@
*/
private Long clientId;
/**
- * 閿�鍞鍗旾D
- */
- private Long saleOrderId;
- /**
- * 閿�鍞鍗曞彿
- */
- private String saleOrderCode;
- /**
* 鍙戣揣鏃ユ湡
*/
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java
index 1219bf6..288cc75 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java
@@ -35,10 +35,6 @@
*/
private Long noticeId;
/**
- * 閿�鍞鍗曟槑缁咺D
- */
- private Long saleOrderItemId;
- /**
* 鐗╂枡缂栧彿
*
* 鍏宠仈 {@link MesMdItemDO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java
index abfce45..8174699 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java
@@ -2,6 +2,9 @@
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
+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.dal.dataobject.pro.workorder.MesProWorkOrderDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
@@ -29,6 +32,28 @@
@TableId
private Long id;
/**
+ * 鐢熶骇鎵规 ID
+ *
+ * 鍏宠仈 {@link MesProBatchDO#getId()}
+ */
+ private Long proBatchId;
+ /**
+ * 琚嬬爜 ID
+ *
+ * 鍏宠仈 {@link MesProBagCodeDO#getId()}
+ */
+ private Long bagCodeId;
+ /**
+ * 鎵樼洏 ID
+ *
+ * 鍏宠仈 {@link MesProPalletDO#getId()}
+ */
+ private Long palletId;
+ /**
+ * 閿�鍞嚭搴撳崟 ID
+ */
+ private Long salesId;
+ /**
* 鎵规 UUID锛堢敤浜庢爣璁板悓涓�鎵规鐢熸垚鐨� SN 鐮侊級
*/
private String uuid;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
index f574a36..b3cce53 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
@@ -107,6 +107,10 @@
* 鍏宠仈 {@link MesWmBatchDO#getCode()}
*/
private String batchCode;
+ /** 琚嬬爜ID */
+ private Long bagCodeId;
+ /** 琚嬬爜 */
+ private String bagCode;
// ==================== 搴撳瓨浣嶇疆 ====================
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java
index 0c8a9b2..b2f75da 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java
@@ -62,6 +62,13 @@
*/
private Boolean frozen;
/**
+ * 浠撳簱绫诲瀷
+ *
+ * 鍏宠仈 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum}锛�
+ * 10 鏆傚瓨搴擄紙濡傝櫄鎷熺嚎杈逛粨搴擄紝瀛樻斁鎵爜鍏ュ簱寰呮/鏆傚瓨搴撳瓨锛夛紱20 鍚堟牸搴擄紙瀛樻斁璐ㄦ鍚堟牸銆佸彲鎷h揣搴撳瓨锛�
+ */
+ private Integer type;
+ /**
* 澶囨敞
*/
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java
index e5a7643..5bb3749 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java
@@ -43,6 +43,23 @@
/** 缁熻鎵樼洏鐮佹�绘暟锛坢es_pro_pallet锛� */
Long selectPalletCount();
+ // ========== 鍑哄簱娴侀�� / 浠撳偍 / 璐ㄩ噺 ==========
+
+ /** 缁熻鍙戣揣閫氱煡鍗曟暟锛坢es_wm_sales_notice锛� */
+ Long selectSalesNoticeCount();
+
+ /** 缁熻閿�鍞嚭搴撳崟鏁帮紙mes_wm_product_sales锛� */
+ Long selectProductSalesCount();
+
+ /** 缁熻閿�鍞��璐у崟鏁帮紙mes_wm_return_sales锛� */
+ Long selectReturnSalesCount();
+
+ /** 缁熻鏈鐞嗗簱瀛橀璀︽暟锛坢es_wm_stock_warning.status=10锛� */
+ Long selectStockWarningPendingCount();
+
+ /** 缁熻寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁帮紙mes_qc_ncr.status=0锛� */
+ Long selectNcrPendingCount();
+
// ========== 鐘舵�佸垎甯� ==========
/**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
index 0675ba6..effcd75 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
@@ -36,6 +36,30 @@
int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId,
@org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode);
+ /** 鎵规鏁存壒鍏ュ簱鏃舵壒閲忔爣璁板叾涓嬫湭鍏ュ簱琚嬬爜锛堝箓绛夛級锛屼繚鎸佽鐮佷笌搴撳瓨鐘舵�佷竴鑷� */
+ @Update("UPDATE mes_pro_bag_code SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, update_time = NOW() "
+ + "WHERE deleted = 0 AND inbound_event_id IS NULL AND batch_id = #{batchId}")
+ int markInboundByBatchId(@Param("batchId") Long batchId, @Param("eventId") Long eventId,
+ @Param("lineCode") String lineCode);
+
+ /** 鏁存墭鍏ュ簱鏃舵壒閲忔爣璁版墭鐩樹笅鏈叆搴撹鐮侊紙骞傜瓑锛� */
+ @Update("UPDATE mes_pro_bag_code SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, update_time = NOW() "
+ + "WHERE deleted = 0 AND inbound_event_id IS NULL AND pallet_id = #{palletId}")
+ int markInboundByPalletId(@Param("palletId") Long palletId, @Param("eventId") Long eventId,
+ @Param("lineCode") String lineCode);
+
+ /**
+ * 鏇存柊琚嬬爜璐ㄦ鐘舵�侊紙绉嶅瓙璐ㄦ鍚堟牸/涓嶅悎鏍兼椂璁板綍璇ヨ缁撴灉锛�
+ *
+ * @param id 琚嬬爜缂栧彿
+ * @param qcStatus 璐ㄦ鐘舵�侊紙瑙� MesProBagCodeQcStatusEnum锛�
+ */
+ default void updateQcStatus(Long id, Integer qcStatus) {
+ update(null, new LambdaUpdateWrapper<MesProBagCodeDO>()
+ .eq(MesProBagCodeDO::getId, id)
+ .set(MesProBagCodeDO::getQcStatus, qcStatus));
+ }
+
default List<MesProBagCodeDO> selectListByUuid(String uuid) {
return selectList(MesProBagCodeDO::getUuid, uuid);
}
@@ -67,9 +91,11 @@
.likeIfPresent(MesProBagCodeDO::getBatchCode, reqVO.getBatchCode())
.eqIfPresent(MesProBagCodeDO::getUuid, reqVO.getUuid())
.eqIfPresent(MesProBagCodeDO::getPalletId, reqVO.getPalletId())
+ .eqIfPresent(MesProBagCodeDO::getItemId, reqVO.getItemId())
.eqIfPresent(MesProBagCodeDO::getStatus, reqVO.getStatus())
.betweenIfPresent(MesProBagCodeDO::getCreateTime, reqVO.getCreateTime())
- .orderByAsc(MesProBagCodeDO::getBagNo));
+ .orderByDesc(MesProBagCodeDO::getCreateTime)
+ .orderByDesc(MesProBagCodeDO::getId));
}
/**
@@ -84,6 +110,18 @@
.set(MesProBagCodeDO::getPalletId, palletId)
.set(MesProBagCodeDO::getPalletCode, palletCode)
.in(MesProBagCodeDO::getId, ids));
+ }
+
+ /**
+ * 鎵樼洏姝e紡鐮佺敓鎴愬悗锛屽洖鍐欏叾涓嬫墍鏈夎鐮佺殑鍐椾綑鎵樼洏鐮�
+ *
+ * @param palletId 鎵樼洏缂栧彿
+ * @param palletCode 姝e紡鎵樼洏鐮�
+ */
+ default void updatePalletCodeByPalletId(Long palletId, String palletCode) {
+ update(null, new LambdaUpdateWrapper<MesProBagCodeDO>()
+ .set(MesProBagCodeDO::getPalletCode, palletCode)
+ .eq(MesProBagCodeDO::getPalletId, palletId));
}
/**
@@ -108,10 +146,24 @@
Integer selectMaxBagNo();
@Update("<script>UPDATE mes_pro_bag_code SET batch_id = #{batchId}, batch_code = #{batchCode}, update_time = NOW() " +
- "WHERE deleted = 0 AND batch_id IS NULL AND status = #{status} AND id IN " +
+ "WHERE deleted = 0 AND batch_id IS NULL AND status IN " +
+ "<foreach collection='statuses' item='st' open='(' separator=',' close=')'>#{st}</foreach> AND id IN " +
"<foreach collection='ids' item='id' open='(' separator=',' close=')'>#{id}</foreach></script>")
int bindBatchByIds(@Param("ids") Collection<Long> ids, @Param("batchId") Long batchId,
- @Param("batchCode") String batchCode, @Param("status") Integer status);
+ @Param("batchCode") String batchCode, @Param("statuses") Collection<Integer> statuses);
+
+ /** 鏌ヨ鎵樼洏涓嬪皻鏈粦瀹氭壒娆$殑琚嬬爜锛堟墭鐩樼粦瀹氭壒娆℃椂绾ц仈褰曞叆鐢級 */
+ default List<MesProBagCodeDO> selectUnboundListByPalletIds(Collection<Long> palletIds) {
+ return selectList(new LambdaQueryWrapperX<MesProBagCodeDO>()
+ .in(MesProBagCodeDO::getPalletId, palletIds)
+ .isNull(MesProBagCodeDO::getBatchId)
+ .orderByAsc(MesProBagCodeDO::getId));
+ }
+
+ /** 鎵规鍐呮湁鏁堣鐮佺殑鍝佺缂栧彿闆嗗悎锛堝拷鐣ュ巻鍙茬┖鍝佺琚嬬爜锛夛紝鐢ㄤ簬褰曞叆鎵规鏃剁殑鍝佺涓�鑷存�ф牎楠� */
+ @Select("SELECT DISTINCT item_id FROM mes_pro_bag_code " +
+ "WHERE deleted = 0 AND status <> 30 AND batch_id = #{batchId} AND item_id IS NOT NULL")
+ List<Long> selectDistinctItemIdsByBatchId(@Param("batchId") Long batchId);
default List<MesProBagCodeDO> selectListByIdsForUpdate(Collection<Long> ids) {
return selectList(new LambdaQueryWrapperX<MesProBagCodeDO>()
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java
index 5c3026e..66b2121 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java
@@ -40,14 +40,20 @@
int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId,
@org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode);
+ /** 鎵规鏁存壒鎵爜鍏ュ簱鍥炲啓锛氬叆搴撹鏁扮洿鎺ョ疆涓烘壒娆¤鏁帮紝骞傜瓑锛堝凡鏈夊叆搴撴爣璁扮殑涓嶅啀鏇存柊锛� */
+ @org.apache.ibatis.annotations.Update("UPDATE mes_pro_batch SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, inbound_bag_quantity = #{bagQuantity}, update_time = NOW() "
+ + "WHERE id = #{id} AND deleted = 0 AND inbound_event_id IS NULL")
+ int markBatchInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId,
+ @org.apache.ibatis.annotations.Param("lineCode") String lineCode, @org.apache.ibatis.annotations.Param("bagQuantity") Integer bagQuantity);
+
default PageResult<MesProBatchDO> selectPage(MesProBatchPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<MesProBatchDO>()
.likeIfPresent(MesProBatchDO::getCode, reqVO.getCode())
.likeIfPresent(MesProBatchDO::getTempCode, reqVO.getTempCode())
- .eqIfPresent(MesProBatchDO::getItemId, reqVO.getItemId())
.eqIfPresent(MesProBatchDO::getLineId, reqVO.getLineId())
.likeIfPresent(MesProBatchDO::getLineCode, reqVO.getLineCode())
.likeIfPresent(MesProBatchDO::getLineName, reqVO.getLineName())
+ .likeIfPresent(MesProBatchDO::getProcessingTeam, reqVO.getProcessingTeam())
.eqIfPresent(MesProBatchDO::getOwnerUserId, reqVO.getOwnerUserId())
.eqIfPresent(MesProBatchDO::getStatus, reqVO.getStatus())
.betweenIfPresent(MesProBatchDO::getProduceDate, reqVO.getProduceDate())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java
index cbbda3f..8853cca 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java
@@ -5,6 +5,7 @@
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@@ -39,6 +40,15 @@
return selectList(MesProPalletDO::getBatchId, batchId);
}
+ /** 鏌ヨ鏈粦瀹氱敓浜ф壒娆$殑涓存椂鎵樼洏锛堟棤姝e紡鎵樼洏鐮佷笖鏈綔搴燂級锛屼緵鎵规鏂板/琛ュ綍缁戝畾鎵樼洏涓嬫媺浣跨敤 */
+ default List<MesProPalletDO> selectUnboundList() {
+ return selectList(new LambdaQueryWrapperX<MesProPalletDO>()
+ .isNull(MesProPalletDO::getBatchId)
+ .isNull(MesProPalletDO::getCode)
+ .eq(MesProPalletDO::getStatus, MesProPalletStatusEnum.IN_USE.getStatus())
+ .orderByAsc(MesProPalletDO::getId));
+ }
+
default PageResult<MesProPalletDO> selectPage(MesProPalletPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<MesProPalletDO>()
.likeIfPresent(MesProPalletDO::getCode, reqVO.getCode())
@@ -64,6 +74,11 @@
void markOutbound(@Param("id") Long id, @Param("salesId") Long salesId,
@Param("outboundTime") java.time.LocalDateTime outboundTime);
+ /** 鏁存墭鎵爜鍏ュ簱鍥炲啓锛氬箓绛夛紙宸叉湁鍏ュ簱鏍囪鐨勪笉鍐嶆洿鏂帮級锛岀敤浜庨槻閲嶅鍏ュ簱 */
+ @org.apache.ibatis.annotations.Update("UPDATE mes_pro_pallet SET inbound_event_id = #{eventId}, inbound_time = NOW(), update_time = NOW() "
+ + "WHERE id = #{id} AND deleted = 0 AND inbound_event_id IS NULL")
+ int markInbound(@Param("id") Long id, @Param("eventId") Long eventId);
+
@org.apache.ibatis.annotations.Update("UPDATE mes_pro_pallet SET sales_id = NULL, outbound_time = NULL, update_time = NOW() "
+ "WHERE id = #{id} AND deleted = 0")
void clearOutbound(@Param("id") Long id);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java
index 314133b..98e3ea2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java
@@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityDO;
import org.apache.ibatis.annotations.Mapper;
@@ -9,6 +11,15 @@
@Mapper
public interface MesQcSeedQualityMapper extends BaseMapperX<MesQcSeedQualityDO> {
+
+ default PageResult<MesQcSeedQualityDO> selectPage(MesQcSeedQualityPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<MesQcSeedQualityDO>()
+ .likeIfPresent(MesQcSeedQualityDO::getCode, reqVO.getCode())
+ .likeIfPresent(MesQcSeedQualityDO::getBatchCode, reqVO.getBatchCode())
+ .eqIfPresent(MesQcSeedQualityDO::getResult, reqVO.getResult())
+ .orderByDesc(MesQcSeedQualityDO::getInspectedAt)
+ .orderByDesc(MesQcSeedQualityDO::getId));
+ }
default MesQcSeedQualityDO selectByCode(String code) {
return selectOne(new LambdaQueryWrapperX<MesQcSeedQualityDO>().eq(MesQcSeedQualityDO::getCode, code));
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
index 084e2ad..8308458 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
@@ -6,6 +6,7 @@
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
@@ -205,6 +206,14 @@
List<MesWmBatchSalesTargetRespVO> selectSalesTargetList(String batchCode);
/**
+ * 鏌ヨ鎵规鍑哄叆搴撴祦姘达紙绉嶅瓙娴佸悜锛�
+ *
+ * @param batchCode 鎵规鍙�
+ * @return 鍑哄叆搴撴祦姘村垪琛�
+ */
+ List<MesWmBatchFlowRespVO> selectBatchFlowList(String batchCode);
+
+ /**
* 鏌ヨ鎵规宸ュ簭娴佽浆锛堜骇鍑�/鎶曞叆浜嬩欢锛�
*
* @param batchCode 鎵规鍙�
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
index cc2413d..d3a7a25 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
@@ -6,6 +6,7 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
@@ -22,13 +23,15 @@
default PageResult<MesWmMaterialStockDO> selectPage(MesWmMaterialStockPageReqVO reqVO,
Collection<Long> itemTypeIds,
Collection<Long> itemIds,
- Long virtualWarehouseId) {
+ Long virtualWarehouseId,
+ Collection<Long> warehouseIds) {
LambdaQueryWrapperX<MesWmMaterialStockDO> wrapper = new LambdaQueryWrapperX<MesWmMaterialStockDO>()
.inIfPresent(MesWmMaterialStockDO::getItemTypeId, itemTypeIds)
.inIfPresent(MesWmMaterialStockDO::getItemId, itemIds)
.likeIfPresent(MesWmMaterialStockDO::getBatchCode, reqVO.getBatchCode())
.eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId())
.eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId())
+ .inIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseIds)
.eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId())
.eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId())
.eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId())
@@ -149,9 +152,10 @@
}
/**
- * 鎸夌粍鍚堥敭鏌ヨ搴撳瓨璁板綍锛堝拷鐣ヤ緵搴斿晢缁村害锛�
+ * 鎸夌粍鍚堥敭鏌ヨ搴撳瓨璁板綍锛堝拷鐣ヤ緵搴斿晢缁村害锛屼粎鍚堟牸搴擄級
*
- * 鐢ㄤ簬绉诲簱鍦烘櫙锛氱Щ搴撴椂灏嗗簱瀛樺悎骞跺埌鐩爣搴撲綅宸叉湁搴撳瓨锛屼笉鍖哄垎渚涘簲鍟�
+ * 鐢ㄤ簬绉诲簱鍦烘櫙锛氱Щ搴撴椂灏嗗悎鏍煎簱瀛樺悎骞跺埌鐩爣搴撲綅宸叉湁鍚堟牸搴撳瓨锛屼笉鍖哄垎渚涘簲鍟�
+ * 鍙尮閰嶅悎鏍煎簱(20)锛岄伩鍏嶅皢绉诲叆鏁伴噺鍚堝苟鍒板悓鎵规鐨勬殏瀛樺簱璁板綍
*/
default MesWmMaterialStockDO selectByCompositeKeyIgnoreVendor(Long itemId, Long warehouseId, Long locationId,
Long areaId, Long batchId) {
@@ -159,7 +163,8 @@
.eq(MesWmMaterialStockDO::getItemId, itemId)
.eq(MesWmMaterialStockDO::getWarehouseId, warehouseId)
.eq(MesWmMaterialStockDO::getLocationId, locationId)
- .eq(MesWmMaterialStockDO::getAreaId, areaId);
+ .eq(MesWmMaterialStockDO::getAreaId, areaId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState());
// batchId=null 鏃剁簿纭尮閰� is null
if (batchId != null) {
wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId);
@@ -170,9 +175,41 @@
return selectOne(wrapper);
}
+ /**
+ * 鎸夌粍鍚堥敭鏌ヨ鍚堟牸搴撳簱瀛樿褰曪紙鐢ㄤ簬鍑哄簱浜嬪姟鍖归厤锛�
+ *
+ * 鍚屾壒娆″彲鑳藉悓鏃跺瓨鍦ㄦ殏瀛樺簱(10)涓庡悎鏍煎簱(20)涓ゆ潯璁板綍锛堢瀛愯川妫�鎸夎鎷嗘暟閲忥級锛�
+ * 鍑哄簱蹇呴』鍙粠鍚堟牸搴撳尮閰嶏紝閬垮厤鎵e埌鏈川妫�鐨勬殏瀛樺簱瀛樸��
+ */
+ default MesWmMaterialStockDO selectQualifiedByCompositeKey(Long itemId, Long warehouseId, Long locationId,
+ Long areaId, Long batchId, Long vendorId) {
+ LambdaQueryWrapperX<MesWmMaterialStockDO> wrapper = new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getItemId, itemId)
+ .eq(MesWmMaterialStockDO::getWarehouseId, warehouseId)
+ .eq(MesWmMaterialStockDO::getLocationId, locationId)
+ .eq(MesWmMaterialStockDO::getAreaId, areaId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState());
+ // batchId=null 鏃剁簿纭尮閰� is null
+ if (batchId != null) {
+ wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId);
+ } else {
+ wrapper.isNull(MesWmMaterialStockDO::getBatchId);
+ }
+ if (vendorId != null) {
+ wrapper.eq(MesWmMaterialStockDO::getVendorId, vendorId);
+ }
+ wrapper.last("ORDER BY quantity DESC LIMIT 1");
+ return selectOne(wrapper);
+ }
+
default List<MesWmMaterialStockDO> selectList(MesWmMaterialStockListReqVO reqVO) {
+ return selectList(reqVO, null);
+ }
+
+ default List<MesWmMaterialStockDO> selectList(MesWmMaterialStockListReqVO reqVO, Collection<Long> warehouseIds) {
return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
.eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId())
+ .inIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseIds)
.eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId())
.eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId())
.eqIfPresent(MesWmMaterialStockDO::getItemId, reqVO.getItemId())
@@ -197,6 +234,36 @@
.orderByAsc(MesWmMaterialStockDO::getReceiptTime));
}
+ /**
+ * 鎸夌墿鏂�/鎵规鏌ヨ鍚堟牸搴撳簱瀛樿褰曪紙浠� stock_state=20锛屼笖浠呴檺鍚堟牸浠撳簱锛�
+ *
+ * <p>鍚屾壒娆″彲鑳藉悓鏃跺瓨鍦ㄦ殏瀛樺簱(10)涓庡悎鏍煎簱(20)涓ゆ潯璁板綍锛堢瀛愯川妫�鎸夎鎷嗘暟閲忥級锛�
+ * 閿�鍞嚭搴撻�夊簱瀛樺彧鑳戒粠鍚堟牸搴撹褰曚腑閫夛紝鏉滅粷閫変腑鏈川妫�鐨勬殏瀛樺簱瀛橈紱
+ * 鍚屾椂闄愬畾鍚堟牸浠撳簱锛坱ype=20锛夛紝閬垮厤浠庢殏瀛樹粨搴撲腑璇�夊悎鏍兼�佸簱瀛樸��</p>
+ */
+ default List<MesWmMaterialStockDO> selectQualifiedListByItemAndBatch(Long itemId, Long batchId,
+ Collection<Long> qualifiedWarehouseIds) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getItemId, itemId)
+ .eqIfPresent(MesWmMaterialStockDO::getBatchId, batchId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState())
+ .in(MesWmMaterialStockDO::getWarehouseId, qualifiedWarehouseIds)
+ .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO)
+ .orderByAsc(MesWmMaterialStockDO::getReceiptTime));
+ }
+
+ /**
+ * 鎸変粨搴撴壒娆℃煡璇㈠叏閮ㄥ簱瀛樿褰曪紙鍚殏瀛樺簱涓庡悎鏍煎簱锛宷uantity>0锛�
+ *
+ * <p>鐢ㄤ簬绉嶅瓙璐ㄦ鎸夎鐮佹祦杞細瀹氫綅璇ユ壒娆℃殏瀛樺簱璁板綍鎵e噺 1 琚嬶紝浠ュ強瀹氫綅/鏂板缓鍚堟牸搴撹褰曠疮鍔� 1 琚嬨��</p>
+ */
+ default List<MesWmMaterialStockDO> selectStockListByBatchId(Long batchId) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getBatchId, batchId)
+ .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO)
+ .orderByAsc(MesWmMaterialStockDO::getReceiptTime));
+ }
+
default List<MesWmMaterialStockDO> selectListByItemIds(Collection<Long> itemIds) {
if (itemIds == null || itemIds.isEmpty()) {
return java.util.Collections.emptyList();
@@ -207,18 +274,16 @@
}
/**
- * 鎸夋壒娆″彿鏇存柊搴撳瓨鐘舵�侊紙鐢ㄤ簬绉嶅瓙璐ㄦ鍚堟牸鍚庯紝灏嗘殏瀛樺簱鏁存壒杞负鍚堟牸搴擄級
+ * 缁熻鎵规鍦ㄦ殏瀛樺簱涓殑搴撳瓨璁板綍鏁帮紙鐢ㄤ簬绉嶅瓙璐ㄦ鍓嶆牎楠岃鐮�/鎵规鏄惁澶勪簬寰呰川妫�鐘舵�侊級
*
- * @param batchId 浠撳簱鎵规ID
- * @param toState 鐩爣搴撳瓨鐘舵��
- * @param fromState 鍘熷簱瀛樼姸鎬侊紙闄愬畾鍙洿鏂拌鐘舵�佺殑璁板綍锛�
- * @return 褰卞搷琛屾暟
+ * @param batchId 浠撳簱鎵规ID
+ * @return 鏆傚瓨搴撳簱瀛樿褰曟暟
*/
- default int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState) {
- return update(new MesWmMaterialStockDO().setStockState(toState),
- new LambdaUpdateWrapper<MesWmMaterialStockDO>()
- .eq(MesWmMaterialStockDO::getBatchId, batchId)
- .eq(MesWmMaterialStockDO::getStockState, fromState));
+ default Long selectTempStockCountByBatchId(Long batchId) {
+ return selectCount(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getBatchId, batchId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.TEMP.getState())
+ .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO));
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java
new file mode 100644
index 0000000..d1727b5
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java
@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagPageReqVO;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper
+public interface MesWmMaterialStockBagMapper extends BaseMapperX<MesWmMaterialStockBagDO> {
+
+ default PageResult<MesWmMaterialStockBagDO> selectPage(MesWmMaterialStockBagPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getMaterialStockId, reqVO.getMaterialStockId())
+ .likeIfPresent(MesWmMaterialStockBagDO::getBagCode, reqVO.getBagCode())
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+
+ default MesWmMaterialStockBagDO selectByBagCode(String bagCode) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCode, bagCode)
+ .orderByDesc(MesWmMaterialStockBagDO::getId)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectByBagCodeId(Long bagCodeId) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCodeId, bagCodeId)
+ .orderByDesc(MesWmMaterialStockBagDO::getId)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectOneActiveByMaterialStockId(Long materialStockId) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getMaterialStockId, materialStockId)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectActiveByBagCode(String bagCode) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCode, bagCode)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectActiveByBagCodeId(Long bagCodeId) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCodeId, bagCodeId)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .last("LIMIT 1"));
+ }
+
+ default List<MesWmMaterialStockBagDO> selectActiveListByItemAndBatch(Long itemId, Long batchId, Integer stockState) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getItemId, itemId)
+ .eqIfPresent(MesWmMaterialStockBagDO::getBatchId, batchId)
+ .eqIfPresent(MesWmMaterialStockBagDO::getStockState, stockState)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .eq(MesWmMaterialStockBagDO::getFrozen, false)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+
+ default List<MesWmMaterialStockBagDO> selectListByMaterialStockIds(Collection<Long> materialStockIds) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .in(MesWmMaterialStockBagDO::getMaterialStockId, materialStockIds)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+
+ default List<MesWmMaterialStockBagDO> selectListByMaterialStockId(Long materialStockId) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getMaterialStockId, materialStockId)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java
index 1659343..3dd15dc 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java
@@ -7,7 +7,6 @@
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
-import java.util.Map;
/**
* MES 閿�鍞嚭搴撳崟琛� Mapper
@@ -31,26 +30,6 @@
.eqIfPresent(MesWmProductSalesLineDO::getSalesId, reqVO.getSalesId())
.inIfPresent(MesWmProductSalesLineDO::getSalesId, reqVO.getSalesIds())
.orderByDesc(MesWmProductSalesLineDO::getId));
- }
-
- /**
- * 鏍规嵁閿�鍞鍗曟槑缁� ID 鍒楄〃鏌ヨ鍑哄簱琛岋紝鎸� saleOrderItemId 鍒嗙粍杩斿洖鎵瑰彿
- */
- default Map<Long, String> selectBatchCodesBySaleOrderItemIds(java.util.Collection<Long> saleOrderItemIds) {
- if (saleOrderItemIds == null || saleOrderItemIds.isEmpty()) {
- return java.util.Collections.emptyMap();
- }
- List<MesWmProductSalesLineDO> lines = selectList(new LambdaQueryWrapperX<MesWmProductSalesLineDO>()
- .in(MesWmProductSalesLineDO::getSaleOrderItemId, saleOrderItemIds));
- return lines.stream()
- .filter(l -> l.getBatchCode() != null && !l.getBatchCode().isEmpty())
- .collect(java.util.stream.Collectors.groupingBy(
- MesWmProductSalesLineDO::getSaleOrderItemId,
- java.util.LinkedHashMap::new,
- java.util.stream.Collectors.collectingAndThen(
- java.util.stream.Collectors.mapping(MesWmProductSalesLineDO::getBatchCode,
- java.util.stream.Collectors.toSet()),
- codes -> String.join("銆�", codes))));
}
default void updateQualityStatusByIds(List<Long> ids, Integer qualityStatus) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java
index 988d14d..c25314f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java
@@ -22,7 +22,6 @@
return selectPage(reqVO, new LambdaQueryWrapperX<MesWmReturnSalesDO>()
.likeIfPresent(MesWmReturnSalesDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmReturnSalesDO::getName, reqVO.getName())
- .likeIfPresent(MesWmReturnSalesDO::getSalesOrderCode, reqVO.getSalesOrderCode())
.eqIfPresent(MesWmReturnSalesDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmReturnSalesDO::getStatus, reqVO.getStatus())
.betweenIfPresent(MesWmReturnSalesDO::getReturnDate, reqVO.getReturnDate())
@@ -36,7 +35,6 @@
LambdaQueryWrapperX<MesWmReturnSalesDO> wrapper = new LambdaQueryWrapperX<MesWmReturnSalesDO>()
.likeIfPresent(MesWmReturnSalesDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmReturnSalesDO::getName, reqVO.getName())
- .likeIfPresent(MesWmReturnSalesDO::getSalesOrderCode, reqVO.getSalesOrderCode())
.eqIfPresent(MesWmReturnSalesDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmReturnSalesDO::getStatus, reqVO.getStatus())
.betweenIfPresent(MesWmReturnSalesDO::getReturnDate, reqVO.getReturnDate())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java
index 23f7af4..088bd2b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java
@@ -8,7 +8,6 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO;
import org.apache.ibatis.annotations.Mapper;
-import java.util.Collection;
import java.util.List;
/**
@@ -21,7 +20,6 @@
return selectPage(reqVO, new LambdaQueryWrapperX<MesWmSalesNoticeDO>()
.likeIfPresent(MesWmSalesNoticeDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmSalesNoticeDO::getName, reqVO.getName())
- .likeIfPresent(MesWmSalesNoticeDO::getSaleOrderCode, reqVO.getSaleOrderCode())
.eqIfPresent(MesWmSalesNoticeDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmSalesNoticeDO::getStatus, reqVO.getStatus())
.orderByDesc(MesWmSalesNoticeDO::getId));
@@ -38,7 +36,6 @@
LambdaQueryWrapperX<MesWmSalesNoticeDO> wrapper = new LambdaQueryWrapperX<MesWmSalesNoticeDO>()
.likeIfPresent(MesWmSalesNoticeDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmSalesNoticeDO::getName, reqVO.getName())
- .likeIfPresent(MesWmSalesNoticeDO::getSaleOrderCode, reqVO.getSaleOrderCode())
.eqIfPresent(MesWmSalesNoticeDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmSalesNoticeDO::getStatus, reqVO.getStatus())
.orderByDesc(MesWmSalesNoticeDO::getId);
@@ -55,19 +52,6 @@
default MesWmSalesNoticeDO selectByCode(String code) {
return selectOne(MesWmSalesNoticeDO::getCode, code);
- }
-
- default MesWmSalesNoticeDO selectBySaleOrderId(Long saleOrderId) {
- return selectOne(MesWmSalesNoticeDO::getSaleOrderId, saleOrderId);
- }
-
- /**
- * 鏌ヨ宸插瓨鍦ㄥ彂璐ч�氱煡鍗曠殑閿�鍞鍗� ID 鍒楄〃
- */
- default List<Long> selectExistingSaleOrderIds(Collection<Long> saleOrderIds) {
- return selectObjs(new LambdaQueryWrapperX<MesWmSalesNoticeDO>()
- .select(MesWmSalesNoticeDO::getSaleOrderId)
- .in(MesWmSalesNoticeDO::getSaleOrderId, saleOrderIds));
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java
index 878347e..1d18be0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java
@@ -17,6 +17,7 @@
return selectPage(reqVO, new LambdaQueryWrapperX<MesWmTransactionDO>()
.eqIfPresent(MesWmTransactionDO::getItemId, reqVO.getItemId())
.likeIfPresent(MesWmTransactionDO::getBatchCode, reqVO.getBatchCode())
+ .likeIfPresent(MesWmTransactionDO::getBagCode, reqVO.getBagCode())
.eqIfPresent(MesWmTransactionDO::getWarehouseId, reqVO.getWarehouseId())
.eqIfPresent(MesWmTransactionDO::getLocationId, reqVO.getLocationId())
.eqIfPresent(MesWmTransactionDO::getAreaId, reqVO.getAreaId())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java
index 2353b9e..3a3cfc1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java
@@ -21,9 +21,16 @@
.likeIfPresent(MesWmWarehouseDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmWarehouseDO::getName, reqVO.getName())
.eqIfPresent(MesWmWarehouseDO::getFrozen, reqVO.getFrozen())
+ .eqIfPresent(MesWmWarehouseDO::getType, reqVO.getType())
.orderByDesc(MesWmWarehouseDO::getId));
}
+ default List<MesWmWarehouseDO> selectListByType(Integer type) {
+ return selectList(new LambdaQueryWrapperX<MesWmWarehouseDO>()
+ .eq(MesWmWarehouseDO::getType, type)
+ .orderByAsc(MesWmWarehouseDO::getId));
+ }
+
default MesWmWarehouseDO selectByCode(String code) {
return selectOne(MesWmWarehouseDO::getCode, code);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java
new file mode 100644
index 0000000..b0a9318
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.mes.dal.redis;
+
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Repository;
+
+/**
+ * MES 涓氬姟缂栫爜鐢熸垚鐨� Redis DAO锛堝疄渚嬬爜锛氳鐮� / 鎵樼洏鐮� / 涓存椂鐮佺瓑锛夈��
+ *
+ * <p>闇�姹傦細鎵�鏈変笟鍔$紪鐮佺粺涓�涓恒��16 浣嶇函鏁板瓧銆嶏紝涓斿叏绯荤粺鍞竴銆�
+ * 杩欓噷澶嶇敤鍏ㄧ郴缁熺粺涓�鐨� Redis 鑷 KEY锛屼繚璇佷笌鍏跺畠妯″潡鐨勭紪鐮佷篃涓嶉噸澶嶃��
+ */
+@Repository
+public class MesCodeRedisDAO {
+
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+
+ /**
+ * 鐢熸垚涓�涓� 16 浣嶇函鏁板瓧涓氬姟缂栫爜锛堝叏绯荤粺鍞竴锛�
+ *
+ * @return 16 浣嶇函鏁板瓧缂栫爜
+ */
+ public String generate() {
+ // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+ String code = BizNoUtils.randomCode();
+ Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+ if (added != null && added > 0) {
+ return code;
+ }
+ }
+ throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
index 1d17581..17303ff 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -455,6 +455,8 @@
ErrorCode WM_WAREHOUSE_HAS_WORKSTATION = new ErrorCode(1_040_700_004, "浠撳簱宸茶宸ヤ綔绔欏紩鐢紝鏃犳硶鍒犻櫎");
ErrorCode WM_WAREHOUSE_HAS_MATERIAL_STOCK = new ErrorCode(1_040_700_005, "浠撳簱涓嬫湁搴撳瓨璁板綍锛屾棤娉曞垹闄�");
ErrorCode WM_WAREHOUSE_IS_VIRTUAL = new ErrorCode(1_040_700_006, "铏氭嫙浠撳簱涓嶅厑璁告搷浣�");
+ ErrorCode WM_WAREHOUSE_TYPE_NOT_QUALIFIED = new ErrorCode(1_040_700_007, "鎵�閫変粨搴撲笉鏄悎鏍煎簱");
+ ErrorCode WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED = new ErrorCode(1_040_700_008, "鏈厤缃悎鏍煎簱锛岃鍏堝湪浠撳簱绠$悊涓垱寤哄苟璁剧疆浠撳簱绫诲瀷涓哄悎鏍煎簱");
// ========== MES 浠撳簱绠$悊-搴撳尯锛�1-040-701-000锛� ==========
ErrorCode WM_WAREHOUSE_LOCATION_NOT_EXISTS = new ErrorCode(1_040_701_000, "搴撳尯涓嶅瓨鍦�");
@@ -496,6 +498,12 @@
ErrorCode WM_MATERIAL_STOCK_SELECTION_MISMATCH = new ErrorCode(1_040_703_014, "搴撳瓨璁板綍涓庢彁浜ょ殑鐗╂枡銆佹壒娆℃垨搴撲綅淇℃伅涓嶄竴鑷�");
ErrorCode WM_MATERIAL_STOCK_QUANTITY_INVALID = new ErrorCode(1_040_703_015, "璋冩暣鏁伴噺涓嶈兘涓虹┖鎴栭浂");
ErrorCode WM_MATERIAL_STOCK_FROZEN = new ErrorCode(1_040_703_016, "搴撳瓨璁板綍宸插喕缁擄紝鏃犳硶绉诲簱");
+ ErrorCode WM_MATERIAL_STOCK_NOT_QUALIFIED = new ErrorCode(1_040_703_017, "闈炲悎鏍煎簱瀛樹笉鍙嚭搴�");
+ ErrorCode WM_MATERIAL_STOCK_BAG_NOT_EXISTS = new ErrorCode(1_040_703_018, "搴撳瓨琚嬬爜鏄庣粏涓嶅瓨鍦�");
+ ErrorCode WM_MATERIAL_STOCK_BAG_DUPLICATE = new ErrorCode(1_040_703_019, "琚嬬爜({})宸插湪搴擄紝绂佹閲嶅鍏ュ簱");
+ ErrorCode WM_MATERIAL_STOCK_BAG_NOT_ACTIVE = new ErrorCode(1_040_703_020, "琚嬬爜({})涓嶅湪搴撴垨宸插嚭搴�/鎶ュ簾锛屾棤娉曟搷浣�");
+ ErrorCode WM_MATERIAL_STOCK_BAG_REQUIRED = new ErrorCode(1_040_703_021, "璇ョ墿鏂欏惎鐢ㄨ鐮佺鐞嗭紝蹇呴』鎼哄甫琚嬬爜");
+ ErrorCode WM_MATERIAL_STOCK_BAG_INSUFFICIENT = new ErrorCode(1_040_703_022, "鍦ㄥ簱琚嬬爜鏄庣粏鏁伴噺涓嶈冻锛屾棤娉曞嚭搴�");
// ========== MES 浠撳簱绠$悊-鍒拌揣閫氱煡鍗曪紙1-040-704-000锛� ==========
ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "鍒拌揣閫氱煡鍗曚笉瀛樺湪");
@@ -727,6 +735,8 @@
ErrorCode WM_PRODUCT_SALES_SCAN_STOCK_NOT_FOUND = new ErrorCode(1_040_714_105, "鎵弿鎵规鍦ㄥ悎鏍煎簱涓湭鎵惧埌瀵瑰簲搴撳瓨璁板綍");
ErrorCode WM_PRODUCT_SALES_SCAN_NO_MATCH_LINE = new ErrorCode(1_040_714_106, "鍑哄簱鍗曚腑娌℃湁涓庤鐗╂枡/鎵规鍖归厤鐨勮");
ErrorCode WM_PRODUCT_SALES_SCAN_BAG_ALREADY_SCANNED = new ErrorCode(1_040_714_107, "璇ヨ鐮佸凡鎵弿鍑哄簱锛岃鍕块噸澶嶆壂鎻�");
+ ErrorCode WM_PRODUCT_SALES_SCAN_BAG_NOT_QUALIFIED = new ErrorCode(1_040_714_108, "璇ヨ鐮佹湭璐ㄦ鍚堟牸锛岀姝㈠嚭搴�");
+ ErrorCode WM_PRODUCT_SALES_SCAN_PALLET_NOT_ALL_QUALIFIED = new ErrorCode(1_040_714_109, "鎵樼洏涓嬪瓨鍦ㄦ湭璐ㄦ琚嬬爜锛岀姝㈡暣鎵樺嚭搴�");
// ========== MES 浠撳簱绠$悊-鏉傞」鍑哄簱鍗曪紙1-040-715-000锛� ==========
ErrorCode WM_MISC_ISSUE_NOT_EXISTS = new ErrorCode(1_040_715_000, "鏉傞」鍑哄簱鍗曚笉瀛樺湪");
@@ -760,9 +770,6 @@
ErrorCode WM_SALES_NOTICE_LINE_NOT_EXISTS = new ErrorCode(1_040_720_010, "鍙戣揣閫氱煡鍗曡涓嶅瓨鍦�");
ErrorCode WM_SALES_NOTICE_LINE_EMPTY = new ErrorCode(1_040_720_011, "鍙戣揣閫氱煡鍗曡涓虹┖锛屼笉鑳芥彁浜�");
ErrorCode WM_SALES_NOTICE_LINE_NOT_MATCH = new ErrorCode(1_040_720_012, "鍙戣揣閫氱煡鍗曡涓嶅睘浜庢寚瀹氱殑鍙戣揣閫氱煡鍗�");
- ErrorCode WM_SALES_NOTICE_SALE_ORDER_NOT_EXISTS = new ErrorCode(1_040_720_013, "閿�鍞鍗曚笉瀛樺湪");
- ErrorCode WM_SALES_NOTICE_SALE_ORDER_ITEM_EMPTY = new ErrorCode(1_040_720_014, "閿�鍞鍗曟槑缁嗕负绌�");
- ErrorCode WM_SALES_NOTICE_ALREADY_EXISTS = new ErrorCode(1_040_720_015, "璇ラ攢鍞鍗曞凡鐢熸垚鍙戣揣閫氱煡鍗曪紝涓嶈兘閲嶅鐢熸垚");
// ========== MES 浠撳簱绠$悊-鏉$爜閰嶇疆锛�1-040-730-000锛� ==========
ErrorCode WM_BARCODE_CONFIG_NOT_EXISTS = new ErrorCode(1_040_730_000, "鏉$爜閰嶇疆涓嶅瓨鍦�");
@@ -844,12 +851,14 @@
ErrorCode PRO_BAG_CODE_BIND_PALLET_MISMATCH = new ErrorCode(1_040_752_003, "琚嬬爜涓庢墭鐩樹笉灞炰簬鍚屼竴鐢熶骇鎵规锛屼笉鍏佽缁戝畾");
ErrorCode PRO_BAG_CODE_BIND_PALLET_BOUND = new ErrorCode(1_040_752_004, "瀛樺湪宸茬粦瀹氭墭鐩樼殑琚嬬爜锛岃鍏堣В缁�");
ErrorCode PRO_BAG_CODE_UUID_NOT_EXISTS = new ErrorCode(1_040_752_005, "琚嬬爜鐢熸垚缁勪笉瀛樺湪");
- ErrorCode PRO_BAG_CODE_BIND_PALLET_OVER_CAPACITY = new ErrorCode(1_040_752_006, "缁戝畾鍚庤鐮佹暟閲忚秴杩囨墭鐩樺彲瑁呰鏁�");
ErrorCode PRO_BAG_CODE_REPLACE_BATCH_STATUS_INVALID = new ErrorCode(1_040_752_007, "鐢熶骇鎵规鐘舵�佷笉鍏佽鐮存崯琚嬬爜鏇挎崲");
ErrorCode PRO_BAG_CODE_REPLACE_BATCH_MISMATCH = new ErrorCode(1_040_752_008, "寰呮浛鎹㈣鐮佷笉灞炰簬鎸囧畾鐢熶骇鎵规");
ErrorCode PRO_BAG_CODE_REPLACE_ALREADY_REPLACED = new ErrorCode(1_040_752_009, "琚嬬爜宸插畬鎴愭浛鎹紝涓嶅厑璁搁噸澶嶆浛鎹�");
ErrorCode PRO_BAG_CODE_REPLACE_STATUS_INVALID = new ErrorCode(1_040_752_010, "琚嬬爜鐘舵�佷笉鍏佽鐮存崯鏇挎崲");
ErrorCode PRO_BAG_CODE_REPLACE_PALLET_INVALID = new ErrorCode(1_040_752_011, "琚嬬爜鍘熸墭鐩樹笉瀛樺湪鎴栧凡浣滃簾锛屼笉鍏佽缁ф壙");
+ ErrorCode PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED = new ErrorCode(1_040_752_012, "鍝佺涓昏閲忓崟浣嶆湭閰嶇疆绫诲瀷锛屼粎鏀寔 48鍗冨厠/100鍗冨厠/鍚�");
+ ErrorCode PRO_BAG_CODE_PALLET_COUNT_REQUIRED = new ErrorCode(1_040_752_013, "璇ュ搧绉嶆寜鎵樼洏鐢熸垚琚嬬爜锛屾墭鐩樻暟蹇呴』澶т簬 0");
+ ErrorCode PRO_BAG_CODE_BIND_BATCH_ITEM_MISMATCH = new ErrorCode(1_040_752_014, "褰曞叆鎵规鐨勮鐮佸繀椤诲睘浜庡悓涓�鍝佺");
// ========== MES 鐢熶骇绠$悊-鎵樼洏鐮侊紙1-040-753-000锛� ==========
ErrorCode PRO_PALLET_NOT_EXISTS = new ErrorCode(1_040_753_000, "鎵樼洏鐮佷笉瀛樺湪");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
index b089810..26e6ab1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
@@ -18,6 +18,7 @@
public static final int QC_IPQC = 2; // 杩囩▼妫�楠岋細MesQcIpqcDO
public static final int QC_OQC = 3; // 鍑鸿揣妫�楠岋細MesQcOqcDO
public static final int QC_RQC = 4; // 閫�璐ф楠岋細MesQcRqcDO
+ public static final int QC_SEED_QUALITY = 5; // 绉嶅瓙璐ㄦ锛歁esQcSeedQualityDO锛堝惈鏆傚瓨鍑哄簱/鍚堟牸鍏ュ簱/鎶ュ簾锛�
// ========== WM 浠撳簱妯″潡 [100, 200) ==========
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java
new file mode 100644
index 0000000..2713dc8
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.mes.enums.pro;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * MES 琚嬬爜锛堜竴琚嬩竴鐮侊級璐ㄦ鐘舵�佹灇涓�
+ *
+ * <p>璁板綍姣忚鐨勭瀛愯川妫�缁撴灉锛岄攢鍞嚭搴撴壂琚嬬爜鏃舵牎楠岃琚嬪凡璐ㄦ鍚堟牸銆�</p>
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Getter
+@AllArgsConstructor
+public enum MesProBagCodeQcStatusEnum implements ArrayValuable<Integer> {
+
+ UNCHECKED(10, "鏈川妫�"),
+ QUALIFIED(20, "璐ㄦ鍚堟牸"),
+ UNQUALIFIED(30, "璐ㄦ涓嶅悎鏍�");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProBagCodeQcStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 鐘舵��
+ */
+ private final Integer status;
+ /**
+ * 鐘舵�佸悕绉�
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java
new file mode 100644
index 0000000..bf6bd86
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.mes.enums.wm;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum MesWmMaterialStockBagStatusEnum {
+ ACTIVE(1, "鍦ㄥ簱"),
+ OUT(2, "宸插嚭搴�"),
+ SCRAPPED(3, "宸叉姤搴�");
+
+ private final Integer status;
+ private final String name;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java
new file mode 100644
index 0000000..d0cd8f9
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.mes.enums.wm;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * MES 浠撳簱绫诲瀷
+ *
+ * 涓� {@link MesWmStockStateEnum} 璇箟瀵归綈锛氭殏瀛樺簱瀛樻斁寰呮/鏆傚瓨搴撳瓨锛屽悎鏍煎簱瀛樻斁璐ㄦ鍚堟牸銆佸彲鎷h揣搴撳瓨銆�
+ */
+@Getter
+@AllArgsConstructor
+public enum MesWmWarehouseTypeEnum {
+
+ TEMP(10, "鏆傚瓨搴�"),
+ QUALIFIED(20, "鍚堟牸搴�");
+
+ private final Integer type;
+ private final String name;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java
index 80b198d..d21aee2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java
@@ -118,6 +118,10 @@
if (StrUtil.isNotEmpty(bagCode.getPalletCode())) {
keyValues.put("缁戝畾鎵樼洏", bagCode.getPalletCode());
}
+ // 鍝佺浼樺厛鍙栬鐮佽嚜韬紙鏁版嵁鍖呯敓鎴愭椂缁戝畾锛屾湭褰曟壒娆′篃鍙墦鍗帮級锛屽巻鍙茶鐮佸洖閫�鎵规鍝佺
+ if (StrUtil.isNotEmpty(bagCode.getItemName())) {
+ keyValues.put("鍝佺", bagCode.getItemName());
+ }
if (batch != null) {
fillBatchKeyValues(keyValues, batch, itemMap, userMap);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java
index 4a14ca7..0282554 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java
@@ -42,7 +42,16 @@
summary.setBagCodeCount(getCount(homeStatisticsMapper.selectBagCodeCount()));
summary.setPalletCount(getCount(homeStatisticsMapper.selectPalletCount()));
- // 3. 鐘舵�佸垎甯�
+ // 3. 鍑哄簱娴侀��
+ summary.setSalesNoticeCount(getCount(homeStatisticsMapper.selectSalesNoticeCount()));
+ summary.setProductSalesCount(getCount(homeStatisticsMapper.selectProductSalesCount()));
+ summary.setReturnSalesCount(getCount(homeStatisticsMapper.selectReturnSalesCount()));
+
+ // 4. 浠撳偍棰勮 / 璐ㄩ噺
+ summary.setStockWarningPendingCount(getCount(homeStatisticsMapper.selectStockWarningPendingCount()));
+ summary.setNcrPendingCount(getCount(homeStatisticsMapper.selectNcrPendingCount()));
+
+ // 5. 鐘舵�佸垎甯�
summary.setBatchStatusList(toStatusList(homeStatisticsMapper.selectBatchCountGroupByStatus()));
summary.setBagCodeStatusList(toStatusList(homeStatisticsMapper.selectBagCodeCountGroupByStatus()));
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
index 983dff0..2e298cd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
@@ -4,6 +4,7 @@
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodePartDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRecordDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRuleDO;
@@ -13,6 +14,7 @@
import cn.iocoder.yudao.module.mes.service.md.autocode.strategy.MesMdAutoCodePartStrategy;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -41,6 +43,9 @@
private MesMdAutoCodeRuleService ruleService;
@Resource
private MesMdAutoCodePartService partService;
+
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
@Resource
private List<MesMdAutoCodePartStrategy> strategyList;
@@ -93,23 +98,17 @@
*/
private String generateCode(MesMdAutoCodeRuleDO rule, List<MesMdAutoCodePartDO> parts,
MesMdAutoCodeContext context) {
- StringBuilder codeBuilder = new StringBuilder();
- for (MesMdAutoCodePartDO part : parts) {
- MesMdAutoCodePartStrategy strategy = strategyMap.get(part.getType());
- Assert.notNull(strategy, () -> exception(AUTO_CODE_GENERATE_FAILED));
- // 鐢熸垚鍒嗘缂栫爜
- String partCode = strategy.generate(part, context);
- // 缁熶竴鎴彇鎸囧畾闀垮害
- partCode = StrUtil.sub(partCode, 0, part.getLength());
- // 鎷兼帴鍒嗘缂栫爜
- codeBuilder.append(partCode);
+ // 闇�姹傦細鎵�鏈変笟鍔$紪鐮佺粺涓�涓恒��16 浣嶇函鏁板瓧銆嶏紝涓斿叏绯荤粺鍞竴銆�
+ // 鍥犳涓嶅啀鎸夎鍒欏垎娈垫嫾瑁咃紙鍥哄畾瀛楃/鏃ユ湡娈典細甯﹀叆瀛楁瘝锛夛紝鏀逛负鍙栧叏绯荤粺缁熶竴鑷搴忓垪銆�
+ // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+ String code = BizNoUtils.randomCode();
+ Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+ if (added != null && added > 0) {
+ return code;
+ }
}
- // 琛ラ綈澶勭悊
- String result = codeBuilder.toString();
- if (Boolean.TRUE.equals(rule.getPadded()) && rule.getMaxLength() != null) {
- result = padCode(result, rule);
- }
- return result;
+ throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
}
/**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
index 319ea0f..012ba93 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
@@ -137,8 +137,10 @@
validateItemCodeUnique(reqVO.getId(), reqVO.getCode());
// 鏍¢獙鐗╂枡鍚嶇О鐨勫敮涓�鎬�
validateItemNameUnique(reqVO.getId(), reqVO.getName());
- // 鏍¢獙鐗╂枡鍒嗙被瀛樺湪
- validateItemTypeExists(reqVO.getItemTypeId());
+ // 鏍¢獙鐗╂枡鍒嗙被瀛樺湪锛圡DM 鍝佺鍚屾涓嶄紶鍒嗙被锛屽厑璁镐负绌猴級
+ if (reqVO.getItemTypeId() != null) {
+ validateItemTypeExists(reqVO.getItemTypeId());
+ }
// 鏍¢獙璁¢噺鍗曚綅瀛樺湪
validateUnitMeasureExists(reqVO.getUnitMeasureId());
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java
index 6ffee5f..546f9d6 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java
@@ -6,6 +6,7 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO;
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.dal.dataobject.pro.bagcode.MesProBagCodeDO;
@@ -31,6 +32,15 @@
*/
MesProBagCodeGenerateRespVO generateBagCodes(@Valid MesProBagCodeGenerateReqVO generateReqVO);
+ /**
+ * 鐢熸垚鍘熷琚嬬爜锛氫粎閫夊搧绉�+琚嬬爜鏁伴噺锛屼笉鏍¢獙璁¢噺鍗曚綅绫诲瀷銆佷笉鐢熸垚鎵樼洏锛�
+ * 琚嬬爜甯﹀搧绉嶅啑浣欙紝鍚庣画鍙甯稿綍鍏ユ壒娆�/缁戝畾鎵樼洏
+ *
+ * @param rawGenerateReqVO 鐢熸垚淇℃伅
+ * @return 鐢熸垚缁� UUID 涓庢暟閲忥紙type/perPallet/palletIds 涓虹┖锛�
+ */
+ MesProBagCodeGenerateRespVO generateRawBagCodes(@Valid MesProBagCodeRawGenerateReqVO rawGenerateReqVO);
+
void bindBatch(@Valid MesProBagCodeBindBatchReqVO bindReqVO);
/**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
index 1611599..f34b350 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
@@ -3,15 +3,20 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
+import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindBatchReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO;
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.MesProBagCodeReplaceItemRespVO;
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.dal.dataobject.mdm.MesMdmItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeReplaceDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
@@ -20,9 +25,11 @@
import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeReplaceMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
+import cn.iocoder.yudao.module.mes.dal.redis.MesCodeRedisDAO;
import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum;
+import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -34,8 +41,13 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -61,29 +73,143 @@
@Resource
private MesProPalletService palletService;
+ @Resource
+ private MesMdmItemService mdmItemService;
+ @Resource
+ private MdmUnitMeasureApi unitMeasureApi;
+
+ /**
+ * 璁¢噺鍗曚綅绫诲瀷銆屽惃銆嶏紙鏃犳墭鐩樻ā寮忥級
+ */
+ private static final String UNIT_TYPE_TON = "鍚�";
+ /**
+ * 璁¢噺鍗曚綅绫诲瀷銆孨鍗冨厠銆嶏細姣忔墭鐩樿 N 涓鐮�
+ */
+ private static final Pattern KG_TYPE_PATTERN = Pattern.compile("^(\\d{1,5})鍗冨厠$");
+
+ @Resource
+ private MesCodeRedisDAO codeRedisDao;
@Override
@Transactional(rollbackFor = Exception.class)
public MesProBagCodeGenerateRespVO generateBagCodes(MesProBagCodeGenerateReqVO generateReqVO) {
- if (generateReqVO.getCount() == null || generateReqVO.getCount() <= 0) {
- throw exception(PRO_BAG_CODE_GENERATE_COUNT_INVALID);
+ // 1. 鏍¢獙鍝佺骞惰鍙栦富璁¢噺鍗曚綅绫诲瀷
+ MesMdmItemDO item = mdmItemService.validateItemExists(generateReqVO.getItemId());
+ String type = getUnitType(item);
+
+ // 2. 鎸夌被鍨嬫崲绠楄鐮佹暟閲忥細N鍗冨厠 = 姣忔墭 N 琚� 脳 鎵樼洏鏁帮紱鍚� = 鐩存帴杈撳叆琚嬬爜鏁帮紙鏃犳墭鐩橈級
+ boolean ton = UNIT_TYPE_TON.equals(type);
+ int perPallet = ton ? 0 : parseKgPerPallet(type);
+ int totalCount;
+ int palletCount = 0;
+ if (ton) {
+ if (generateReqVO.getBagCount() == null || generateReqVO.getBagCount() <= 0) {
+ throw exception(PRO_BAG_CODE_GENERATE_COUNT_INVALID);
+ }
+ totalCount = generateReqVO.getBagCount();
+ } else {
+ if (generateReqVO.getPalletCount() == null || generateReqVO.getPalletCount() <= 0) {
+ throw exception(PRO_BAG_CODE_PALLET_COUNT_REQUIRED);
+ }
+ palletCount = generateReqVO.getPalletCount();
+ totalCount = perPallet * palletCount;
}
- // 鐢熸垚闃舵鍙垱寤哄叏灞�鍞竴琚嬬爜锛岀敓浜ф壒娆″湪鍚庣画褰曞叆
- int startNo = bagCodeMapper.selectMaxBagNo() + 1;
+ // 3. 鐢熸垚闃舵锛氳鐮佺洿鎺ョ粦瀹氬搧绉嶏紱鐢熶骇鎵规鍦ㄥ悗缁綍鍏�
String uuid = IdUtil.fastSimpleUUID();
+ List<MesProPalletDO> pallets = new ArrayList<>(palletCount);
+ if (!ton) {
+ for (int i = 0; i < palletCount; i++) {
+ pallets.add(new MesProPalletDO()
+ .setTempCode(codeRedisDao.generate())
+ .setBagCount(perPallet)
+ .setAutoGenerated(true)
+ .setStatus(MesProPalletStatusEnum.IN_USE.getStatus()));
+ }
+ palletMapper.insertBatch(pallets);
+ }
+ int startNo = bagCodeMapper.selectMaxBagNo() + 1;
+ List<MesProBagCodeDO> bagCodes = new ArrayList<>(totalCount);
+ for (int i = 0; i < totalCount; i++) {
+ int bagNo = startNo + i;
+ MesProPalletDO pallet = ton ? null : pallets.get(i / perPallet);
+ bagCodes.add(new MesProBagCodeDO()
+ .setUuid(uuid)
+ .setCode(codeRedisDao.generate())
+ .setBagNo(bagNo)
+ .setItemId(item.getId())
+ .setItemCode(item.getCode())
+ .setItemName(item.getName())
+ .setPalletId(pallet == null ? null : pallet.getId())
+ .setPalletCode(pallet == null ? null : pallet.getTempCode())
+ .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus())
+ .setRemark(generateReqVO.getRemark()));
+ }
+ bagCodeMapper.insertBatch(bagCodes);
+ return new MesProBagCodeGenerateRespVO()
+ .setUuid(uuid)
+ .setType(type)
+ .setPerPallet(perPallet)
+ .setTotalCount(totalCount)
+ .setPalletIds(pallets.stream().map(MesProPalletDO::getId).toList());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public MesProBagCodeGenerateRespVO generateRawBagCodes(MesProBagCodeRawGenerateReqVO generateReqVO) {
+ // 鍘熷琚嬬爜涓嶄緷璧栬閲忓崟浣嶇被鍨嬩笌鎵樼洏锛氫粎鎸夋暟閲忕敓鎴愶紝琚嬬爜甯﹀搧绉嶅啑浣欙紝鍚庣画鍙甯稿綍鍏ユ壒娆�/缁戝畾鎵樼洏
+ MesMdmItemDO item = mdmItemService.validateItemExists(generateReqVO.getItemId());
+ String uuid = IdUtil.fastSimpleUUID();
+ int startNo = bagCodeMapper.selectMaxBagNo() + 1;
List<MesProBagCodeDO> bagCodes = new ArrayList<>(generateReqVO.getCount());
for (int i = 0; i < generateReqVO.getCount(); i++) {
int bagNo = startNo + i;
bagCodes.add(new MesProBagCodeDO()
.setUuid(uuid)
- .setCode("BAG-" + StrUtil.padPre(String.valueOf(bagNo), 8, '0'))
+ .setCode(codeRedisDao.generate())
.setBagNo(bagNo)
+ .setItemId(item.getId())
+ .setItemCode(item.getCode())
+ .setItemName(item.getName())
.setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus())
.setRemark(generateReqVO.getRemark()));
}
bagCodeMapper.insertBatch(bagCodes);
- return new MesProBagCodeGenerateRespVO().setUuid(uuid);
+ return new MesProBagCodeGenerateRespVO()
+ .setUuid(uuid)
+ .setTotalCount(bagCodes.size())
+ .setPalletIds(List.of());
+ }
+
+ /**
+ * 璇诲彇鍝佺涓昏閲忓崟浣嶇殑绫诲瀷锛�48鍗冨厠/100鍗冨厠/鍚級锛屾湭閰嶇疆鎴栨棤娉曡瘑鍒椂鎶ラ敊
+ */
+ private String getUnitType(MesMdmItemDO item) {
+ String type = null;
+ if (item.getUnitMeasureId() != null) {
+ CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasure(item.getUnitMeasureId());
+ if (result != null && result.isSuccess() && result.getData() != null) {
+ type = StrUtil.trimToNull(result.getData().getType());
+ }
+ }
+ if (type == null) {
+ throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED);
+ }
+ if (!UNIT_TYPE_TON.equals(type) && !KG_TYPE_PATTERN.matcher(type).matches()) {
+ throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED);
+ }
+ return type;
+ }
+
+ /**
+ * 瑙f瀽銆孨鍗冨厠銆嶇被鍨嬪緱鍑烘瘡鎵樼洏琚嬫暟
+ */
+ private int parseKgPerPallet(String type) {
+ Matcher matcher = KG_TYPE_PATTERN.matcher(type);
+ if (!matcher.matches()) {
+ throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED);
+ }
+ return Integer.parseInt(matcher.group(1));
}
@Override
@@ -103,15 +229,60 @@
List<Long> ids = bindReqVO.getIds().stream().distinct().toList();
List<MesProBagCodeDO> bagCodes = bagCodeMapper.selectListByIdsForUpdate(ids);
if (bagCodes.size() != ids.size() || bagCodes.stream().anyMatch(code ->
- code.getBatchId() != null || !MesProBagCodeStatusEnum.GENERATED.getStatus().equals(code.getStatus()))) {
+ code.getBatchId() != null
+ || (!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(code.getStatus())
+ && !MesProBagCodeStatusEnum.PRINTED.getStatus().equals(code.getStatus())))) {
throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED);
}
+ // 褰曞叆鐨勮鐮佸繀椤诲睘浜庡悓涓�鍝佺锛屼笖涓庢壒娆″凡鏈夎鐮佸搧绉嶄竴鑷达紙鍘嗗彶绌虹櫧琚嬬爜 item 涓虹┖涓嶅弬涓庢牎楠岋級
+ Set<Long> itemIds = new LinkedHashSet<>();
+ bagCodes.stream().map(MesProBagCodeDO::getItemId).filter(Objects::nonNull).forEach(itemIds::add);
+ itemIds.addAll(bagCodeMapper.selectDistinctItemIdsByBatchId(batch.getId()));
+ if (itemIds.size() > 1) {
+ throw exception(PRO_BAG_CODE_BIND_BATCH_ITEM_MISMATCH);
+ }
if (bagCodeMapper.bindBatchByIds(ids, batch.getId(), batch.getCode(),
- MesProBagCodeStatusEnum.GENERATED.getStatus()) != ids.size()) {
+ List.of(MesProBagCodeStatusEnum.GENERATED.getStatus(),
+ MesProBagCodeStatusEnum.PRINTED.getStatus())) != ids.size()) {
throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED);
}
batchMapper.updateById(new MesProBatchDO().setId(batch.getId())
.setBagQuantity(bagCodeMapper.selectEffectiveCountByBatchId(batch.getId())));
+ // 绾ц仈锛氭湰缁勮鐮佺粦瀹氱殑鏈叆鎵规鎵樼洏锛屽垎閰嶆寮忔墭鐩樼爜骞剁粦瀹氭壒娆�
+ bindPalletsToBatch(bagCodes, batch);
+ }
+
+ /**
+ * 琚嬬爜褰曞叆鎵规鏃讹紝灏嗗叾缁戝畾鐨勪复鏃舵墭鐩橈紙鏈粦瀹氭壒娆★級绾ц仈缁戝畾鍒板悓涓�鎵规锛�
+ * 鍒嗛厤姝e紡鎵樼洏鐮侊紙16 浣嶉殢鏈烘暟瀛楋紝涓庢墭鐩樼爜鐢熸垚瑙勫垯涓�鑷达級銆佸洖鍐欒鐮佷笂鐨勫啑浣欐墭鐩樼爜銆佺疮璁℃壒娆℃墭鐩樻暟
+ */
+ private void bindPalletsToBatch(List<MesProBagCodeDO> bagCodes, MesProBatchDO batch) {
+ List<Long> palletIds = bagCodes.stream().map(MesProBagCodeDO::getPalletId)
+ .filter(Objects::nonNull).distinct().sorted().toList();
+ if (palletIds.isEmpty()) {
+ return;
+ }
+ int nextPalletNo = palletMapper.selectMaxPalletNo(batch.getId()) + 1;
+ int boundCount = 0;
+ for (Long palletId : palletIds) {
+ MesProPalletDO pallet = palletMapper.selectByIdForUpdate(palletId);
+ if (pallet == null || pallet.getBatchId() != null || StrUtil.isNotEmpty(pallet.getCode())) {
+ continue;
+ }
+ String palletCode = codeRedisDao.generate();
+ palletMapper.updateById(new MesProPalletDO().setId(palletId)
+ .setCode(palletCode)
+ .setBatchId(batch.getId())
+ .setBatchCode(batch.getCode())
+ .setPalletNo(nextPalletNo++));
+ // 琚嬬爜涓婄殑鍐椾綑鎵樼洏鐮佺敱涓存椂鐮佹洿鏂颁负姝e紡鐮�
+ bagCodeMapper.updatePalletCodeByPalletId(palletId, palletCode);
+ boundCount++;
+ }
+ if (boundCount > 0) {
+ batchMapper.updateById(new MesProBatchDO().setId(batch.getId())
+ .setPalletQuantity((batch.getPalletQuantity() == null ? 0 : batch.getPalletQuantity()) + boundCount));
+ }
}
@Override
@@ -171,10 +342,13 @@
MesProPalletDO pallet = oldBagCode.getPalletId() == null ? null : palletMap.get(oldBagCode.getPalletId());
MesProBagCodeDO newBagCode = new MesProBagCodeDO()
.setUuid(replaceUuid)
- .setCode(batch.getCode() + "-" + StrUtil.padPre(String.valueOf(newBagNo), 4, '0'))
+ .setCode(codeRedisDao.generate())
.setBagNo(newBagNo)
.setBatchId(batch.getId())
.setBatchCode(batch.getCode())
+ .setItemId(oldBagCode.getItemId())
+ .setItemCode(oldBagCode.getItemCode())
+ .setItemName(oldBagCode.getItemName())
.setPalletId(pallet == null ? null : pallet.getId())
.setPalletCode(pallet == null ? null : pallet.getCode())
.setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus())
@@ -234,17 +408,26 @@
if (CollUtil.isEmpty(bagCodes)) {
throw exception(PRO_BAG_CODE_UUID_NOT_EXISTS);
}
- // 2. 鏍¢獙鍧囦负宸茬敓鎴愮姸鎬佷笖鏈粦瀹氭墭鐩�
+ // 2. 鏍¢獙鍧囦负宸茬敓鎴愮姸鎬�
if (bagCodes.stream().anyMatch(bagCode ->
!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(bagCode.getStatus()))) {
throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED);
}
- if (bagCodes.stream().anyMatch(bagCode -> bagCode.getPalletId() != null)) {
- throw exception(PRO_BAG_CODE_BIND_PALLET_BOUND);
+ // 3. 缁戝畾鐨勬墭鐩樹粎闄�"鑷姩鐢熸垚涓旀湭缁戝畾鎵规"锛堢敓鎴愭暟鎹寘鏃惰嚜鍔ㄧ粦瀹氾級锛岀骇鑱斿垹闄わ紱宸插叆鎵规鐨勬墭鐩樹笉鍏佽闅忓寘鍒犻櫎
+ Set<Long> palletIds = new LinkedHashSet<>();
+ bagCodes.stream().map(MesProBagCodeDO::getPalletId).filter(Objects::nonNull).forEach(palletIds::add);
+ for (Long palletId : palletIds) {
+ MesProPalletDO pallet = palletMapper.selectById(palletId);
+ if (pallet != null && (pallet.getBatchId() != null || StrUtil.isNotEmpty(pallet.getCode()))) {
+ throw exception(PRO_BAG_CODE_BIND_PALLET_BOUND);
+ }
}
- // 3. 鍒犻櫎鐢熸垚缁�
+ // 4. 鍒犻櫎鐢熸垚缁勪笌鍏惰嚜鍔ㄧ敓鎴愮殑涓存椂鎵樼洏
bagCodeMapper.deleteByIds(bagCodes.stream().map(MesProBagCodeDO::getId).toList());
- // 4. 鍥炲噺鎵规琚嬬爜鏁伴噺
+ if (!palletIds.isEmpty()) {
+ palletMapper.deleteByIds(palletIds);
+ }
+ // 5. 鍥炲噺鎵规琚嬬爜鏁伴噺
MesProBatchDO batch = batchMapper.selectById(bagCodes.get(0).getBatchId());
if (batch != null && batch.getBagQuantity() != null) {
batchMapper.updateById(new MesProBatchDO().setId(batch.getId())
@@ -262,13 +445,8 @@
}
// 2. 閿佸畾骞舵牎楠岃鐮�
List<MesProBagCodeDO> bagCodes = validateBagCodesForBind(bindReqVO.getIds(), pallet, true);
- // 3. 鏍¢獙涓嶈秴杩囨墭鐩樺彲瑁呰鏁�
+ // 3. 缁戝畾琚嬬爜骞剁疮鍔犳墭鐩樺凡瑁呰鏁帮紙鎵樼洏鏃犲閲忎笂闄愶級
int currentCount = pallet.getBagCount() == null ? 0 : pallet.getBagCount();
- if (pallet.getCapacity() != null && pallet.getCapacity() > 0
- && currentCount + bagCodes.size() > pallet.getCapacity()) {
- throw exception(PRO_BAG_CODE_BIND_PALLET_OVER_CAPACITY);
- }
- // 4. 缁戝畾琚嬬爜骞剁疮鍔犳墭鐩樺凡瑁呰鏁�
bagCodeMapper.bindPalletByIds(bindReqVO.getIds(), pallet.getId(), pallet.getCode());
palletService.updatePalletBagCount(pallet.getId(), currentCount + bagCodes.size());
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java
index 0fe4f45..a5d4fbe 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/batch/MesProBatchServiceImpl.java
@@ -7,7 +7,7 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchPreGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.batch.vo.MesProBatchSaveReqVO;
-import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletBindBatchReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchWorkerDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.line.MesProLineDO;
@@ -15,11 +15,12 @@
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchWorkerMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
+import cn.iocoder.yudao.module.mes.dal.redis.MesCodeRedisDAO;
import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
-import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.pro.line.MesProLineService;
+import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService;
import cn.iocoder.yudao.module.mes.service.trace.integrity.MesTraceIntegrityService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
@@ -59,11 +60,15 @@
private MesProPalletMapper palletMapper;
@Resource
+ private MesProPalletService palletService;
+
+ @Resource
+ private MesCodeRedisDAO codeRedisDao;
+
+ @Resource
private MesMdAutoCodeRecordService autoCodeRecordService;
@Resource
private AdminUserApi adminUserApi;
- @Resource
- private MesMdmItemService mdmItemService;
@Resource
private MesProLineService lineService;
@Resource
@@ -72,27 +77,30 @@
@Override
@Transactional(rollbackFor = Exception.class)
public Long createBatch(MesProBatchSaveReqVO createReqVO) {
- // 1. 鏍¢獙鍏宠仈鏁版嵁锛堝搧绉嶃�佷骇绾裤�佺敓浜т汉鍛橈級
- MesMdmItemDO item = mdmItemService.validateItemExists(createReqVO.getItemId());
+ // 1. 鏍¢獙鍏宠仈鏁版嵁锛堜骇绾裤�佺敓浜т汉鍛橈級
MesProLineDO line = lineService.validateLineExistsAndEnable(createReqVO.getLineId());
validateRelations(createReqVO);
- // 2. 鐢熸垚鎵规鍙凤紙缂栫爜瑙勫垯锛氬墠缂� + 鏃ユ湡 + 浜х嚎缂栫爜 + 鍝佺缂栫爜 + 娴佹按鍙凤級
- String code = generateBatchCode(line.getCode(), item.getCode());
+ // 2. 鐢熸垚鎵规鍙凤紙缂栫爜瑙勫垯锛氬墠缂� + 鏃ユ湡 + 浜х嚎缂栫爜 + 娴佹按鍙凤級
+ String code = generateBatchCode(line.getCode());
- // 3. 鎻掑叆鎵规锛堜骇绾跨紪鐮�/鍚嶇О鍐椾綑鍥炲~锛�
+ // 3. 鎻掑叆鎵规锛堜骇绾跨紪鐮�/鍚嶇О鍐椾綑鍥炲~锛涘嬀閫夌粦瀹氭墭鐩樻椂鎵规鐩存帴杩涘叆鐢熶骇涓級
+ boolean bindPallets = CollUtil.isNotEmpty(createReqVO.getPalletIds());
MesProBatchDO batch = BeanUtils.toBean(createReqVO, MesProBatchDO.class)
.setCode(code)
.setLineCode(line.getCode())
.setLineName(line.getName())
.setBagQuantity(0)
.setPalletQuantity(0)
- .setStatus(MesProBatchStatusEnum.DRAFT.getStatus());
+ .setStatus(bindPallets ? MesProBatchStatusEnum.PRODUCING.getStatus()
+ : MesProBatchStatusEnum.DRAFT.getStatus());
batchMapper.insert(batch);
// 4. 鎻掑叆鐢熶骇浜哄憳閰嶇疆
insertBatchWorkers(batch.getId(), createReqVO.getWorkers());
- // 5. 鐢熸垚鎵规瀹屾暣鎬ф憳瑕�
+ // 5. 缁戝畾鎵樼洏锛堢骇鑱旂敓鎴愭寮忔墭鐩樼爜骞跺綍鍏ユ墭鐩樹笅琚嬬爜锛屽け璐ユ暣浣撳洖婊氾級
+ bindPalletsToBatch(batch.getId(), createReqVO.getPalletIds());
+ // 6. 鐢熸垚鎵规瀹屾暣鎬ф憳瑕�
integrityService.recordBatchIntegrity(batch.getId());
return batch.getId();
}
@@ -105,7 +113,7 @@
List<MesProBatchDO> list = new ArrayList<>(reqVO.getCount());
for (int i = 0; i < reqVO.getCount(); i++) {
list.add(new MesProBatchDO()
- .setTempCode("PB-" + StrUtil.padPre(String.valueOf(startSeq + i), 8, '0'))
+ .setTempCode(codeRedisDao.generate())
.setBagQuantity(0)
.setPalletQuantity(0)
.setStatus(MesProBatchStatusEnum.DRAFT.getStatus())
@@ -130,21 +138,24 @@
throw exception(PRO_BATCH_ALREADY_FILLED);
}
// 2. 鏍¢獙鍏宠仈鏁版嵁骞剁敓鎴愭寮忔壒娆″彿
- MesMdmItemDO item = mdmItemService.validateItemExists(fillReqVO.getItemId());
MesProLineDO line = lineService.validateLineExistsAndEnable(fillReqVO.getLineId());
validateRelations(fillReqVO);
- String code = generateBatchCode(line.getCode(), item.getCode());
- // 3. 钀藉簱涓氬姟淇℃伅锛堜繚鐣欎复鏃舵壒娆$爜鐢ㄤ簬鍘嗗彶鎵爜杩芥函锛涗骇绾跨紪鐮�/鍚嶇О鍐椾綑鍥炲~锛�
+ String code = generateBatchCode(line.getCode());
+ // 3. 钀藉簱涓氬姟淇℃伅锛堜繚鐣欎复鏃舵壒娆$爜鐢ㄤ簬鍘嗗彶鎵爜杩芥函锛涗骇绾跨紪鐮�/鍚嶇О鍐椾綑鍥炲~锛涘嬀閫夌粦瀹氭墭鐩樻椂鎵规鐩存帴杩涘叆鐢熶骇涓級
+ boolean bindPallets = CollUtil.isNotEmpty(fillReqVO.getPalletIds());
MesProBatchDO updateObj = BeanUtils.toBean(fillReqVO, MesProBatchDO.class)
.setCode(code)
.setLineCode(line.getCode())
.setLineName(line.getName())
- .setStatus(MesProBatchStatusEnum.DRAFT.getStatus());
+ .setStatus(bindPallets ? MesProBatchStatusEnum.PRODUCING.getStatus()
+ : MesProBatchStatusEnum.DRAFT.getStatus());
batchMapper.updateById(updateObj);
// 4. 閲嶅缓鐢熶骇浜哄憳閰嶇疆
batchWorkerMapper.deleteByBatchId(fillReqVO.getId());
insertBatchWorkers(fillReqVO.getId(), fillReqVO.getWorkers());
- // 5. 鐢熸垚鎵规瀹屾暣鎬ф憳瑕侊紙琛ュ綍姝e紡淇℃伅鍚庤鐩栵級
+ // 5. 缁戝畾鎵樼洏锛堢骇鑱旂敓鎴愭寮忔墭鐩樼爜骞跺綍鍏ユ墭鐩樹笅琚嬬爜锛屽け璐ユ暣浣撳洖婊氾級
+ bindPalletsToBatch(fillReqVO.getId(), fillReqVO.getPalletIds());
+ // 6. 鐢熸垚鎵规瀹屾暣鎬ф憳瑕侊紙琛ュ綍姝e紡淇℃伅鍚庤鐩栵級
integrityService.recordBatchIntegrity(fillReqVO.getId());
}
@@ -157,29 +168,33 @@
// 2. 鏍¢獙鍏宠仈鏁版嵁锛堢敓浜т汉鍛橈級
validateRelations(updateReqVO);
- // 3. 鏈敓鎴愭寮忔壒娆″彿鎴栧搧绉�/浜х嚎鍙樺寲鏃堕噸鏂扮敓鎴愭壒娆″彿锛堟壒娆″彿鍖呭惈浜х嚎缂栫爜 + 鍝佺缂栫爜瑕佺礌锛�
+ // 3. 鏈敓鎴愭寮忔壒娆″彿鎴栦骇绾垮彉鍖栨椂閲嶆柊鐢熸垚鎵规鍙凤紙鎵规鍙峰寘鍚骇绾跨紪鐮佽绱狅級
boolean codeEmpty = StrUtil.isEmpty(oldBatch.getCode());
- boolean itemChanged = !Objects.equals(oldBatch.getItemId(), updateReqVO.getItemId());
boolean lineChanged = !Objects.equals(oldBatch.getLineId(), updateReqVO.getLineId());
String code = oldBatch.getCode();
MesProBatchDO updateObj = BeanUtils.toBean(updateReqVO, MesProBatchDO.class);
- if (codeEmpty || itemChanged || lineChanged) {
- MesMdmItemDO item = mdmItemService.validateItemExists(updateReqVO.getItemId());
+ if (codeEmpty || lineChanged) {
// 鍙樻洿浜х嚎鏃讹紝鐩爣浜х嚎蹇呴』鍚敤锛涙湭鍙樻洿鍒欎粎鏍¢獙瀛樺湪锛堥伩鍏嶅仠鐢ㄤ骇绾跨殑鍘嗗彶鎵规鏃犳硶缂栬緫鍏朵粬瀛楁锛�
MesProLineDO line = (lineChanged || codeEmpty)
? lineService.validateLineExistsAndEnable(updateReqVO.getLineId())
: lineService.validateLineExists(updateReqVO.getLineId());
- code = generateBatchCode(line.getCode(), item.getCode());
+ code = generateBatchCode(line.getCode());
updateObj.setLineCode(line.getCode()).setLineName(line.getName());
}
- // 4. 鏇存柊鎵规
+ // 4. 鏇存柊鎵规锛堝嬀閫夌粦瀹氭墭鐩樻椂鎵规鐩存帴杩涘叆鐢熶骇涓紱鍙栨秷鍕鹃�変笉鍥為��锛屽凡缁戝畾鎵樼洏涓嶅彲瑙g粦锛�
+ boolean bindPallets = CollUtil.isNotEmpty(updateReqVO.getPalletIds());
updateObj.setCode(code);
+ if (bindPallets) {
+ updateObj.setStatus(MesProBatchStatusEnum.PRODUCING.getStatus());
+ }
batchMapper.updateById(updateObj);
// 5. 閲嶅缓鐢熶骇浜哄憳閰嶇疆
batchWorkerMapper.deleteByBatchId(updateReqVO.getId());
insertBatchWorkers(updateReqVO.getId(), updateReqVO.getWorkers());
- // 6. 鎽樿瑕嗙洊鑼冨洿鍚搧绉�/浜х嚎/鐢熶骇鏃ユ湡/璁″垝鏁伴噺锛岀紪杈戝悗閲嶆柊鐢熸垚閬垮厤璇姤绡℃敼
+ // 6. 缁戝畾鏂板鍕鹃�夌殑鎵樼洏锛堢骇鑱旂敓鎴愭寮忔墭鐩樼爜骞跺綍鍏ユ墭鐩樹笅琚嬬爜锛屽け璐ユ暣浣撳洖婊氾級
+ bindPalletsToBatch(updateReqVO.getId(), updateReqVO.getPalletIds());
+ // 7. 鎽樿瑕嗙洊鑼冨洿鍚搧绉�/浜х嚎/鐢熶骇鏃ユ湡/璁″垝鏁伴噺锛岀紪杈戝悗閲嶆柊鐢熸垚閬垮厤璇姤绡℃敼
integrityService.recordBatchIntegrity(updateReqVO.getId());
}
@@ -283,7 +298,7 @@
/**
* 鏍¢獙鍏宠仈鏁版嵁锛堢敓浜т汉鍛橈細璐d换浜� + 鐢熶骇浜哄憳閰嶇疆锛�
* <p>
- * 鍝佺銆佷骇绾跨殑鏍¢獙鍦ㄥ垱寤�/鏇存柊娴佺▼涓唴鑱旀墽琛岋紙闇�鍙栫紪鐮佸弬涓庢壒娆″彿鐢熸垚锛�
+ * 浜х嚎鐨勬牎楠屽湪鍒涘缓/鏇存柊娴佺▼涓唴鑱旀墽琛岋紙闇�鍙栫紪鐮佸弬涓庢壒娆″彿鐢熸垚锛�
*/
private void validateRelations(MesProBatchSaveReqVO reqVO) {
Set<Long> userIds = new HashSet<>();
@@ -293,16 +308,29 @@
}
/**
+ * 鎵规缁戝畾鎵樼洏锛堝彲閫夛級锛氬悓浜嬪姟鍐呭鐢ㄦ墭鐩樼粦瀹氭壒娆¢�昏緫锛�
+ * 鐢熸垚姝e紡鎵樼洏鐮佸苟绾ц仈褰曞叆鎵樼洏涓嬫湭缁戞壒娆$殑琚嬬爜锛屽け璐ユ暣浣撳洖婊�
+ */
+ private void bindPalletsToBatch(Long batchId, List<Long> palletIds) {
+ if (CollUtil.isEmpty(palletIds)) {
+ return;
+ }
+ MesProPalletBindBatchReqVO bindReqVO = new MesProPalletBindBatchReqVO();
+ bindReqVO.setBatchId(batchId);
+ bindReqVO.setIds(palletIds);
+ palletService.bindBatch(bindReqVO);
+ }
+
+ /**
* 鐢熸垚鎵规鍙�
* <p>
- * 缂栫爜瑙勫垯锛氬浐瀹氬墠缂�(PC) + 鏃ユ湡(yyyyMMdd) + 杈撳叆瀛楃(浜х嚎缂栫爜 + 鍝佺缂栫爜) + 娴佹按鍙�(鎸夋棩寰幆)
+ * 缂栫爜瑙勫垯锛氬浐瀹氬墠缂�(PC) + 鏃ユ湡(yyyyMMdd) + 杈撳叆瀛楃(浜х嚎缂栫爜) + 娴佹按鍙�(鎸夋棩寰幆)
*
* @param lineCode 浜х嚎缂栫爜
- * @param itemCode 鍝佺锛堢墿鏂欙級缂栫爜
* @return 鎵规鍙�
*/
- private String generateBatchCode(String lineCode, String itemCode) {
- String inputChar = StrUtil.emptyToDefault(lineCode, "") + StrUtil.emptyToDefault(itemCode, "");
+ private String generateBatchCode(String lineCode) {
+ String inputChar = StrUtil.emptyToDefault(lineCode, "");
return autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.PRO_BATCH_CODE.getCode(), inputChar);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletService.java
index e8c8fc4..d2e2873 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletService.java
@@ -90,6 +90,13 @@
List<MesProPalletDO> getPalletListByBatchId(Long batchId);
/**
+ * 鑾峰緱鏈粦瀹氱敓浜ф壒娆$殑涓存椂鎵樼洏鍒楄〃锛堜緵鎵规鏂板/琛ュ綍缁戝畾鎵樼洏涓嬫媺浣跨敤锛�
+ *
+ * @return 鎵樼洏鐮佸垪琛�
+ */
+ List<MesProPalletDO> getUnboundPalletList();
+
+ /**
* 鑾峰緱鎵樼洏鐮佸垪琛紙鎸夌紪鍙峰垪琛級
*
* @param ids 缂栧彿鍒楄〃
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java
index 33794e4..fd5557a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java
@@ -7,11 +7,14 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletBindBatchReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.pallet.vo.MesProPalletPreGenerateReqVO;
+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.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
+import cn.iocoder.yudao.module.mes.dal.redis.MesCodeRedisDAO;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum;
import jakarta.annotation.Resource;
@@ -22,7 +25,9 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -43,6 +48,9 @@
private MesProBagCodeMapper bagCodeMapper;
@Resource
private MesProBatchMapper batchMapper;
+
+ @Resource
+ private MesCodeRedisDAO codeRedisDao;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -67,11 +75,10 @@
for (int i = 0; i < createReqVO.getCount(); i++) {
int palletNo = startNo + i;
pallets.add(new MesProPalletDO()
- .setCode(batch.getCode() + "-P" + StrUtil.padPre(String.valueOf(palletNo), 2, '0'))
+ .setCode(codeRedisDao.generate())
.setBatchId(batch.getId())
.setBatchCode(batch.getCode())
.setPalletNo(palletNo)
- .setCapacity(createReqVO.getCapacity())
.setBagCount(0)
.setAutoGenerated(false)
.setStatus(MesProPalletStatusEnum.IN_USE.getStatus())
@@ -94,8 +101,7 @@
List<MesProPalletDO> list = new ArrayList<>(reqVO.getCount());
for (int i = 0; i < reqVO.getCount(); i++) {
list.add(new MesProPalletDO()
- .setTempCode("PL-" + StrUtil.padPre(String.valueOf(startSeq + i), 8, '0'))
- .setCapacity(reqVO.getCapacity())
+ .setTempCode(codeRedisDao.generate())
.setBagCount(0)
.setAutoGenerated(false)
.setStatus(MesProPalletStatusEnum.IN_USE.getStatus())
@@ -136,20 +142,50 @@
}
pallets.add(pallet);
}
- // 3. 鍒嗛厤姝e紡鎵樼洏鐮侊細鎵规鍙� + -P + 2 浣嶆墭鐩樺簭鍙凤紙鍚�昏緫鍒犻櫎璁板綍鍙備笌搴忓彿锛屼繚璇佷笉鍥為��銆佺爜鍊煎敮涓�锛�
+ // 3. 绾ц仈鍑嗗锛氭墭鐩樹笅鏈粦鎵规鐨勮鐮侀殢鎵樼洏涓�璧峰綍鍏ユ壒娆★紝鍝佺椤讳笌鎵规宸叉湁琚嬬爜涓�鑷�
+ List<MesProBagCodeDO> bags = bagCodeMapper.selectUnboundListByPalletIds(ids);
+ List<Long> bindBagIds = new ArrayList<>();
+ Set<Long> bagItemIds = new LinkedHashSet<>();
+ for (MesProBagCodeDO bag : bags) {
+ if (!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(bag.getStatus())
+ && !MesProBagCodeStatusEnum.PRINTED.getStatus().equals(bag.getStatus())) {
+ continue;
+ }
+ bindBagIds.add(bag.getId());
+ if (bag.getItemId() != null) {
+ bagItemIds.add(bag.getItemId());
+ }
+ }
+ if (!bindBagIds.isEmpty()) {
+ bagItemIds.addAll(bagCodeMapper.selectDistinctItemIdsByBatchId(batch.getId()));
+ if (bagItemIds.size() > 1) {
+ throw exception(PRO_BAG_CODE_BIND_BATCH_ITEM_MISMATCH);
+ }
+ }
+ // 4. 鍒嗛厤姝e紡鎵樼洏鐮侊細鎵规鍙� + -P + 2 浣嶆墭鐩樺簭鍙凤紙鍚�昏緫鍒犻櫎璁板綍鍙備笌搴忓彿锛屼繚璇佷笉鍥為��銆佺爜鍊煎敮涓�锛�
int startNo = palletMapper.selectMaxPalletNo(batch.getId()) + 1;
for (int i = 0; i < pallets.size(); i++) {
int palletNo = startNo + i;
palletMapper.updateById(new MesProPalletDO()
.setId(pallets.get(i).getId())
- .setCode(batch.getCode() + "-P" + StrUtil.padPre(String.valueOf(palletNo), 2, '0'))
+ .setCode(codeRedisDao.generate())
.setBatchId(batch.getId())
.setBatchCode(batch.getCode())
.setPalletNo(palletNo));
+ // 鎵樼洏涓嬭鐮佺殑鍐椾綑鎵樼洏鐮佺敱涓存椂鐮佹洿鏂颁负姝e紡鐮�
+ bagCodeMapper.updatePalletCodeByPalletId(pallets.get(i).getId(),
+ batch.getCode() + "-P" + StrUtil.padPre(String.valueOf(palletNo), 2, '0'));
}
- // 4. 鍥炲啓鎵规鎵樼洏鐮佹暟閲�
+ // 5. 鎵樼洏涓嬭鐮佹壒閲忕粦瀹氭湰鎵规
+ if (!bindBagIds.isEmpty() && bagCodeMapper.bindBatchByIds(bindBagIds, batch.getId(), batch.getCode(),
+ List.of(MesProBagCodeStatusEnum.GENERATED.getStatus(),
+ MesProBagCodeStatusEnum.PRINTED.getStatus())) != bindBagIds.size()) {
+ throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED);
+ }
+ // 6. 鍥炲啓鎵规鎵樼洏鐮佹暟閲忎笌鏈夋晥琚嬬爜鏁伴噺
batchMapper.updateById(new MesProBatchDO().setId(batch.getId())
- .setPalletQuantity((batch.getPalletQuantity() == null ? 0 : batch.getPalletQuantity()) + pallets.size()));
+ .setPalletQuantity((batch.getPalletQuantity() == null ? 0 : batch.getPalletQuantity()) + pallets.size())
+ .setBagQuantity(bagCodeMapper.selectEffectiveCountByBatchId(batch.getId())));
return pallets.size();
}
@@ -206,6 +242,11 @@
}
@Override
+ public List<MesProPalletDO> getUnboundPalletList() {
+ return palletMapper.selectUnboundList();
+ }
+
+ @Override
public List<MesProPalletDO> getPalletListByIds(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return List.of();
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
index 6ee0402..4657035 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
@@ -5,11 +5,13 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.scan.vo.MesProScanEventPageReqVO;
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.dal.dataobject.pro.scan.MesProScanEventDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.scan.MesProScanEventMapper;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.enums.MesProScanEventStatusEnum;
@@ -20,47 +22,102 @@
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+@Slf4j
@Service
@Validated
public class MesProScanEventServiceImpl implements MesProScanEventService {
@Resource private MesProScanEventMapper eventMapper;
@Resource private MesProBagCodeMapper bagCodeMapper;
@Resource private MesProBatchMapper batchMapper;
+ @Resource private MesProPalletMapper palletMapper;
@Resource private MesWmTransactionService transactionService;
@Resource private MesWmWarehouseService warehouseService;
@Resource private MesWmBatchService mesWmBatchService;
+
+ /** 鎵爜绫诲瀷锛氳鐮侊紙榛樿锛� */
+ private static final String SCAN_TYPE_BAG = "BAG";
+ /** 鎵爜绫诲瀷锛氭墭鐩樼爜锛堟寜鎵樼洏宸茶琚嬫暟鏁存墭鍏ュ簱锛� */
+ private static final String SCAN_TYPE_PALLET = "PALLET";
+ /** 鎵爜绫诲瀷锛氭壒娆$爜锛堟寜鎵规琚嬫暟鏁存壒鍏ュ簱锛� */
+ private static final String SCAN_TYPE_BATCH = "BATCH";
@Override
@Transactional(rollbackFor = Exception.class)
public MesProScanEventDO createInbound(MesProScanEventCreateReqVO req) {
MesProScanEventDO existing = eventMapper.selectByEventIdForUpdate(req.getEventId());
if (existing != null) {
- if (!req.getBagCode().equals(existing.getBagCode()) || !req.getDeviceCode().equals(existing.getDeviceCode())) {
+ boolean contentMatch = req.getBagCode().equals(existing.getBagCode())
+ && (req.getDeviceCode() == null || req.getDeviceCode().equals(existing.getDeviceCode()));
+ if (!contentMatch) {
return failed(existing, "MES_SCAN_EVENT_ID_CONFLICT", "浜嬩欢鍙峰凡瀛樺湪浣嗗唴瀹逛笉涓�鑷�");
}
return existing;
}
+ String scanType = (req.getScanType() == null || req.getScanType().isBlank()) ? SCAN_TYPE_BAG : req.getScanType();
MesProScanEventDO event = new MesProScanEventDO();
- event.setEventId(req.getEventId()).setBagCode(req.getBagCode()).setQuantity(req.getQuantity())
- .setDeviceCode(req.getDeviceCode()).setLineCode(req.getLineCode()).setRemark(req.getRemark())
- .setStatus(MesProScanEventStatusEnum.FAILED).setReceivedTime(LocalDateTime.now());
+ event.setEventId(req.getEventId()).setBagCode(req.getBagCode()).setScanType(scanType)
+ .setQuantity(req.getQuantity()).setDeviceCode(req.getDeviceCode()).setLineCode(req.getLineCode())
+ .setRemark(req.getRemark()).setStatus(MesProScanEventStatusEnum.FAILED).setReceivedTime(LocalDateTime.now());
eventMapper.insert(event);
- MesProBagCodeDO bag = bagCodeMapper.selectByCodeForUpdate(req.getBagCode());
- if (bag == null) return failed(event, "MES_SCAN_BAG_NOT_EXISTS", "琚嬬爜涓嶅瓨鍦�");
- event.setBagCodeId(bag.getId());
- if (bag.getInboundEventId() != null) return failed(event, "MES_SCAN_BAG_ALREADY_INBOUND", "琚嬬爜宸插叆搴�");
- MesProBatchDO batch = batchMapper.selectByIdForUpdate(bag.getBatchId());
- if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
- event.setBatchId(batch.getId()).setBatchCode(batch.getCode()).setItemId(batch.getItemId());
+ // 1. 鎸夋壂鐮佺被鍨嬭В鏋愭壂鐮佺洰鏍囦笌鍏ュ簱鏁伴噺锛堟墭鐩樻寜宸茶琚嬫暟銆佹壒娆℃寜鎵规琚嬫暟鏁存壒/鏁存墭鍏ュ簱锛�
+ Long targetId;
+ Long batchId;
+ BigDecimal quantity;
+ MesProBatchDO batch;
+ // 鍗曡鎵爜鍏ュ簱鏃朵紶閫掕鐮侊紝渚涘簱瀛樿鐮佹槑缁嗗湪鍏ュ簱绗竴鏃堕棿寤虹珛锛涙墭鐩�/鎵规鏁存壒鍏ュ簱涓烘壒閲忥紝涓嶉�愯寤烘槑缁�
+ Long bagCodeId = null;
+ String bagCode = null;
+ if (SCAN_TYPE_PALLET.equals(scanType)) {
+ MesProPalletDO pallet = palletMapper.selectByCode(req.getBagCode());
+ if (pallet == null) {
+ pallet = palletMapper.selectByTempCode(req.getBagCode());
+ }
+ if (pallet == null) return failed(event, "MES_SCAN_PALLET_NOT_EXISTS", "鎵樼洏鐮佷笉瀛樺湪");
+ if (pallet.getInboundEventId() != null) return failed(event, "MES_SCAN_PALLET_ALREADY_INBOUND", "鎵樼洏宸插叆搴�");
+ batch = batchMapper.selectByIdForUpdate(pallet.getBatchId());
+ if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
+ batchId = batch.getId();
+ targetId = pallet.getId();
+ quantity = pallet.getBagCount() != null && pallet.getBagCount() > 0
+ ? BigDecimal.valueOf(pallet.getBagCount())
+ : BigDecimal.valueOf(bagCodeMapper.selectCountByPalletId(pallet.getId()));
+ } else if (SCAN_TYPE_BATCH.equals(scanType)) {
+ batch = batchMapper.selectByCode(req.getBagCode());
+ if (batch == null) {
+ batch = batchMapper.selectByTempCode(req.getBagCode());
+ }
+ if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
+ if (batch.getInboundEventId() != null) return failed(event, "MES_SCAN_BATCH_ALREADY_INBOUND", "鎵规宸叉暣鎵瑰叆搴�");
+ batchId = batch.getId();
+ targetId = batch.getId();
+ quantity = batch.getBagQuantity() != null && batch.getBagQuantity() > 0
+ ? BigDecimal.valueOf(batch.getBagQuantity())
+ : BigDecimal.valueOf(bagCodeMapper.selectCountByBatchId(batch.getId()));
+ } else {
+ MesProBagCodeDO bag = bagCodeMapper.selectByCodeForUpdate(req.getBagCode());
+ if (bag == null) return failed(event, "MES_SCAN_BAG_NOT_EXISTS", "琚嬬爜涓嶅瓨鍦�");
+ event.setBagCodeId(bag.getId());
+ bagCodeId = bag.getId();
+ bagCode = req.getBagCode();
+ if (bag.getInboundEventId() != null) return failed(event, "MES_SCAN_BAG_ALREADY_INBOUND", "琚嬬爜宸插叆搴�");
+ batch = batchMapper.selectByIdForUpdate(bag.getBatchId());
+ if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
+ batchId = batch.getId();
+ targetId = bag.getId();
+ quantity = req.getQuantity();
+ }
+ event.setBatchId(batchId).setBatchCode(batch.getCode()).setItemId(batch.getItemId());
MesWmWarehouseDO warehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE);
if (warehouse == null) return failed(event, "MES_SCAN_WIP_WAREHOUSE_NOT_EXISTS", "WIP铏氭嫙浠撲笉瀛樺湪");
event.setWarehouseId(warehouse.getId()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId());
@@ -72,19 +129,31 @@
}
Long txId = transactionService.createTransaction(new MesWmTransactionSaveReqDTO()
.setType(MesWmTransactionTypeEnum.IN.getType()).setBizType(MesBizTypeConstants.WM_PRODUCT_PRODUCE)
- .setBizId(batch.getId()).setBizCode(batch.getCode()).setBizLineId(bag.getId())
- .setItemId(batch.getItemId()).setQuantity(req.getQuantity())
+ .setBizId(batchId).setBizCode(batch.getCode()).setBizLineId(targetId)
+ .setItemId(batch.getItemId()).setQuantity(quantity)
.setBatchId(wmBatch.getId()).setBatchCode(batch.getCode())
+ .setBagCodeId(bagCodeId).setBagCode(bagCode)
.setWarehouseId(warehouse.getId()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId())
.setReceiptTime(LocalDateTime.now()).setCheckFlag(true)
.setStockState(MesWmStockStateEnum.TEMP.getState()));
event.setTransactionId(txId).setStatus(MesProScanEventStatusEnum.SUCCESS).setEventTime(LocalDateTime.now());
eventMapper.updateById(event);
- bagCodeMapper.markInbound(bag.getId(), event.getId(), req.getDeviceCode(), req.getLineCode());
- batchMapper.markInbound(batch.getId(), event.getId(), req.getDeviceCode(), req.getLineCode());
+ // 2. 鍥炲啓鍏ュ簱鏍囪锛堟墭鐩�/鎵规鏁存墭/鏁存壒鍏ュ簱鏃跺悓姝ユ爣璁板叾涓嬫湭鍏ュ簱琚嬬爜锛屼繚鎸佺姸鎬佷竴鑷达級
+ if (SCAN_TYPE_PALLET.equals(scanType)) {
+ palletMapper.markInbound(targetId, event.getId());
+ bagCodeMapper.markInboundByPalletId(targetId, event.getId(), req.getLineCode());
+ } else if (SCAN_TYPE_BATCH.equals(scanType)) {
+ batchMapper.markBatchInbound(targetId, event.getId(), req.getLineCode(), batch.getBagQuantity());
+ bagCodeMapper.markInboundByBatchId(targetId, event.getId(), req.getLineCode());
+ } else {
+ bagCodeMapper.markInbound(targetId, event.getId(), req.getDeviceCode(), req.getLineCode());
+ batchMapper.markInbound(batchId, event.getId(), req.getDeviceCode(), req.getLineCode());
+ }
return event;
} catch (Exception ex) {
- return failed(event, "MES_SCAN_TRANSACTION_FAILED", "搴撳瓨浜嬪姟澶勭悊澶辫触");
+ log.error("[createInbound] 搴撳瓨浜嬪姟澶勭悊澶辫触锛宔ventId={}, bagCode={}, batchId={}, itemId={}",
+ req.getEventId(), req.getBagCode(), batchId, batch.getItemId(), ex);
+ throw ex;
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
index 8fbf16c..ed096f1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.mes.service.qc.seedquality;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityIndicatorDO;
@@ -10,6 +12,8 @@
Long submit(MesQcSeedQualitySubmitReqVO reqVO);
+ PageResult<MesQcSeedQualityDO> getQualityPage(MesQcSeedQualityPageReqVO reqVO);
+
/**
* 鏍规嵁鎵规鍙锋煡璇㈣川妫�璁板綍锛堟寜妫�楠屾椂闂村�掑簭锛屽彇鏈�鏂帮級锛岀敤浜庡叕寮�婧簮銆�
* 绉嶅瓙璐ㄦ琛ㄦ湭鍒濆鍖栨椂杩斿洖绌哄垪琛紙瀹归敊锛屼笉褰卞搷杩芥函锛夈��
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
index 60b78c1..492d1d0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
@@ -1,41 +1,117 @@
package cn.iocoder.yudao.module.mes.service.qc.seedquality;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
+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.qc.seedquality.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.*;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.batch.MesWmBatchMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
-import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
-import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_NOT_EXISTS;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_TYPE_NOT_QUALIFIED;
@Service @Validated @Slf4j
public class MesQcSeedQualityServiceImpl implements MesQcSeedQualityService {
private static final Set<String> REQUIRED = Set.of("purity", "cleanliness", "germination_rate", "moisture");
@Resource private MesQcSeedQualityMapper qualityMapper;
@Resource private MesQcSeedQualityIndicatorMapper indicatorMapper;
+ @Resource private MesProBagCodeMapper bagCodeMapper;
@Resource private MesProBatchService proBatchService;
- @Resource private MesWmBatchService mesWmBatchService;
- @Resource private MesWmMaterialStockService materialStockService;
+ @Resource private MesWmBatchMapper mesWmBatchMapper;
+ @Resource private MesWmMaterialStockMapper materialStockMapper;
+ @Resource private MesWmMaterialStockBagMapper materialStockBagMapper;
+ @Resource private MesWmMaterialStockBagService materialStockBagService;
+ @Resource private MesWmTransactionService wmTransactionService;
+ @Resource private MesWmWarehouseService warehouseService;
+ @Resource private MesWmWarehouseLocationService warehouseLocationService;
+ @Resource private MesWmWarehouseAreaService warehouseAreaService;
+
+ @Override
+ public PageResult<MesQcSeedQualityDO> getQualityPage(MesQcSeedQualityPageReqVO reqVO) {
+ return qualityMapper.selectPage(reqVO);
+ }
@Override @Transactional(rollbackFor = Exception.class)
public Long submit(MesQcSeedQualitySubmitReqVO reqVO) {
if (reqVO.getIndicators().size() != 4) throw new IllegalArgumentException("蹇呴』鎻愪氦鍥涢」鎸囨爣");
if (qualityMapper.selectByCode(reqVO.getCode()) != null) throw new IllegalArgumentException("璇ヨ鐮佸凡璐ㄦ锛岀姝㈤噸澶嶆彁浜�");
+ // 绉嶅瓙璐ㄦ蹇呴』浠ヨ鐮侊紙鍗曡锛夋彁浜わ紝鐗╂枡淇℃伅鐢辫鐮佽嚜鍔ㄨВ鏋愶紝鍓嶇涓嶅啀鍗曠嫭閫夋嫨鐗╂枡
+ MesProBagCodeDO bag = bagCodeMapper.selectByCode(reqVO.getCode());
+ if (bag == null) {
+ throw new IllegalArgumentException("鏈В鏋愬埌鏈夋晥琚嬬爜锛岀瀛愯川妫�蹇呴』浠ヨ鐮佹彁浜�");
+ }
+ MesProBatchDO batch = resolveBatch(reqVO.getCode(), reqVO.getBatchCode());
+ if (batch == null || batch.getItemId() == null) {
+ throw new IllegalArgumentException("鏈牴鎹鐮佽В鏋愬埌鐗╂枡淇℃伅锛岃纭鎵爜鍐呭鎴栨壒娆″彿姝g‘");
+ }
+ // 琚嬬爜瀵瑰簲鎵规鐨勫簱瀛樺繀椤诲浜庢殏瀛樺簱锛堝緟璐ㄦ锛変腑锛屾墠鑳借繘琛岀瀛愯川妫�
+ MesWmBatchDO wmBatch = mesWmBatchMapper.selectByCode(batch.getCode());
+ if (wmBatch == null || materialStockMapper.selectTempStockCountByBatchId(wmBatch.getId()) == 0) {
+ throw new IllegalArgumentException("璇ヨ鐮�/鎵规瀵瑰簲鐨勫簱瀛樹笉鍦ㄦ殏瀛樺簱涓紝鏃犳硶杩涜璐ㄦ");
+ }
+ // 鏍¢獙鐩爣鍚堟牸搴擄細蹇呴』瀛樺湪涓斾粨搴撶被鍨嬩负鍚堟牸搴�(20)
+ if (warehouseService.getFirstQualifiedWarehouse() == null) {
+ throw exception(WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED);
+ }
+ MesWmWarehouseDO qualifiedWarehouse = warehouseService.getWarehouse(reqVO.getQualifiedWarehouseId());
+ if (qualifiedWarehouse == null) {
+ throw exception(WM_WAREHOUSE_NOT_EXISTS);
+ }
+ if (!MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(qualifiedWarehouse.getType())) {
+ throw exception(WM_WAREHOUSE_TYPE_NOT_QUALIFIED);
+ }
+ // 瑙f瀽鍚堟牸搴撻粯璁ゅ簱鍖�/搴撲綅锛堝彇璇ヤ粨搴撲笅绗竴涓簱鍖恒�佸叾涓嬬涓�涓簱浣嶏紝鏈厤缃垯涓� null锛�
+ Long qualifiedLocationId = null;
+ Long qualifiedAreaId = null;
+ List<MesWmWarehouseLocationDO> locations = warehouseLocationService.getWarehouseLocationList(qualifiedWarehouse.getId());
+ if (CollUtil.isNotEmpty(locations)) {
+ qualifiedLocationId = locations.get(0).getId();
+ List<MesWmWarehouseAreaDO> areas = warehouseAreaService.getWarehouseAreaList(qualifiedLocationId);
+ if (CollUtil.isNotEmpty(areas)) {
+ qualifiedAreaId = areas.get(0).getId();
+ }
+ }
Set<String> codes = new HashSet<>();
boolean passed = true;
- MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(reqVO.getCode()).itemId(reqVO.getItemId())
- .batchCode(reqVO.getBatchCode()).reason(reqVO.getReason()).result(0)
+ MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(reqVO.getCode()).itemId(batch.getItemId())
+ .batchCode(batch.getCode()).reason(reqVO.getReason()).result(0)
.inspectedAt(LocalDateTime.now()).build();
qualityMapper.insert(quality);
for (MesQcSeedQualitySubmitReqVO.Indicator item : reqVO.getIndicators()) {
@@ -47,20 +123,151 @@
if (!codes.equals(REQUIRED)) throw new IllegalArgumentException("鍥涢」鎸囨爣涓嶅畬鏁�");
quality.setResult(passed ? 1 : 2);
qualityMapper.updateById(quality);
- // 璐ㄦ鍚堟牸 鈫� 搴撳瓨鏁存壒鐢辨殏瀛樺簱锛堝緟璐ㄦ锛夎浆涓哄悎鏍煎簱锛堟寮忓簱瀛橈級
+ // 鎸夎鐮佺矑搴︽祦杞簱瀛橈細閿佸畾璇ヨ鍦ㄦ殏瀛樺簱涓殑娲诲姩鏄庣粏锛岀姝㈡寜鎵规浠绘剰鎵e噺
+ MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectActiveByBagCode(bag.getCode());
+ MesWmMaterialStockDO tempStock = resolveTempStock(bag, wmBatch, stockBag);
+ // A. 鏆傚瓨鍑哄簱锛�-1锛夛細璇ヨ绂诲紑鏆傚瓨搴擄紝鍐欏叆璐ㄦ鏆傚瓨鍑哄簱浜嬪姟锛堣烦杩囪鐮佽嚜鍔ㄧ淮鎶わ紝鐢辫川妫�缁熶竴鎺у埗琚嬬爜鏈�缁堣惤鐐癸級
+ MesWmTransactionSaveReqDTO tempOutReq = new MesWmTransactionSaveReqDTO()
+ .setType(MesWmTransactionTypeEnum.OUT.getType())
+ .setBizType(MesBizTypeConstants.QC_SEED_QUALITY)
+ .setBizId(quality.getId())
+ .setBizCode(reqVO.getCode())
+ .setBizLineId(quality.getId())
+ .setItemId(batch.getItemId())
+ .setQuantity(BigDecimal.ONE.negate())
+ .setBatchId(tempStock.getBatchId())
+ .setBatchCode(tempStock.getBatchCode())
+ .setBagCodeId(bag.getId())
+ .setBagCode(bag.getCode())
+ .setWarehouseId(tempStock.getWarehouseId())
+ .setLocationId(tempStock.getLocationId())
+ .setAreaId(tempStock.getAreaId())
+ .setVendorId(tempStock.getVendorId())
+ .setMaterialStockId(tempStock.getId())
+ .setCheckFlag(true)
+ .setSkipBagManage(true);
+ Long tempOutTxId = wmTransactionService.createTransaction(tempOutReq);
if (passed) {
- MesProBatchDO proBatch = proBatchService.getBatchByCode(reqVO.getBatchCode());
- if (proBatch != null) {
- MesWmBatchDO wmBatch = mesWmBatchService.getOrCreateByProBatch(proBatch);
- if (wmBatch != null) {
- int updated = materialStockService.updateStockStateByBatchId(wmBatch.getId(),
- MesWmStockStateEnum.QUALIFIED.getState(), MesWmStockStateEnum.TEMP.getState());
- log.info("[submit][璐ㄦ鍚堟牸锛屾壒娆� {} 搴撳瓨鐢辨殏瀛樺簱杞悎鏍煎簱锛屽奖鍝� {} 鏉", reqVO.getBatchCode(), updated);
+ // B1. 璐ㄦ鍚堟牸 鈫� 璇ヨ杞叆鎿嶄綔鍛橀�夋嫨鐨勫悎鏍煎簱锛屽啓鍏ュ悎鏍煎叆搴撲簨鍔★紙璺宠繃琚嬬爜鑷姩缁存姢锛�
+ MesWmMaterialStockDO qualifiedStock = getOrCreateQualifiedStock(tempStock, qualifiedWarehouse.getId(), qualifiedLocationId, qualifiedAreaId);
+ MesWmTransactionSaveReqDTO qualInReq = new MesWmTransactionSaveReqDTO()
+ .setType(MesWmTransactionTypeEnum.IN.getType())
+ .setBizType(MesBizTypeConstants.QC_SEED_QUALITY)
+ .setBizId(quality.getId())
+ .setBizCode(reqVO.getCode())
+ .setBizLineId(quality.getId())
+ .setItemId(batch.getItemId())
+ .setQuantity(BigDecimal.ONE)
+ .setBatchId(qualifiedStock.getBatchId())
+ .setBatchCode(qualifiedStock.getBatchCode())
+ .setBagCodeId(bag.getId())
+ .setBagCode(bag.getCode())
+ .setWarehouseId(qualifiedStock.getWarehouseId())
+ .setLocationId(qualifiedStock.getLocationId())
+ .setAreaId(qualifiedStock.getAreaId())
+ .setVendorId(qualifiedStock.getVendorId())
+ .setMaterialStockId(qualifiedStock.getId())
+ .setCheckFlag(false)
+ .setStockState(MesWmStockStateEnum.QUALIFIED.getState())
+ .setSkipBagManage(true);
+ Long qualInTxId = wmTransactionService.createTransaction(qualInReq);
+ // B2. 鍚屾杩佺Щ琚嬬爜鏄庣粏鍒板悎鏍煎簱瀛樿惤鐐�
+ materialStockBagService.moveIn(qualInReq, qualifiedStock, qualInTxId);
+ bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.QUALIFIED.getStatus());
+ log.info("[submit][璐ㄦ鍚堟牸锛岃鐮� {} 鐢辨殏瀛樺簱杞悎鏍煎簱 {}]", bag.getCode(), qualifiedWarehouse.getName());
+ } else {
+ // C. 璐ㄦ涓嶅悎鏍� 鈫� 璇ヨ鎶ュ簾锛涙殏瀛樺嚭搴撲簨鍔″凡鎵e噺鏆傚瓨搴撳瓨锛屾爣璁拌鐮佹姤搴�
+ materialStockBagService.scrap(tempOutReq, tempOutTxId);
+ bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.UNQUALIFIED.getStatus());
+ log.info("[submit][璐ㄦ涓嶅悎鏍硷紝琚嬬爜 {} 鎶ュ簾]", bag.getCode());
+ }
+ return quality.getId();
+ }
+
+ /**
+ * 瀹氫綅璇ヨ鐨勬殏瀛樺簱瀛樻眹鎬昏褰曪紙鍙畾浣嶏紝涓嶆墸鍑忥紱鎵e噺鐢辫川妫�鏆傚瓨鍑哄簱浜嬪姟瀹屾垚锛夈��
+ * <p>
+ * 浼樺厛涓ユ牸鎸夎鐮侀攣瀹氬叾娲诲姩鏄庣粏瀵瑰簲鐨勬殏瀛樿褰曪紱鍘嗗彶鏃犳槑缁嗘椂鍥為��鎸夋壒娆″畾浣嶅苟琛ュ缓鏄庣粏銆�
+ */
+ private MesWmMaterialStockDO resolveTempStock(MesProBagCodeDO bag, MesWmBatchDO wmBatch, MesWmMaterialStockBagDO stockBag) {
+ if (stockBag != null && stockBag.getMaterialStockId() != null) {
+ MesWmMaterialStockDO stock = materialStockMapper.selectById(stockBag.getMaterialStockId());
+ if (stock != null && MesWmStockStateEnum.TEMP.getState().equals(stock.getStockState())) {
+ return stock;
+ }
+ }
+ MesWmMaterialStockDO tempStock = materialStockMapper.selectStockListByBatchId(wmBatch.getId()).stream()
+ .filter(s -> MesWmStockStateEnum.TEMP.getState().equals(s.getStockState()))
+ .max(Comparator.comparing(MesWmMaterialStockDO::getQuantity))
+ .orElse(null);
+ if (tempStock == null) {
+ throw new IllegalArgumentException("璇ユ壒娆℃殏瀛樺簱瀛樹笉瓒筹紝鏃犳硶璐ㄦ");
+ }
+ getOrCreateStockBag(bag, tempStock);
+ return tempStock;
+ }
+
+ /**
+ * 璐ㄦ鍚堟牸锛氬皢璐ㄦ閫氳繃鐨勯偅琚嬭浆鍏ユ搷浣滃憳閫夋嫨鐨勫悎鏍煎簱锛堝悓缁勫悎閿悎鏍煎簱璁板綍 +1锛屼笉瀛樺湪鍒欐柊寤猴級銆�
+ *
+ * @param tempStock 浠庢殏瀛樺簱鎵e噺鍚庤繑鍥炵殑鏆傚瓨璁板綍锛堟惡甯� item/batch/vendor 缁村害锛�
+ * @param qualifiedWarehouseId 鐩爣鍚堟牸搴撲粨搴撶紪鍙�
+ * @param qualifiedLocationId 鐩爣鍚堟牸搴撳簱鍖虹紪鍙凤紙鏈厤缃垯涓� null锛�
+ * @param qualifiedAreaId 鐩爣鍚堟牸搴撳簱浣嶇紪鍙凤紙鏈厤缃垯涓� null锛�
+ */
+ private MesWmMaterialStockBagDO getOrCreateStockBag(MesProBagCodeDO bag, MesWmMaterialStockDO tempStock) {
+ MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectByBagCode(bag.getCode());
+ if (stockBag != null) {
+ return stockBag;
+ }
+ stockBag = MesWmMaterialStockBagDO.builder().materialStockId(tempStock.getId())
+ .bagCodeId(bag.getId()).bagCode(bag.getCode()).itemId(tempStock.getItemId())
+ .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId())
+ .warehouseId(tempStock.getWarehouseId()).locationId(tempStock.getLocationId()).areaId(tempStock.getAreaId())
+ .stockState(MesWmStockStateEnum.TEMP.getState()).status(1).quantity(BigDecimal.ONE)
+ .frozen(false).inboundTime(tempStock.getReceiptTime()).build();
+ materialStockBagMapper.insert(stockBag);
+ return stockBag;
+ }
+
+ private MesWmMaterialStockDO getOrCreateQualifiedStock(MesWmMaterialStockDO tempStock, Long qualifiedWarehouseId,
+ Long qualifiedLocationId, Long qualifiedAreaId) {
+ MesWmMaterialStockDO qualified = materialStockMapper.selectQualifiedByCompositeKey(
+ tempStock.getItemId(), qualifiedWarehouseId, qualifiedLocationId,
+ qualifiedAreaId, tempStock.getBatchId(), tempStock.getVendorId());
+ if (qualified != null) {
+ return qualified;
+ }
+ // 涓嶅瓨鍦ㄥ垯鏂板缓鍚堟牸搴撹褰曪紙浠撳簱/搴撳尯/搴撲綅閲囩敤鎵�閫夊悎鏍煎簱鐨勭淮搴︼紝鏁伴噺鐢辫川妫�鍏ュ簱浜嬪姟 +1锛�
+ MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder()
+ .itemId(tempStock.getItemId()).itemTypeId(tempStock.getItemTypeId())
+ .warehouseId(qualifiedWarehouseId).locationId(qualifiedLocationId).areaId(qualifiedAreaId)
+ .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId())
+ .quantity(BigDecimal.ZERO).receiptTime(LocalDateTime.now())
+ .stockState(MesWmStockStateEnum.QUALIFIED.getState())
+ .frozen(false)
+ .build();
+ materialStockMapper.insert(newStock);
+ return newStock;
+ }
+
+ /**
+ * 鐢辫鐮佹垨鐢熶骇鎵规瑙f瀽鎵�灞炵敓浜ф壒娆★紙琚嬬爜浼樺厛锛屾壒娆$爜鍏煎涓存椂鐮侊級
+ */
+ private MesProBatchDO resolveBatch(String code, String batchCode) {
+ if (StrUtil.isNotBlank(code)) {
+ MesProBagCodeDO bag = bagCodeMapper.selectByCode(code);
+ if (bag != null && bag.getBatchId() != null) {
+ MesProBatchDO batch = proBatchService.getBatch(bag.getBatchId());
+ if (batch != null) {
+ return batch;
}
}
}
- // 搴撲綅鐢卞悗鍙伴厤缃湇鍔℃帴绠★紝褰撳墠鐗堟湰淇濈暀瀹¤闂幆锛岀姝㈠墠绔紶鍏ュ簱浣嶃��
- return quality.getId();
+ if (StrUtil.isNotBlank(batchCode)) {
+ return proBatchService.getBatchByCode(batchCode);
+ }
+ return null;
}
@Override
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
index 110c7b1..b19e03a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
@@ -2,6 +2,7 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
@@ -29,6 +30,9 @@
import cn.iocoder.yudao.module.mes.service.trace.crossregion.MesTraceCrossRegionService;
import cn.iocoder.yudao.module.mes.service.trace.integrity.MesTraceIntegrityService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
+import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
+import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
@@ -38,8 +42,12 @@
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -75,6 +83,8 @@
@Resource
private MesMdmItemService mdmItemService;
@Resource
+ private MdmUnitMeasureApi unitMeasureApi;
+ @Resource
private AdminUserApi adminUserApi;
@Resource
private MesWmBatchService mesWmBatchService;
@@ -97,13 +107,13 @@
}
TraceEntry entry = null;
try {
- // 1. 瑙f瀽杩芥函鍏ュ彛锛屽畾浣嶆壒娆�
+ // 1. 瑙f瀽杩芥函鍏ュ彛锛屽畾浣嶆壒娆★紙琚嬬爜/鎵樼洏宸茬敓鎴愪絾鏈綍鍏ユ壒娆℃椂锛岄檷绾т负浠呰繑鍥炲搧绉嶄俊鎭級
entry = resolveEntry(traceCode);
- if (entry.batchId == null) {
+ if (entry.batchId == null && entry.bagItemId == null) {
throw exception(MES_TRACE_CODE_NOT_FOUND);
}
// 2. 鑱氬悎鍏ㄧ▼淇℃伅
- MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId);
+ MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId, entry.bagItemId);
recordConsumerScan(rawCode, traceCode, entry.sourceType, entry.batchId, true);
return result;
} catch (RuntimeException ex) {
@@ -163,33 +173,44 @@
// 鈶� 琚嬬爜
MesProBagCodeDO bag = bagCodeService.getBagCodeByCode(traceCode);
if (bag != null) {
- return new TraceEntry("BAG", bag.getBatchId());
+ return new TraceEntry("BAG", bag.getBatchId(), bag.getItemId());
}
// 鈶� 鎵樼洏鐮�
MesProPalletDO pallet = palletService.getPalletByCode(traceCode);
if (pallet != null) {
- return new TraceEntry("PALLET", pallet.getBatchId());
+ // 鏈綍鍏ユ壒娆$殑鎵樼洏鍙栨墭鐩樺唴浠讳竴琚嬬爜鍝佺锛屼繚璇佷粛鑳藉睍绀哄搧绉嶄俊鎭�
+ Long itemId = pallet.getBatchId() == null
+ ? firstItemId(bagCodeService.getBagCodeListByPalletId(pallet.getId())) : null;
+ return new TraceEntry("PALLET", pallet.getBatchId(), itemId);
}
// 鈶� 鎵规鐮侊紙鍚复鏃舵壒娆$爜锛実etBatchByCode 鍐呴儴鍏煎锛�
MesProBatchDO batch = batchService.getBatchByCode(traceCode);
if (batch != null) {
- return new TraceEntry("BATCH", batch.getId());
+ return new TraceEntry("BATCH", batch.getId(), null);
}
- return new TraceEntry("", null);
+ return new TraceEntry("", null, null);
}
// ==================== 鑱氬悎鏋勫缓 ====================
- private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId) {
- MesProBatchDO batch = batchService.getBatch(batchId);
- if (batch == null) {
+ private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId, Long bagItemId) {
+ MesProBatchDO batch = batchId == null ? null : batchService.getBatch(batchId);
+ if (batchId != null && batch == null) {
throw exception(MES_TRACE_CODE_NOT_FOUND);
}
MesProTracePublicRespVO resp = new MesProTracePublicRespVO();
resp.setSourceType(sourceType);
resp.setRequestCode(requestCode);
// 鍝佺鍖哄潡
- fillItem(resp, batch);
+ fillItem(resp, batch, bagItemId);
+ if (batch == null) {
+ // 琚嬬爜/鎵樼洏宸茬敓鎴愪絾灏氭湭褰曞叆鐢熶骇鎵规锛氬彧杩斿洖鍝佺淇℃伅锛岀敱鍓嶇鎻愮ず鏈粦瀹氭壒娆�
+ resp.setBatchBound(false);
+ fillAntiFake(resp, traceCode);
+ fillTimelineAndDecision(resp);
+ return resp;
+ }
+ resp.setBatchBound(true);
// 鎵规鍖哄潡
resp.setBatchCode(batch.getCode()).setTempCode(batch.getTempCode())
.setBatchStatus(batch.getStatus()).setBatchStatusName(batchStatusName(batch.getStatus()))
@@ -212,18 +233,49 @@
fillAntiFake(resp, traceCode);
// 鍙�夋墿灞曞尯鍧楋紙鏈夋暟鎹墠杩斿洖锛�
fillOptionalModules(resp, batch);
+ fillTimelineAndDecision(resp);
return resp;
}
- private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch) {
- if (batch.getItemId() == null) {
+ /**
+ * 鍝佺宸蹭笅娌夊埌琚嬬爜鏁版嵁鍖咃細浼樺厛鍙栨壂鐮佽鐮佸搧绉嶏紝鍘嗗彶鎵规鍥為��鎵规鍝佺锛屾壒娆�/鎵樼洏鍏ュ彛鍙栨壒鍐呬换涓�琚嬬爜鍝佺
+ */
+ private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch, Long bagItemId) {
+ Long itemId = bagItemId != null ? bagItemId : (batch == null ? null : batch.getItemId());
+ if (itemId == null && batch != null) {
+ itemId = firstItemId(bagCodeService.getBagCodeListByBatchId(batch.getId()));
+ }
+ if (itemId == null) {
return;
}
- MesMdmItemDO item = mdmItemService.getItem(batch.getItemId());
+ MesMdmItemDO item = mdmItemService.getItem(itemId);
if (item == null) {
return;
}
- resp.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification());
+ resp.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification())
+ .setItemUnitMeasureName(unitMeasureName(item.getUnitMeasureId()));
+ }
+
+ /**
+ * 璇诲彇琚嬬爜鍒楄〃涓涓�涓潪绌哄搧绉嶇紪鍙�
+ */
+ private Long firstItemId(List<MesProBagCodeDO> bags) {
+ return CollUtil.isEmpty(bags) ? null : bags.stream().map(MesProBagCodeDO::getItemId)
+ .filter(Objects::nonNull).findFirst().orElse(null);
+ }
+
+ /**
+ * 璇诲彇鍝佺涓昏閲忓崟浣嶅悕绉帮紝鏈厤缃崟浣嶆垨鍗曚綅涓嶅瓨鍦ㄦ椂杩斿洖 null
+ */
+ private String unitMeasureName(Long unitMeasureId) {
+ if (unitMeasureId == null) {
+ return null;
+ }
+ CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasure(unitMeasureId);
+ if (result == null || !result.isSuccess() || result.getData() == null) {
+ return null;
+ }
+ return StrUtil.trimToNull(result.getData().getName());
}
private List<MesProTracePublicRespVO.WorkerVO> buildWorkers(Long batchId) {
@@ -329,13 +381,57 @@
resp.setPurchaseSources(CollUtil.isNotEmpty(purchaseSources) ? purchaseSources : List.of());
resp.setSalesTargets(CollUtil.isNotEmpty(salesTargets) ? salesTargets : List.of());
resp.setProcessTraces(CollUtil.isNotEmpty(processTraces) ? processTraces : List.of());
+ List<MesWmBatchFlowRespVO> seedFlows = mesWmBatchService.getBatchFlowList(batch.getCode());
+ resp.setSeedFlows(CollUtil.isNotEmpty(seedFlows) ? seedFlows : List.of());
} catch (Exception ex) {
// 浠撳簱鎵规浣撶郴锛堥噰璐�/閿�鍞�/娴佽浆锛夋湭鍚敤鏃跺閿欙紝涓嶅奖鍝嶆牳蹇冭拷婧�
log.warn("[fillOptionalModules][鎵规 {} 鎵╁睍妯″潡鏌ヨ澶辫触: {}]", batch.getCode(), ex.getMessage());
resp.setPurchaseSources(List.of());
resp.setSalesTargets(List.of());
resp.setProcessTraces(List.of());
+ resp.setSeedFlows(List.of());
}
+ }
+
+ private void fillTimelineAndDecision(MesProTracePublicRespVO resp) {
+ List<MesProTracePublicRespVO.TimelineVO> timeline = new ArrayList<>();
+ if (resp.getProduceDate() != null) {
+ timeline.add(timeline("鐢熶骇", "BATCH_CREATED", "鐢熶骇鎵规寤虹珛", resp.getProduceDate(), null,
+ resp.getBatchStatusName()));
+ }
+ if (resp.getProcessTraces() != null) {
+ resp.getProcessTraces().forEach(item -> timeline.add(timeline("鍔犲伐", item.getEventType(),
+ item.getEventType() == null ? "宸ュ簭娴佽浆" : ("IN".equals(item.getEventType()) ? "宸ュ簭鎶曞叆" : "宸ュ簭浜у嚭"),
+ item.getEventTime(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus()))));
+ }
+ if (resp.getInbound() != null) {
+ timeline.add(timeline("浠撳偍", "INBOUND", "浠撳偍鍏ュ簱", resp.getInbound().getEventTime(),
+ resp.getInbound().getQuantity(), resp.getInbound().getStatus()));
+ }
+ if (resp.getSalesTargets() != null) {
+ resp.getSalesTargets().forEach(item -> timeline.add(timeline("閿�鍞�", "OUTBOUND", "閿�鍞嚭搴�",
+ item.getSalesDate(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus()))));
+ }
+ timeline.sort(Comparator.comparing(MesProTracePublicRespVO.TimelineVO::getEventTime,
+ Comparator.nullsLast(Comparator.naturalOrder())));
+ resp.setTimeline(timeline);
+
+ MesProTracePublicRespVO.DecisionVO decision = new MesProTracePublicRespVO.DecisionVO();
+ decision.setQualityRisk(resp.getQuality() != null && Integer.valueOf(2).equals(resp.getQuality().getResult()));
+ decision.setInboundQuantity(resp.getInbound() == null ? null : resp.getInbound().getQuantity());
+ decision.setSalesTargetCount(resp.getSalesTargets() == null ? 0 : resp.getSalesTargets().size());
+ decision.setConsumerScanCount(resp.getAntiFake() == null ? 0L : resp.getAntiFake().getScanCount());
+ decision.setRiskLevel(Boolean.TRUE.equals(decision.getQualityRisk()) ? "HIGH" : "NORMAL");
+ resp.setDecision(decision);
+ }
+
+ private MesProTracePublicRespVO.TimelineVO timeline(String stage, String eventType, String eventName,
+ java.time.LocalDateTime eventTime, BigDecimal quantity,
+ String status) {
+ MesProTracePublicRespVO.TimelineVO vo = new MesProTracePublicRespVO.TimelineVO();
+ vo.setStage(stage).setEventType(eventType).setEventName(eventName).setEventTime(eventTime)
+ .setQuantity(quantity).setStatus(status);
+ return vo;
}
// ==================== 鍚嶇О鏄犲皠 ====================
@@ -409,7 +505,7 @@
};
}
- private record TraceEntry(String sourceType, Long batchId) {
+ private record TraceEntry(String sourceType, Long batchId, Long bagItemId) {
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
index ebc00b9..464d525 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.mes.service.wm.batch;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
@@ -125,6 +126,14 @@
List<MesWmBatchProcessTraceRespVO> getProcessTraceList(String code);
/**
+ * 鑾峰緱鎵规鍑哄叆搴撴祦姘达紙绉嶅瓙娴佸悜锛氬叆搴� + 閿�鍞嚭搴撶瓑鍏ㄩ儴搴撳瓨浜嬪姟锛�
+ *
+ * @param code 鎵规鍙�
+ * @return 鍑哄叆搴撴祦姘村垪琛�
+ */
+ List<MesWmBatchFlowRespVO> getBatchFlowList(String code);
+
+ /**
* 鏍规嵁 SN 鐮佽幏寰楁壒娆�
*
* @param sn SN 鐮�
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
index 313063f..39a8381 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
@@ -4,6 +4,7 @@
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
@@ -409,6 +410,11 @@
}
@Override
+ public List<MesWmBatchFlowRespVO> getBatchFlowList(String code) {
+ return batchMapper.selectBatchFlowList(code);
+ }
+
+ @Override
public MesWmBatchDO getBatchBySn(String sn) {
MesWmSnDO snDO = snMapper.selectOne(MesWmSnDO::getCode, sn);
if (snDO == null || StrUtil.isBlank(snDO.getBatchCode())) {
@@ -423,13 +429,21 @@
if (proBatch == null || StrUtil.isBlank(proBatch.getCode())) {
return null;
}
- // 1. 澶嶇敤宸叉湁浠撳簱鎵规锛堝悓涓�鐢熶骇鎵规鍙凤級
- MesWmBatchDO existing = batchMapper.selectByCode(proBatch.getCode());
+ // 1. 浼樺厛鎸夌敓浜ф壒娆� ID 澶嶇敤锛屽吋瀹瑰巻鍙叉暟鎹啀鎸夋壒娆″彿鍖归厤
+ MesWmBatchDO existing = batchMapper.selectOne(MesWmBatchDO::getProBatchId, proBatch.getId());
+ if (existing == null) {
+ existing = batchMapper.selectByCode(proBatch.getCode());
+ }
if (existing != null) {
+ if (existing.getProBatchId() == null && proBatch.getId() != null) {
+ existing.setProBatchId(proBatch.getId());
+ batchMapper.updateById(existing);
+ }
return existing;
}
// 2. 鏂板缓浠撳簱鎵规锛氫互鐢熶骇鎵规鍙蜂綔涓轰粨搴撴壒娆″彿锛岃川閲忕姸鎬佺疆涓哄緟妫�楠�
MesWmBatchDO batch = MesWmBatchDO.builder()
+ .proBatchId(proBatch.getId())
.code(proBatch.getCode())
.itemId(proBatch.getItemId())
.produceDate(proBatch.getProduceDate())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
index 2e6a51f..8d9a29d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
@@ -132,6 +132,18 @@
List<MesWmMaterialStockDO> getMaterialStockListByItemAndBatch(Long itemId, Long batchId);
/**
+ * 鏌ヨ鐗╂枡/鎵规鐨勫悎鏍煎簱搴撳瓨璁板綍锛堜粎 stock_state=20锛�
+ *
+ * <p>鍚屾壒娆″彲鑳藉悓鏃跺瓨鍦ㄦ殏瀛樺簱涓庡悎鏍煎簱涓ゆ潯璁板綍锛堢瀛愯川妫�鎸夎鎷嗘暟閲忥級锛�
+ * 閿�鍞嚭搴撻�夊簱瀛樺繀椤讳粠鍚堟牸搴撹褰曚腑閫夛紝閬垮厤閫変腑鏈川妫�鐨勬殏瀛樺簱瀛樸��</p>
+ *
+ * @param itemId 鐗╂枡缂栧彿
+ * @param batchId 鎵规缂栧彿
+ * @return 鍚堟牸搴撳簱瀛樿褰曞垪琛�
+ */
+ List<MesWmMaterialStockDO> getQualifiedMaterialStockListByItemAndBatch(Long itemId, Long batchId);
+
+ /**
* 鏇存柊搴撳瓨鏁伴噺
*
* @param id 搴撳瓨璁板綍缂栧彿
@@ -165,16 +177,6 @@
* @return 浠撳簱姹囨�诲垪琛�
*/
List<MesWmStockSummaryRespVO> getStockSummaryByWarehouse(MesWmMaterialStockListReqVO reqVO);
-
- /**
- * 鎸変粨搴撴壒娆℃洿鏂板簱瀛樼姸鎬侊紙鐢ㄤ簬绉嶅瓙璐ㄦ鍚堟牸鍚庯紝灏嗘殏瀛樺簱鏁存壒杞负鍚堟牸搴擄級
- *
- * @param batchId 浠撳簱鎵规ID
- * @param toState 鐩爣搴撳瓨鐘舵��
- * @param fromState 鍘熷簱瀛樼姸鎬侊紙闄愬畾鍙洿鏂拌鐘舵�佺殑璁板綍锛�
- * @return 褰卞搷琛屾暟
- */
- int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState);
/**
* 搴撲綅娣锋斁瑙勫垯鏍¢獙
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
index 4318153..b3b7ec6 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
@@ -29,6 +29,9 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
import jakarta.annotation.Resource;
@@ -44,6 +47,7 @@
import java.util.function.Function;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -74,6 +78,11 @@
@Resource
@Lazy
private MesWmBatchService batchService;
+
+ @Resource
+ private MesWmMaterialStockBagMapper materialStockBagMapper;
+ @Resource
+ private MesWmMaterialStockBagService materialStockBagService;
@Override
public MesWmMaterialStockDO getMaterialStock(Long id) {
@@ -121,9 +130,27 @@
Assert.notNull(virtualWarehouse, "铏氭嫙浠撳簱锛圵IP_VIRTUAL_WAREHOUSE锛変笉瀛樺湪");
virtualWarehouseId = virtualWarehouse.getId();
}
+ // 1.4 瑙f瀽 warehouseType锛氳浆鎹负璇ョ被鍨嬩粨搴� warehouseIds锛堜笌 warehouseId / virtualFilter 骞跺瓨锛屼繚鐣欏吋瀹癸級
+ List<Long> warehouseIds = resolveWarehouseIdsByType(pageReqVO.getWarehouseType());
+ if (warehouseIds != null && warehouseIds.isEmpty()) {
+ return PageResult.empty();
+ }
// 2. 鍒嗛〉鏌ヨ
- return materialStockMapper.selectPage(pageReqVO, itemTypeIds, itemIds, virtualWarehouseId);
+ return materialStockMapper.selectPage(pageReqVO, itemTypeIds, itemIds, virtualWarehouseId, warehouseIds);
+ }
+
+ /**
+ * 灏嗕粨搴撶被鍨嬭В鏋愪负浠撳簱 id 闆嗗悎锛坵arehouseType 涓� null 鏃朵笉鍔犺繃婊わ紝杩斿洖 null锛�
+ *
+ * @param warehouseType 浠撳簱绫诲瀷锛岃 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum}
+ * @return 璇ョ被鍨嬩粨搴� id 闆嗗悎锛泈arehouseType 涓� null 杩斿洖 null锛涜绫诲瀷鏃犱粨搴撹繑鍥炵┖闆嗗悎
+ */
+ private List<Long> resolveWarehouseIdsByType(Integer warehouseType) {
+ if (warehouseType == null) {
+ return null;
+ }
+ return convertList(warehouseService.getWarehouseListByType(warehouseType), MesWmWarehouseDO::getId);
}
@Override
@@ -169,7 +196,11 @@
@Override
public List<MesWmMaterialStockDO> getMaterialStockList(MesWmMaterialStockListReqVO reqVO) {
- return materialStockMapper.selectList(reqVO);
+ List<Long> warehouseIds = resolveWarehouseIdsByType(reqVO.getWarehouseType());
+ if (warehouseIds != null && warehouseIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return materialStockMapper.selectList(reqVO, warehouseIds);
}
@Override
@@ -282,7 +313,17 @@
@Override
public MesWmMaterialStockDO getMaterialStockByCompositeKey(Long itemId, Long warehouseId, Long locationId, Long areaId,
Long batchId, Long vendorId) {
- return materialStockMapper.selectByCompositeKey(itemId, warehouseId, locationId, areaId, batchId, vendorId);
+ // 鍑哄簱/鍗犵敤鍙粠鍚堟牸搴撳尮閰嶏紝閬垮厤鎵e埌鍚屾壒娆$殑鏆傚瓨搴擄紙绉嶅瓙璐ㄦ鎸夎鎷嗘暟閲忓悗鍚屾壒娆″弻鐘舵�佸苟瀛橈級
+ return materialStockMapper.selectQualifiedByCompositeKey(itemId, warehouseId, locationId, areaId, batchId, vendorId);
+ }
+
+ @Override
+ public List<MesWmMaterialStockDO> getQualifiedMaterialStockListByItemAndBatch(Long itemId, Long batchId) {
+ List<Long> qualifiedWarehouseIds = warehouseService.getQualifiedWarehouseIds();
+ if (CollUtil.isEmpty(qualifiedWarehouseIds)) {
+ return Collections.emptyList();
+ }
+ return materialStockMapper.selectQualifiedListByItemAndBatch(itemId, batchId, qualifiedWarehouseIds);
}
@Override
@@ -302,11 +343,6 @@
@Override
public void updateMaterialStockState(Long id, Integer stockState) {
materialStockMapper.updateById(new MesWmMaterialStockDO().setId(id).setStockState(stockState));
- }
-
- @Override
- public int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState) {
- return materialStockMapper.updateStockStateByBatchId(batchId, toState, fromState);
}
@Override
@@ -356,7 +392,11 @@
|| ObjUtil.notEqual(stock.getAreaId(), areaId)) {
throw exception(WM_MATERIAL_STOCK_SELECTION_MISMATCH);
}
- // 3. 鏍¢獙搴撳瓨鏁伴噺鍏呰冻锛堝鏋滃墠绔紶浜� quantity锛屽垯蹇呴』淇濊瘉搴撳瓨鏁伴噺 >= quantity锛�
+ // 3. 鏍¢獙搴撳瓨璁板綍蹇呴』鏄悎鏍煎簱锛堟殏瀛樺簱瀛樻湭璐ㄦ锛屼笉鍙敤浜庡嚭搴�/鍗犵敤锛�
+ if (!MesWmStockStateEnum.QUALIFIED.getState().equals(stock.getStockState())) {
+ throw exception(WM_MATERIAL_STOCK_NOT_QUALIFIED);
+ }
+ // 4. 鏍¢獙搴撳瓨鏁伴噺鍏呰冻锛堝鏋滃墠绔紶浜� quantity锛屽垯蹇呴』淇濊瘉搴撳瓨鏁伴噺 >= quantity锛�
if (quantity != null && stock.getQuantity() != null && stock.getQuantity().compareTo(quantity) < 0) {
throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
}
@@ -592,6 +632,32 @@
.setRelatedTransactionId(outTransactionId)
.setCheckFlag(false);
wmTransactionService.createTransaction(inTransaction);
+
+ // 9. 鏁翠綅缃Щ搴撴椂锛岄�愯杩佺Щ琚嬬爜鏄庣粏浣嶇疆锛堟暟閲忕瓑浜庢簮搴撲綅娲诲姩琚嬫暟涓斾负鏁存暟鎵嶈涓烘暣浣嶇Щ搴擄級
+ MesWmMaterialStockDO finalTargetStock = materialStockMapper.selectByCompositeKeyIgnoreVendor(
+ sourceStock.getItemId(), reqVO.getToWarehouseId(), reqVO.getToLocationId(),
+ reqVO.getToAreaId(), sourceStock.getBatchId());
+ relocateBagsForMove(sourceStock, reqVO.getQuantity(), inTransaction, finalTargetStock);
+ }
+
+ /**
+ * 鏁翠綅绉诲簱锛氬皢婧愬簱浣嶇殑娲诲姩琚嬬爜鏄庣粏杩佺Щ鍒扮洰鏍囧簱浣嶃��
+ * <p>
+ * 浠呭綋绉诲簱鏁伴噺绛変簬婧愬簱浣嶆椿鍔ㄨ鏁颁笖涓烘暣鏁版椂鎵ц锛堟暣浣嶇疆鎼Щ锛夛紝灏嗘瘡琚嬫槑缁嗙殑搴撳瓨姹囨�汇�佷粨搴撱�佸簱鍖恒�佸簱浣�
+ * 鏇存柊涓虹洰鏍囦綅缃紱閮ㄥ垎绉诲簱/鏃犺鐮佹槑缁嗙殑鏃у簱瀛樹笉鍋氳鐮佽縼绉伙紝淇濇寔姹囨�诲簱瀛樺彉鍔ㄥ嵆鍙��
+ */
+ private void relocateBagsForMove(MesWmMaterialStockDO sourceStock, BigDecimal quantity,
+ MesWmTransactionSaveReqDTO moveInReq, MesWmMaterialStockDO targetStock) {
+ List<MesWmMaterialStockBagDO> bags = materialStockBagMapper.selectActiveListByItemAndBatch(
+ sourceStock.getItemId(), sourceStock.getBatchId(), sourceStock.getStockState());
+ if (CollUtil.isEmpty(bags) || targetStock == null || quantity == null
+ || quantity.compareTo(BigDecimal.valueOf(bags.size())) != 0) {
+ return;
+ }
+ for (MesWmMaterialStockBagDO bag : bags) {
+ moveInReq.setBagCodeId(bag.getBagCodeId()).setBagCode(bag.getBagCode());
+ materialStockBagService.moveIn(moveInReq, targetStock, null);
+ }
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java
new file mode 100644
index 0000000..ce3eb1d
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java
@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.mes.service.wm.materialstockbag;
+
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+
+/**
+ * MES 搴撳瓨琚嬬爜鏄庣粏 Service 鎺ュ彛
+ *
+ * 缁熶竴灏佽琚嬬爜搴撳瓨鏄庣粏鐨勫缓绔嬨�佽縼绉汇�佸嚭搴撱�佹姤搴熼�昏緫锛屼緵鎵�鏈夊甫琚嬬爜鐨勫簱瀛樺彉鍔ㄥ叆鍙e鐢ㄣ��
+ * 姣忎釜琚嬬爜鍦ㄥ悓涓�鏃堕棿鍙湁涓�鏉″湪搴撴槑缁嗭紙鍞竴绾︽潫 bag_code锛夛紝娴佽浆閫氳繃鏇存柊鏄庣粏浣嶇疆/鐘舵�佸疄鐜般��
+ */
+public interface MesWmMaterialStockBagService {
+
+ /**
+ * 鍏ュ簱锛氬缓绔嬫垨婵�娲绘椿鍔ㄨ鐮佹槑缁嗐��
+ * <p>
+ * 琚嬬爜棣栨鍏ュ簱鏃舵柊寤烘槑缁嗭紱宸插嚭搴�/宸叉姤搴熺殑琚嬬爜鍐嶆鍏ュ簱鏃舵縺娲讳负鍦ㄥ簱骞舵洿鏂颁綅缃紱宸插湪搴撳垯瑙嗕负閲嶅鍏ュ簱鎶涘嚭寮傚父銆�
+ *
+ * @param reqDTO 浜嬪姟璇锋眰
+ * @param stock 鐩爣搴撳瓨姹囨�昏褰�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ * @return 琚嬬爜鏄庣粏
+ */
+ MesWmMaterialStockBagDO inbound(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO stock, Long transactionId);
+
+ /**
+ * 鍑哄簱锛氬皢鎸囧畾琚嬬爜鏄庣粏缃负宸插嚭搴撱��
+ *
+ * @param reqDTO 浜嬪姟璇锋眰锛堥渶鎼哄甫 bagCode/bagCodeId锛�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ */
+ void outbound(MesWmTransactionSaveReqDTO reqDTO, Long transactionId);
+
+ /**
+ * 绉诲叆/杩佺Щ锛氭洿鏂版椿鍔ㄨ鐮佹槑缁嗙殑浣嶇疆涓庡簱瀛樼姸鎬侊紙绉诲簱銆佽皟鎷ㄣ�佽川妫�鍚堟牸杩佺Щ锛夈��
+ *
+ * @param reqDTO 浜嬪姟璇锋眰锛堥渶鎼哄甫 bagCode锛�
+ * @param targetStock 鐩爣搴撳瓨姹囨�昏褰�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ */
+ void moveIn(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO targetStock, Long transactionId);
+
+ /**
+ * 鎶ュ簾锛氬皢鎸囧畾琚嬬爜鏄庣粏缃负鎶ュ簾銆�
+ *
+ * @param reqDTO 浜嬪姟璇锋眰锛堥渶鎼哄甫 bagCode锛�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ */
+ void scrap(MesWmTransactionSaveReqDTO reqDTO, Long transactionId);
+
+ /**
+ * 鏍规嵁搴撳瓨姹囨�� ID 鏌ヨ鍦ㄥ簱琚嬬爜鏄庣粏銆�
+ *
+ * @param materialStockId 搴撳瓨姹囨�� ID
+ * @return 琚嬬爜鏄庣粏锛堟棤鍒� null锛�
+ */
+ MesWmMaterialStockBagDO getActiveByMaterialStockId(Long materialStockId);
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java
new file mode 100644
index 0000000..3929602
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java
@@ -0,0 +1,165 @@
+package cn.iocoder.yudao.module.mes.service.wm.materialstockbag;
+
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmMaterialStockBagStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
+
+/**
+ * MES 搴撳瓨琚嬬爜鏄庣粏 Service 瀹炵幇绫�
+ *
+ * 琚嬬爜鏄庣粏鐢熷懡鍛ㄦ湡锛氶娆″叆搴撳缓绔嬶紙ACTIVE锛夆啋 绉诲簱/璐ㄦ杩佺Щ浣嶇疆鐘舵�� 鈫� 鍑哄簱/鎶ュ簾缁撴潫锛圤UT/SCRAPPED锛夈��
+ * 鍞竴绾︽潫 bag_code 淇濊瘉姣忎釜琚嬬爜浠呬竴鏉℃槑缁嗭紝澶嶇敤鍚屼竴琛屽畬鎴愬叏鐢熷懡鍛ㄦ湡娴佽浆銆�
+ */
+@Service
+@Validated
+public class MesWmMaterialStockBagServiceImpl implements MesWmMaterialStockBagService {
+
+ @Resource
+ private MesWmMaterialStockBagMapper materialStockBagMapper;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public MesWmMaterialStockBagDO inbound(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO stock, Long transactionId) {
+ String bagCode = reqDTO.getBagCode();
+ if (StrUtil.isBlank(bagCode)) {
+ throw exception(WM_MATERIAL_STOCK_BAG_REQUIRED);
+ }
+ // 1. 鏌ヨ璇ヨ鐮佹棦鏈夋槑缁嗭細浼樺厛鎸� bagCodeId锛屽叾娆℃寜 bagCode
+ MesWmMaterialStockBagDO existing = materialStockBagMapper.selectByBagCode(bagCode);
+ if (existing == null && reqDTO.getBagCodeId() != null) {
+ existing = materialStockBagMapper.selectByBagCodeId(reqDTO.getBagCodeId());
+ }
+ if (existing != null) {
+ // 2. 宸插湪搴� 鈫� 閲嶅鍏ュ簱锛岀姝�
+ if (MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus().equals(existing.getStatus())) {
+ throw exception(WM_MATERIAL_STOCK_BAG_DUPLICATE, bagCode);
+ }
+ // 3. 宸插嚭搴�/鎶ュ簾 鈫� 閲嶆柊婵�娲诲苟鏇存柊浣嶇疆
+ return reactivate(existing, reqDTO, stock, transactionId);
+ }
+ // 4. 棣栨鍏ュ簱 鈫� 鏂板缓鏄庣粏
+ MesWmMaterialStockBagDO bag = MesWmMaterialStockBagDO.builder()
+ .materialStockId(stock.getId())
+ .bagCodeId(reqDTO.getBagCodeId())
+ .bagCode(bagCode)
+ .itemId(stock.getItemId())
+ .batchId(stock.getBatchId())
+ .batchCode(stock.getBatchCode())
+ .vendorId(stock.getVendorId())
+ .warehouseId(stock.getWarehouseId())
+ .locationId(stock.getLocationId())
+ .areaId(stock.getAreaId())
+ .stockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), stock.getStockState()))
+ .status(MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus())
+ .quantity(BigDecimal.ONE)
+ .frozen(false)
+ .lastTransactionId(transactionId)
+ .inboundTime(LocalDateTime.now())
+ .build();
+ materialStockBagMapper.insert(bag);
+ return bag;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void outbound(MesWmTransactionSaveReqDTO reqDTO, Long transactionId) {
+ MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO);
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(bag.getId());
+ update.setStatus(MesWmMaterialStockBagStatusEnum.OUT.getStatus());
+ update.setStockState(MesWmStockStateEnum.OUT.getState());
+ update.setLastTransactionId(transactionId);
+ update.setOutboundTime(LocalDateTime.now());
+ materialStockBagMapper.updateById(update);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void moveIn(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO targetStock, Long transactionId) {
+ MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO);
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(bag.getId());
+ update.setMaterialStockId(targetStock.getId());
+ update.setWarehouseId(targetStock.getWarehouseId());
+ update.setLocationId(targetStock.getLocationId());
+ update.setAreaId(targetStock.getAreaId());
+ update.setStockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), targetStock.getStockState()));
+ update.setLastTransactionId(transactionId);
+ materialStockBagMapper.updateById(update);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void scrap(MesWmTransactionSaveReqDTO reqDTO, Long transactionId) {
+ MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO);
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(bag.getId());
+ update.setStatus(MesWmMaterialStockBagStatusEnum.SCRAPPED.getStatus());
+ update.setStockState(MesWmStockStateEnum.OUT.getState());
+ update.setQuantity(BigDecimal.ZERO);
+ update.setLastTransactionId(transactionId);
+ update.setOutboundTime(LocalDateTime.now());
+ materialStockBagMapper.updateById(update);
+ }
+
+ @Override
+ public MesWmMaterialStockBagDO getActiveByMaterialStockId(Long materialStockId) {
+ return materialStockBagMapper.selectOneActiveByMaterialStockId(materialStockId);
+ }
+
+ /**
+ * 鏌ヨ鎸囧畾琚嬬爜鐨勬椿鍔ㄦ槑缁嗭紝涓嶅瓨鍦ㄦ垨宸插嚭搴�/鎶ュ簾鍒欐姏寮傚父銆�
+ */
+ private MesWmMaterialStockBagDO requireActiveBag(MesWmTransactionSaveReqDTO reqDTO) {
+ MesWmMaterialStockBagDO bag = null;
+ if (reqDTO.getBagCodeId() != null) {
+ bag = materialStockBagMapper.selectActiveByBagCodeId(reqDTO.getBagCodeId());
+ }
+ if (bag == null && StrUtil.isNotBlank(reqDTO.getBagCode())) {
+ bag = materialStockBagMapper.selectActiveByBagCode(reqDTO.getBagCode());
+ }
+ if (bag == null) {
+ String code = StrUtil.blankToDefault(reqDTO.getBagCode(), String.valueOf(reqDTO.getBagCodeId()));
+ throw exception(WM_MATERIAL_STOCK_BAG_NOT_ACTIVE, code);
+ }
+ return bag;
+ }
+
+ private MesWmMaterialStockBagDO reactivate(MesWmMaterialStockBagDO existing, MesWmTransactionSaveReqDTO reqDTO,
+ MesWmMaterialStockDO stock, Long transactionId) {
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(existing.getId());
+ update.setMaterialStockId(stock.getId());
+ update.setItemId(stock.getItemId());
+ update.setBatchId(stock.getBatchId());
+ update.setBatchCode(stock.getBatchCode());
+ update.setVendorId(stock.getVendorId());
+ update.setWarehouseId(stock.getWarehouseId());
+ update.setLocationId(stock.getLocationId());
+ update.setAreaId(stock.getAreaId());
+ update.setStockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), stock.getStockState()));
+ update.setStatus(MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus());
+ update.setQuantity(BigDecimal.ONE);
+ update.setFrozen(false);
+ update.setLastTransactionId(transactionId);
+ update.setInboundTime(LocalDateTime.now());
+ update.setOutboundTime(null);
+ materialStockBagMapper.updateById(update);
+ return existing;
+ }
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java
index a54a1eb..628720f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java
@@ -27,6 +27,7 @@
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmSalesNoticeStatusEnum;
@@ -43,8 +44,6 @@
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService;
-import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi;
-import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
@@ -104,9 +103,6 @@
@Resource
private MesTraceIntegrityService integrityService;
-
- @Resource
- private ErpSaleOrderApi saleOrderApi;
@Override
public Long createProductSales(MesWmProductSalesSaveReqVO createReqVO) {
@@ -242,6 +238,15 @@
if (pallet != null && pallet.getBatchId() == null) {
throw exception(PRO_PALLET_NOT_BIND_BATCH);
}
+ // 绉嶅瓙璐ㄦ鎸夎鐮佺矑搴︽祦杞悗锛屽嚭搴撳彧鍏佽宸茶川妫�鍚堟牸鐨勮鐮�/鎵樼洏
+ if (pallet != null) {
+ List<MesProBagCodeDO> palletBags = bagCodeService.getBagCodeListByPalletId(pallet.getId());
+ if (palletBags.stream().anyMatch(b -> !MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(b.getQcStatus()))) {
+ throw exception(WM_PRODUCT_SALES_SCAN_PALLET_NOT_ALL_QUALIFIED);
+ }
+ } else if (!MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(bag.getQcStatus())) {
+ throw exception(WM_PRODUCT_SALES_SCAN_BAG_NOT_QUALIFIED);
+ }
Long codeId = pallet != null ? pallet.getId() : bag.getId();
MesWmProductSalesDetailDO existed = pallet != null
? productSalesDetailMapper.selectBySalesIdAndPalletCodeId(reqVO.getSalesId(), codeId)
@@ -270,7 +275,8 @@
if (quantity == null) {
quantity = line.getQuantity();
}
- List<MesWmMaterialStockDO> stocks = materialStockService.getMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId());
+ // 鍙粠鍚堟牸搴撹褰曚腑閫夊簱瀛橈紙鍚屾壒娆℃殏瀛樺簱璁板綍涓嶅彲鍑哄簱锛�
+ List<MesWmMaterialStockDO> stocks = materialStockService.getQualifiedMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId());
BigDecimal outboundQuantity = quantity;
MesWmMaterialStockDO stock = stocks.stream().filter(item -> item.getQuantity().compareTo(outboundQuantity) >= 0).findFirst().orElse(null);
if (stock == null) {
@@ -338,12 +344,6 @@
// 鎵ц鎷h揣锛堝緟鎷h揣 鈫� 寰呭~鍐欒繍鍗曪級
productSalesMapper.updateById(new MesWmProductSalesDO()
.setId(id).setStatus(MesWmProductSalesStatusEnum.SHIPPING.getStatus()));
-
- // 鍥炲啓 ERP 閿�鍞鍗曞嚭搴撶姸鎬佷负"閮ㄥ垎鍑哄簱"锛堣〃绀哄凡鎷h揣/鍗犵敤锛�
- if (sales.getSaleOrderId() != null) {
- saleOrderApi.updateOrderOutStatusTo(sales.getSaleOrderId(),
- ErpSaleOrderOutStatusEnum.PART_OUT.getStatus());
- }
}
@Override
@@ -392,10 +392,7 @@
updateSalesNoticeOutCount(sales);
}
- // 6. 鍥炲啓 ERP 閿�鍞鍗曠殑鍑哄簱鏁伴噺鍜岀姸鎬�
- updateErpSaleOrderOutCount(sales);
-
- // 7. 鍥炲啓琚嬬爜/鎵樼洏鍑哄簱鍘诲悜锛堜緵绐滆揣绋芥煡瀹氫綅缁忛攢鍟嗗湴鍖猴級锛屽苟鐢熸垚鍑哄簱瀹屾暣鎬ф憳瑕�
+ // 6. 鍥炲啓琚嬬爜/鎵樼洏鍑哄簱鍘诲悜锛堜緵绐滆揣绋芥煡瀹氫綅缁忛攢鍟嗗湴鍖猴級锛屽苟鐢熸垚鍑哄簱瀹屾暣鎬ф憳瑕�
List<MesWmProductSalesDetailDO> outDetails = productSalesDetailService.getProductSalesDetailListBySalesId(id);
for (MesWmProductSalesDetailDO detail : outDetails) {
if (detail.getBagCodeId() != null) {
@@ -425,43 +422,13 @@
}
}
- /**
- * 鍥炲啓 ERP 閿�鍞鍗曠殑鍑哄簱鏁伴噺鍜岀姸鎬�
- */
- private void updateErpSaleOrderOutCount(MesWmProductSalesDO sales) {
- // 鑾峰彇鍑哄簱鍗曡
- List<MesWmProductSalesLineDO> lines = productSalesLineService.getProductSalesLineListBySalesId(sales.getId());
- if (CollUtil.isEmpty(lines)) {
- return;
- }
- // 鐢ㄤ簬瀛樺偍閿�鍞鍗� ID锛岄伩鍏嶉噸澶嶆洿鏂�
- Long saleOrderId = null;
- // 閬嶅巻琛岋紝鎸� saleOrderItemId 鏇存柊鍑哄簱鏁伴噺
- for (MesWmProductSalesLineDO line : lines) {
- if (line.getSaleOrderItemId() != null && line.getQuantity() != null) {
- saleOrderApi.updateOrderItemOutCount(line.getSaleOrderItemId(), line.getQuantity());
- // 鑾峰彇閿�鍞鍗� ID锛堜粠绗竴涓湁鏁堢殑鏄庣粏椤硅幏鍙栵級
- if (saleOrderId == null) {
- cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO itemDTO =
- saleOrderApi.getSaleOrderItem(line.getSaleOrderItemId()).getCheckedData();
- if (itemDTO != null && itemDTO.getOrderId() != null) {
- saleOrderId = itemDTO.getOrderId();
- }
- }
- }
- }
- // 鏇存柊閿�鍞鍗曠殑鍑哄簱鐘舵��
- if (saleOrderId != null) {
- saleOrderApi.updateOrderOutStatus(saleOrderId);
- }
- }
-
private void createTransactionList(MesWmProductSalesDO sales) {
List<MesWmProductSalesDetailDO> details = productSalesDetailService.getProductSalesDetailListBySalesId(sales.getId());
wmTransactionService.createTransactionList(convertList(details, detail -> new MesWmTransactionSaveReqDTO()
.setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(detail.getItemId())
.setQuantity(detail.getQuantity().negate()) // 鍑哄簱鏁伴噺涓鸿礋鏁�
.setBatchId(detail.getBatchId()).setBatchCode(detail.getBatchCode())
+ .setBagCodeId(detail.getBagCodeId()) // 琚嬬爜鍨嬫槑缁嗗嚭搴撴椂缃鐮佸凡鍑哄簱锛涙墭鐩樺瀷鏄庣粏涓嶉�愯澶勭悊
.setWarehouseId(detail.getWarehouseId()).setLocationId(detail.getLocationId()).setAreaId(detail.getAreaId())
.setBizType(MesBizTypeConstants.WM_PRODUCT_SALES).setBizId(sales.getId())
.setBizCode(sales.getCode()).setBizLineId(detail.getLineId())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java
index 7f40f15..fed11df 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java
@@ -7,16 +7,19 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.salesnotice.vo.line.MesWmSalesNoticeLinePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.salesnotice.vo.line.MesWmSalesNoticeLineSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.salesnotice.MesWmSalesNoticeLineMapper;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -38,6 +41,8 @@
private MesWmSalesNoticeService salesNoticeService;
@Resource
private MesWmBatchService batchService;
+ @Resource
+ private MesWmMaterialStockService materialStockService;
@Resource
private MesMdmItemService mdmItemService;
@@ -118,12 +123,36 @@
}
private void validateLineSaveData(MesWmSalesNoticeLineSaveReqVO reqVO) {
- // 鏍¢獙鐖跺崟鎹瓨鍦ㄤ笖涓鸿崏绋跨姸鎬�
validateNoticeStatusDraft(reqVO.getNoticeId());
- // 鏍¢獙鐗╂枡瀛樺湪
- if (reqVO.getItemId() != null) {
- mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
+ mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
+
+ MesWmBatchDO batch = resolveBatch(reqVO);
+ if (batch == null) {
+ throw exception(WM_MATERIAL_STOCK_NOT_EXISTS);
}
+ if (ObjUtil.notEqual(batch.getItemId(), reqVO.getItemId())) {
+ throw exception(WM_MATERIAL_STOCK_NOT_EXISTS);
+ }
+ BigDecimal qualifiedQuantity = materialStockService
+ .getQualifiedMaterialStockListByItemAndBatch(reqVO.getItemId(), batch.getId()).stream()
+ .map(MesWmMaterialStockDO::getQuantity)
+ .filter(quantity -> quantity != null)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ if (qualifiedQuantity.compareTo(reqVO.getQuantity()) < 0) {
+ throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
+ }
+ reqVO.setBatchId(batch.getId());
+ reqVO.setBatchCode(batch.getCode());
+ }
+
+ private MesWmBatchDO resolveBatch(MesWmSalesNoticeLineSaveReqVO reqVO) {
+ if (reqVO.getBatchId() != null) {
+ return batchService.getBatch(reqVO.getBatchId());
+ }
+ if (StrUtil.isNotBlank(reqVO.getBatchCode())) {
+ return batchService.getBatchByCode(reqVO.getBatchCode());
+ }
+ return null;
}
/**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java
index be5338c..18e1cd2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java
@@ -89,14 +89,6 @@
}
/**
- * 浠庨攢鍞鍗曠敓鎴愬彂璐ч�氱煡鍗�
- *
- * @param saleOrderId 閿�鍞鍗旾D
- * @return 鍙戣揣閫氱煡鍗旾D
- */
- Long generateSalesNoticeFromSaleOrder(Long saleOrderId);
-
- /**
* 瀹屾垚鍙戣揣閫氱煡鍗曪紙鍑哄簱瀹屾垚鍚庤皟鐢級
* 绱姞鍑哄簱鏁伴噺骞惰绠楀嚭搴撶姸鎬�
*
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java
index a233210..115bebf 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java
@@ -18,10 +18,6 @@
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
-import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi;
-import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO;
-import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderRespDTO;
-import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -53,8 +49,6 @@
@Resource
private CrmCustomerApi customerApi;
- @Resource
- private ErpSaleOrderApi saleOrderApi;
@Resource
private MesMdAutoCodeRecordService autoCodeRecordService;
@@ -125,7 +119,7 @@
@Transactional(rollbackFor = Exception.class)
public void submitSalesNotice(Long id) {
// 1.1 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
- MesWmSalesNoticeDO notice = validateSalesNoticeExistsAndDraft(id);
+ validateSalesNoticeExistsAndDraft(id);
// 1.2 妫�鏌ユ槸鍚︽湁琛岄」鐩�
List<MesWmSalesNoticeLineDO> lines = salesNoticeLineService.getSalesNoticeLineListByNoticeId(id);
if (CollUtil.isEmpty(lines)) {
@@ -135,12 +129,6 @@
// 2. 鏇存柊鐘舵�侊細鑽夌 鈫� 寰呭嚭搴�
salesNoticeMapper.updateById(new MesWmSalesNoticeDO()
.setId(id).setStatus(APPROVED.getStatus()));
-
- // 3. 鍥炲啓 ERP 閿�鍞鍗曞嚭搴撶姸鎬佷负"宸查鐣�"
- if (notice.getSaleOrderId() != null) {
- saleOrderApi.updateOrderOutStatusTo(notice.getSaleOrderId(),
- ErpSaleOrderOutStatusEnum.RESERVED.getStatus());
- }
}
@Override
@@ -188,54 +176,6 @@
if (ObjUtil.notEqual(id, notice.getId())) {
throw exception(WM_SALES_NOTICE_CODE_DUPLICATE);
}
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Long generateSalesNoticeFromSaleOrder(Long saleOrderId) {
- // 1. 鏍¢獙鏄惁宸茬敓鎴愯繃鍙戣揣閫氱煡鍗曪紙闃叉閲嶅鐢熸垚锛�
- MesWmSalesNoticeDO existNotice = salesNoticeMapper.selectBySaleOrderId(saleOrderId);
- if (existNotice != null) {
- throw exception(WM_SALES_NOTICE_ALREADY_EXISTS);
- }
-
- // 2. 鑾峰彇閿�鍞鍗曚俊鎭�
- ErpSaleOrderRespDTO saleOrder = saleOrderApi.getSaleOrder(saleOrderId).getCheckedData();
- if (saleOrder == null) {
- throw exception(WM_SALES_NOTICE_SALE_ORDER_NOT_EXISTS);
- }
-
- // 3. 鑾峰彇閿�鍞鍗曟槑缁�
- List<ErpSaleOrderItemRespDTO> saleOrderItems = saleOrderApi.getSaleOrderItemList(saleOrderId).getCheckedData();
- if (CollUtil.isEmpty(saleOrderItems)) {
- throw exception(WM_SALES_NOTICE_SALE_ORDER_ITEM_EMPTY);
- }
-
- // 4. 鐢熸垚鍙戣揣閫氱煡鍗曠紪鐮�
- String code = autoCodeRecordService.generateAutoCode("SALESNOTICE_CODE", null);
-
- // 5. 鍒涘缓鍙戣揣閫氱煡鍗曚富琛�
- MesWmSalesNoticeDO notice = new MesWmSalesNoticeDO();
- notice.setCode(code);
- notice.setName("閿�鍞鍗昜" + saleOrder.getNo() + "]鍙戣揣閫氱煡");
- notice.setClientId(saleOrder.getCustomerId());
- notice.setSaleOrderId(saleOrderId);
- notice.setSaleOrderCode(saleOrder.getNo());
- notice.setSalesDate(java.time.LocalDateTime.now());
- notice.setStatus(PREPARE.getStatus());
- salesNoticeMapper.insert(notice);
-
- // 6. 閬嶅巻鏄庣粏鍒涘缓鍙戣揣閫氱煡鍗曡
- for (ErpSaleOrderItemRespDTO saleOrderItem : saleOrderItems) {
- MesWmSalesNoticeLineDO line = new MesWmSalesNoticeLineDO();
- line.setNoticeId(notice.getId());
- line.setSaleOrderItemId(saleOrderItem.getId());
- line.setItemId(saleOrderItem.getProductId());
- line.setQuantity(saleOrderItem.getCount());
- salesNoticeLineService.createSalesNoticeLine(line);
- }
-
- return notice.getId();
}
@Override
@@ -350,8 +290,6 @@
productSales.setCode(code);
productSales.setName("鍙戣揣閫氱煡鍗昜" + notice.getCode() + "]鍑哄簱");
productSales.setClientId(notice.getClientId());
- productSales.setSaleOrderId(notice.getSaleOrderId());
- productSales.setSalesOrderCode(notice.getSaleOrderCode());
productSales.setNoticeId(noticeId);
productSales.setSalesDate(notice.getSalesDate());
// 鏀惰揣淇℃伅浠庡彂璐ч�氱煡鍗曞甫鍏�
@@ -365,7 +303,6 @@
for (MesWmSalesNoticeLineDO noticeLine : noticeLines) {
MesWmProductSalesLineDO salesLine = new MesWmProductSalesLineDO();
salesLine.setSalesId(productSales.getId());
- salesLine.setSaleOrderItemId(noticeLine.getSaleOrderItemId());
salesLine.setNoticeLineId(noticeLine.getId());
salesLine.setItemId(noticeLine.getItemId());
salesLine.setQuantity(noticeLine.getQuantity());
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
index fd75003..eb43c7e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
@@ -16,6 +16,7 @@
import cn.iocoder.yudao.module.mes.dal.mysql.wm.transaction.MesWmTransactionMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
@@ -23,6 +24,7 @@
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -57,6 +59,9 @@
private MesWmWarehouseLocationService locationService;
@Resource
private MesWmWarehouseAreaService areaService;
+
+ @Resource
+ private MesWmMaterialStockBagService materialStockBagService;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -127,11 +132,20 @@
materialStockService.updateMaterialStockQuantity(materialStock.getId(), reqDTO.getQuantity(), checkFlag);
MesWmMaterialStockDO updatedStock = materialStockService.getMaterialStock(materialStock.getId());
BigDecimal newQuantity = updatedStock.getQuantity();
- // 搴撳瓨鐘舵�侊細鏄惧紡鎸囧畾浼樺厛锛堝鎵爜鍏ユ殏瀛樺簱锛夛紝鍚﹀垯鎸夋暟閲忚嚜鍔ㄥ垽瀹氾紙鈮�0 宸插嚭搴擄紝>0 鍚堟牸搴擄級
+ // 搴撳瓨鐘舵�侊細鏄惧紡鎸囧畾浼樺厛锛堝鎵爜鍏ユ殏瀛樺簱锛夛紝鍚﹀垯鑷姩鍒ゅ畾鈥斺�斺墹0 宸插嚭搴擄紱
+ // >0 鏃朵粎鐩爣浠撳簱涓哄悎鏍煎簱(20)鎵嶇疆鍚堟牸鎬侊紝鍚﹀垯淇濇寔鏆傚瓨鎬�(10)锛�
+ // 閬垮厤鐩樼偣/璋冩暣/璋冩嫧绛夋搷浣滄妸鏆傚瓨浠撳簱搴撳瓨缈绘垚鍚堟牸鎬�
Integer stockState = reqDTO.getStockState();
if (stockState == null) {
- stockState = newQuantity.signum() <= 0
- ? MesWmStockStateEnum.OUT.getState() : MesWmStockStateEnum.QUALIFIED.getState();
+ if (newQuantity.signum() <= 0) {
+ stockState = MesWmStockStateEnum.OUT.getState();
+ } else {
+ MesWmWarehouseDO warehouse = warehouseService.getWarehouse(reqDTO.getWarehouseId());
+ boolean qualifiedWarehouse = warehouse != null
+ && MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(warehouse.getType());
+ stockState = qualifiedWarehouse
+ ? MesWmStockStateEnum.QUALIFIED.getState() : MesWmStockStateEnum.TEMP.getState();
+ }
}
materialStockService.updateMaterialStockState(updatedStock.getId(), stockState);
@@ -139,14 +153,46 @@
MesWmTransactionDO transaction = MesWmTransactionDO.builder()
.type(reqDTO.getType()).quantity(reqDTO.getQuantity()).transactionTime(LocalDateTime.now())
.itemId(reqDTO.getItemId()).batchId(reqDTO.getBatchId()).batchCode(reqDTO.getBatchCode())
+ .bagCodeId(reqDTO.getBagCodeId()).bagCode(reqDTO.getBagCode())
.warehouseId(reqDTO.getWarehouseId()).locationId(reqDTO.getLocationId()).areaId(reqDTO.getAreaId())
.bizType(reqDTO.getBizType()).bizId(reqDTO.getBizId()).bizCode(reqDTO.getBizCode()).bizLineId(reqDTO.getBizLineId())
.materialStockId(materialStock.getId()).relatedTransactionId(reqDTO.getRelatedTransactionId())
.build();
transactionMapper.insert(transaction);
+ // 4. 甯﹁鐮佹椂锛屽悓姝ョ淮鎶ゅ簱瀛樿鐮佹槑缁嗭紙鍏ュ簱寤虹珛/婵�娲汇�佸嚭搴撶疆宸插嚭搴撱�佺Щ鍏ヨ縼绉汇�佹姤搴燂級
+ boolean skipBagManage = ObjUtil.defaultIfNull(reqDTO.getSkipBagManage(), false);
+ if (!skipBagManage && (StrUtil.isNotBlank(reqDTO.getBagCode()) || reqDTO.getBagCodeId() != null)) {
+ handleStockBag(reqDTO, materialStock, transaction.getId(), transactionType);
+ }
return transaction.getId();
}
+ /**
+ * 鎸変簨鍔$被鍨嬬淮鎶よ鐮佹槑缁嗭紝淇濊瘉姹囨�诲簱瀛樸�佽鐮佹槑缁嗐�佷簨鍔℃祦姘翠笁鑰呬竴鑷淬��
+ */
+ private void handleStockBag(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO materialStock,
+ Long transactionId, MesWmTransactionTypeEnum transactionType) {
+ switch (transactionType) {
+ case MOVE_IN:
+ // 绉诲叆/璋冩嫧/璐ㄦ杩佺Щ锛氭洿鏂版槑缁嗕綅缃笌鐘舵��
+ materialStockBagService.moveIn(reqDTO, materialStock, transactionId);
+ break;
+ case IN:
+ case ADJUST_IN:
+ // 鍏ュ簱/鐩樼泩锛氬缓绔嬫垨婵�娲绘槑缁�
+ materialStockBagService.inbound(reqDTO, materialStock, transactionId);
+ break;
+ case MOVE_OUT:
+ case OUT:
+ case ADJUST_OUT:
+ // 绉诲嚭/鍑哄簱/鐩樹簭锛氱疆涓哄凡鍑哄簱
+ materialStockBagService.outbound(reqDTO, transactionId);
+ break;
+ default:
+ break;
+ }
+ }
+
@Override
@Transactional(rollbackFor = Exception.class)
public void createTransactionList(List<MesWmTransactionSaveReqDTO> reqDTOs) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java
index 39a7693..6ac1ead 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java
@@ -69,6 +69,10 @@
* 鎵规鍙�
*/
private String batchCode;
+ /** 琚嬬爜ID */
+ private Long bagCodeId;
+ /** 琚嬬爜 */
+ private String bagCode;
// ===== 搴撳瓨浣嶇疆 =====
@@ -128,4 +132,12 @@
*/
private Integer stockState;
+ /**
+ * 鏄惁璺宠繃琚嬬爜鏄庣粏鑷姩缁存姢锛堥粯璁� false锛夈��
+ * <p>
+ * 璐ㄦ绛夐渶瑕佽嚜琛屾帶鍒惰鐮佺敓鍛藉懆鏈燂紙濡傛殏瀛樺嚭搴撲笌鍚堟牸鍏ュ簱鎴愬鍙戠敓銆佽鐮佷粎鍦ㄦ渶缁堣惤鐐硅縼绉伙級鐨勫満鏅紝
+ * 鍦ㄥ啓浜嬪姟鏃剁疆 true锛岄伩鍏� createTransaction 鎸夊崟绗斾簨鍔$被鍨嬭嚜鍔ㄧ疆宸插嚭搴�/杩佺Щ锛屽鑷磋鐮佺姸鎬侀敊涔便��
+ */
+ private Boolean skipBagManage;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java
index c038d5a..d983b1c 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java
@@ -90,4 +90,26 @@
*/
MesWmWarehouseDO getWarehouseByCode(String code);
+ /**
+ * 鎸変粨搴撶被鍨嬭幏寰椾粨搴撳垪琛紙鎸� id 鍗囧簭锛�
+ *
+ * @param type 浠撳簱绫诲瀷锛岃 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum}
+ * @return 浠撳簱鍒楄〃
+ */
+ List<MesWmWarehouseDO> getWarehouseListByType(Integer type);
+
+ /**
+ * 鑾峰緱鍚堟牸搴擄紙type=QUALIFIED锛夌殑缂栧彿闆嗗悎锛岀敤浜庢寜浠撳簱绫诲瀷杩囨护鍚堟牸搴撳瓨
+ *
+ * @return 鍚堟牸浠撳簱 id 闆嗗悎
+ */
+ List<Long> getQualifiedWarehouseIds();
+
+ /**
+ * 鑾峰緱绗竴涓悎鏍煎簱锛坱ype=QUALIFIED锛屾寜 id 鍗囧簭锛�
+ *
+ * @return 鍚堟牸浠撳簱锛屾湭閰嶇疆杩斿洖 null
+ */
+ MesWmWarehouseDO getFirstQualifiedWarehouse();
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java
index bd85c14..5ca72bd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java
@@ -9,6 +9,7 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseMapper;
import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
@@ -22,6 +23,7 @@
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
/**
@@ -175,6 +177,7 @@
if (MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE.equals(code)) {
MesWmWarehouseDO newWarehouse = MesWmWarehouseDO.builder()
.code(code).name("铏氭嫙绾胯竟浠撳簱").frozen(false)
+ .type(MesWmWarehouseTypeEnum.TEMP.getType())
.remark("绯荤粺鑷姩鍒濆鍖栫殑铏氭嫙绾胯竟浠撳簱锛堢敤浜庣敓浜ф姤宸ヤ笌鍦ㄥ埗鍝佺鐞嗚В鑰︼級")
.build();
warehouseMapper.insert(newWarehouse);
@@ -183,4 +186,21 @@
return null;
}
+ @Override
+ public List<MesWmWarehouseDO> getWarehouseListByType(Integer type) {
+ return warehouseMapper.selectListByType(type);
+ }
+
+ @Override
+ public List<Long> getQualifiedWarehouseIds() {
+ return convertList(getWarehouseListByType(MesWmWarehouseTypeEnum.QUALIFIED.getType()),
+ MesWmWarehouseDO::getId);
+ }
+
+ @Override
+ public MesWmWarehouseDO getFirstQualifiedWarehouse() {
+ List<MesWmWarehouseDO> list = getWarehouseListByType(MesWmWarehouseTypeEnum.QUALIFIED.getType());
+ return CollUtil.isNotEmpty(list) ? list.get(0) : null;
+ }
+
}
diff --git a/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml b/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml
index 8e19a64..b59a960 100644
--- a/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml
+++ b/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml
@@ -62,6 +62,45 @@
WHERE deleted = 0
</select>
+ <!-- ========== 鍑哄簱娴侀�� / 浠撳偍 / 璐ㄩ噺 ========== -->
+
+ <!-- 缁熻鍙戣揣閫氱煡鍗曟暟锛坢es_wm_sales_notice锛� -->
+ <select id="selectSalesNoticeCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_sales_notice
+ WHERE deleted = 0
+ </select>
+
+ <!-- 缁熻閿�鍞嚭搴撳崟鏁帮紙mes_wm_product_sales锛� -->
+ <select id="selectProductSalesCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_product_sales
+ WHERE deleted = 0
+ </select>
+
+ <!-- 缁熻閿�鍞��璐у崟鏁帮紙mes_wm_return_sales锛� -->
+ <select id="selectReturnSalesCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_return_sales
+ WHERE deleted = 0
+ </select>
+
+ <!-- 缁熻鏈鐞嗗簱瀛橀璀︽暟锛坢es_wm_stock_warning.status=10锛� -->
+ <select id="selectStockWarningPendingCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_stock_warning
+ WHERE deleted = 0
+ AND status = 10
+ </select>
+
+ <!-- 缁熻寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁帮紙mes_qc_ncr.status=0锛� -->
+ <select id="selectNcrPendingCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_qc_ncr
+ WHERE deleted = 0
+ AND status = 0
+ </select>
+
<!-- ========== 鐘舵�佸垎甯� ========== -->
<!-- 鎸夌姸鎬佺粺璁℃壒娆℃暟閲� -->
diff --git a/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml b/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml
index 0eda416..aa5871c 100644
--- a/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml
+++ b/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml
@@ -55,16 +55,50 @@
WHERE rl.batch_code = #{batchCode} AND rl.deleted = 0
</select>
- <!-- 鎵规閿�鍞幓鍚戯細鎵规 鈫� 閿�鍞嚭搴撹 鈫� 閿�鍞嚭搴撳崟 鈫� OQC -->
+ <!--
+ 鎵规閿�鍞幓鍚戯紙绉嶅瓙娴佸悜锛夛細
+ 鈶� 琛岀骇鍖归厤锛氭壒娆� 鈫� 閿�鍞嚭搴撹 鈫� 閿�鍞嚭搴撳崟 鈫� OQC锛堣涓婄洿鎺ヨ褰曟壒娆$殑娴佺▼锛夛紱
+ 鈶� 鏄庣粏绾у尮閰嶏細鎵规 鈫� 鎵爜鍑哄簱鏄庣粏 鈫� 閿�鍞嚭搴撳崟 鈫� OQC锛堢瀛愯鐮�/鎵樼洏鎵爜鍑哄簱鏃舵壒娆″彧鍐欏叆鏄庣粏琛紝鎸夊崟鎹仛鍚堟暟閲忥級銆�
+ 鍚屼竴鍑哄簱琛岃嫢宸叉湁鏄庣粏绾у尮閰嶅垯涓嶅啀閲嶅鍑鸿绾ц褰曪紱鎺掗櫎宸插彇娑堬紙鐘舵�� 5锛夊崟鎹��
+ -->
<select id="selectSalesTargetList" parameterType="String"
resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO">
- SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id,
+ SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name,
oqc.code AS oqc_code, oqc.check_result AS check_result,
sl.batch_code, sl.item_id, sl.quantity, sl.quality_status
FROM mes_wm_product_sales_line sl
JOIN mes_wm_product_sales s ON s.id = sl.sales_id AND s.deleted = 0
LEFT JOIN mes_qc_oqc oqc ON oqc.id = sl.oqc_id AND oqc.deleted = 0
- WHERE sl.batch_code = #{batchCode} AND sl.deleted = 0
+ WHERE sl.batch_code = #{batchCode} AND sl.deleted = 0 AND s.status != 5
+ AND NOT EXISTS (SELECT 1 FROM mes_wm_product_sales_detail d
+ WHERE d.line_id = sl.id AND d.batch_code = #{batchCode} AND d.deleted = 0)
+ UNION ALL
+ SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name,
+ oqc.code AS oqc_code, oqc.check_result AS check_result,
+ d.batch_code, d.item_id, SUM(d.quantity) AS quantity, MAX(sl.quality_status) AS quality_status
+ FROM mes_wm_product_sales_detail d
+ JOIN mes_wm_product_sales s ON s.id = d.sales_id AND s.deleted = 0
+ JOIN mes_wm_product_sales_line sl ON sl.id = d.line_id AND sl.deleted = 0
+ LEFT JOIN mes_qc_oqc oqc ON oqc.id = sl.oqc_id AND oqc.deleted = 0
+ WHERE d.batch_code = #{batchCode} AND d.deleted = 0 AND s.status != 5
+ GROUP BY s.id, s.code, s.sales_date, s.sales_order_code, s.client_id, s.client_name,
+ oqc.code, oqc.check_result, d.batch_code, d.item_id
+ ORDER BY sales_date
+ </select>
+
+ <!-- 鎵规鍑哄叆搴撴祦姘达紙绉嶅瓙娴佸悜锛夛細搴撳瓨浜嬪姟 鈫� 浠撳簱/搴撳尯/搴撲綅 鈫� 閿�鍞嚭搴撳崟锛坆iz_type 119 甯﹀嚭瀹㈡埛鍚嶇О锛� -->
+ <select id="selectBatchFlowList" parameterType="String"
+ resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO">
+ SELECT tx.type, tx.biz_type, tx.biz_code, tx.quantity, tx.transaction_time,
+ w.name AS warehouse_name, loc.name AS location_name, area.name AS area_name,
+ sales.client_name
+ FROM mes_wm_transaction tx
+ LEFT JOIN mes_wm_warehouse w ON w.id = tx.warehouse_id AND w.deleted = 0
+ LEFT JOIN mes_wm_warehouse_location loc ON loc.id = tx.location_id AND loc.deleted = 0
+ LEFT JOIN mes_wm_warehouse_area area ON area.id = tx.area_id AND area.deleted = 0
+ LEFT JOIN mes_wm_product_sales sales ON tx.biz_type = 119 AND sales.id = tx.biz_id AND sales.deleted = 0
+ WHERE tx.batch_code = #{batchCode} AND tx.deleted = 0
+ ORDER BY tx.transaction_time
</select>
<!-- 鎵规宸ュ簭娴佽浆锛氫骇鍑�(OUT)/鎶曞叆(IN) 浜嬩欢鑱氬悎锛屾棤闇�寤鸿〃 -->
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java
new file mode 100644
index 0000000..8f538f3
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java
@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.server.framework.bizno;
+
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 宸茬敤涓氬姟缂栫爜闆嗗悎鍏滃簳鍒濆鍖栥��
+ *
+ * <p>涓氬姟缂栫爜涓恒�岄殢鏈� 16 浣嶇函鏁板瓧銆嶏紝鍞竴鎬ч潬 Redis 闆嗗悎锛坽@link BizNoUtils#USED_SET_KEY}锛夋煡閲嶃��
+ * 鑻� Redis 涓㈠け璇ラ泦鍚堬紝宸茬敓鎴愮殑鍘嗗彶缂栫爜浼氳"蹇樿"锛屼箣鍚庡彲鑳借閲嶆柊闅忔満鍛戒腑鑰岄噸鍙枫��
+ *
+ * <p>鍥犳锛氬惎鍔ㄦ椂鑻ュ彂鐜拌闆嗗悎 **涓嶅瓨鍦�**锛屽垯浠庢暟鎹簱涓壂鎻忔墍鏈変笟鍔$紪鐮佸垪閲岀殑
+ * 銆�16 浣嶇函鏁板瓧銆嶇紪鐮侊紝閲嶆柊杞藉叆闆嗗悎锛屾仮澶嶉槻閲嶈兘鍔涖��
+ *
+ * <p>璇存槑锛�
+ * <ul>
+ * <li>浠呭湪闆嗗悎缂哄け鏃舵壂鎻忥紙姝e父鍚姩鏃犻澶栧紑閿�锛夛紱</li>
+ * <li>best-effort锛屽け璐ュ彧鍛婅銆佷笉褰卞搷鍚姩锛�</li>
+ * <li>鏃х殑甯﹀瓧姣嶇紪鐮佷細琚拷鐣ャ��</li>
+ * </ul>
+ */
+@Component
+@Slf4j
+public class BizCodeSetInitializer implements ApplicationRunner {
+
+ /** 闆嗗悎鍒濆鍖栨爣璁帮紙闈� 16 浣嶏紝涓嶄細涓庣湡瀹炵紪鐮佸啿绐侊級锛岀敤浜庡湪搴撳唴鏃犵紪鐮佹椂涔熸爣璁颁负宸插垵濮嬪寲 */
+ private static final String INIT_MARKER = "__initialized__";
+
+ private final StringRedisTemplate stringRedisTemplate;
+ private final JdbcTemplate jdbcTemplate;
+
+ public BizCodeSetInitializer(StringRedisTemplate stringRedisTemplate, DataSource dataSource) {
+ this.stringRedisTemplate = stringRedisTemplate;
+ this.jdbcTemplate = new JdbcTemplate(dataSource);
+ }
+
+ @Override
+ public void run(ApplicationArguments args) {
+ if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(BizNoUtils.USED_SET_KEY))) {
+ log.info("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 闆嗗悎宸插瓨鍦紝璺宠繃搴撳唴鎵弿");
+ return;
+ }
+ long start = System.currentTimeMillis();
+ long total = 0L;
+ try {
+ String schema = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class);
+ List<Map<String, Object>> columns = jdbcTemplate.queryForList(
+ "SELECT table_name, column_name FROM information_schema.columns " +
+ "WHERE table_schema = ? AND data_type IN ('varchar', 'char') " +
+ "AND (column_name = 'no' OR column_name = 'code' OR column_name = 'temp_code' " +
+ " OR column_name LIKE '%\\_no' OR column_name LIKE '%\\_code')",
+ schema);
+ for (Map<String, Object> column : columns) {
+ String table = String.valueOf(column.get("table_name"));
+ String col = String.valueOf(column.get("column_name"));
+ if (table.toLowerCase().startsWith("qrtz_") || table.toLowerCase().startsWith("act_")) {
+ continue;
+ }
+ List<String> codes = jdbcTemplate.queryForList(
+ "SELECT `" + col + "` FROM `" + table + "` WHERE `" + col + "` REGEXP '^[0-9]{"
+ + BizNoUtils.CODE_LENGTH + "}$'",
+ String.class);
+ if (!codes.isEmpty()) {
+ stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, codes.toArray(new String[0]));
+ total += codes.size();
+ }
+ }
+ // 鏍囪涓哄凡鍒濆鍖栵紝閬垮厤涓嬫鍚姩閲嶅鎵弿
+ stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, INIT_MARKER);
+ log.info("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 闆嗗悎缂哄け锛屽凡杞藉叆搴撳唴 {} 涓紪鐮�", total);
+ } catch (Exception e) {
+ log.warn("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 鍒濆鍖栧け璐ワ紙涓嶅奖鍝嶅惎鍔級锛岃鎺掓煡", e);
+ } finally {
+ log.info("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 搴撳唴鎵弿鑰楁椂 {} ms", System.currentTimeMillis() - start);
+ }
+ }
+
+}
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index 28d2c2b..41742db 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -3,7 +3,7 @@
# H5 婧簮椤甸潰鍩虹鍦板潃锛堜簩缁寸爜鍐呭鍓嶇紑锛夛紝闇�涓哄叕浼楁壂鐮佸彲璁块棶鐨勫湴鍧�
mes:
- trace-base-url: http://192.168.0.10:48080/trace.html
+ trace-base-url: http://192.168.1.7:48080/trace.html
--- #################### 鏁版嵁搴撶浉鍏抽厤缃� ####################
spring:
diff --git a/yudao-server/src/main/resources/application-test.yaml b/yudao-server/src/main/resources/application-test.yaml
index 74cb6da..93bfc26 100644
--- a/yudao-server/src/main/resources/application-test.yaml
+++ b/yudao-server/src/main/resources/application-test.yaml
@@ -14,7 +14,7 @@
- org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Milvus锛屾墜鍔ㄥ垱寤�
- org.dromara.trans.config.TransServiceConfig # TODO 鑺嬭壙锛歟asy-trans 鍏煎 Spring Boot 4 鍚庣Щ闄わ紙TransServiceConfig 寮曠敤浜嗗凡绉婚櫎鐨� RestTemplateBuilder锛�
# 绂佺敤鏈厤缃� API Key 鐨勬ā鍨嬭嚜鍔ㄩ厤缃紙鍙繚鐣欓�氫箟鍗冮棶 Embedding 鐨勬墜鍔ㄩ厤缃級
- - org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration
+ - org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration
- org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration
- org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration
- org.springframework.ai.model.openai.autoconfigure.OpenAiAudioSpeechAutoConfiguration
diff --git a/yudao-server/src/main/resources/application-thzy.yaml b/yudao-server/src/main/resources/application-thzy.yaml
index 5862482..22c2a28 100644
--- a/yudao-server/src/main/resources/application-thzy.yaml
+++ b/yudao-server/src/main/resources/application-thzy.yaml
@@ -3,7 +3,7 @@
# H5 婧簮椤甸潰鍩虹鍦板潃锛堜簩缁寸爜鍐呭鍓嶇紑锛夛紝闇�涓哄叕浼楁壂鐮佸彲璁块棶鐨勫湴鍧�
mes:
- trace-base-url: http://47.97.181.254:9001/trace.html
+ trace-base-url: http://1.95.78.124:9008/prod/trace.html
--- #################### 鏁版嵁搴撶浉鍏抽厤缃� ####################
spring:
@@ -55,11 +55,12 @@
min-idle: 1 # 鏈�灏忚繛鎺ユ睜鏁伴噺
max-active: 20 # 鏈�澶ц繛鎺ユ睜鏁伴噺
max-wait: 60000 # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂达紝鍗曚綅锛氭绉掞紙1 鍒嗛挓锛�
- time-between-eviction-runs-millis: 60000 # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶏細姣锛�1 鍒嗛挓锛�
+ time-between-eviction-runs-millis: 30000 # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶏細姣锛�30 绉掞紝鍘嬬缉绌洪棽杩炴帴鏈妫�娴嬬殑缂濋殭锛�
min-evictable-idle-time-millis: 600000 # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶏細姣锛�10 鍒嗛挓锛�
max-evictable-idle-time-millis: 1800000 # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶏細姣锛�30 鍒嗛挓锛�
validation-query: SELECT 1 FROM DUAL # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
test-while-idle: true
+ keepAlive: true # 绌洪棽杩炴帴瀹氭湡鍙戦�佹娴嬪寘淇濇椿锛岄伩鍏嶈鏈嶅姟绔� wait_timeout 鍥炴敹
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true # 鏄惁寮�鍚� PreparedStatement 缂撳瓨
@@ -67,16 +68,16 @@
primary: master
datasource:
master:
- url: jdbc:mysql://172.17.0.1:9000/mom-thzy?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 杩炴帴鐨勭ず渚�
+ url: jdbc:mysql://172.17.0.1:9000/mom-thzynew?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 杩炴帴鐨勭ず渚�
username: root
- password: thzy@123456..
+ password: xinjiang@123456..
# Redis 閰嶇疆銆俁edisson 榛樿鐨勯厤缃冻澶熶娇鐢紝涓�鑸笉闇�瑕佽繘琛岃皟浼�
data:
redis:
host: 172.17.0.1 # 鍦板潃
port: 6379 # 绔彛
- database: 1 # 鏁版嵁搴撶储寮�
+ database: 3 # 鏁版嵁搴撶储寮�
# password: dev # 瀵嗙爜锛屽缓璁敓浜х幆澧冨紑鍚�
--- #################### 瀹氭椂浠诲姟鐩稿叧閰嶇疆 ####################
@@ -191,7 +192,7 @@
storage: # 鏂囦欢涓婁紶閰嶇疆
path: /home/mom/javaWork/file # 鏂囦欢瀛樺偍鏍圭洰褰�
url-prefix: /admin-api/system/storage-blob # URL璺緞鍓嶇紑
- domain: http://47.97.181.254:9001 # 鍩熷悕鍓嶇紑锛堟寜瀹為檯鍩熷悕閰嶇疆锛夛紝鍓嶇閰嶇疆濂藉儚涓嶅お瀵圭幇鍦ㄦ槸鐩磋繛鍚庣锛屾墍鏈夎鍚庣绔彛
+ domain: http://1.95.78.124:9008 # 鍩熷悕鍓嶇紑锛堟寜瀹為檯鍩熷悕閰嶇疆锛夛紝鍓嶇閰嶇疆濂藉儚涓嶅お瀵圭幇鍦ㄦ槸鐩磋繛鍚庣锛屾墍鏈夎鍚庣绔彛
expired: 120 # token杩囨湡鏃堕棿锛堝垎閽燂級
use-limit: 10 # token浣跨敤娆℃暟涓婇檺
jwt-secret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG # JWT瀵嗛挜
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index 4c9c073..ce5b8ba 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -96,8 +96,10 @@
aj:
captcha:
- jigsaw: classpath:images/jigsaw # 婊戝姩楠岃瘉锛屽簳鍥捐矾寰勶紝涓嶉厤缃皢浣跨敤榛樿鍥剧墖锛涗互 classpath: 寮�澶达紝鍙� resource 鐩綍涓嬭矾寰�
- pic-click: classpath:images/pic-click # 婊戝姩楠岃瘉锛屽簳鍥捐矾寰勶紝涓嶉厤缃皢浣跨敤榛樿鍥剧墖锛涗互 classpath: 寮�澶达紝鍙� resource 鐩綍涓嬭矾寰�
+ # 娉ㄦ剰锛氬繀椤荤敤 classpath*: 鍓嶇紑銆俢lasspath: 閫氶厤鎵弿涓嶄簡 jar 鍐呯洰褰曪紝
+ # fat jar 閮ㄧ讲鏃跺簳鍥惧湪 BOOT-INF/lib/yudao-module-system-*.jar 鍐呬細鎵弿涓虹┖锛屽鑷� /captcha/get 鎶� 6113
+ jigsaw: classpath*:images/jigsaw # 婊戝姩楠岃瘉锛屽簳鍥捐矾寰勶紝涓嶉厤缃皢浣跨敤榛樿鍥剧墖锛涗互 classpath 寮�澶达紝鍙� resource 鐩綍涓嬭矾寰�
+ pic-click: classpath*:images/pic-click # 鏂囧瓧鐐归�夛紝搴曞浘璺緞锛屼笉閰嶇疆灏嗕娇鐢ㄩ粯璁ゅ浘鐗囷紱浠� classpath 寮�澶达紝鍙� resource 鐩綍涓嬭矾寰�
cache-type: redis # 缂撳瓨 local/redis...
cache-number: 1000 # local 缂撳瓨鐨勯槇鍊�,杈惧埌杩欎釜鍊硷紝娓呴櫎缂撳瓨
timing-clear: 180 # local瀹氭椂娓呴櫎杩囨湡缂撳瓨(鍗曚綅绉�),璁剧疆涓�0浠h〃涓嶆墽琛�
diff --git a/yudao-server/src/main/resources/static/trace.html b/yudao-server/src/main/resources/static/trace.html
index afafce6..b5a75cc 100644
--- a/yudao-server/src/main/resources/static/trace.html
+++ b/yudao-server/src/main/resources/static/trace.html
@@ -4,130 +4,222 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no">
-<title>浜у搧婧簮</title>
+<title>鏂扮枂濉旈噷鏈ㄦ渤绉嶄笟鑲′唤鏈夐檺鍏徃 路 浜у搧婧簮</title>
<style>
:root {
- --primary: #2e7d32;
- --primary-light: #43a047;
- --primary-bg: #e8f5e9;
+ --primary: #1f7a38;
+ --primary-light: #35a055;
+ --primary-bg: #eef7ef;
+ --brand-blue: #0d5faa;
--text: #1f2933;
+ --text-strong: #111827;
--text-sub: #6b7280;
- --border: #e5e7eb;
- --bg: #f5f7f4;
- --card-shadow: 0 1px 4px rgba(0,0,0,.06);
- --green: #2e7d32;
- --red: #d32f2f;
+ --text-mute: #9aa1ab;
+ --line: #e9ecef;
+ --line-soft: #f1f3f5;
+ --bg: #f6f7f6;
+ --green: #1f7a38;
+ --red: #c62828;
--blue: #1565c0;
+ --amber: #b06f00;
--gray: #6b7280;
+ --radius: 12px;
+ --radius-sm: 8px;
+ --shadow: 0 1px 2px rgba(16, 24, 40, .05);
+ --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Courier New", monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
- html, body { height: 100%; }
body {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", "Microsoft YaHei", sans-serif;
background: var(--bg);
color: var(--text);
- line-height: 1.5;
+ font-size: 16px;
+ line-height: 1.7;
-webkit-font-smoothing: antialiased;
+ text-size-adjust: 100%;
}
- .wrap { max-width: 480px; margin: 0 auto; padding: 0 12px 32px; }
- /* 椤堕儴鍝佺墝鍖� */
- .brand {
+ /* ========== 椤堕儴鍝佺墝鍖� ========== */
+ .hero { background: #fff; box-shadow: var(--shadow); }
+ .hero-top {
max-width: 480px; margin: 0 auto;
- padding: 20px 16px 14px;
- text-align: center;
+ display: flex; align-items: center; gap: 12px;
+ padding: 12px 16px;
}
- .brand .logo {
- display: inline-flex; align-items: center; gap: 8px;
- font-size: 20px; font-weight: 700; color: var(--primary);
+ .hero-logo { flex: 0 0 auto; height: 44px; width: auto; }
+ .hero-name {
+ flex: 1; min-width: 0;
+ font-size: clamp(16px, 4.6vw, 20px);
+ font-weight: 800; line-height: 1.35;
+ color: var(--brand-blue);
+ letter-spacing: .3px;
}
- .brand .logo .mark {
- width: 26px; height: 26px; border-radius: 50%;
- background: linear-gradient(135deg, var(--primary-light), var(--primary));
- position: relative;
+ /* 瀹炴櫙澶у浘浠� base64 鍐呰仈鍦� background-image锛氬悗绔畨鍏ㄨ繃婊や粎鏀捐 html銆乧ss銆乯s 闈欐�佽祫婧愶紝
+ 鐙珛鍥剧墖鏂囦欢浼氳鎷︽垚 401 JSON锛涘唴鑱斿悓鏃剁渷鎺� /prod/ 鐨勫鏂囦欢閮ㄧ讲 */
+ .hero-banner {
+ position: relative; width: 100%; padding-top: 40%; overflow: hidden;
+ background-image: url("data:image/jpeg;base64,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"), linear-gradient(180deg, #6fb8ea 0%, #a9d8f2 34%, #eaf6e2 60%, #8fc96f 78%, #4e9e4a 100%);
+ background-size: cover; background-position: center;
}
- .brand .logo .mark::after {
- content: ""; position: absolute; left: 50%; top: 50%;
- width: 10px; height: 10px; border: 2px solid #fff; border-radius: 50%;
- transform: translate(-50%, -50%);
- }
- .brand .sub { margin-top: 4px; font-size: 12px; color: var(--text-sub); }
- /* 鏌ヨ鏍� */
- .query-bar { display: flex; gap: 8px; margin-bottom: 14px; }
+ .wrap { max-width: 480px; margin: 0 auto; padding: 16px 16px 28px; }
+
+ /* ========== 鏌ヨ鏍� ========== */
+ .query-bar { display: flex; gap: 10px; }
.query-bar input {
- flex: 1; height: 42px; padding: 0 12px;
- border: 1px solid var(--border); border-radius: 8px;
- font-size: 14px; background: #fff; outline: none;
+ flex: 1; min-width: 0; height: 46px; padding: 0 14px;
+ border: 1px solid var(--line); border-radius: var(--radius); font-size: 15px;
+ background: #fff; outline: none; color: var(--text-strong);
+ transition: border-color .2s, box-shadow .2s;
}
- .query-bar input:focus { border-color: var(--primary); }
+ .query-bar input::placeholder { color: var(--text-mute); }
+ .query-bar input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(31, 122, 56, .1); }
.query-bar button {
- height: 42px; padding: 0 18px;
- border: none; border-radius: 8px;
- background: var(--primary); color: #fff; font-size: 14px;
- cursor: pointer;
+ flex: 0 0 auto; height: 46px; padding: 0 24px;
+ border: none; border-radius: var(--radius); font-size: 15px; font-weight: 600;
+ letter-spacing: 1px; color: #fff; cursor: pointer;
+ background: linear-gradient(180deg, var(--primary-light), var(--primary));
+ box-shadow: 0 2px 6px rgba(31, 122, 56, .25);
+ transition: opacity .2s;
}
- .query-bar button:active { background: var(--primary-light); }
+ .query-bar button:active { opacity: .85; }
- /* 鐘舵�� */
- .state { padding-top: 8px; }
- .loading { text-align: center; padding: 48px 0; color: var(--text-sub); }
+ /* ========== 鐘舵�佹彁绀� ========== */
+ .loading { text-align: center; padding: 48px 0; color: var(--text-sub); font-size: 15px; }
.spinner {
- width: 32px; height: 32px; margin: 0 auto 12px;
+ width: 32px; height: 32px; margin: 0 auto 14px;
border: 3px solid var(--primary-bg); border-top-color: var(--primary);
border-radius: 50%; animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.empty-tip {
- padding: 12px 16px; border-radius: 10px; background: #fff;
- box-shadow: var(--card-shadow); font-size: 14px; color: var(--text-sub);
- text-align: center;
+ margin-top: 16px; padding: 16px 18px; border-radius: var(--radius);
+ background: #fff; border: 1px solid var(--line); box-shadow: var(--shadow);
+ font-size: 15px; line-height: 1.7; color: var(--text-sub); text-align: center;
}
- .empty-tip.error { color: var(--red); background: #fdecec; }
- .empty-tip.primary { color: var(--primary); background: var(--primary-bg); }
+ .empty-tip.error { color: var(--red); background: #fdf3f3; border-color: #f3dcdc; }
+ .empty-tip.primary { color: var(--primary); background: var(--primary-bg); border-color: #d7ead9; }
- /* 鍗$墖 */
- .card {
- background: #fff; border-radius: 12px; box-shadow: var(--card-shadow);
- margin-bottom: 12px; overflow: hidden;
+ /* ========== 鍖哄潡锛堝弬鑰冮〉锛氱豢绔栨潯鏍囬 + 缁嗙嚎 + 鐧藉簳鎻忚竟鍗$墖锛� ========== */
+ .sec { margin-top: 22px; }
+ .sec-hd {
+ position: relative;
+ display: flex; align-items: center; gap: 9px;
+ padding-bottom: 11px;
+ border-bottom: 1px solid var(--line);
+ font-size: 18px; font-weight: 700; letter-spacing: .3px;
+ color: var(--text);
}
- .card .card-hd {
- display: flex; align-items: center; gap: 8px;
- padding: 12px 16px; border-bottom: 1px solid var(--border);
- font-size: 15px; font-weight: 600;
+ .sec-hd::after {
+ content: ""; position: absolute; left: 0; bottom: -1px;
+ width: 46px; height: 2px; background: var(--primary);
}
- .card .card-hd .bar { width: 4px; height: 16px; border-radius: 2px; background: var(--primary); }
- .card .card-hd .count { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--text-sub); }
- .card .card-bd { padding: 12px 16px; }
+ .sec-hd .bar { width: 4px; height: 18px; border-radius: 2px; background: var(--primary); }
+ .sec-hd .count { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--text-sub); }
+ .sec-hd .caret { font-size: 12px; color: var(--text-mute); transition: transform .2s; }
- /* 淇℃伅琛� */
- .kv { display: flex; padding: 6px 0; font-size: 14px; }
- .kv .k { flex: 0 0 88px; color: var(--text-sub); }
- .kv .v { flex: 1; word-break: break-all; }
- .kv .v.dim { color: var(--text-sub); }
+ .sec.collapsible .sec-hd { cursor: pointer; }
+ .sec.collapsible:not(.open) .sec-hd .caret { transform: rotate(-90deg); }
+ .sec.collapsible .sec-bd { display: none; }
+ .sec.collapsible.open .sec-bd { display: block; }
- /* 寰界珷 */
- .badge {
- display: inline-block; padding: 2px 8px; border-radius: 4px;
- font-size: 12px; line-height: 18px;
+ .panel {
+ margin-top: 12px; padding: 15px 16px;
+ background: #fff; border: 1px solid var(--line);
+ border-radius: var(--radius); box-shadow: var(--shadow);
}
- .badge.green { color: var(--green); background: #e8f5e9; }
+
+ /* ========== 瀛楁琛岋細鏍囩灏忎竴鍙锋祬鑹诧紝鍊兼繁鑹插姞绮楋紝褰㈡垚灞傜骇 ========== */
+ .kv { display: flex; padding: 6px 0; font-size: 15px; line-height: 1.65; }
+ .kv .k { flex: 0 0 auto; padding-top: 1px; font-size: 13px; color: var(--text-sub); }
+ .kv .k::after { content: "锛�"; }
+ .kv .v { flex: 1; min-width: 0; word-break: break-all; color: var(--text-strong); font-weight: 500; }
+ .kv .v.dim { color: var(--text-sub); font-weight: 400; }
+ .kv .v .link { color: var(--primary); text-decoration: none; border-bottom: 1px solid rgba(31,122,56,.35); }
+
+ .tip { margin-top: 8px; font-size: 15px; line-height: 1.75; color: #374151; }
+ .meta {
+ margin-top: 10px; padding-top: 10px;
+ border-top: 1px dashed var(--line);
+ font-size: 12px; color: var(--text-sub);
+ }
+
+ /* ========== 闃蹭吉鏌ヨ锛氱姸鎬佹潯 ========== */
+ .verify { display: flex; gap: 10px; padding: 13px 14px; border-radius: var(--radius-sm); }
+ .verify.ok { background: linear-gradient(135deg, #eff8f1, #e2f2e6); border: 1px solid #cfe7d6; }
+ .verify.warn { background: linear-gradient(135deg, #fff9ec, #fdf1d6); border: 1px solid #eeddb4; }
+ .verify .vico {
+ flex: 0 0 22px; height: 22px; margin-top: 1px;
+ display: flex; align-items: center; justify-content: center;
+ border-radius: 50%; color: #fff;
+ }
+ .verify.ok .vico { background: var(--primary); }
+ .verify.warn .vico { background: #d2961b; }
+ .verify .vico svg { width: 13px; height: 13px; }
+ .verify .vtxt { flex: 1; min-width: 0; }
+ .verify .vt { font-size: 16px; font-weight: 700; line-height: 1.4; color: #1b4332; }
+ .verify.warn .vt { color: #8a5a00; }
+ .verify .vs { margin-top: 4px; font-size: 13px; line-height: 1.65; color: #5b6670; }
+
+ /* ========== 闃蹭吉缂栫爜 ========== */
+ .code-box {
+ display: flex; align-items: center; justify-content: space-between; gap: 10px;
+ margin-top: 12px; padding: 10px 12px;
+ background: #f8faf8; border: 1px dashed #cfe0d2; border-radius: var(--radius-sm);
+ }
+ .code-box .cl { flex: 0 0 auto; font-size: 13px; color: var(--text-sub); }
+ .code-box .cv {
+ font-family: var(--mono); font-size: 16px; font-weight: 700;
+ letter-spacing: .5px; color: #14532d; word-break: break-all; text-align: right;
+ }
+
+ /* ========== 鏌ヨ璁板綍锛堢粺璁℃牸锛� ========== */
+ .stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
+ .stat { padding: 9px 11px; background: #fafbfa; border: 1px solid var(--line); border-radius: var(--radius-sm); }
+ .stat .sl { font-size: 12px; color: var(--text-sub); }
+ .stat .sv {
+ margin-top: 3px; font-size: 13px; font-weight: 600; color: var(--text-strong);
+ font-variant-numeric: tabular-nums;
+ }
+ .stat.span2 { grid-column: 1 / -1; }
+ .stat.count { background: var(--primary-bg); border-color: #d7ead9; }
+ .stat.count .sv { font-size: 21px; font-weight: 800; color: var(--primary); letter-spacing: .5px; }
+ .stat.count .sv .u { margin-left: 3px; font-size: 13px; font-weight: 600; }
+
+ /* ========== 搴曢儴璇存槑 ========== */
+ .notice {
+ margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line);
+ font-size: 12px; line-height: 1.75; color: var(--text-mute);
+ }
+
+ /* ========== 寰界珷 ========== */
+ .badge { display: inline-block; padding: 3px 9px; border-radius: 6px; font-size: 12px; line-height: 18px; }
+ .badge.green { color: var(--green); background: var(--primary-bg); }
.badge.red { color: var(--red); background: #fdecec; }
.badge.blue { color: var(--blue); background: #e3f2fd; }
.badge.gray { color: var(--gray); background: #f1f2f4; }
- .badge-big { display: inline-block; padding: 4px 12px; border-radius: 16px; font-size: 14px; }
- .badge-big.green { color: #fff; background: var(--green); }
- .badge-big.red { color: #fff; background: var(--red); }
- .badge-big.gray { color: #fff; background: var(--gray); }
+ /* ========== 鏄庣粏鏉$洰 ========== */
+ .li { padding: 10px 0; border-bottom: 1px dashed var(--line); }
+ .li:first-child { padding-top: 0; }
+ .li:last-child { padding-bottom: 0; border-bottom: none; }
+ .li-hd { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 2px; }
+ .li-ttl { font-size: 14px; font-weight: 600; }
+ .li-time { margin-left: auto; font-size: 12px; color: var(--text-sub); }
+ .li-bd .kv { font-size: 13px; padding: 2px 0; }
+ .li-bd .kv .k { flex: 0 0 auto; min-width: 74px; }
- /* 鍒楄〃 */
+ .scroll-list { max-height: 320px; overflow-y: auto; }
+ .scroll-list::-webkit-scrollbar { width: 4px; }
+ .scroll-list::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 2px; }
+
+ .tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.mini-table { width: 100%; border-collapse: collapse; font-size: 13px; }
- .mini-table th, .mini-table td { text-align: left; padding: 8px 6px; border-bottom: 1px solid var(--border); }
+ .mini-table th, .mini-table td { text-align: left; padding: 7px 6px; border-bottom: 1px solid var(--line); }
.mini-table th { color: var(--text-sub); font-weight: 400; background: #fafbf9; white-space: nowrap; }
.mini-table tr:last-child td { border-bottom: none; }
- .mini-table td { word-break: break-all; }
+ .mini-table td { overflow-wrap: break-word; }
.pill-list { display: flex; flex-wrap: wrap; gap: 8px; }
.pill {
@@ -135,55 +227,58 @@
padding: 6px 12px; border-radius: 16px; font-size: 13px;
background: #f3f4f6;
}
- .pill .dot { width: 6px; height: 6px; border-radius: 50%; }
-
- .scroll-list { max-height: 300px; overflow-y: auto; }
- .scroll-list::-webkit-scrollbar { width: 4px; }
- .scroll-list::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 2px; }
-
- /* 姝e搧楠岃瘉鍗★紙椤堕儴锛屾壂鐮佷紭鍏堝睍绀猴級 */
- .verify-card {
- border: 1px solid var(--primary-light);
- background: linear-gradient(180deg, #eef8ee, #fff);
+ /* ========== 鍏徃浠嬬粛 ========== */
+ .company-stats { margin-bottom: 12px; }
+ .company-stats .pill { background: var(--primary-bg); color: var(--primary); font-weight: 600; }
+ .company-bd { font-size: 16px; color: #374151; line-height: 1.9; text-align: justify; }
+ .company-bd p { text-indent: 2em; }
+ .company-bd p + p { margin-top: 10px; }
+ .company-clip { position: relative; max-height: 164px; overflow: hidden; }
+ .company-clip::after {
+ content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 56px;
+ background: linear-gradient(180deg, rgba(255,255,255,0), #fff);
+ pointer-events: none;
}
- .verify-card .card-bd { padding: 14px 16px; }
- .verify-title {
- display: flex; align-items: center; gap: 8px;
- font-size: 16px; font-weight: 700; color: var(--primary);
- margin-bottom: 4px;
- }
- .verify-title::before { content: ""; width: 5px; height: 16px; border-radius: 2px; background: var(--primary); }
- .verify-sub { font-size: 12px; color: var(--text-sub); margin-bottom: 10px; }
- .verify-badge { margin-bottom: 10px; }
- .verify-stats { margin-top: 10px; border-top: 1px dashed var(--border); padding-top: 4px; }
+ .company-clip.open { max-height: none; }
+ .company-clip.open::after { display: none; }
+ .company-more { margin-top: 12px; text-align: center; }
+ .company-more a { color: var(--brand-blue); font-size: 15px; cursor: pointer; }
- /* 鍙姌鍙犲崱鐗� */
- .card.collapsible .card-hd { cursor: pointer; position: relative; padding-right: 30px; }
- .card.collapsible .card-hd::after {
- content: "鈻�"; position: absolute; right: 12px; top: 50%;
- transform: translateY(-50%); color: var(--text-sub); font-size: 12px;
- transition: transform .2s;
+ /* ========== 鑱旂郴鎴戜滑 ========== */
+ .contact-item { display: flex; gap: 12px; padding: 13px 0; }
+ .contact-item:first-child { padding-top: 0; }
+ .contact-item:last-child { padding-bottom: 0; }
+ .contact-item + .contact-item { border-top: 1px dashed var(--line); }
+ .contact-item .ico {
+ flex: 0 0 30px; height: 30px;
+ display: flex; align-items: center; justify-content: center;
+ border: 1px solid var(--primary); border-radius: 50%;
+ color: var(--primary);
}
- .card.collapsible:not(.open) .card-hd::after { transform: translateY(-50%) rotate(-90deg); }
- .card.collapsible .card-hd .count { margin-right: 16px; }
- .card.collapsible .card-bd { display: none; }
- .card.collapsible.open .card-bd { display: block; }
+ .contact-item .ico svg { width: 15px; height: 15px; }
+ .contact-item .txt { flex: 1; min-width: 0; }
+ .contact-item .lbl { font-size: 14px; font-weight: 700; letter-spacing: .3px; color: var(--primary); }
+ .contact-item .val { margin-top: 2px; font-size: 15px; line-height: 1.6; color: var(--text); word-break: break-all; }
+ .contact-item .val a { color: inherit; text-decoration: none; }
footer {
max-width: 480px; margin: 0 auto;
- padding: 20px 16px 28px; text-align: center;
- font-size: 12px; color: #9ca3af;
+ padding: 20px 16px 32px; text-align: center;
+ font-size: 12px; line-height: 1.8; color: var(--text-mute);
}
</style>
</head>
<body>
-<div class="brand">
- <div class="logo"><span class="mark"></span>绉嶅瓙浜у搧婧簮</div>
- <div class="sub">鏉ユ簮鍙煡 路 鍘诲悜鍙拷 路 璐d换鍙┒</div>
-</div>
+<header class="hero">
+ <div class="hero-top">
+ <img class="hero-logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJIAAACACAYAAADgZTAeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAEoASURBVHhe7b0FdBxH8gcs2wJbZubYTswggyxmZmbmlcXMsGJmXJC0K5ZWzGyRbVm2ZI7ZsZ04F07OiUHSzE59b1Zan6Ioufzv7vu+2Nnfe/Vmdra7Z6anprq6qrqGi4sDDjjggAMOOOCAAw444IADDjjggAMOOOCAAw444IADDjjggAMOOOCAAw4+HBgxGMuIg4PcALBk4X8ccPDHAK4lDAZjGc5EC//igIM/B4AlAFy49GFJIPKXX/In9PVtXFiMAw7+EESApWwmwuEzUBvnN1g3FD82IsA+xhnmOPgjLCEOErnxnZCxlq2xX15Ic7peVqhRHfGl3UgxELqp1eculm3B/+cMeRz8DmAJkUhcagSwLP7+xOGAOz2ZXp93gPGn+bA/Rx+RqvMBs670Z5ppvpvw0jaDxOULW+CAA5aEYUuZsJuD4X5fDoFQmx/yUanO9IZsaeRopRmot4c+dr5ElWBVYDEdYxlniOPgVzBiGL1jJJNucqTOVRLsKjdEVlHEZlYWCmHrskRRiTb3GY8HVU8Dr9Yq4eUIE2QeXIqxGphVzjn4O4PNQNkPO/kCbveH6g0XPdhXYoesoShiK2gisLJECFbnCTEPlOmD8WQWhH7Rey/5+Zg2u77gBJmHPDHBg0uoXzXMwd8LBDKZB9+m3rix0vV6+1XDT6thbZbWDG++JMZbLAT8RYKwliICG3Ik0YM00xnbR+Xgcqfxlt+jAatBAJbOxAbOTLjxcm7mx8HfCTJzM7X0S5dWWIyUtsr0psCqTE2EL08G46GIAh9ZEPgLz8LqAjHYWKCA7aYazChfSgOr6+VvnCZr4l1vNEqm/XhHkvb2q72/bhmWsHUvNuEMxtGrPlCwGYk4McFve6mmR/F8NqxK15penquE8VFlgLdIDHiLhICPKgQrKCLAnyeFbafrY8cbXUGyI2TafJL6fewvE79EfTZaHTzeuJH845O1DzGMj9U4rkPh+hPOPGzCMe8Yzlgc5voA8K+hrWel783eS5afNsKWLLMp/mwNjJesBNzF0sBdIgLLaGeBm34GeEqEgJcswlxFlmHurNCHs51eoHM1A/TOp762vUK9FPiwazTh7pAvAPyuiQBX7nEGxokI+FDI8eX99QGwBGeWdzOsBWAdB64lxDsM3tDbo1p2VxkTalcLYXOhyQxfjiK6vEgBeIslgLtECJbRT8My+ingpp0BXqogxkc6i64uFEc25isgByotQO5iDOhO5oF6a/yXWu0pJSaDBcmE8apU31ttKTH/GM9M+cek70MM27zwGtgQJBN4cObCZ4Q4sRT4/3ZGCLCEAbCMMDHBapNN+AQBZ+CFxTlYBH/WAk0E4lKc8H2XSzWK9ncZN5XH0mAXzRTjy5Ca5suTYPKRxYC3+CzwlpwGHtop4KWdBD7aGeArPgv8xWKwkiqL8RfKzfDnKCHbik3hVJs/KIwmg9aVXDC6RgXC82awvlzyVr8nI1O1OVrPpC9Dx/lCiU700369nJfXNTAMW7Hwuuaw5J30+h1FHpdm+H/scjLEf9HCsr8BkbgUr4P31W/Ow5GSc8AlDZG41KWpenfAhebVC//+FXDJNTE7zHlcqxN3fVL3RPNyChytsWNuo2jBqixJ5opcYSZf/mkmT+EJJjdZAOOlngLe4tPAUyI4O/wViWHLSJIYd74strxAGV1VqI6uLVRHNxSqMzcXaKI7SYZwpNwexNoDZlQH4mYMRzOm3J7UIYEvul47DJNspMq9txu25OxzHqzeS7zetbfz++/XLLxMFojEpb8nYRdD5T//uT7z6fW9sZMX94RdHNiTNDHxUc6zZ/vKvvqK5fL5XeAMyj7X35SplrAUXVwHaiwSc2il3bZrKdbEf+Nv2+91Cmv6Plcv9EGbcNBnzQ9dn9eCRL0PHKCaojtJGsimAjl0TZ4kuipfDOUvEMb4SWdhOVUIeIqEgbdYBPho4sBTJIlxU6SZ3CRpJk+hBJOvQILJlyvOXJkng20oUYft5fqwu8IEPq6yBoEWNxDp8IOzDM9vxBuCPlVti71nOUK5532n5UHojY4M2jdPt+HXM18px69zobQFrn8p7vPLZjy48nHkzd7i6MejjwIme+75Xe6+GzDe+2nSl58+jrs/2UYcHGSZMGBuRrlQ+WdJK7xf5iT23we4FAJY+gRgrVN3ibnRQMFVnbYskIz3Zrk3lMpSV+L6wsJqbAjOKd84Up4PKoY8bjW36ssp8fm8BRyflILOeDIojEbCqZZzsD1fDd2QLTOzJldyhi9bZIY35+wMb6HwzAqKGLKySAZbRVOANTR5WFsiD+tKFGFNkSKsJMsylxdII3y50sjybFl0RZYcsjpLEd1dYQaHGpxBoN4dpLrCQHs0HdSa4n5Wb07o1m1NK3W8UFkW8+U4I/HRZR329RkZGbF0KL+RHpHAmxdKz13pqNDtJJdqtmZVKDUmVijUxZSpNsYNGLSnTVlPlILxaDEYDZWAyRAd7K43gVk/DdQb0tu02/PoJt1FVZZ9ZWVOl5vLAz8droq5Pe4IAAuHxiVsXeuDnhzMf0u9LzUamw6SX0h0RcEBqsM/VfoSU5N+nPhoXnHWULbYEMHSOea9gbl3xw+mfH05n/iil3Rugl5oNJSao9ZK7Da+nA/6V7NArjcMxLp84UynC5zsdoLDrZawu0ILNpEVkY1kZWQTWQXZSFJG1pOUkTVkJWRVoRKyMl8R4c9VQFbkKCDLs+QR3lSpt9yJ4q/5EqXerk5VQDamqyF7KWZwpskH5PpiQW+8ANy/6gGzQcpli8kS59Cv+m2zH15mDX0OrWVavk8vgPmdJpBoSwChtig43RIMp1v8QYDhDnsLTGBLutbrzZl6bzZlGr7ZkmnyZnOq0etdOdbISUYIiLbEgmRbEsh1poPWxRKwvtMKZv305xb9tFjHyXpC8NPhcwU/PTz9q05iSatZvYylU304UaSzD5945w5vyJWe46Z9hcPy55NgdbLq2w052ojmzVwwH6OQiF+MCGR///Do/Jtmef4ZRizxPWs4JLLE/Oz+4jOb8Ctdh8Ie9w8FP+664TBCvWoxmHNN/3zipEZvxKRyV9BDxQ7/GZXhSJAfiADpvjCQ7gsByd4gEO7yg5NtXnCkyRUONjjDJ3WOsLfGDnZXWsKuSnPYUqwPq9IVmSvTFNDV6crImgzV6Y25WtM7qcbIxzQb5ESlO+jeIoPzk/oZ58lyZ+KTvoOu16r8jMeoUydqfGdWJWm84U2Qm+JJkJ7iT5GdWpMmP72NpA17Ki1hX6Uj7Kt2hY9rPGB/rRfsZ3jDgRpv2F/pCZ9UeMLe4nOwPdtm+qNch6kTNF+QbIoDg8t0OPe4C1yvt3R6XO9Rjnl65XTu149PAMCiE5nFXsz3CuwHHjbcs8/3avekTn8ebM81QpanyTJXZMtheyotQLwt6I3Hi45vIr+8cCv8Zu8JGsDyCQAeLiLXUpZONadYspXLWQZjLJv9f64MHrdEnGU08s/3N6U8Hd8WMla11X+Qts1hjLrVsiF1i9+1GiG/a7VNwc8733o/annterfulds9xmuXT6tf298qf20xWfLacKzgte6F7NdawxmvVc6nvFbsj3sjOxD1SrQjCDnV5AmHGE7M3XQL5haKAbKRpI2szVFF12SpopsL9LD9FQ4g1hYMxlfyfg76uutF6Nc9P9lcp6LirQHoLrIJsjZDFdmYrY7sKzFFBGodEdFGT6ZCb9QvauezXmkMU15pjpa80rqEU/ErtZHCV4rnc17J96X/LNkePy1cH8Y8UeGDHC5xhUN0TzhRFQRirQkg05bG1Ownf+v12eA3kc8uPwm43CaFv7SMb75Z1YNhK3HC+3/uBX1/JRN7xuXWUX3QdrD8a4mWKOCLk55enisHvAWSsDxPkrm70hhkLkWD5oUM0BvKHfd9cf582P1ht4VtsYHrIPgUWnCCwIPHIMnMkWitzwouhtGibyQbOU8nDkc86NUI/bRHzedGi6rfzUY1nNyvVas5jVWoWY8Wq1kPkdXM+wvU9Huz1HX7sjRVW+MVzC7kRnp/3wnOPzSBxpV0kBmNgVNdPrCr2ATbkKc1sy5bE12fqYHuJpkwRdoDweJ+Efj8oxk8n9aA/aMSUBmJA6EWf5DuCAOLWxQIfdUPhCsUhk5brKzJQJGyxXC1suVQrZLlaK2S5VitkulolZLpCE1VuydP2vpSWUjg1yPg+U0f6F8kgVJ/OmvYO80gwrGKUBCoigSlgRwwuEACg/7sWw7jVZ1+N7p6k7642Zf27F5PxPkeEfzecbvVeyuZ2EqyTRNtr05T2s0TZa6wPEUS4cuXAB6qKGtGtYIizuTPk57ZSNZkCnT5gManJJBtjXpyusI9WqUlOsq8ryA64FZbXPz9Ybd//IHh8P9tpKDXjdxfNNnqD2cGqPTERym1RxVb3ikBw0fFcLiCABsztJmbc/VgU44OerDM+q3RrRym79cNP7ndK83V6ogNlasNjVZriolwvVYZkfzDWAL1u0nBhedYDJcxbE3qT7cDQr8YjrYbKw0z7CNFKzWlRIiURUbrdFFe2D3sBrXOTBCj+2EqPYmgOZoH6oMFYHixDMyGq8G8veymTXOZBXvm914y0zuJ1Fd90Ha05GvR9iDgTRadWkERB+4SQVhKOw3LigWBmyIC3IVisDRHDF2WIT6zqUQbTnS6g/R5fKaUCoQH1eA4VvzGoi8zVYLupSZS4qYkSfNRlaL7K8vR/ZWVyoOVlarDlJWqicqqdbHvSKmO+I4U66NVFOuJ6iq10RoqVREaKuWhGgrlgb8i2Xf7oRrqtdEa+m3J6pY92VpOQyS5kInWw+Xf3TvEvjdcH0n4fizZ+3lHh2pH7AupvijYVWjGXJ+tydxC1kWUrsWD42flj4hf9fyxXWgh8GF8kLYct/yzfY6/h6TPrgcm/XB3wP1q4xXr85QZzfZE5uEi55nVibrTa1IMp09UBoNBZ9Eru5bKCFaFudnzwnb+8ninI11u2edxjXFVsScGNuarovxkCYyXJgjcpTgznYElxWdgabEQLKWIYNxkEYy/SArbUKbE3FauzvyoTI+5v9QUPUKzgON0a1Sgyv71qSqn12eqXV8L1bi/Fq31fC3J8Hkt2RD4Wqop5LVMc+hrmbaw15Jtoa8lWkJeS7TNUUvIa8nW0DcSLSFvxBsD34jX+70Rqfd7I8wi37mt/xuxev83Eg1Bb2Rbwt+o9cS9MRzJemt1mfKz99OWH2J/GfvR/1a9r15D6paAyeYdDIBV+P153GQ4uj5rfKkykAAHiu3QLXkGU2e7A0BjOOWpSV/aQbyMamc239xKGK6m60/XDX7/xS7G+OA2xp32be1PB7f13pvccf2nn9axOm7OaMuWHrNWfpi19M/pjbjOAwA8gwDLo293CkU/H/jW61EDiNUHTX9cQkAEWyPAaLLse6uBEnMjBoOX5dp5H6XRHFizNjJM8Phdrj2q1ZU4JNoXAKvzZBE+sgi2vEwEeCuEgbdcBHjLxICbLgrcNBHgLhLGllEEUR7yGZSPLMhcmSeMrskTxzZQZWETTQm20lVhO10TdtK1YXeZHuwpN4S9lSawt8oc9laaw95qM/ioygx2VZvBrhoz2I0Tvl9lBjsrzWBHpQlsrzCGbXO0FadyE9hWYQY7KsxgZ4UZ7Km2hoMMRzjR4ApnW3xBfiAadMYzQL0v4SedgZRJ17t1t6K+vjAYcbmdNUT53G229nrUNGV4KR/259u8OlXnAyqdCc8M+1OP4v9bdGazzAIMI8ay4c9vk2+/fnS/537bZNu9mmvtDxjXhp723em+3l/VeecOqzyr7Jzp5NdhL3MMNo8pEu52HCQ+6/va4WYZnC33ea0ymgkWk2U/Eq7X676bCb/vZoBf2ZHG64y1+hLv7aUZzqwhyUzzUoSZ3MVCwE0TBh6aCPDSRYGnVBS4S4VhWemcZ592CpbTTsPy4jMYL+UUylN4CuEtPIMsLzyLLC8QQlYUiiD8hWIIf6E4soIkjiwvFEf4CsUQ3kIxhIckhvCQZ7fcJFGEu0AUWZoninDliiJcOWIIV67Y3FYcWZIrjnBli09zZYm+XZIlNsWdI4Xw5sghfJnyyMpMRWRdlgqyOUcTPcRwBJHeQFC/nAYOT2qBcKfyZvCjVpOHD79fE/GoOyb4RQ9mMJIPovRA0KxPemTSOCuRcBDJrfzDX41kjX8/NPXpq2649HkhDD1Jhf57yTBypxAYLWkzHZ21g+OTt/PaLl3fidcZxK3+i4AlsQYHuRPujKtGPRzushgmTQlX+jFPlXsj+sOF3/nd7UkF4uwwhju/F9Z/L4G/RfjbhTtBz12g5ds/rwCJ0SBYT1KApVlnkKW5gihX/hmEq/AMwkU6jXBRTiJcxSeQJcXH0WW0Exh36THgph8HHpaXXxB4aLj74yxwU84weShnmdxkQXQZSRBZRj6LcFOEkGVUIWQpVQhZQhVCuKhnkSVFQsiSYmFkGU0U4aNLIitK5JAVRfLICqoci5ZTZJEVZGl0XaUabGk2gI21WrCSIsfkJ8kjqyiKyGqSErKGpIysLlBG+HPlp/hzFN+syVF5s7vYZEZlMgUMLmR84/FZXVrMy+GA8KftYa7jjInwF5fAY6D6J9uS9BN4H9Q+69nX+U1n/MWfW2HoyzRovGz6tnVMC2nolpkprxSeoWaKzJBi1bCeyiS4NnIBhrquUIZ6HxzB3SRs0wa7P/FhyqOzkxVfFTDa6xXy9RUQqQ9Gd+WYvtW/WwZOk/W3s58//IRtd5v/LP7yYL0hrHF8lubbLViMNBc/HXWvzyLqu5G7phN5D6U7QhHRniA4wLCDHRWGsKlMA9aXKsH6CgXYUC0La8pFYTlVAOMlH0F5KUeZvJQTTB7yKSZ34SnmCrIQtoYuAWtokrCuXA42VCnBhioV2FitCptr1WBrnRZsbdCFbU16sKfDFPb3WsOxYScQuuwF0leDQe5qGMhfDWeR3GQkyF8jgmi/D1Owz+MrkX6f17JXiCB3LQpkrkaA1Hg4CI8EwLEed/i4yQF2Mixha6UxrMlXwzYUaKH7y2zA8AEZfL5t/9b7UcOZyCsDdqTXzx7HT54f9KwsPIDfd/1n7QFXsCHofBrNrL+ii3RelcJ6LgpAW9s+qKVug9KonVDseQQKHKRmygK9Z673XIP+rmsZ7L5lD3OzwXezfUu8PrjOsK0oUb49g/kJjYAerXZ7a/+k9Yegzy7kshmP5cd8n8A2FLJpEQMY63feN3dWZX9/c5f7Rdrh0IeDF0L/McY07M9/I9ccPiXe7DMt3OwyLdRKmBJpt58+3WCCHa/WgSOV6uiBChXmJ5UqzIM1mswjNXrosVojEKgzw07WWGCn6mwRoWbClFDzuekz9U7TQi0u0xKd3tMyvYHTSsOR07rjKdPmt/Knbe9TpwlPSt94f8H4Ofir1p8jfuj+OfyHnpfRr4Z/jp0e/9n3UXOl061SRc/79cSIn4a/jXx76Rffrzv/6fGi5WebB+U/617J/VmuP+Fnofawl8eavV9/UuUIO4tNmVsKDOBjuh1TdSAFwr+79DTh6ZhryQ8vdmffHNxFG6Sxgunqb9d6jXxfCx03z6Etw+LI+ZGjcL5nJ3Q1bIJW8iZoDt8GDLs9kKe4F0lTlpvpz6+Brsrzqey+xXUrfB/vW5xJsh8+5HMcqSfpj9Be7c62e/sx3RnRv1kCDtdr4rO/f7jmnWL+2+fwAWCBwlfy7ZdnUr+4q+/YXaGpXZugrVIbrK1S568jX+OhpdbqpetwITHT+1b+29Cvy8H5ZgbYX08Fwt0cCPyuGs5dzf6H9VBCjuOFtGzdllCCTIWbpkK1t450uZu2Uq2/nlpTqIFma7SBcXeKgc1wroHbFZqB20S5ntfVctnwaw0n85+MCFT9eF+g9pfHJ1qmvxboxH4RmB9BOY5hBxnT35wi/XDzRPwXYwL+k3UCBi1ZAqKkgDO85+QOnaZ5Gpg/ob/UuJsLuwrMEX6i8tQnec7T7k/7wfNqqw+7HbZ/sPJiMaHlWjbWPGAO7a2n0NGOT+BS4w4YLN8GPdk7oNdvJ7Qa7IYCwR3MpLNn0IbwDGijtEWz2phjJLakj719ZXfo7Qsl5qOVb0/VBMCaOLVpgRpfNAK9CZGfjQTNnneQFSHAvo6/NNji0+NhJ1/4xcuGXv29YQ499SGBV4c8PSf6PsJF8G+8+izn6yA37kf71fFF8BWGbSF92++d/kVbeuhkUaLvZXJS4E16YsKLtoz0zzqcHmHY7u8xbNfCen+Ehxi2JuBpq6797TJTvYF0I52+NBOtrlRjlfYkY7XeTCfNgfQA+e4kdxFGuKl0LdFYuTXNRKs329h0tNjY9VajMfGri6Zl8K0RDXtmEcu8mOHxbcMjo8lcTLo5FGRbY0CnMYtp10DLKrz+YCcRn3bP3WdZXzGhbigTq6g2gsrCo2g39WMYzN8J/YnboNtvG3SbbYNGmZ2Qd2Qnmikug47mM6CzvDcbr4v382wmFiJLaXZlMLadu9r+neJABvCGS7zakq2PyXbE/uL/2UB16refSrNNBO+Nw5ZtcMQRMHy+y+f2JbAdbwGv671TwaM97yy3bMfrrwhXGB9m89k8pS3HXR3v3B202a1qp8dssP5/gJQvxgSIz4eVncfKZW2HKfIW5/MUDPoyZS2GCrQdJ4oZzp+Vg+1zOujfyAbdGzmgcyMXtG7kg9rVbFAYSwXZS6kgfzkTVK7mguZkPmhfJ4HeDSqY3SsHp88bgQgTEPxT/w9un5aGBX/VMJQMY+DztOYb65H8626XasGrt7Y3/dLkfvxa2LajmvNtfiO3OoBe4oDmRwtM0SP2Q5XPNqi2Xg/V6muhUmQ9kA9vwdIOHkAKtc2ne8gNP/U0j/nidd/pSPjU//7gJuuhKmP55vjP95faAW+M8JszHX5gd7d22n6w6ixe3ugOkfe/Dgf+/xKz3nlYSrzTvcGsjdqp3JIBQpWhoNWd8aNxd7Yc8afr64hfTvCzCrPT0szbshmM5SNjE/42sbd/AHxVSNqXE5tyX/RtxFeKhFyr3WzeXrDefqBoT/DjruHQ7wffWF8t+snoYt5L7ZH0lypDSS/l+qNeibb6wOlWAhxusMD21RjCR1UG2EdVxtjuKjNsR4UJtrnMkLmx1ADdXG6Cbq+0QHdVW6O7q2zQjypt0X01juiRZjemSH8IqjgYjeldTPnZ/ErGW79v6yDgS8aVsPvNbuHX2h8EX2mJZUU+4KEcjNmpd8f4uNPYvSuvO9ozgZ5phuYHiEK66R4sQ34jlnV6PZZ1eAuWdGAfk6SkizWFpGFtxS35k89f78Dr4kzEfmldxhr1nW43vTzb5IOuy5BDN+UpooqjcczAL85/Sbw7KoqXmTMEvx+MxJ6FEccG9wbe6WnXP5/7055sM2Rzug52sNj6rUxXyA3Xbxqv+jxpjFlY97/FHYBV8Q8HgqNfDIwHPmq57Hy99KLVFfK43mj6RaXuqGvKfXGo0oVEEOrwh+PNHnCgngD76uxhd60lbC7VgjUkSSZ/riDKl30a5ck+g/LmCKN8ueIob64Eugy3J+WIT3Plir/lypF4uyRH8u3SbCkWLcuWfsuTLze1Ml/57XaSHnK8ygnO1riCdLMv0/Y26efwLzsuRlypU/PozOabH7WAM8Lg9afrei4NO1yeHJgaG64CcqwjpDuoIOlaYkiOgihSqKyIkPTMsKHUErjTfR36my+a4vfKTi7G9lvqNWfpGU6Q4WC9FfCln317tM0OVM5H3fa71yVb9N13q/+MyvCXAvsNcR+oOXnuZsMvauMZsCFLbWZVljyszVeCAy22oHY/DXTHUr41v56XQ/i0NMPtYU2295PGTL8nrZkBj2Yp6EFHZtCDnsyABz2ZQfe6ZulRe2bQo+ZMv3u1md6fVmS63yrJPHeDkmV3tSDL+FJ6uvGFlDLT0YyvbB/SweBGFiiORoPEYCgI9vnCsQ4X2FFsAOtyVZA1BaoIf4EywpevgPDmySG8hbLocpI0yl8ghqzMFUVW5krMrCqQRtaSlJD1FDVkPVkD2VxqCPvanOBIrycc6/GC473ecKLPGwT6vUFgwIe1FTzvB6fbvODjXDNkb6bx9N5MkynRWh+wvkqGoAcd+UmPRo+xlOy58A321J1AIPBcvD5mN3Sxt6CuuvzbodYm6CFTYCCfArfrO6G3mPF6qHaAduvSI/fJyecsaUTGGWiundQnk1rOk4yeM3XuUxspikzeTMFp4WFv0LuYdJ4tgfCoiAWP6q8N9hui35pzWHsw84lQfwCsL1KdWUmRAz6SJPDli6OrcqRnDjAsQPFGDOg8yAb9R4Vg/KQITB+XgNnDEjB/SAOLB2Vg8aAcLO9XgOX9crC6XwpWD2hg9RDXSQrA9NNsML6TDvq3kkHjRhzIT0SC2KgPHGmyhO3FmsgGkuLMqjxphC9LYoYvW2JmRb4ksooqj60qUoKVRUrAX6QEy6nyKB9FDuUukEZXU1SwvfU2cKzFHc50BoLYQBTIDKeA0uVc0Pm0DNSGc0G+J/GKXHt0nWJ7dJ1KZ2y9WndcnVpvbJ1KH2vbqN4bW63ZmXDe/CIZjK+QQaaVCGdKfUC1Mw3ip+5B0OX2dLxv5sdx42Ec7L678B22umPkauDA0FhTV2MXo7+xp2Zy9HrzpUt348a/AVY8OI55BkUWk0TeO1/u9+0AfEIzR1ZmSaDLM0QQ8UE/sJ4svOz3eNY5/O8cvX85sBlJsz7+sHxX9GfHutxgTYnCzCq6LPCXyQA/XQqWk8UxvnwJjJ8qh64tU0fXV2ij68t10HVlOuh6ui66gYaTHrqJpo9uLsFJD91SootuKdFCt9A00c0l6ujmElV0c4kyuommiK6ny6Fr6DLoaroUuqpYAltZJA78VDFsBVUMVlDxfUlYWSSFraBKMnnJUsxl+XiQvwy2oUobdjSawsEuApxodgPBOv8vZFvjH2v25X5mPEJ/YjVe99jpVtfjwK+vPQ96PNaW+HxSENdv8IdPxkN/58JWWXSHwcsKxxjr2hvzdHQk9PPzz80HSI/U6hMfqdQkP7YfqvvMrrHMBe8blm9svq43lweTtQuwZBCAm014LDZ7loVP9dn7LEaaU5xdr1bnmVwrhF1kPXRNrgy6PF0MkRgKAacbJWPBL2ZTIRLI76lE0m1MOqLQHf3sYJM9cOeIzvBQxYGPLgG8peLAUyIGy8giGFehMJOLIsLkKhJnLqFKMLko4kwuihSLlpKlmctIMsxlJHyFhxSThyTB5CGJzxJZlMlDFmbykIWYvJSzTF7qWSZfsSBzRYkwk58uhq0qlQB+ujjwl4ix1rHxUyVgFVkaVlHl0DVURXQDVR3ZVWoEJ9pcMPkLkTPnfmoEt+f1dzXakoQVKhM/NmslH7btrTzgPNR2wOfOpf0xn907RPr22+0L7/X3kP/i0e6Yzy4cch0s229Ym7dfmZqwX7Ew5oBF+ayDdjHgLo9/pwjjPrLFGMnuEjVL82IqbCNpo2vyZNEVmRKI9EgEON+pGEv//NIGvAx7lfJ7A7aO5DxQfNLhGv0X2ZFw4M+QmOIrkAJuigQsKxaHZSUSsIwmAUvoEsBVKg5LyiRmqXR2u7RcEpaVSgE3XQp45oh3jvjoksBHFwdeuhjw0kVgOU0UVpSIAH+RCKygisByVjIJUeArFAW+HGF0Ra74zOpcmZntxZqo0HlvUJ6MB/vvqsHuHm1GqSsyQGcwXjf4+x6bzJmb0gvvZTHMX8I9n9jHWWG+/ynm7EK4Q3aQOEe4BJyzWs8v+itGukjN0bycBlvJWujqPDl0ZbYsInspBpzvVb2/jMQOkCLe6Nnif7MhwWg49cdTdY6wKkN2enm+HMZXpADcJXKwhC4NXKUSwFUuDlxlYrNUjm9FYUm5GCwpE4OlpWKwrFQcuHEpVirBIl66OPDQxYAHjwigiQJfiSgsJ4sAT9ZZlDvtDMKbJoTwpYkia7Pk0cN19iDeFwy6t3LA4g4VdIeS2y2uFqRG/PM8Je3VeNhvlvAYGbFmQSyat2QaN57+X1Ze4NNsvM67tsiz7fwvoxDnM5LtRWqO1ngabKVooytxRspTROSvJoLLA8b7y0g45it2hP68fJORDDhe5ghrs9RR7mxFZGmhAnNpkTy2lC4DS8skYWmpBCwtFf8X0cVgCV0cltIkYFkJHjUpDtxUcWwZRZS5lCyCLiWJoNwUUZSbIsbkLRRH11EUmfuqzeFInRMIMPDMI2GgOZgG2j0pX1hcIF0I+bL/etw3lwaSPx1iOUrnYXaJNRC52WaL9wXzGcn6IjlHczyVxUj8eXLoqgJlROlaKrg+any/GWnuzWPdJPX+mID7+ZI2w74M5FSlJ7Yx3wTlL9DFlpM18QwiGB9FFuOhSGLcJHGMhySOcZMlMG6yJMZNlsb4SDLY8kIZbHmBLLayUB5bTVFhri1SZ26iazG3Vugxd1QZYgfqbZgibf6gOpD81vAS6aX5haKXvg+7f4n9YvynwPFWc0IfY23KN+PbarHPWR06z683awRlec3fv3Q1v5JIY9QczfF02ELWRvlz5dBV+cqIwtUUcL5XN0Z8nxmJjblkVTxh3dW7XYaKA93u1IHOJAWONvjDngoCbKEYI5tIWjMbSKrIunwVZG2eMrK2QAVZW6CGrM/XRDYV6CBbCvWQbYWGyH66LZxs9gHRnjCQG44D1StpoD2ZCa7ftYHP0y7EbrTMzWGkQsL1Yp0C8f5F+bxvH0hf+vw3yR5mE2otsoz6fcN8RnK4Qs/RnsiEzWRtdEWOLLoiWwmRHI4F68mKMZ873SxGmr8q+X0F62YHv/lmVdSTQR+7q5VhSi3Jqdrd6Z+Z36GBwWQeaI6mgNpwIigOxLBIZTABNIZSQWswE4zGKGBzowr0O7I/V2uKz1ZojAnR7k4LMxkpDLMZowaHfj0ckfTNdfd3CbMWAE8/w56iL4wyeJ8x347kfI2eo3MtCzZTtNHl2TIob5o8crY7AowuFI35XGIz0ns2/V8MC41h+EqLuIcD9oEPWzu8bjA6CBdobfaDlA6LnvwOi57cDpv+gg6n80UdhAF6m9flxo6w2wOdcTcvuuLSbX47C4EryPi53inI/0Pl9q+G+Yx07jo9R+9GNmzBGSlLBuVJkUVOtYWAbn/hmM+l2g+HkWb1ETxMBFjLrfEDuE5Ce/p0OU7EwcHfEI29nSszZ2dhTb9xbzfL4z1/FQVL3/m13rPwIj4k/JqRKnL0r+fCVrIOujxLFuVOkUZOtASBdl/emMMHxkg45hjpv8hsxnIN4Hm259O/ArsWFv+QMb8fnS7Tc/SuZsM2sj66IksBXZYihxxtDgT17twxh+4Pj5F+BZYkYekuvzXuzad3Loi/IbP8EdiMhEt288GCfJXRFNhK1kP5sxVRnlR5FiOpdWV9+IzEwX+H+RJJtTU2QXYklqVsr8xTRHnTFZCjTf6g3J455tBN5TASB38AIC7FQ5lj7w/vU2mPqTjT6QMbKOoof4ECypPBZqQMDiNx8PtgLyVKGG/c6H+ro9tgvGBqG0UHXUlWwJZT5DDuLNmZE+2BoNGT80Eq2xz8j8AO9lf1UOWzGKLcVBhPBv482WleijRwU6RhabbMjGBfOBhdoI753OEwEgeLgOXKAa4lYZd79nldbo2UbSQ+211qhvFRZJjLiiRhKVkCW5YtMyMxHAe2k1VjeNw8Xo/DSBz8CwBLbOYWVnr31Eu4TjZhkp1E4M9RmOEtkYWlNElYRpHE+HIUZ2RGUsDpesMo8c4H4Gvj4H8K3MjKStiO/zBpydVU60z95UClM/DmyyLcNGlYSpcGniJ5bHW+xrTWRBF43+ubIE7MplTmMBIHLODTfXbQoMP5UhOzK7RHR0pdp9bnaTGXUxVgWakMcNPlgL9EHfuowm6K8GU/RD6bvBN/7Rorm938tYYc/E0xmyt71mbkdbXOzGqC9kh2KA62kA0w/gJFbEWpAvCUycJSiixzPd2IqXW/HFzv992O//yWLu5eYrmnPmC/Iwd/Argjmr0fdLNFx/5G2XOVK8mwsVB9mr9QDltOlwO+chngpslgy6mqzD1V56ZMbtSOe0z2aLEqva9p/Tj4n2Eud/isJAm7367q8mnN94oXY2FrsdbM2hJFjK9IHHjwz2CUysCSPMmZ3dV2mNqFAtBpLTDA6+Cp/f5Okug/9Z/9p/UWw/+yrfn4T9tlSRE8Wz/+I+ZRv27glx1fKV2Ihu00beZqqixzVakM8BWLAzdFHHhIMtiqXNUZic4o8H7YjwaN9+jh9fDc2n8XRlr0+2y4reSPQl/x8ng9o7ncQDhYa8rmZdpgtTkvrHbhOdggEmcdw+z6+Nr8hWX+zPUsDFvBpQnrO2v/QUIrXCdih9sEXKszc3/EeKJ1LRV20LXRlYUS6JpSWVhFl4KVxdLAT5aBFZnS04KdAWB+qWTK/0a3R8azu9vx+n90ze8rfvMg5j/0WfzxTc+W/W2ZuYWFvzn+v8DCa/4Xs/3PMZtYAmc6osw7xvO7VmvodIPGYqKtFPXpNSRpbB1dFtbR5WA9XR5WU2SwNQVy06e6PUD3YuaPhLFqVg4kHO9NDqT/BvMfhheFcSqkuPNXCddZISZzCTMXA5E4yG2TWCCoRyz4Va7q7MuX16T29KzEmSuzaXAdgzG7HJqdYnAeY7C2+O9wavUR97Scw/h+EqNvbfZcDsb5IFa2bgouqFy/8DgO/FqDK9vX4wlF5x1e4pxVeSCsZkA6pnng0Lv48D8pIZqe/rTOqrtA0+Ji7lfKF6NhO1ljeh1FDtaWyMC6ElnYVKwE6wvlmRtISuiJdlfQGc/8p8VIXiirMsyujFnY5gcBMnmCh0gbxKMc54adQW6cmQLLmsQjajo+D6Q1eLLL4knJQ+nNehFVzaxPHLCjHYk02vK5hYJLiZVtpp6U6n84ZVLz/FLLVvqVla0MpdfqJdS2+qc39Z4gtrbyZ7Z06Wc29h7Bm0hitH4UU11vnlTewEq+hSuhrC2RyBtWXNMeWVZ/M6G21SS9qdsguar5XZIGPEoTX54dRKuTDaPUys8fptj3wjp3SaNOCL1OgP2fjAyR2ymttDT1/N3XUfXDvS5zTLjQKMh+oXBmLPru3mriw8trsiZGP3IZKE/T7k356XSdM+ykaKIbSYrMdWQ5WEeVhfUkWWxjngJza54aKlDvAnqTeVMWowXe7OSksxGkf45h3w/MMQC+m1LXKZDW0KGEMxP77xASXS66pvXzxLZB8MkvpRZcvMiSLn4FZVuCi6tuBxdXZbHL4tIptrxJNrGy/mOcGaIrGu8RazvAl1QORFpdSXRVg14wpexZJL1mIqu+9wDOuAk1zXbJjFbXzocP+UJI5QqhRZXfhBdXsD4o6JNeO7u6REaG2zuvuLdgeALiq5ufJzJaPDKbmljJ0TObuvamNXZrklsHWdIosarzdEZzr0ZKbasYkcFgJWTHEVBUtJpIY5jG0JveJRCTkZHhtogpaE4ZeQTBFV13CWnkRa3L7PTEwVfaP456dKHV+3bHqFZj2mXJyqCfBRjnYGuhGrYuWw7dVKAMGwuUYFOBEmzJV0W3ZKq9FWr2BcPxQtTyYrGbT206635Ykug/jT79y2IeI2Ux+j7CmQlXPtl/hxXXKMZUt4yHFFe2h1ErUrLbB8Tx40Rq7Yawosq6sKJqf3ZZ/E2Lqao7Fl9buzmptPWj+JqWxiBKaU8QubQ/ury+Lb6i3i+UWhEfVlRhlVrWw/ryT0x57aHk2g6v7Ob+oyFUukAErbaHSK9hLctmJ7nCjXyeWSS/mKomRkJ1S1B8Tc1xmJtux9d2bk5r6hFMYjDW4r/bbz1fH1PRmB9ELnvmm0tRYV9bclHz6viKJvOE8gYh9jEbInG5XSrtkl9pJ/jRW0JYKWjmJVrHMV//8htu1iAMMzDzixUgWhYCBwvsYXuG9ttteeoz2/I1kW3ZmjPbszRm9ubpISLNXmB8hwSW49SXTuMVfviybrwNdkTA3wbsDkxuvrA6vqzheGJV8+n01l6ZzNou1vc88OEjub7tQFx5w2zShnkMiQMfbnDmyO0aPpPZ3HUouqpZJKm8hZWR7F35OaQ3dJ9kSaiJCZ7MroFD2Z2zH997N8QCcWlybfMhYh7tXcqY3wOeGSS0qMreL79o1D2HrMg+jkvZ2LImcVxaso/hQ6dLbk2KR34Nmdp/a+u7RuYPZ0Ti0ojeERnihcuB59rqhi3by0C/jQKqdWmg3JIECh3RINcTwSL5TiJoj6SC2XgB6HUnXfN63NDmd7Mpit3m38n98W9XdSycIS2Oxcvg34jFt4tZcP/sLOu3s8jfKse4qYBAJvMv/CL2YnUJuF64yJez2XoWXj6if6Q4ZOgC6lhf+73X+bbnPhc7nrsMNz63HSh/bjlAem4xWPDc5gLlue0I9anfg9Yvol4MPw6ZbFXA9TacsefNhhftlw8R/5aR/gT+sP4iU/M/LL8QizHD/+CaF8O7Nol9fQf9z49I2DXUnAwcaj8SPjZ0xG+k86hLb/URh14qi1yGSo+4D1YeJj7sP5r78u7BXyW+YNmv/m/3+UGC/fAWPkR8/zcPdR7m18G3vyd15rfze+39u3PNx+y5fpuVZDGpwHJv4BLpT7b9fwEu1d73Jecc/A9hxMAzv03w4LO5f6XQIc/+XnhsbvXwQibmgAMO/gOwRf/Ct2n+8T9Dv4PfXaK9sP6foT/CwrILaSH+6L8/gXdD5sI2Fjv2YQMXxbhzFU8BPF9nwPUNAoHMI0gg8AgKCvIIChJY+3g5Ns3+N/c/gfArJ+389vF2Fjp/8eOshObsdv4kLeqamcsiyzrPwuubI/zaFup5+Aeb2fe12Izy3wF38bD7aP5MET/Xv653cf3wQ8ISXDFd7K1ZaOH9T7GYvvD/txKK3zPOZIvd91yy9t8o62ywIhEWY+Q/j0WjKT4YBJTUH7BJIKl65lVKsvNKG/qkr3DOpMlKO/gqHVQ1UDhr7qSo4RKsaEVMUXSKzVC0CktU1HYPVhQ1dlI8rWOvoO8bp3IupoD9EeJ3H64TNfRZEVLaKZM9cFmZ2Nk5+1lPxh3ejIau7Y5JFFEd3zgVWRtfBVFzF0VRK3dFSStvFomauysKm56Tl7RyV5S1D1DQ9SAq24dkKfjnMRY1TrrGFu1xSaErO8RTlVxSyIreOaWKxsEpiqe07RT3Kegr6gXFnMTdMfPr6AfEHBCz8lJxTCyQ73n81e9+DJk9+5x/jMi4wxta2S1sSsxTVfeIVXWMKxBV9Zj9DouMje9hebtQNXWXaDm2++VDHepY0qig/dZ6Ute4mFFIUqt+aOqUWWTmVyaBcWq4Z94nq8TVJb3kZ2Fzl1e7ZdR/Pmvk8ErXO/KVc0LOK7e0gld2UWmvtN2DX53Rtfplv6LBL3qByW9to3NK2O3L2BBZfjs9nwRVQmbpD5E1XW8CSeW+c3mpl2W39Km6pxffto3Nf6PmEvqLglPgK2Xn4FdqrmFzFP5K3S38lcq5kFeSVh6/yFn7vjZwj/7ZI56U23D55q++rJRS1y/gm1vZ4JlZ8do+lvTKJiLrF/uY3FfaXlG/iJq5vlIgBL0xD0upbb/9jyPFI9c2p5Y1bKH1jorK2ni0COjZvdXyjHzpk05Nze0YOVg+Z11/h3nSqWB0dH1R84XV+H5SQ+eumJre67ZJxVMa3vFT5mHp1zQJvptGH3z9sa5HTL+Ypd+UIiH8n26p9MTBp6/YzL8kvnZkc2rPDZab6L0G23KbUdn3cWLdQPu5tKLPTqibTO+T14aTWuag5xH8NKak5mYEuWLaOjINDinrwabTknBKywQMfcPAOT4DXBKywCIkBpRs3eATaTXYeFISVN3CwSwgoWH+uV5g2MZzyZRUZZdQkLfzBfck0svsmq4Q/L/ClvMSQdn0zz3TqGDgFQG67qGg5xkGxn5EsAyNB3tiKjhEZ4CBdzgIapnDdgEpOCGnD+5xeVOplW3u888TWdJQGFPRCYSYPNBxCQUJIyc4q20FZ7UtQc3RF/xzaBCcSyMVNA64pFQ0XXGOSr2m5+r/8JiCNrr6oCDsFJQDUR2zlw5RqQ+C88vqSgcnWV8rwoFbwPGtj0/6iojSlqaI0uZI/HdObcu+hKr2z2yic0HC0hOkrdyvKxoZra0euJbsGJUDO4RU4aweAXxyql+lMc4T8DrBZd37w+jdl8LpnZb4b1zH+r1h9C8PI+KsQzSCXCMUW9kFtnF5sOGYILZsx76ZjcfOoMr2buCbnv9NVm1rqVN4fKO6vetLCQNLVMbUZtrEKwCxCY5CrALCESM3P0TFwnFGXNd0RsbEesbMJ+yOb3K+Cfs8+FDwOYatCMyt8rYOToHjsnoga0gAY5fQL01cgjKjc0rrYvPLv3OLTGPqOXpNa1g5IxpWBETPyX3aIyaJGZVL+SYik1TmQUy4Ia1ryuRaufnN7mOiU+E5NMiqxL9i9C/ElrXaJZQ23/ZNzJ/RtvGY+fiM9Mz6j49NC6nooM7B0d9lVdRlVnWeT8mg1zzwjEsHBVM7EFTWhV3HzwLXqg3I0nXb0O3Hz4K4oRWY+EYCISqj0Tsu450vMbmqd4dXVkWOBTEbLIhZ3zvFF5g3jo9vzKhqG7X0j4KTKoZwUtlgQFNTk7+s+2KtS1QWcG/55OVBKe3pMHIDpFR32Wq4BK93z6hocc9hgFlIpvNsH/3WePregD2zCs0gbfdMJWfquPh/cUhGhbnuwLGZ/ZLyTMvAcPCMSy7Ah6CqrtFj8cUVT31Tc0D3nMe0iacfauEbzDT1CmQaungzNW1dZix8QiAirwjSSqs88HbxzmFZjeckH73z6icxJEazvp3va1lNKzB2CgZiViUU1Q9CYn4lmDv7g5y2OchomqCymsaIkr7ZjG9MIqQXlT28fP2eHL2xvcLaMwB41m2dFpRRQ3MqWoBU1xU3/54qR2+tTyltyE2k1oKtdxicEJdn7jh0gimvZwT+0fE/ZlGL07NLysaJGTkgoqQ6vf3AkeljIhLIvuOnmSu37ISdh4/DISFx5o6jJ1+fVtEDLYLvD4ZugayPI+NIrumXi2cMgqSNH4haeIK+T1wLPjzn1bZ324ckgLCmGQirG48qKSmtpLcPUewCooF/x6GpU0qGWHheObPlwk0dVWtvZbOwTJC08p36SExdA28Xj4t6r/WmeTOnpa7RKQx9Vz/YdUp4SkrfDI2h0v+ZV9dohv9JZrRKJlDoz85FxIGapT3TyicI3KMSwDMmCZyCo0DLxhnTsXeFgKQcLJFa5XcHgB0qMZv5bU5Rza7sdCGmUr/1Ck555uQZNR6RRPk0nVTzqW9Y6ksFLQsQltMCaxd/IPiEgaaxNWZk4wxe4TEvyhraghp7z5939AmCVVt2IxLKOmg6ve4lvWPI693N4MNk29ABYnZplW9MNuhaEeCokARz16HjcEJUAoztHLDAqFjUKyQMdMwsmKclpDABEXHQs7ACKRU12PbxARBTUAZDG0eQ09SfFlUzADkj26cyZjaH2e0XtV05HlvRdVna2mfqmLo1HFezoD18+HBNfnXbmF1QLJxVNQLROUYq7xgscgqKhTV7jk0LqxthUfmlUN13ucTEKyzjlKbFzEktm5mTama6eLvvPSOxvd541F5iSXWdfUgsHJNWAnUbx5kEamkWLo3CcgrkEyilz2y9g1EFPTOmvu05pn982tvs0qq3pKr6qaT84jdOPqEzasY2mI6lMxqRUfTPxMKqpPTa2hU4E3l4ZPPh7Zv5R4uFZJY+Sqc2YvEpFA9RUdEVQcSsjwIDk3bZuYa0ahk7gbKuFZpOqpyh1XVOE7xCmCIyaqBjZocWllb/VNfe99bUzoW5+eOjIKquj/gl5hRc/Owfe+bfT/XIk4MBifnVps7+cEJCATZ+tJ+5Ydc+2HXwMAhKyYCJnQM4efngzIMJyciCiJwCuPoHgLGtPRwRFAIdU3PwCgoHew/fGT0bF1A2tPtMTtuCNQNVVfXgGxwEbq9E2l4lx6DzKoRwENNx7KK1DBhR6rtuW3qHYSKapiCpYzGqpGS5srJrqMg5LAE27BdAzijpYsGphUBtPf/GISzpn0fl9ZlyVp6InnuYEd42y/b0vg5tOObsR1ytExP8OYz2VteYFDitpAmqVg4/hWbludePjIVF5JK+MzznBTKahpiTdyjEZ5LG2gcveVy59zjg6t3HEaNX7zgXlzfSYlLzEH0LZ1DUswbX8BQsubiuntrSz4rxiavvI3hkl30lZ+oKkirmaFhs4Vj34A1WFOTD77E1jh6R/ZaEYNA2dbydSakyaz9/WcPJI6RNWdsClLRMIItSDrWtfWBqcw7ddugkCGsZzjjHpkdiGMaaObE/0odLwsh0SgAhMAYOCUkD77rN6IqNW2HTR/tASFoWPINDmHkldIyYkgZqBkYgoaQCfhFEsDnnBkfPCoGuuSUEEuPALSBsxsDeDeR1LZ+dlTNkMZKSpeW7GZZtZHaTrkcc6DuF/kyu67vA6LsUomzm0Kdh5wEKJg7Dgpqa/DV9F4pcIpJh04FTiJCaIRaaQQZqy3mwCYyF0xoWYBuRCT7pVJay/Uc2q/cCbEbC0xnn1nc3uMamgbCGHmjYnfvOIybJuLJ/2Dk0M29CxcxmSlbTEHX0DIKAyKSbQdEpCQFRiel+EXF5XiGxMWEx6c1BkcmoprEdJiitPm3hFvwsldaQXtrI+nTUkpi6Lv0gat2krksobP5YEFXVdwQnT+IzO5eQwNiMknJHz8gfzR0DQd3Qrp99bUZWbrGGlm6gomOOxKTkzVTUdWLm9u7o5v3H4KyWAeKRlpvxLYaxFGFc8uFx3fh+ZFqhhXtYIghIKsHqrbuQ1Vt3wrodu+GMpAwERsVAVXMr5FBLwNDKFqRV1VmMZEk4BwdOngItY3MWIzn7Bs9oWjiAlIbxs7Ny2ixG0iQQWIsG0msvbYgobr5pE5kPquZeEJFViiQWVZcomNgNq9u4g4KRHYuR6gbHi9yiUmHzwdMIPrR5x2dBdEEZqk3wQ09rWiCu8QUXSzovsqI18ev/IBip8yHGl93Y2+edRgIxHUPQI7j/aOEdIoX/F51ToBaTVzRj4xkIKnpmiK6FIxjbuoKRjQsY2pwDYzt3MLR2ARVdc6ayrgXiFZEKPsRUVhz3XOgIy46UVtpxMIZSN2rtEQVnJDRAWsUY/CMzITq1GGxdQjE9C3dQ07cb17Pw3o53qom1W76uKQHU9W3QxEwqs6apF0xtXdG1Hx2E0xo6iGdqVurXGMaSeLOunVkrvK1nsI0JwRdOS6vAniMCyI79h2Hdtl3w8TEBMHd0gtT8QohNy2TpRrLqmuAbHglmjk5wQOA0aBqZg194DDh6BcxomjuCjJbpO0YyNPRhxVuTJyb4k2r6sswCUv9xTEpvWtXcFSWEJYGsoQ0Iq5uAlJ7lqJGR66qGwfFij5h02HzoDHJEShXTdvAEQ5eAaSljRxBQNf6SQMzUxRV11oN4n5kIx3xGym0aYHgk5c5I6JmApq3TD9pOrqzVIZkl1SbZZXWob1QyGNmcQwysnUHPwhHTNbPHialr5oDpmTth+hYEphXBF0nMLYPE3FLS3ClwSzDr81P4D0br6Efkis7B4JjcKTM7b2Z4QiEzJrUItXMNnzGw8gI1fYeLkhrmrJUc5g6emUZW7qBhYIsmZRYxa5r7wdjGFV21az+cwRkpeT4jGc3GFHFxcWlZOttqmBFAVEkHhORVkKOCIrB5917Yf/I0SxeKTk2HiMRklkRS0tFjMZKFEwEOnhIEdQNT8A4lgoOn/4y2BQEUdK2eiavMDm24Lw4/Dy49Bp8+Xa5hG5iiYuUPpxQNMEEVfWzPGSnklKI+yOjbjODT/4aBsSKvmAxY9/FxZOPB09hBSRU4rqCDypi7g7K9zxMlS8d9rHZn3TTvN9iBXvib0XH9sYSus0+3jKkNaNgTvhXV0WFNe6PyqXZRORTUzjMYVPTMEVV9C1DTt0TV9C1mVHXNZpS1TGdUdCxRbSNbppH1OSQoNgdCEvKL2a4EXFrMOkJnf//4I6y194ioJPjGQWhc/lRCdukbJ++oKUMbX1DRdxji4uJiDVHWzn6JxrYeoKhljsamkpnVzf1gYueGrttzCES0DGa80/JTnswxEnvG8yPAWmtvYpqykT0o6JqBrqU9Kq6gCts/OQjHhEXByMYeQuMTISQ2HgysbEFeUxdc/YJYSvgRQWFQ0TUCF99gsHDymNE0sQclA6tnctqzjISvOGENoUazK2ujcmvi40s6QM3KEw6KKzLX7TsxLaCgBwomjsNcXFzcDYNjZK/YLFi1+zDCt30/tuW4CJxRMwavtBKIotZ9FZxXxvocPHFuSH6vMd9xmlXXY2nkFX7vqJwqqmJDeJNSxqj9EmCThp3dSUJo9BslI2s4I6WCqOhbgKWzN5zzi4RzfhHg7B0BDu4hoGfmyJTXMEGMHXzB1NmP+u4c86QFjszSFn0lQ8crIgqGTK+wVIxS0wfe4ekgo24ByvqOX6WSagsqm4eTCb5R12U0zEBOwwyLTaNiZfU9YOrgiW47dBok9SzQwJyivM8xbCe7XRyR+TUejiEpL1SMHZhaZo6IpbMXU1pNB3YcPIYdFxZHtYwtMI+gcPAMCgdVPWMQEJVC1A1MESkVTWzvsZMgqqACaobmTCllnTeSyvqgoGP+SEHX6iDeNs5IuKOWPYSmV3YLp5d1edoHJhSoW7v9eEhcGY5IqYGUrtWVgvLmQw2D4zWuxDRYtfvI9MYDpzERLQuQNXaoCsgo8cqq6z0XklW1FZ8k4Euy3mv9iO2AxMf8lJYR1cCC6nsGPpGw+djp1yI6xkhSRR1Q23vT3aLi3fScPF4LKmiBhIoe6hOZCCmF9JcpJPpAcm5RZ0pucXtqXtm1yMRc1MDaDVMysANZHSvy3GmWGBnNvnH4+SoGrlilFDX+U0TFDA4Jq0BkRgmSQ2vu8AxP+4e8rj2cldPDAuIKIS63EnStPeDwWSVEzcgRScotR6nVnZiutRu65dBZENO1eOWZnOcHAPi6tXcPwcI7ttrcJw5UTAmIrVcE2HuHgYSqDhwVlQE5LUOQVdfDdMxsEWMbAiKjroudlVcDMWVtOCgoDpv3HYYDp0XguJgMHBdXBHVTZzC09/7R0NaNJZnZ9zF3L6wXA8Mwvq6rD6KIOaU/Kpo4wUExJVAwtv+KVNNWVNE7es/aPxo2HTo7c1JRDyNEpEF6RbMTu40PBuwQkRBqiwCxeuBrQgad5Uc7KKsGJ9X1QNfNF4jUcogglyKyRjaw95Q4Jq6iNxMQl4HF55Y8CU7MJfhGpxj5x6XoJefQ0mPSyVN61q6YtI4NSGpa0tnnwWdT+MJFn3Sag18G7bWhSxjsOiHD1LEPhMLavpaenhsrvaNz05yCU0FS2wZUzNxB1dwNJLVsQMHQCZyDkyGFWg+RaSUgIKExtfGwMKg7+EzZhMQr4O3jUQVsZhLWtqvUdokEa99ozDMy7aW1R9gbCTVDkNYwfGPu7PNSzdgWlPQtwfycL1i6+oOSodULBT3zF0dFZKfWfXQI23tCGD0lpfJKREnvcyOC/zMn/+gxW89w1kcIcamKR0IYesUccovPNbcNTLDxjs3NjiPVvHGNTMdOKugiGw8KMgWV9TDP6HTwScjBhDVMmKv3CSCHpdRRvXOBmHNESou+vZ80F9c63P61h2vrob0qTqHby95n563gnIi2jMk5aZtU9L2KVzSc1DJFpM0dmeLGNkwpM3umVVgcZk9MBnF9K9gnJIsdEFJABBV1MGFl/ddn5HUfnlXSvyumbvCpnI75FxKqhjMfn5ZGRDWtQMGQUDb/XMGkWl+76DzsmIo5bD0uzVS28AFbv8Qeetsl1tBEqu0TC00vueCbVASE0EymtW8cauOfyPSIycPCssow/yQypm7lDev3C709Iq8HnimkqeiiahYjGfr4rGAPDXvEdUttwvMhvaLjs9SSuiDjc4GX9J0CQMfa9Wp0RnHwuaD4J+auQRCSUgAZdMZTe69gseCEPBElI9vz+0XkMUldsymnoJhCt9C4s/q2ngfcw1L3EYkMXrY7yTkm/aRJQMK9U1r2P6w5KPGPj86qvjkqqw97ziow+fcKIMu2HkDX7j+N7ZdQhX0iStiaA4Ioz84j6Io9J9DNx8TQPcLKb/aKq3+xSUD27joBmU9P6jndNw5Ia6i89ESY3VcLw1T++pi7YO2A5NWyToEaJ/XsLU5rm5kqWJ0zlzZxMBc3trGQMbE10nD2srYNjmvyiMsB7yQSOIYkAyE8FbwSCsEniQQ+iQXgHpUJhNAUOBeRCbb+cQ/sQ5JZpv/ZWRssDS6oFCQkUhi2xDzQcAwetvJMOOcUmMgaMnBFHB8iMspbz8QW1FqFZZabecXmmXnGF5gHpRdbBqcVm1n6RlkYe0XfdE+vAPOgpB8CsksciztHNuOdzlZ+cWw7qypkHZThWNl3TbHn4uMtQZn0oeLeGxCUVnS5Yfju9rBUiryNe6htaEq+dXXPBWV2PduAmOTgwmoIL6yEtIoWlqF0Ptg6XkBR0Q7XxEKGRWgmGAVmgIFPIuh5xoCRbywY+8eDcUA8mPrHgZFfNBj5xYBpQAKYBiaCkU8M6HkSwdA3FizDM8GKmAc2cRSIqB4Gz4zyYdrgHTy85DexTh8c+u9/IUBqHkjOre8lZVS05qaXtuQllzTmJBTX5cQUVOZE5Zdnp9Fb8vMYfYUl7aP67O+1scJ054bQwrZLO3NbL+Z23v7y3QOcdej+OUUzpqRdP6tlrCyC2vgudGSxhY3zkVnZ40zrvV6aVNKC1/ltRKbMbGoal9hs8cz6AWpuy/kUn/RClpTEl3MvFjl64d7zHdElLaFx5V0FkUVN2THFzfnx9Jb8+Iq2/EQWteTHlzX/i+jN+bG05vwoal1+OKUmN5zCyI4qacyMr+zJzGm/UpBU3a+Gt8uyuf0HYb5/JSzBfT0skpHhxh2Is1sZ1jH2tP2/wW/eNJYk+fX6evb6svmEnx/fLgzLXSxSkQUjo2V4nd/LxcS+t/m2rb8C3utZ26+A38jsg2Hbe3BiH2PZmv4Dmg/26pGF9A5s5phPeB32dl7539SdB9Y1z3swC8432w7e5u88vMWOLYaF9/Hf0N8HeKfjb/DvES4x2PtzkuI3HcRuY1FJ8icwx1z/p6B7vOycdPvDOuxrm5V8izLYO7Cl5/+C/pv+4IADDjjggAMOOOCAAw444IADDjjggAMOOOCAAw444IADDjjggAMOOOCAAw44+Cvg/wEsSzbqbFQaZAAAAABJRU5ErkJggg==" alt="濉旀渤绉嶄笟">
+ <div class="hero-name">鏂扮枂濉旈噷鏈ㄦ渤绉嶄笟鑲′唤鏈夐檺鍏徃</div>
+ </div>
+ <div class="hero-banner"></div>
+</header>
-<div class="wrap">
+<main class="wrap">
<!-- 鎵嬪姩鏌ヨ鏍忥細鏃� code 鍙傛暟鏃舵彁绀鸿緭鍏ワ紱鏈夊弬鏁版椂鑷姩鏌ヨ -->
<div class="query-bar">
<input id="codeInput" type="text" placeholder="璇疯緭鍏ヨ拷婧爜锛堣鐮� / 鎵樼洏鐮� / 鎵规鐮侊級" autocomplete="off">
@@ -191,22 +286,86 @@
</div>
<section id="state" class="state"></section>
-</div>
-<footer>鏈郴缁熸暟鎹粎鐢ㄤ簬浜у搧婧簮锛岃閫氳繃姝h娓犻亾璐拱銆�</footer>
+ <!-- 鍏徃浠嬬粛锛堝父椹伙級 -->
+ <section class="sec">
+ <div class="sec-hd">
+ <span class="bar"></span><span class="ttl">鍏徃浠嬬粛</span>
+ <span class="count">鏂扮枂 路 鍥芥湁鎺ц偂</span>
+ </div>
+ <div class="sec-bd">
+ <div class="panel">
+ <div class="pill-list company-stats">
+ <span class="pill">鎴愮珛 2002 骞�</span>
+ <span class="pill">娉ㄥ唽璧勬湰 1.1 浜垮厓</span>
+ <span class="pill">鑷富鍝佺 61 涓�</span>
+ <span class="pill">鐮斿彂鍥㈤槦 16 浜�</span>
+ </div>
+ <div class="company-bd company-clip" id="companyClip">
+ <p>鏂扮枂濉旈噷鏈ㄦ渤绉嶄笟鑲′唤鏈夐檺鍏徃浜�2002骞�12鏈�30鏃ュ湪鏂扮枂缁村惥灏旇嚜娌诲尯宸ュ晢灞�娉ㄥ唽鎴愮珛锛屾槸涓�瀹堕泦鍐滀綔鐗╃瀛愶紙妫夎姳銆佸皬楹︺�佹按绋荤瓑锛夎偛銆佺箒銆佹帹銆佸姞銆侀攢銆佺鏈嶄负涓�浣撶殑鍥芥湁鎺ц偂鍏徃銆傚叕鍙歌捣濮嬫敞鍐岃祫鏈�6500涓囧厓锛�2015骞村璧勫悗娉ㄥ唽璧勬湰杈�1.1浜垮厓锛岀敱鏂板啘寮�鍙戙�侀殕骞抽珮绉戙�佸閲屾湪澶у绉戞妧鍏徃銆佸反妤氫赴鍜岀涓氬洓瀹惰偂涓滃崟浣嶇粍鎴愩�傛棗涓嬫嫢鏈変袱瀹舵帶鑲″瓙鍏徃锛屽垎鍒槸涓昏惀鐢熶骇銆佸姞宸ャ�佹壒鍙戦攢鍞啘浣滅墿绉嶅瓙鍖呰。鍓傜殑濉旀渤鍕や赴鍏ㄨ祫瀛愬叕鍙革紝浠ュ強浠ュ啘浣滅墿绉嶅瓙鐢熶骇銆佺粡钀ュ強鍐滀笟鎶�鏈紑鍙戙�佹帹骞裤�佹湇鍔′负涓荤殑浼藉笀濉旀渤绉嶄笟鍏徃銆�</p>
+ <p>鍏徃鑷垚绔嬩互鏉ワ紝濮嬬粓鍧氭寔浠ュ啘涓氱瀛愪骇涓氬寲缁忚惀涓虹洰鏍囷紝鍏ㄥ姏鎵撻�犫�滆偛绉嶈兘鍔涘己銆佺敓浜у姞宸ユ妧鏈厛杩涖�佸競鍦鸿惀閿�缃戠粶鍋ュ叏銆佹妧鏈帹骞挎湇鍔″埌浣嶁�濓紝鈥滆偛绻佹帹鈥濅竴浣撳寲銆佲�滀骇瀛︾爺鈥濈浉缁撳悎鐨勭幇浠e啘浣滅墿绉嶅瓙缁忚惀浼佷笟銆傚叕鍙告嫢鏈夊己鏈夊姏鐨�16浜虹爺鍙戝洟闃燂紝鍧氭寔绉戠爺鍒涙柊鐨勫師鍒涙�э紝鍧氭寔鑷偛涓轰富锛屽悓鏃堕�氳繃寤虹珛鑱斿悎鐢熸�佽瘯楠岀珯锛屾煍鎬у紩鏅猴紝甯稿勾澶栬仒涓闄㈤櫌澹�佷腑鍥藉啘澶с�佹禉澶с�佷腑妫夋墍绛�12鍚嶅浗鍐呭惈鍗氬鍦ㄥ唴鐨勯《绾ф鑺变笓瀹跺洟闃燂紝涓庝竴甯堝啘绉戞墍寮�灞曚簡杩炵画鍗佷簲骞寸殑闄紒鍚堜綔锛岃В鍐充骇涓氬墠娌夸俊鎭拰浼樿川绉嶈川璧勬簮鈥滅煭鏉库�濋棶棰樸�傜洰鍓嶏紝鍏徃鎷ユ湁鑷湁鐭ヨ瘑浜ф潈鍝佺61涓紝鍏朵腑妫夎姳鍝佺46涓紝绮鍝佺15涓�傚嚟鍊熷湪绉嶄笟棰嗗煙鐨勭獊鍑鸿〃鐜帮紝鍏徃鐩哥户鑽h幏鍏靛洟鍜屽浗瀹跺啘涓氫骇涓氬寲閲嶇偣榫欏ご浼佷笟銆侀珮鏂版妧鏈紒涓氥��3A淇$敤浼佷笟銆佹柊鐤嗗悕鐗屻�佷腑鍥藉悕鐗岋紱鍥藉銆佽嚜娌诲尯3A绾ф爣鍑嗗寲鑹ソ琛屼负璇曠偣浼佷笟銆佷腑鍥界涓氫俊鐢ㄩ骞蹭紒涓氥�佽嚜娌诲尯浼佷笟鎶�鏈腑蹇冦�佹柊鐤嗕骇瀛︾爺鑱斿悎寮�鍙戠ず鑼冨熀鍦般�佸叺鍥㈤鎵瑰垱鏂板瀷浼佷笟銆佸叏鍥藉啘鍨﹀啘浣滅墿鑹灞曠ず绀鸿寖鍩哄湴绛夎崳瑾夌О鍙枫�傝嚜2020骞磋捣锛屽叕鍙告鑺卞晢鍝佺瀛愰攢鍞繛缁綅灞呭叏鍥芥棣栵紝2022骞村叆閫夊浗瀹跺啘浣滅墿绉嶄笟妫夎姳琛ョ煭鏉块樀鍨嬩紒涓氾紝2023骞�1鏈堣崳鑾锋柊鐤嗗啘浣滅墿绉嶄笟浼樺娍浼佷笟锛�2025骞�7鏈堣崳鑾峰叺鍥㈠垱鏂板瀷鍜屸�滀笓绮剧壒鏂扳�濅紒涓氱О鍙凤紝2025骞�8鏈堚�滄満閲囨鏂板搧绉嶉�夎偛鍙婃彁璐ㄥ鏁堝叧閿妧鏈泦鎴愬簲鐢ㄢ�濊幏寰楀叺鍥㈢鎶�杩涙濂栦竴绛夊锛�2026骞磋崳鑾峰叏鍥芥鑺辩瀛愯偛绻佹帹鐢熶骇缁忚惀A璇併��</p>
+ </div>
+ <div class="company-more" id="companyMoreWrap"><a id="companyMore">鐐瑰嚮鏌ョ湅鏇村</a></div>
+ </div>
+ </div>
+ </section>
+
+ <!-- 鑱旂郴鎴戜滑锛堝父椹伙級 -->
+ <section class="sec">
+ <div class="sec-hd">
+ <span class="bar"></span><span class="ttl">鑱旂郴鎴戜滑</span>
+ </div>
+ <div class="sec-bd">
+ <div class="panel">
+ <div class="contact-item">
+ <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></span>
+ <span class="txt"><span class="lbl">鍏徃鍦板潃</span><div class="val">鏂扮枂闃挎媺灏斿競鍗楁偿婀惧ぇ閬�1865鍙�</div></span>
+ </div>
+ <div class="contact-item">
+ <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 1.9.7 2.8a2 2 0 0 1-.5 2.1L8.1 9.9a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.8.6 2.8.7a2 2 0 0 1 1.7 2z"/></svg></span>
+ <span class="txt"><span class="lbl">鑱旂郴鐢佃瘽</span><div class="val">琛屾斂绠$悊閮細<a href="tel:09974615802">0997-4615802</a></div></span>
+ </div>
+ <div class="contact-item">
+ <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5 12 3l9 6.5V20a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9.5 22v-6h5v6"/></svg></span>
+ <span class="txt"><span class="lbl">鍏徃缃戝潃</span><div class="val"><a href="https://www.talimu.net" target="_blank" rel="noopener">www.talimu.net</a></div></span>
+ </div>
+ <div class="contact-item">
+ <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.4 8.4 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.4 8.4 0 0 1-3.8-.9L3 21l1.9-5.7a8.4 8.4 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.4 8.4 0 0 1 3.8-.9h.5a8.5 8.5 0 0 1 8 8z"/></svg></span>
+ <span class="txt"><span class="lbl">寰俊鍏紬鍙�</span><div class="val">濉旀渤绉嶄笟涔嬪</div></span>
+ </div>
+ </div>
+ </div>
+ </section>
+</main>
+
+<footer>
+ 鏈郴缁熸暟鎹粎鐢ㄤ簬浜у搧婧簮锛岃閫氳繃姝h娓犻亾璐拱銆�<br>
+ 鏂扮枂濉旈噷鏈ㄦ渤绉嶄笟鑲′唤鏈夐檺鍏徃
+</footer>
<script>
(function () {
'use strict';
+ // ========== 椤甸潰鍙厤缃」 ==========
+ // 鐢熶骇缁忚惀鑰咃紙杩芥函鏌ヨ鍖哄潡灞曠ず锛�
+ var COMPANY_NAME = '鏂扮枂濉旈噷鏈ㄦ渤绉嶄笟鑲′唤鏈夐檺鍏徃';
+ // 杩芥函缃戝潃锛堝缃戣闂湴鍧�锛屼笌鍖呰/浜岀淮鐮佷笂鍗板埗鐨勪竴鑷达級
+ var TRACE_URL = 'http://1.95.78.124:9008/';
+
var STATE = document.getElementById('state');
var CODE_INPUT = document.getElementById('codeInput');
var SEARCH_BTN = document.getElementById('searchBtn');
- var BATCH_STATUS = { 10: ['鑽夌', 'gray'], 20: ['鐢熶骇涓�', 'blue'], 30: ['宸插畬鎴�', 'green'], 40: ['宸蹭綔搴�', 'red'] };
- var BAG_STATUS = { 10: ['宸茬敓鎴�', 'gray'], 20: ['宸插鍑哄嵃鍒�', 'blue'], 30: ['宸蹭綔搴�', 'red'] };
- var QUALITY_RESULT = { 0: ['澶勭悊涓�', 'gray'], 1: ['鍚堟牸', 'green'], 2: ['涓嶅悎鏍�', 'red'] };
- var WORKER_TYPE = { 10: '缁勯暱', 20: '鎿嶄綔宸�', 30: '鍖呰宸�', 40: '璐ㄦ鍛�', 50: '鍏朵粬' };
+ var FLOW_DIRECTION = { 1: ['鍏ュ簱', 'green'], 2: ['鍑哄簱', 'blue'] };
+ var FLOW_BIZ_TYPE = {
+ 110: '閲囪喘鍏ュ簱', 111: '閲囪喘鍏ュ簱鍙栨秷', 112: '璋冩嫧鍑哄簱', 113: '璋冩嫧鍏ュ簱',
+ 114: '鍏朵粬鍑哄簱', 115: '鍏朵粬鍏ュ簱', 116: '鐢熶骇棰嗘枡', 117: '鐢熶骇閫�鏂�',
+ 118: '鐢熶骇鍏ュ簱', 119: '閿�鍞嚭搴�', 120: '閿�鍞��璐у叆搴�', 121: '澶栧崗鍙戞枡',
+ 122: '澶栧崗鍏ュ簱', 123: '鐢熶骇娑堣��', 124: '浜у搧浜у嚭', 125: '渚涘簲鍟嗛��璐у嚭搴�',
+ 126: '搴撳瓨璋冩暣鍏ュ簱', 127: '搴撳瓨璋冩暣鍑哄簱'
+ };
+ var SOURCE_TYPE = { BAG: '琚嬬爜', PALLET: '鎵樼洏鐮�', BATCH: '鎵规鐮�' };
// ========== 宸ュ叿鍑芥暟 ==========
function esc(v) {
@@ -225,8 +384,18 @@
return esc(String(s).replace('T', ' ').replace(/\.\d+$/, '').slice(0, 16));
}
+ function fmtDay(s) {
+ if (!s) return '-';
+ return esc(String(s).replace('T', ' ').slice(0, 10));
+ }
+
function fmtNum(v) {
- return (v === null || v === undefined) ? '-' : esc(v);
+ return (v === null || v === undefined || v === '') ? '-' : esc(v);
+ }
+
+ // 琛ㄦ牸绐勫垪锛堟暟閲� / 鏃ユ湡锛変笉鎹㈣锛岄伩鍏嶆暟瀛楄鎷嗚
+ function nw(html) {
+ return '<span style="white-space:nowrap">' + html + '</span>';
}
function statusBadge(map, key) {
@@ -235,25 +404,44 @@
return '<span class="badge ' + item[1] + '">' + esc(item[0]) + '</span>';
}
- function card(title, countHtml, bodyHtml, opts) {
- opts = opts || {};
- var collapsible = !!opts.collapsible;
- var open = collapsible && !!opts.open;
- var hd = '<div class="card-hd"' +
- (collapsible ? ' onclick="this.parentNode.classList.toggle(\'open\')"' : '') +
- '><span class="bar"></span>' + esc(title) +
- (countHtml ? '<span class="count">' + countHtml + '</span>' : '') +
- '</div>';
- return '<div class="card' + (collapsible ? ' collapsible' : '') + (open ? ' open' : '') + '">' +
- hd + '<div class="card-bd">' + bodyHtml + '</div>' + '</div>';
- }
-
function kv(k, v, dim) {
return '<div class="kv"><span class="k">' + esc(k) + '</span><span class="v' + (dim ? ' dim' : '') + '">' + v + '</span></div>';
}
function isEmptyList(list) {
return !list || list.length === 0;
+ }
+
+ // 鍖哄潡锛氱豢绔栨潯鏍囬 + 缁嗙嚎 + 鐧藉簳鎻忚竟闈㈡澘
+ function sec(title, countHtml, bodyHtml, opts) {
+ opts = opts || {};
+ var collapsible = !!opts.collapsible;
+ var cls = 'sec' + (collapsible ? ' collapsible' : '') + (collapsible && opts.open ? ' open' : '');
+ return '<section class="' + cls + '">' +
+ '<div class="sec-hd"><span class="bar"></span><span class="ttl">' + esc(title) + '</span>' +
+ '<span class="count">' + (countHtml || '') + '</span>' +
+ (collapsible ? '<span class="caret">鈻�</span>' : '') +
+ '</div>' +
+ '<div class="sec-bd"><div class="panel">' + bodyHtml + '</div></div>' +
+ '</section>';
+ }
+
+ function table(heads, rows) {
+ var h = '<div class="tbl-wrap"><table class="mini-table"><thead><tr>';
+ heads.forEach(function (t) { h += '<th>' + esc(t) + '</th>'; });
+ h += '</tr></thead><tbody>';
+ rows.forEach(function (cells) {
+ h += '<tr>';
+ cells.forEach(function (c) { h += '<td>' + c + '</td>'; });
+ h += '</tr>';
+ });
+ return h + '</tbody></table></div>';
+ }
+
+ function li(titleHtml, timeHtml, bodyHtml) {
+ return '<div class="li"><div class="li-hd">' + titleHtml +
+ (timeHtml ? '<span class="li-time">' + timeHtml + '</span>' : '') +
+ '</div><div class="li-bd">' + bodyHtml + '</div></div>';
}
// ========== 鏌ヨ ==========
@@ -270,8 +458,7 @@
if (res.code === 0) {
renderResult(res.data);
} else {
- var msg = res.msg || '鏌ヨ澶辫触锛岃绋嶅悗閲嶈瘯';
- renderState('<div class="empty-tip error">' + esc(msg) + '</div>');
+ renderState('<div class="empty-tip error">' + esc(res.msg || '鏌ヨ澶辫触锛岃绋嶅悗閲嶈瘯') + '</div>');
}
})
.catch(function () {
@@ -284,27 +471,21 @@
window.scrollTo({ top: 0, behavior: 'smooth' });
}
- // ========== 缁撴灉娓叉煋锛堜俊鎭尯鍧楁ā鍧楀寲锛屽悗缁柊鏁版嵁婧愬湪姝よ拷鍔犲尯鍧楋級 ==========
+ // ========== 缁撴灉娓叉煋 ==========
function renderResult(d) {
if (!d) {
renderState('<div class="empty-tip error">鏈煡璇㈠埌璇ヨ拷婧爜锛岃鏍稿浜岀淮鐮佹垨鑱旂郴瀹樻柟</div>');
return;
}
var html = '';
- html += buildVerifyCard(d);
- html += buildItemCard(d);
- html += buildBatchCard(d);
- html += buildQualityCard(d);
- html += buildWorkerCard(d);
- html += buildInboundCard(d);
- html += buildPalletCard(d);
- html += buildBagCard(d);
- html += buildOptionalCard(d);
+ html += sec('闃蹭吉鏌ヨ', null, fakePanel(d), null);
+ html += sec('杩芥函鏌ヨ', null, tracePanel(d), null);
+ // 鐢熶骇鏄庣粏鎶樺彔鍖猴紙鎵规/璐ㄦ/浜哄憳/鎵樼洏/琚嬬爜/閲囪喘鏉ユ簮/绉嶅瓙娴佸悜/鍔犲伐娴佽浆锛夋寜闇�姹備笉灞曠ず锛�
+ // detailSections 淇濈暀浠ヤ究鍚庣画鎸夐渶寮�鍚�
STATE.innerHTML = html || '<div class="empty-tip">鏆傛棤杩芥函鏁版嵁</div>';
window.scrollTo({ top: 0, behavior: 'smooth' });
}
- // 鍖哄潡0锛氭鍝侀獙璇侊紙椤堕儴锛屾壂鐮佷紭鍏堝睍绀洪獙璇佺粨璁轰笌鏌ヨ缁熻锛�
function stripUrl(v) {
if (!v) return v;
if (/^https?:\/\//i.test(v)) {
@@ -314,195 +495,207 @@
return v;
}
- function buildVerifyCard(d) {
- var typeLabel = { BAG: '琚嬬爜', PALLET: '鎵樼洏鐮�', BATCH: '鎵规鐮�' }[d.sourceType] || '杩芥函鐮�';
- var code = stripUrl(d.requestCode) || d.batchCode || d.tempCode || '-';
- var bagNo = '-';
- if (d.sourceType === 'BAG' && d.bags) {
- for (var i = 0; i < d.bags.length; i++) {
- if (d.bags[i].code === code) {
- bagNo = d.bags[i].bagNo;
- break;
- }
- }
- }
- var statsHtml = '<div class="verify-stats">';
- if (d.antiFake && d.antiFake.scanCount > 0) {
- statsHtml += kv('绱鏌ヨ', esc(d.antiFake.scanCount) + ' 娆�') +
- kv('棣栨鏌ヨ', fmtDate(d.antiFake.firstScanTime)) +
- kv('鏈�杩戞煡璇�', fmtDate(d.antiFake.lastScanTime));
- } else {
- statsHtml += kv('绱鏌ヨ', '鏆傛棤鏌ヨ璁板綍');
- }
- statsHtml += '</div>';
- return '<div class="card verify-card">' +
- '<div class="card-bd">' +
- '<div class="verify-title">姝e搧楠岃瘉</div>' +
- '<div class="verify-badge"><span class="badge-big green">鉁� 姝e搧楠岃瘉閫氳繃</span></div>' +
- '<div class="verify-sub">璇ヨ拷婧爜涓烘瑙勬笭閬撲骇鍝侊紝婧簮淇℃伅鐪熷疄鏈夋晥</div>' +
- kv('杩芥函绫诲瀷', typeLabel) +
- kv(typeLabel, text(code)) +
- (d.sourceType === 'BAG' ? kv('琚嬪彿', bagNo) : '') +
- kv('鎵规鍙�', text(d.batchCode)) +
- kv('鍝佺', text(d.itemName)) +
- statsHtml +
- '</div></div>';
+ // 杩芥函鐮侊細鎵爜鍊� 鈫� 鎵规鐮� 鈫� 涓存椂鎵规鐮�
+ function resolveCode(d) {
+ return stripUrl(d.requestCode) || d.batchCode || d.tempCode || '';
}
- // 鍖哄潡1锛氬搧绉嶄俊鎭�
- function buildItemCard(d) {
- if (!d.itemCode && !d.itemName && !d.itemSpecification) return '';
- return card('鍝佺淇℃伅', null,
- kv('鍝佺鍚嶇О', text(d.itemName)) +
- kv('瑙勬牸', text(d.itemSpecification)) +
- kv('鍝佺缂栫爜', text(d.itemCode)),
- { collapsible: true, open: true }
- );
- }
+ // 鍖哄潡1锛氶槻浼煡璇紙楠岃瘉鐘舵�佹潯 + 闃蹭吉缂栫爜 + 瀵瑰簲浜у搧 + 鏌ヨ璁板綍锛�
+ function fakePanel(d) {
+ var code = resolveCode(d);
+ var af = d.antiFake || {};
+ var n = Number(af.scanCount || 0);
+ var repeated = n > 0;
+ var icon = repeated
+ ? '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><path d="M12 7.5v6"/><path d="M12 17h.01"/></svg>'
+ : '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.5l5.5 5.5L20 6.5"/></svg>';
+ var title = repeated ? '璇ラ槻浼爜宸茶鏌ヨ ' + n + ' 娆�' : '棣栨鏌ヨ 路 鏈寮傚父';
+ var desc = repeated
+ ? '姝ょ爜姝ゅ墠宸茶鏌ヨ杩囷紝棣栨鏌ヨ鏃堕棿涓� ' + fmtDate(af.firstScanTime) + '銆傝嫢棣栨鏌ヨ骞堕潪鏈汉鎿嶄綔锛岃娉ㄦ剰浜у搧鏉ユ簮銆�'
+ : '璇ラ槻浼爜姝ゅ墠娌℃湁鏌ヨ璁板綍锛屽寘瑁呮湭琚噸澶嶄娇鐢ㄣ��';
+ var name = [d.itemName, d.itemSpecification, d.itemUnitMeasureName].filter(Boolean).join(' ');
- // 鍖哄潡2锛氱敓浜ф壒娆�
- function buildBatchCard(d) {
- if (!d.batchCode && !d.tempCode) return '';
- var status = statusBadge(BATCH_STATUS, d.batchStatus);
- return card('鐢熶骇鎵规', status,
- kv('鎵规鍙�', text(d.batchCode)) +
- kv('鐘舵��', status) +
- kv('鐢熶骇鏃ユ湡', fmtDate(d.produceDate)) +
- kv('浜х嚎', text(d.lineName ? (d.lineName + (d.lineCode ? ' / ' + d.lineCode : '')) : d.lineCode)) +
- kv('璐d换浜�', text(d.ownerUserName)) +
- kv('璁″垝鏁伴噺', fmtNum(d.planQuantity) === '-' ? '-' : fmtNum(d.planQuantity)) +
- kv('宸茬敓鎴愯鐮�', fmtNum(d.bagQuantity)) +
- kv('宸茬敓鎴愭墭鐩�', fmtNum(d.palletQuantity)) +
- kv('鍏ュ簱鏃堕棿', fmtDate(d.inboundTime)) +
- (d.remark ? kv('澶囨敞', text(d.remark)) : ''),
- { collapsible: true, open: true }
- );
- }
-
- // 鍖哄潡3锛氱瀛愯川妫�
- function buildQualityCard(d) {
- var q = d.quality;
- if (!q) return '';
- var result = QUALITY_RESULT[q.result];
- var badge = result
- ? '<span class="badge-big ' + result[1] + '">' + esc(result[0]) + '</span>'
- : '<span class="badge-big gray">鏈煡</span>';
-
- var rows = '';
- if (q.indicators && q.indicators.length) {
- rows = '<table class="mini-table"><thead><tr><th>鎸囨爣</th><th>妫�娴嬪��</th><th>鏍囧噯鑼冨洿</th><th>缁撴灉</th></tr></thead><tbody>';
- q.indicators.forEach(function (i) {
- var range = (i.minValue !== null && i.minValue !== undefined && i.maxValue !== null && i.maxValue !== undefined)
- ? esc(i.minValue) + ' ~ ' + esc(i.maxValue) : '-';
- var pass = (i.pass === true)
- ? '<span class="badge green">鍚堟牸</span>'
- : (i.pass === false ? '<span class="badge red">涓嶅悎鏍�</span>' : '<span class="badge gray">--</span>');
- rows += '<tr><td>' + text(i.indicatorName) + '</td><td>' + text(i.value) + '</td><td>' + range + '</td><td>' + pass + '</td></tr>';
- });
- rows += '</tbody></table>';
- }
-
- return card('绉嶅瓙璐ㄦ', badge,
- kv('妫�楠岀粨璁�', badge) +
- kv('妫�楠屽憳', text(q.inspectorName)) +
- kv('妫�楠屾椂闂�', fmtDate(q.inspectedAt)) +
- (q.reason ? kv('涓嶅悎鏍煎師鍥�', text(q.reason)) : '') +
- (rows ? '<div style="margin-top:8px">' + rows + '</div>' : ''),
- { collapsible: true, open: false }
- );
- }
-
- // 鍖哄潡4锛氱敓浜т汉鍛�
- function buildWorkerCard(d) {
- if (isEmptyList(d.workers)) return '';
- var html = '<div class="pill-list">';
- d.workers.forEach(function (w) {
- var name = w.userName || '-';
- var type = w.workerTypeName || (WORKER_TYPE[w.workerType] || '');
- var color = { 10: 'var(--blue)', 20: 'var(--green)', 30: 'var(--primary-light)', 40: 'var(--red)', 50: 'var(--gray)' }[w.workerType] || 'var(--gray)';
- html += '<span class="pill"><span class="dot" style="background:' + color + '"></span>' +
- esc(type) + '锛�' + esc(name) + '</span>';
- });
- html += '</div>';
- return card('鐢熶骇浜哄憳', null, html, { collapsible: true, open: false });
- }
-
- // 鍖哄潡5锛氭壂鐮佸叆搴撲簨浠�
- function buildInboundCard(d) {
- var e = d.inbound;
- if (!e) return '';
- return card('鎵爜鍏ュ簱', null,
- kv('浜嬩欢鍙�', text(e.eventId)) +
- kv('鍏ュ簱鏁伴噺', fmtNum(e.quantity)) +
- kv('璁惧缂栫爜', text(e.deviceCode)) +
- kv('浜х嚎', text(e.lineCode)) +
- kv('鍏ュ簱鏃堕棿', fmtDate(e.eventTime)),
- { collapsible: true, open: false }
- );
- }
-
- // 鍖哄潡6锛氭墭鐩�
- function buildPalletCard(d) {
- if (isEmptyList(d.pallets)) return '';
- var countHtml = '鍏� ' + esc(d.palletCount || d.pallets.length) + ' 涓�';
- var rows = '<table class="mini-table"><thead><tr><th>鎵樼洏鐮�</th><th>搴忓彿</th><th>宸茶/鍙</th></tr></thead><tbody>';
- d.pallets.forEach(function (p) {
- rows += '<tr><td>' + text(p.code) + '</td><td>' + fmtNum(p.palletNo) + '</td><td>' +
- fmtNum(p.bagCount) + ' / ' + fmtNum(p.capacity) + '</td></tr>';
- });
- rows += '</tbody></table>';
- return card('鎵樼洏淇℃伅', countHtml, rows, { collapsible: true, open: false });
- }
-
- // 鍖哄潡7锛氳鐮侊紙涓�琚嬩竴鐮侊級
- function buildBagCard(d) {
- if (d.bagTotal === null || d.bagTotal === undefined || d.bagTotal === 0) return '';
- var countHtml = '鍏� ' + esc(d.bagTotal) + ' 涓�' + (d.bags && d.bags.length < d.bagTotal ? '锛堝睍绀哄墠 ' + esc(d.bags.length) + ' 涓級' : '');
- var rows = '<table class="mini-table"><thead><tr><th>琚嬬爜</th><th>琚嬪彿</th><th>鎵樼洏</th><th>鐘舵��</th></tr></thead><tbody>';
- (d.bags || []).forEach(function (b) {
- rows += '<tr><td>' + text(b.code) + '</td><td>' + fmtNum(b.bagNo) + '</td><td>' + text(b.palletCode) + '</td><td>' +
- statusBadge(BAG_STATUS, b.status) + '</td></tr>';
- });
- rows += '</tbody></table>';
- return card('琚嬬爜淇℃伅', countHtml,
- '<div class="scroll-list">' + rows + '</div>',
- { collapsible: true, open: false }
- );
- }
-
- // 鍖哄潡8锛氬彲閫夋墿灞曪紙閲囪喘鏉ユ簮 / 閿�鍞幓鍚� / 鍔犲伐娴佽浆锛夛紝鏈夋暟鎹墠灞曠ず
- function buildOptionalCard(d) {
- var html = '';
- if (!isEmptyList(d.purchaseSources)) {
- var rows = '<table class="mini-table"><thead><tr><th>閲囪喘鍏ュ簱鍗�</th><th>渚涘簲鍟�</th><th>鏁伴噺</th><th>鏃ユ湡</th></tr></thead><tbody>';
- d.purchaseSources.forEach(function (s) {
- rows += '<tr><td>' + text(s.receiptCode) + '</td><td>' + text(s.vendorName) + '</td><td>' + fmtNum(s.receivedQuantity) + '</td><td>' + fmtDate(s.receiptDate) + '</td></tr>';
- });
- rows += '</tbody></table>';
- html += card('閲囪喘鏉ユ簮', null, rows, { collapsible: true, open: false });
- }
- if (!isEmptyList(d.salesTargets)) {
- var rows2 = '<table class="mini-table"><thead><tr><th>閿�鍞嚭搴撳崟</th><th>瀹㈡埛</th><th>鏁伴噺</th><th>鏃ユ湡</th></tr></thead><tbody>';
- d.salesTargets.forEach(function (s) {
- rows2 += '<tr><td>' + text(s.outCode || s.salesOrderCode || '') + '</td><td>' + text(s.customerName) + '</td><td>' + fmtNum(s.quantity) + '</td><td>' + fmtDate(s.outTime) + '</td></tr>';
- });
- rows2 += '</tbody></table>';
- html += card('閿�鍞幓鍚�', null, rows2, { collapsible: true, open: false });
- }
- if (!isEmptyList(d.processTraces)) {
- var rows3 = '<table class="mini-table"><thead><tr><th>鑺傜偣</th><th>璇存槑</th><th>鏃堕棿</th></tr></thead><tbody>';
- d.processTraces.forEach(function (t) {
- rows3 += '<tr><td>' + text(t.nodeName) + '</td><td>' + text(t.description) + '</td><td>' + fmtDate(t.processTime) + '</td></tr>';
- });
- rows3 += '</tbody></table>';
- html += card('鍔犲伐娴佽浆', null, rows3, { collapsible: true, open: false });
- }
+ var html = '<div class="verify ' + (repeated ? 'warn' : 'ok') + '">' +
+ '<span class="vico">' + icon + '</span>' +
+ '<div class="vtxt"><div class="vt">' + title + '</div><div class="vs">' + desc + '</div></div>' +
+ '</div>';
+ html += '<div class="code-box"><span class="cl">闃蹭吉缂栫爜</span><span class="cv">' + esc(code || '-') + '</span></div>';
+ html += kv('瀵瑰簲鍝佺', text(name));
+ html += d.batchCode
+ ? kv('瀵瑰簲鎵规', text(d.batchCode))
+ : kv('瀵瑰簲鎵规', '灏氭湭缁戝畾鎵规', true);
+ html += '<div class="stat-grid">' +
+ '<div class="stat span2 count"><div class="sl">璇ョ爜绱琚煡璇㈡鏁�</div>' +
+ '<div class="sv">' + n + '<span class="u">娆�</span></div></div>' +
+ '<div class="stat"><div class="sl">棣栨鏌ヨ鏃堕棿</div><div class="sv">' + fmtDate(af.firstScanTime) + '</div></div>' +
+ '<div class="stat"><div class="sl">鏈�杩戞煡璇㈡椂闂�</div><div class="sv">' + fmtDate(af.lastScanTime) + '</div></div>' +
+ '</div>';
+ html += '<div class="notice">' + (repeated
+ ? '鍚屼竴闃蹭吉鐮佽閲嶅鏌ヨ锛屽彲鑳芥剰鍛崇潃鍖呰琚鍒躲�傝鏍稿鍖呰涓婂嵃鍒剁殑闃蹭吉缂栫爜涓庢湰椤垫樉绀烘槸鍚︿竴鑷达紝濡傛湁鐤戦棶璇疯仈绯诲畼鏂规牳瀹炪��'
+ : '璇锋牳瀵瑰寘瑁呬笂鍗板埗鐨勯槻浼紪鐮佷笌鏈〉鏄剧ず鏄惁涓�鑷达紝骞剁‘璁ゅ寘瑁呭畬濂姐��') + '</div>';
return html;
}
- // ========== 鍒濆鍖� ==========
+ // 鍖哄潡2锛氳拷婧煡璇紙鏈綍鍏ユ壒娆℃椂鍙睍绀哄搧绉嶄俊鎭� + 鎻愮ず锛�
+ function tracePanel(d) {
+ var code = resolveCode(d);
+ var name = [d.itemName, d.itemSpecification].filter(Boolean).join(' ');
+ var unbound = d.batchBound === false;
+ var batchRows = unbound
+ ? '<div class="notice">璇ヨ拷婧爜灏氭湭褰曞叆鐢熶骇鎵规锛屾壒娆″彿銆佺敓浜ф棩鏈熴�佷骇绾跨瓑淇℃伅寰呭畬鍠勶紱褰撳墠灞曠ず璇ョ爜瀵瑰簲鐨勫搧绉嶄俊鎭��</div>'
+ : kv('鎵规鍙�', text(d.batchCode)) +
+ kv('鐢熶骇鏃ユ湡', fmtDate(d.produceDate)) +
+ kv('浜х嚎', text(d.lineName || d.lineCode));
+ return kv('鍝佺鍚嶇О', text(name)) +
+ kv('璁¢噺鍗曚綅', text(d.itemUnitMeasureName)) +
+ kv('鐢熶骇缁忚惀鑰�', esc(COMPANY_NAME)) +
+ kv('鍗曞厓璇嗗埆浠g爜', text(code || '-')) +
+ kv('杩芥函缃戝潃', '<a class="link" href="' + esc(TRACE_URL) + '">' + esc(TRACE_URL) + '</a>') +
+ kv('杩芥函绫诲瀷', esc(SOURCE_TYPE[d.sourceType] || '杩芥函鐮�')) +
+ batchRows;
+ }
+
+ // 鍖哄潡3~锛氱敓浜ф槑缁嗭紙鎶樺彔锛屾湁鏁版嵁鎵嶅睍绀猴級
+ function detailSections(d) {
+ var html = '';
+
+ // 鐢熶骇鎵规淇℃伅
+ var batchBody =
+ kv('鎵规鐘舵��', d.batchStatusName ? statusBadge({ v: [d.batchStatusName, 'blue'] }, 'v') : text(d.batchStatus)) +
+ kv('璁″垝鏁伴噺', fmtNum(d.planQuantity)) +
+ kv('宸茬敓鎴愯鐮�', fmtNum(d.bagQuantity)) +
+ kv('宸茬敓鎴愭墭鐩�', fmtNum(d.palletQuantity)) +
+ kv('鍏ュ簱鏃堕棿', fmtDate(d.inboundTime)) +
+ kv('涓存椂鎵规鐮�', text(d.tempCode)) +
+ kv('澶囨敞', text(d.remark));
+ html += sec('鐢熶骇鎵规淇℃伅', null, batchBody, { collapsible: true, open: false });
+
+ // 璐ㄦ淇℃伅
+ if (d.quality) {
+ var q = d.quality;
+ var qBody =
+ kv('璐ㄦ缁撹', q.resultName ? '<span class="badge ' + (q.result === 1 ? 'green' : 'red') + '">' + esc(q.resultName) + '</span>' : '-') +
+ kv('妫�楠屽憳', text(q.inspectorName)) +
+ kv('妫�楠屾椂闂�', fmtDate(q.inspectedAt)) +
+ (q.reason ? kv('涓嶅悎鏍煎師鍥�', text(q.reason)) : '');
+ if (!isEmptyList(q.indicators)) {
+ var rows = q.indicators.map(function (i) {
+ var hasMin = i.minValue !== null && i.minValue !== undefined;
+ var hasMax = i.maxValue !== null && i.maxValue !== undefined;
+ var range = '-';
+ if (hasMin && hasMax) range = fmtNum(i.minValue) + ' ~ ' + fmtNum(i.maxValue);
+ else if (hasMin) range = '鈮� ' + fmtNum(i.minValue);
+ else if (hasMax) range = '鈮� ' + fmtNum(i.maxValue);
+ var pass = i.pass === null || i.pass === undefined
+ ? '-'
+ : '<span class="badge ' + (i.pass ? 'green' : 'red') + '">' + (i.pass ? '鍚堟牸' : '涓嶅悎鏍�') + '</span>';
+ return [text(i.indicatorName), fmtNum(i.value), range, pass];
+ });
+ qBody += '<div style="margin-top:8px">' + table(['妫�娴嬮」', '妫�娴嬪��', '鏍囧噯鑼冨洿', '缁撹'], rows) + '</div>';
+ }
+ html += sec('璐ㄦ淇℃伅', null, qBody, { collapsible: true, open: false });
+ }
+
+ // 鐢熶骇浜哄憳
+ if (!isEmptyList(d.workers)) {
+ var wBody = d.workers.map(function (w) {
+ return li('<span class="li-ttl">' + text(w.userName) + '</span>' +
+ (w.workerTypeName ? '<span class="badge gray">' + esc(w.workerTypeName) + '</span>' : ''),
+ null,
+ w.remark ? kv('澶囨敞', text(w.remark)) : '');
+ }).join('');
+ html += sec('鐢熶骇浜哄憳', d.workers.length + ' 浜�', '<div class="scroll-list">' + wBody + '</div>', { collapsible: true, open: false });
+ }
+
+ // 鎵樼洏淇℃伅
+ if (!isEmptyList(d.pallets)) {
+ var pRows = d.pallets.map(function (p) {
+ return [text(p.code), fmtNum(p.palletNo), fmtNum(p.bagCount), fmtNum(p.capacity)];
+ });
+ html += sec('鎵樼洏淇℃伅', '鍏� ' + fmtNum(d.palletCount || d.pallets.length) + ' 涓�',
+ '<div class="scroll-list">' + table(['鎵樼洏鐮�', '搴忓彿', '宸茶琚�', '鍙琚�'], pRows) + '</div>',
+ { collapsible: true, open: false });
+ }
+
+ // 琚嬬爜鍒楄〃
+ if (!isEmptyList(d.bags)) {
+ var bBody = d.bags.map(function (b) {
+ return li('<span class="li-ttl">' + text(b.code) + '</span>' +
+ (b.statusName ? '<span class="badge gray">' + esc(b.statusName) + '</span>' : ''),
+ fmtDate(b.inboundTime),
+ kv('琚嬪彿', fmtNum(b.bagNo)) + (b.palletCode ? kv('鎵樼洏鐮�', text(b.palletCode)) : ''));
+ }).join('');
+ var bagCountText = '鍏� ' + fmtNum(d.bagTotal || d.bags.length) + ' 琚�' +
+ (Number(d.bagTotal) > d.bags.length ? '锛堟樉绀哄墠 ' + d.bags.length + ' 鏉★級' : '');
+ html += sec('琚嬬爜鍒楄〃', bagCountText, '<div class="scroll-list">' + bBody + '</div>', { collapsible: true, open: false });
+ }
+
+ // 閲囪喘鏉ユ簮
+ if (!isEmptyList(d.purchaseSources)) {
+ var psRows = d.purchaseSources.map(function (s) {
+ return [text(s.receiptCode), text(s.vendorName), nw(fmtNum(s.receivedQuantity)), nw(fmtDay(s.receiptDate))];
+ });
+ html += sec('閲囪喘鏉ユ簮', null, table(['閲囪喘鍏ュ簱鍗�', '渚涘簲鍟�', '鏁伴噺', '鏃ユ湡'], psRows), { collapsible: true, open: false });
+ }
+
+ // 绉嶅瓙娴佸悜淇℃伅锛堜粎閿�鍞嚭搴� bizType=119锛�
+ var salesFlows = (d.seedFlows || []).filter(function (f) { return f.bizType === 119; });
+ if (!isEmptyList(salesFlows)) {
+ var sfBody = salesFlows.map(function (f) {
+ var qty = (f.quantity === null || f.quantity === undefined) ? '-' : fmtNum(Math.abs(Number(f.quantity)));
+ var wh = [f.warehouseName, f.locationName].filter(Boolean).join(' / ') || '-';
+ return li(statusBadge(FLOW_DIRECTION, f.type) + '<span class="li-ttl">' + esc(FLOW_BIZ_TYPE[f.bizType] || '') + '</span>',
+ fmtDate(f.transactionTime),
+ kv('鏉ユ簮鍗曞彿', text(f.bizCode)) +
+ kv('瀹㈡埛', text(f.clientName)) +
+ kv('鏁伴噺', qty) +
+ kv('浠撳簱/搴撳尯', text(wh)));
+ }).join('');
+ html += sec('绉嶅瓙娴佸悜淇℃伅', null, '<div class="scroll-list">' + sfBody + '</div>', { collapsible: true, open: false });
+ } else if (!isEmptyList(d.salesTargets)) {
+ var stRows = d.salesTargets.map(function (s) {
+ return [text(s.salesCode || s.salesOrderCode || ''), text(s.clientName), nw(fmtNum(s.quantity)), nw(fmtDay(s.salesDate))];
+ });
+ html += sec('绉嶅瓙娴佸悜淇℃伅', null, table(['閿�鍞嚭搴撳崟', '瀹㈡埛', '鏁伴噺', '鏃ユ湡'], stRows), { collapsible: true, open: false });
+ }
+
+ // 鍔犲伐娴佽浆
+ if (!isEmptyList(d.processTraces)) {
+ var ptBody = d.processTraces.map(function (t) {
+ return li('<span class="li-ttl">' + text(t.nodeName) + '</span>', fmtDate(t.processTime),
+ t.description ? kv('璇存槑', text(t.description)) : '');
+ }).join('');
+ html += sec('鍔犲伐娴佽浆', null, '<div class="scroll-list">' + ptBody + '</div>', { collapsible: true, open: false });
+ }
+
+ return html;
+ }
+
+ // ========== 浜や簰 ==========
+ // 鎶樺彔鍖哄潡锛氭爣棰樼偣鍑诲睍寮�/鏀惰捣
+ STATE.addEventListener('click', function (e) {
+ var hd = e.target.closest ? e.target.closest('.sec.collapsible .sec-hd') : null;
+ if (hd) hd.parentNode.classList.toggle('open');
+ });
+
SEARCH_BTN.addEventListener('click', function () { query(CODE_INPUT.value); });
CODE_INPUT.addEventListener('keydown', function (e) { if (e.key === 'Enter') query(CODE_INPUT.value); });
+
+ // 鍏徃浠嬬粛锛氬唴瀹硅秴鍑哄彲鎶樺彔楂樺害鏃舵墠鏄剧ず鈥滅偣鍑绘煡鐪嬫洿澶氣��
+ (function initCompanyToggle() {
+ var clip = document.getElementById('companyClip');
+ var wrap = document.getElementById('companyMoreWrap');
+ var more = document.getElementById('companyMore');
+ if (clip.scrollHeight <= clip.clientHeight + 4) {
+ clip.classList.add('open');
+ wrap.style.display = 'none';
+ return;
+ }
+ more.addEventListener('click', function () {
+ var open = clip.classList.toggle('open');
+ more.textContent = open ? '鏀惰捣' : '鐐瑰嚮鏌ョ湅鏇村';
+ });
+ })();
var initialCode = new URLSearchParams(location.search).get('code') || '';
CODE_INPUT.value = initialCode;
@@ -510,7 +703,6 @@
query(initialCode);
} else {
renderState('<div class="empty-tip">鎵爜鎴栬緭鍏ヨ拷婧爜锛屽嵆鍙煡璇骇鍝佸叏绋嬫函婧愪俊鎭�</div>');
- CODE_INPUT.focus();
}
})();
</script>
--
Gitblit v1.9.3