From 1b3fd46c7ccbf636208bcf098c5588441bb71f78 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 25 八月 2026 17:53:53 +0800
Subject: [PATCH] feat(mes): 添加销售出库扫码拣货功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java           |   12 
 .playwright-mcp/page-2026-08-25T06-48-56-741Z.yml                                                                                |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletService.java                           |   15 
 .playwright-mcp/page-2026-08-25T09-20-39-383Z.yml                                                                                |    1 
 .playwright-mcp/page-2026-08-25T09-06-50-446Z.yml                                                                                |   98 +++++
 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/dal/dataobject/pro/pallet/MesProPalletDO.java                         |    8 
 .playwright-mcp/page-2026-08-25T08-09-30-148Z.yml                                                                                |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java             |   78 ++++
 img/img.png                                                                                                                      |    0 
 .playwright-mcp/page-2026-08-25T09-44-56-418Z.yml                                                                                |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanRespVO.java  |   75 ++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java                       |    2 
 .playwright-mcp/page-2026-08-25T09-06-42-806Z.yml                                                                                |   94 +++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java          |   12 
 .playwright-mcp/page-2026-08-25T08-47-21-216Z.yml                                                                                |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java     |   10 
 .playwright-mcp/page-2026-08-25T07-31-24-236Z.yml                                                                                |    1 
 sql/mysql/mes_wm_sales_outbound_traceability.sql                                                                                 |   25 +
 .playwright-mcp/page-2026-08-25T09-07-28-054Z.yml                                                                                |   98 +++++
 .playwright-mcp/page-2026-08-25T09-50-51-027Z.yml                                                                                |   78 ++++
 .playwright-mcp/page-2026-08-25T07-11-38-160Z.yml                                                                                |    1 
 .playwright-mcp/page-2026-08-25T07-07-54-966Z.yml                                                                                |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java                         |   15 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java                     |   10 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java                       |   10 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java                        |    9 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java              |   10 
 .playwright-mcp/page-2026-08-25T09-06-04-966Z.yml                                                                                |   94 +++++
 /dev/null                                                                                                                        |    0 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java         |    8 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanReqVO.java   |   25 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java             |    5 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java                                         |   10 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java                 |    4 
 .playwright-mcp/page-2026-08-25T09-07-17-780Z.yml                                                                                |    1 
 docs/mes_product_sales_scan_integration.md                                                                                       |   76 ++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java                          |    9 
 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/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java    |    4 
 .playwright-mcp/page-2026-08-25T09-08-01-907Z.yml                                                                                |   94 +++++
 img/img_1.png                                                                                                                    |    0 
 .playwright-mcp/page-2026-08-25T09-07-53-861Z.yml                                                                                |    1 
 sql/mysql/mes_wm_stock_state_init.sql                                                                                            |   32 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmStockStateEnum.java                                     |   16 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java               |    4 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java               |    5 
 47 files changed, 1,061 insertions(+), 0 deletions(-)

diff --git "a/.image/Java\347\233\221\346\216\247.jpg" "b/.image/Java\347\233\221\346\216\247.jpg"
deleted file mode 100644
index 6ad522a..0000000
--- "a/.image/Java\347\233\221\346\216\247.jpg"
+++ /dev/null
Binary files differ
diff --git a/.image/MySQL.jpg b/.image/MySQL.jpg
deleted file mode 100644
index 64a1940..0000000
--- a/.image/MySQL.jpg
+++ /dev/null
Binary files differ
diff --git "a/.image/OA\350\257\267\345\201\207-\345\210\227\350\241\250.jpg" "b/.image/OA\350\257\267\345\201\207-\345\210\227\350\241\250.jpg"
deleted file mode 100644
index 787bb73..0000000
--- "a/.image/OA\350\257\267\345\201\207-\345\210\227\350\241\250.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/OA\350\257\267\345\201\207-\345\217\221\350\265\267.jpg" "b/.image/OA\350\257\267\345\201\207-\345\217\221\350\265\267.jpg"
deleted file mode 100644
index 1a7342d..0000000
--- "a/.image/OA\350\257\267\345\201\207-\345\217\221\350\265\267.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/OA\350\257\267\345\201\207-\350\257\246\346\203\205.jpg" "b/.image/OA\350\257\267\345\201\207-\350\257\246\346\203\205.jpg"
deleted file mode 100644
index a83e7c1..0000000
--- "a/.image/OA\350\257\267\345\201\207-\350\257\246\346\203\205.jpg"
+++ /dev/null
Binary files differ
diff --git a/.image/Redis.jpg b/.image/Redis.jpg
deleted file mode 100644
index 9569352..0000000
--- a/.image/Redis.jpg
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/01.png b/.image/admin-uniapp/01.png
deleted file mode 100644
index 0f65d99..0000000
--- a/.image/admin-uniapp/01.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/02.png b/.image/admin-uniapp/02.png
deleted file mode 100644
index 05ec781..0000000
--- a/.image/admin-uniapp/02.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/03.png b/.image/admin-uniapp/03.png
deleted file mode 100644
index f400c68..0000000
--- a/.image/admin-uniapp/03.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/04.png b/.image/admin-uniapp/04.png
deleted file mode 100644
index d5d5ea0..0000000
--- a/.image/admin-uniapp/04.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/05.png b/.image/admin-uniapp/05.png
deleted file mode 100644
index 1de6d8a..0000000
--- a/.image/admin-uniapp/05.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/06.png b/.image/admin-uniapp/06.png
deleted file mode 100644
index 400ae90..0000000
--- a/.image/admin-uniapp/06.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/07.png b/.image/admin-uniapp/07.png
deleted file mode 100644
index 2ed8c0f..0000000
--- a/.image/admin-uniapp/07.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/08.png b/.image/admin-uniapp/08.png
deleted file mode 100644
index 090e64a..0000000
--- a/.image/admin-uniapp/08.png
+++ /dev/null
Binary files differ
diff --git a/.image/admin-uniapp/09.png b/.image/admin-uniapp/09.png
deleted file mode 100644
index f2032c8..0000000
--- a/.image/admin-uniapp/09.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/ai-feature.png b/.image/common/ai-feature.png
deleted file mode 100644
index 1c22dbe..0000000
--- a/.image/common/ai-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/ai-preview.gif b/.image/common/ai-preview.gif
deleted file mode 100644
index 5f13ac4..0000000
--- a/.image/common/ai-preview.gif
+++ /dev/null
Binary files differ
diff --git a/.image/common/bpm-feature.png b/.image/common/bpm-feature.png
deleted file mode 100644
index 23787fb..0000000
--- a/.image/common/bpm-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/crm-feature.png b/.image/common/crm-feature.png
deleted file mode 100644
index e1c9670..0000000
--- a/.image/common/crm-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/erp-feature.png b/.image/common/erp-feature.png
deleted file mode 100644
index d30b30e..0000000
--- a/.image/common/erp-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/im-feature.png b/.image/common/im-feature.png
deleted file mode 100644
index da3f012..0000000
--- a/.image/common/im-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/im-preview-home.png b/.image/common/im-preview-home.png
deleted file mode 100644
index c4790a3..0000000
--- a/.image/common/im-preview-home.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/im-preview-manager.png b/.image/common/im-preview-manager.png
deleted file mode 100644
index b8bb057..0000000
--- a/.image/common/im-preview-manager.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/infra-feature.png b/.image/common/infra-feature.png
deleted file mode 100644
index f5cef50..0000000
--- a/.image/common/infra-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/iot-feature.png b/.image/common/iot-feature.png
deleted file mode 100644
index 357781c..0000000
--- a/.image/common/iot-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/iot-preview.png b/.image/common/iot-preview.png
deleted file mode 100644
index 58e8940..0000000
--- a/.image/common/iot-preview.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/mall-feature.png b/.image/common/mall-feature.png
deleted file mode 100644
index cca05c0..0000000
--- a/.image/common/mall-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/mall-preview.png b/.image/common/mall-preview.png
deleted file mode 100644
index e164cd2..0000000
--- a/.image/common/mall-preview.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/mes-feature.png b/.image/common/mes-feature.png
deleted file mode 100644
index 33196fd..0000000
--- a/.image/common/mes-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/mes-preview.png b/.image/common/mes-preview.png
deleted file mode 100644
index a140979..0000000
--- a/.image/common/mes-preview.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/project-vs.png b/.image/common/project-vs.png
deleted file mode 100644
index 561e092..0000000
--- a/.image/common/project-vs.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/ruoyi-vue-pro-architecture.png b/.image/common/ruoyi-vue-pro-architecture.png
deleted file mode 100644
index 7bd7d59..0000000
--- a/.image/common/ruoyi-vue-pro-architecture.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/ruoyi-vue-pro-biz.png b/.image/common/ruoyi-vue-pro-biz.png
deleted file mode 100644
index 3554919..0000000
--- a/.image/common/ruoyi-vue-pro-biz.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/system-feature.png b/.image/common/system-feature.png
deleted file mode 100644
index 366087c..0000000
--- a/.image/common/system-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/wms-feature.png b/.image/common/wms-feature.png
deleted file mode 100644
index 0d7790b..0000000
--- a/.image/common/wms-feature.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/wms-preview.png b/.image/common/wms-preview.png
deleted file mode 100644
index 31c5187..0000000
--- a/.image/common/wms-preview.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/yudao-cloud-architecture.png b/.image/common/yudao-cloud-architecture.png
deleted file mode 100644
index 59416d8..0000000
--- a/.image/common/yudao-cloud-architecture.png
+++ /dev/null
Binary files differ
diff --git a/.image/common/yudao-roadmap.png b/.image/common/yudao-roadmap.png
deleted file mode 100644
index f4becc9..0000000
--- a/.image/common/yudao-roadmap.png
+++ /dev/null
Binary files differ
diff --git "a/.image/\344\270\252\344\272\272\344\270\255\345\277\203.jpg" "b/.image/\344\270\252\344\272\272\344\270\255\345\277\203.jpg"
deleted file mode 100644
index ce57f6e..0000000
--- "a/.image/\344\270\252\344\272\272\344\270\255\345\277\203.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\344\273\243\347\240\201\347\224\237\346\210\220.jpg" "b/.image/\344\273\243\347\240\201\347\224\237\346\210\220.jpg"
deleted file mode 100644
index 751603e..0000000
--- "a/.image/\344\273\243\347\240\201\347\224\237\346\210\220.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\344\273\244\347\211\214\347\256\241\347\220\206.jpg" "b/.image/\344\273\244\347\211\214\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 04abf4d..0000000
--- "a/.image/\344\273\244\347\211\214\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\256\241\346\211\271.jpg" "b/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\256\241\346\211\271.jpg"
deleted file mode 100644
index cba312a..0000000
--- "a/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\256\241\346\211\271.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\267\262\345\212\236.jpg" "b/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\267\262\345\212\236.jpg"
deleted file mode 100644
index 7a8d0fb..0000000
--- "a/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\267\262\345\212\236.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\276\205\345\212\236.jpg" "b/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\276\205\345\212\236.jpg"
deleted file mode 100644
index a90323f..0000000
--- "a/.image/\344\273\273\345\212\241\345\210\227\350\241\250-\345\276\205\345\212\236.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\344\273\273\345\212\241\346\227\245\345\277\227.jpg" "b/.image/\344\273\273\345\212\241\346\227\245\345\277\227.jpg"
deleted file mode 100644
index 599e50a..0000000
--- "a/.image/\344\273\273\345\212\241\346\227\245\345\277\227.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\225\206\346\210\267\344\277\241\346\201\257.jpg" "b/.image/\345\225\206\346\210\267\344\277\241\346\201\257.jpg"
deleted file mode 100644
index 483eace..0000000
--- "a/.image/\345\225\206\346\210\267\344\277\241\346\201\257.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\234\250\347\272\277\347\224\250\346\210\267.jpg" "b/.image/\345\234\250\347\272\277\347\224\250\346\210\267.jpg"
deleted file mode 100644
index b183009..0000000
--- "a/.image/\345\234\250\347\272\277\347\224\250\346\210\267.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\345\210\227\350\241\250.jpg" "b/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\345\210\227\350\241\250.jpg"
deleted file mode 100644
index 9a45c3b..0000000
--- "a/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\345\210\227\350\241\250.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\347\274\226\350\276\221.jpg" "b/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\347\274\226\350\276\221.jpg"
deleted file mode 100644
index 63298a0..0000000
--- "a/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\347\274\226\350\276\221.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\351\242\204\350\247\210.jpg" "b/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\351\242\204\350\247\210.jpg"
deleted file mode 100644
index 501d9ea..0000000
--- "a/.image/\345\244\247\345\261\217\350\256\276\350\256\241\345\231\250-\351\242\204\350\247\210.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\255\227\345\205\270\346\225\260\346\215\256.jpg" "b/.image/\345\255\227\345\205\270\346\225\260\346\215\256.jpg"
deleted file mode 100644
index 8298c89..0000000
--- "a/.image/\345\255\227\345\205\270\346\225\260\346\215\256.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\255\227\345\205\270\347\261\273\345\236\213.jpg" "b/.image/\345\255\227\345\205\270\347\261\273\345\236\213.jpg"
deleted file mode 100644
index 6613392..0000000
--- "a/.image/\345\255\227\345\205\270\347\261\273\345\236\213.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\256\232\346\227\266\344\273\273\345\212\241.jpg" "b/.image/\345\256\232\346\227\266\344\273\273\345\212\241.jpg"
deleted file mode 100644
index d5bbd85..0000000
--- "a/.image/\345\256\232\346\227\266\344\273\273\345\212\241.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\262\227\344\275\215\347\256\241\347\220\206.jpg" "b/.image/\345\262\227\344\275\215\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 42b64d2..0000000
--- "a/.image/\345\262\227\344\275\215\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\267\245\344\275\234\346\265\201\350\256\276\350\256\241\345\231\250-bpmn.jpg" "b/.image/\345\267\245\344\275\234\346\265\201\350\256\276\350\256\241\345\231\250-bpmn.jpg"
deleted file mode 100644
index 2a61f60..0000000
--- "a/.image/\345\267\245\344\275\234\346\265\201\350\256\276\350\256\241\345\231\250-bpmn.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\267\245\344\275\234\346\265\201\350\256\276\350\256\241\345\231\250-simple.jpg" "b/.image/\345\267\245\344\275\234\346\265\201\350\256\276\350\256\241\345\231\250-simple.jpg"
deleted file mode 100644
index 9ef2c9e..0000000
--- "a/.image/\345\267\245\344\275\234\346\265\201\350\256\276\350\256\241\345\231\250-simple.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\272\224\347\224\250\344\277\241\346\201\257-\345\210\227\350\241\250.jpg" "b/.image/\345\272\224\347\224\250\344\277\241\346\201\257-\345\210\227\350\241\250.jpg"
deleted file mode 100644
index da419a2..0000000
--- "a/.image/\345\272\224\347\224\250\344\277\241\346\201\257-\345\210\227\350\241\250.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\272\224\347\224\250\344\277\241\346\201\257-\347\274\226\350\276\221.jpg" "b/.image/\345\272\224\347\224\250\344\277\241\346\201\257-\347\274\226\350\276\221.jpg"
deleted file mode 100644
index 913cfbc..0000000
--- "a/.image/\345\272\224\347\224\250\344\277\241\346\201\257-\347\274\226\350\276\221.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\345\272\224\347\224\250\347\256\241\347\220\206.jpg" "b/.image/\345\272\224\347\224\250\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 6e7789f..0000000
--- "a/.image/\345\272\224\347\224\250\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\345\210\227\350\241\250.jpg" "b/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\345\210\227\350\241\250.jpg"
deleted file mode 100644
index 223d17a..0000000
--- "a/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\345\210\227\350\241\250.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\345\217\221\350\265\267.jpg" "b/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\345\217\221\350\265\267.jpg"
deleted file mode 100644
index 7a83306..0000000
--- "a/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\345\217\221\350\265\267.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\350\257\246\346\203\205.jpg" "b/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\350\257\246\346\203\205.jpg"
deleted file mode 100644
index 6a01541..0000000
--- "a/.image/\346\210\221\347\232\204\346\265\201\347\250\213-\350\257\246\346\203\205.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\345\233\276\345\275\242\346\212\245\350\241\250.jpg" "b/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\345\233\276\345\275\242\346\212\245\350\241\250.jpg"
deleted file mode 100644
index 681b318..0000000
--- "a/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\345\233\276\345\275\242\346\212\245\350\241\250.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\346\211\223\345\215\260\350\256\276\350\256\241.jpg" "b/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\346\211\223\345\215\260\350\256\276\350\256\241.jpg"
deleted file mode 100644
index bb86da6..0000000
--- "a/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\346\211\223\345\215\260\350\256\276\350\256\241.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\346\225\260\346\215\256\346\212\245\350\241\250.jpg" "b/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\346\225\260\346\215\256\346\212\245\350\241\250.jpg"
deleted file mode 100644
index 9ca5b9b..0000000
--- "a/.image/\346\212\245\350\241\250\350\256\276\350\256\241\345\231\250-\346\225\260\346\215\256\346\212\245\350\241\250.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\223\215\344\275\234\346\227\245\345\277\227.jpg" "b/.image/\346\223\215\344\275\234\346\227\245\345\277\227.jpg"
deleted file mode 100644
index 4a0611a..0000000
--- "a/.image/\346\223\215\344\275\234\346\227\245\345\277\227.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\224\257\344\273\230\350\256\242\345\215\225.jpg" "b/.image/\346\224\257\344\273\230\350\256\242\345\215\225.jpg"
deleted file mode 100644
index 0a56dd7..0000000
--- "a/.image/\346\224\257\344\273\230\350\256\242\345\215\225.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\225\217\346\204\237\350\257\215.jpg" "b/.image/\346\225\217\346\204\237\350\257\215.jpg"
deleted file mode 100644
index 92a5397..0000000
--- "a/.image/\346\225\217\346\204\237\350\257\215.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\225\260\346\215\256\345\272\223\346\226\207\346\241\243.jpg" "b/.image/\346\225\260\346\215\256\345\272\223\346\226\207\346\241\243.jpg"
deleted file mode 100644
index a4339d9..0000000
--- "a/.image/\346\225\260\346\215\256\345\272\223\346\226\207\346\241\243.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\226\207\344\273\266\347\256\241\347\220\206.jpg" "b/.image/\346\226\207\344\273\266\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 054b19f..0000000
--- "a/.image/\346\226\207\344\273\266\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\226\207\344\273\266\347\256\241\347\220\2062.jpg" "b/.image/\346\226\207\344\273\266\347\256\241\347\220\2062.jpg"
deleted file mode 100644
index b12e5c3..0000000
--- "a/.image/\346\226\207\344\273\266\347\256\241\347\220\2062.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\226\207\344\273\266\351\205\215\347\275\256.jpg" "b/.image/\346\226\207\344\273\266\351\205\215\347\275\256.jpg"
deleted file mode 100644
index e618049..0000000
--- "a/.image/\346\226\207\344\273\266\351\205\215\347\275\256.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\227\245\345\277\227\344\270\255\345\277\203.jpg" "b/.image/\346\227\245\345\277\227\344\270\255\345\277\203.jpg"
deleted file mode 100644
index 27c1c6c..0000000
--- "a/.image/\346\227\245\345\277\227\344\270\255\345\277\203.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\345\210\227\350\241\250.jpg" "b/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\345\210\227\350\241\250.jpg"
deleted file mode 100644
index ffdc584..0000000
--- "a/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\345\210\227\350\241\250.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\345\256\232\344\271\211.jpg" "b/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\345\256\232\344\271\211.jpg"
deleted file mode 100644
index 18b316c..0000000
--- "a/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\345\256\232\344\271\211.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\350\256\276\350\256\241.jpg" "b/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\350\256\276\350\256\241.jpg"
deleted file mode 100644
index 9614969..0000000
--- "a/.image/\346\265\201\347\250\213\346\250\241\345\236\213-\350\256\276\350\256\241.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\346\265\201\347\250\213\350\241\250\345\215\225.jpg" "b/.image/\346\265\201\347\250\213\350\241\250\345\215\225.jpg"
deleted file mode 100644
index 60669c1..0000000
--- "a/.image/\346\265\201\347\250\213\350\241\250\345\215\225.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\224\237\346\210\220\346\225\210\346\236\234.jpg" "b/.image/\347\224\237\346\210\220\346\225\210\346\236\234.jpg"
deleted file mode 100644
index 98ff2cc..0000000
--- "a/.image/\347\224\237\346\210\220\346\225\210\346\236\234.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\224\250\346\210\267\345\210\206\347\273\204.jpg" "b/.image/\347\224\250\346\210\267\345\210\206\347\273\204.jpg"
deleted file mode 100644
index 39af1cd..0000000
--- "a/.image/\347\224\250\346\210\267\345\210\206\347\273\204.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\224\250\346\210\267\347\256\241\347\220\206.jpg" "b/.image/\347\224\250\346\210\267\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 844604a..0000000
--- "a/.image/\347\224\250\346\210\267\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\231\273\345\275\225.jpg" "b/.image/\347\231\273\345\275\225.jpg"
deleted file mode 100644
index b782b98..0000000
--- "a/.image/\347\231\273\345\275\225.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\231\273\345\275\225\346\227\245\345\277\227.jpg" "b/.image/\347\231\273\345\275\225\346\227\245\345\277\227.jpg"
deleted file mode 100644
index 25662d9..0000000
--- "a/.image/\347\231\273\345\275\225\346\227\245\345\277\227.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\237\255\344\277\241\346\227\245\345\277\227.jpg" "b/.image/\347\237\255\344\277\241\346\227\245\345\277\227.jpg"
deleted file mode 100644
index ada8e56..0000000
--- "a/.image/\347\237\255\344\277\241\346\227\245\345\277\227.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\237\255\344\277\241\346\250\241\346\235\277.jpg" "b/.image/\347\237\255\344\277\241\346\250\241\346\235\277.jpg"
deleted file mode 100644
index 09381cc..0000000
--- "a/.image/\347\237\255\344\277\241\346\250\241\346\235\277.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\237\255\344\277\241\346\270\240\351\201\223.jpg" "b/.image/\347\237\255\344\277\241\346\270\240\351\201\223.jpg"
deleted file mode 100644
index df3a5c3..0000000
--- "a/.image/\347\237\255\344\277\241\346\270\240\351\201\223.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\247\237\346\210\267\345\245\227\351\244\220.png" "b/.image/\347\247\237\346\210\267\345\245\227\351\244\220.png"
deleted file mode 100644
index 9663167..0000000
--- "a/.image/\347\247\237\346\210\267\345\245\227\351\244\220.png"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\247\237\346\210\267\347\256\241\347\220\206.jpg" "b/.image/\347\247\237\346\210\267\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 647416a..0000000
--- "a/.image/\347\247\237\346\210\267\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\347\263\273\347\273\237\346\216\245\345\217\243.jpg" "b/.image/\347\263\273\347\273\237\346\216\245\345\217\243.jpg"
deleted file mode 100644
index 6d39d42..0000000
--- "a/.image/\347\263\273\347\273\237\346\216\245\345\217\243.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\350\217\234\345\215\225\347\256\241\347\220\206.jpg" "b/.image/\350\217\234\345\215\225\347\256\241\347\220\206.jpg"
deleted file mode 100644
index ad3b797..0000000
--- "a/.image/\350\217\234\345\215\225\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\350\241\250\345\215\225\346\236\204\345\273\272.jpg" "b/.image/\350\241\250\345\215\225\346\236\204\345\273\272.jpg"
deleted file mode 100644
index 81f0374..0000000
--- "a/.image/\350\241\250\345\215\225\346\236\204\345\273\272.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\350\247\222\350\211\262\347\256\241\347\220\206.jpg" "b/.image/\350\247\222\350\211\262\347\256\241\347\220\206.jpg"
deleted file mode 100644
index eed776e..0000000
--- "a/.image/\350\247\222\350\211\262\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\350\256\277\351\227\256\346\227\245\345\277\227.jpg" "b/.image/\350\256\277\351\227\256\346\227\245\345\277\227.jpg"
deleted file mode 100644
index ef301aa..0000000
--- "a/.image/\350\256\277\351\227\256\346\227\245\345\277\227.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\200\200\346\254\276\350\256\242\345\215\225.jpg" "b/.image/\351\200\200\346\254\276\350\256\242\345\215\225.jpg"
deleted file mode 100644
index 2c6c6c9..0000000
--- "a/.image/\351\200\200\346\254\276\350\256\242\345\215\225.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\200\232\347\237\245\345\205\254\345\221\212.jpg" "b/.image/\351\200\232\347\237\245\345\205\254\345\221\212.jpg"
deleted file mode 100644
index 97bb42f..0000000
--- "a/.image/\351\200\232\347\237\245\345\205\254\345\221\212.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\203\250\351\227\250\347\256\241\347\220\206.jpg" "b/.image/\351\203\250\351\227\250\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 6eab233..0000000
--- "a/.image/\351\203\250\351\227\250\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\205\215\347\275\256\347\256\241\347\220\206.jpg" "b/.image/\351\205\215\347\275\256\347\256\241\347\220\206.jpg"
deleted file mode 100644
index 0abaec9..0000000
--- "a/.image/\351\205\215\347\275\256\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\223\276\350\267\257\350\277\275\350\270\252.jpg" "b/.image/\351\223\276\350\267\257\350\277\275\350\270\252.jpg"
deleted file mode 100644
index 12f7aa8..0000000
--- "a/.image/\351\223\276\350\267\257\350\277\275\350\270\252.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\224\231\350\257\257\346\227\245\345\277\227.jpg" "b/.image/\351\224\231\350\257\257\346\227\245\345\277\227.jpg"
deleted file mode 100644
index eb615ea..0000000
--- "a/.image/\351\224\231\350\257\257\346\227\245\345\277\227.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\224\231\350\257\257\347\240\201\347\256\241\347\220\206.jpg" "b/.image/\351\224\231\350\257\257\347\240\201\347\256\241\347\220\206.jpg"
deleted file mode 100644
index ea91dde..0000000
--- "a/.image/\351\224\231\350\257\257\347\240\201\347\256\241\347\220\206.jpg"
+++ /dev/null
Binary files differ
diff --git "a/.image/\351\246\226\351\241\265.jpg" "b/.image/\351\246\226\351\241\265.jpg"
deleted file mode 100644
index 10a7fde..0000000
--- "a/.image/\351\246\226\351\241\265.jpg"
+++ /dev/null
Binary files differ
diff --git a/.playwright-mcp/page-2026-08-25T06-48-56-741Z.yml b/.playwright-mcp/page-2026-08-25T06-48-56-741Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T06-48-56-741Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T07-07-54-966Z.yml b/.playwright-mcp/page-2026-08-25T07-07-54-966Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T07-07-54-966Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T07-11-38-160Z.yml b/.playwright-mcp/page-2026-08-25T07-11-38-160Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T07-11-38-160Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T07-31-24-236Z.yml b/.playwright-mcp/page-2026-08-25T07-31-24-236Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T07-31-24-236Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T08-09-30-148Z.yml b/.playwright-mcp/page-2026-08-25T08-09-30-148Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T08-09-30-148Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T08-47-21-216Z.yml b/.playwright-mcp/page-2026-08-25T08-47-21-216Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T08-47-21-216Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-06-04-966Z.yml b/.playwright-mcp/page-2026-08-25T09-06-04-966Z.yml
new file mode 100644
index 0000000..ef6adbc
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-06-04-966Z.yml
@@ -0,0 +1,94 @@
+- generic [ref=f1e4]:
+  - generic [ref=f1e5]:
+    - generic [ref=f1e6]:
+      - generic [ref=f1e7]:
+        - generic:
+          - button [ref=f1e8] [cursor=pointer]
+          - button [ref=f1e10] [cursor=pointer]
+          - button [ref=f1e12] [cursor=pointer]
+          - button [ref=f1e14] [cursor=pointer]
+          - button [ref=f1e16] [cursor=pointer]
+          - button [ref=f1e18] [cursor=pointer]
+          - button [ref=f1e22] [cursor=pointer]
+        - button [ref=f1e24] [cursor=pointer]
+      - button [ref=f1e31] [cursor=pointer]
+    - button [ref=f1e35] [cursor=pointer]
+    - button "light" [active] [ref=f1e236] [cursor=pointer]
+  - generic [ref=f1e50]:
+    - generic [ref=f1e79]:
+      - generic [ref=f1e88]:
+        - generic [ref=f1e89]: 鏅�
+        - strong [ref=f1e90]: 26.8掳C
+      - generic [ref=f1e94]:
+        - generic [ref=f1e95]: 婀垮害
+        - strong [ref=f1e96]: 68%
+      - generic [ref=f1e104]:
+        - generic [ref=f1e105]: 闄嶉洦姒傜巼
+        - strong [ref=f1e106]: 20%
+      - generic [ref=f1e111]:
+        - generic [ref=f1e112]: 灞变笢鐪�
+        - strong [ref=f1e113]: 娴庡崡甯�
+    - generic [ref=f1e114]:
+      - generic [ref=f1e115]:
+        - generic [ref=f1e125]:
+          - generic [ref=f1e126]: 绉嶆涓氭暟瀛楀寲骞冲彴
+          - generic [ref=f1e127]: AGRICULTURE DIGITAL PLATFORM
+        - generic [ref=f1e128]: 鏁板瓧璧嬭兘鍐滀笟 路 绉戞妧寮曢鏈潵
+      - generic [ref=f1e132]:
+        - generic "骞冲彴杩愯姒傝" [ref=f1e133]:
+          - generic [ref=f1e139]:
+            - text: 绉嶆闈㈢Н
+            - generic [ref=f1e140]: 12,580浜�
+            - generic [ref=f1e141]: 杈冩槰鏃� 鈫� 2.35%
+          - generic [ref=f1e148]:
+            - text: 鍦ㄧ嚎璁惧
+            - generic [ref=f1e149]: 1,286鍙�
+            - generic [ref=f1e150]: 杈冩槰鏃� 鈫� 5.21%
+          - generic [ref=f1e156]:
+            - text: 浠婃棩鐏屾簤
+            - generic [ref=f1e157]: 328浜�
+            - generic [ref=f1e158]: 杈冩槰鏃� 鈫� 1.15%
+          - generic [ref=f1e164]:
+            - text: AI 棰勮
+            - generic [ref=f1e165]: 6鏉�
+            - generic [ref=f1e166]: 杈冩槰鏃� 鈫� 12.50%
+        - generic [ref=f1e167]:
+          - generic [ref=f1e168]:
+            - generic [ref=f1e169]: 鍦熷¥澧掓儏鐩戞祴
+            - generic [ref=f1e170]:
+              - strong [ref=f1e173]: 68.5%
+              - generic [ref=f1e174]: 鍦熷¥婀垮害
+            - img [ref=f1e175]:
+              - generic [ref=f1e177]:
+                - generic [ref=f1e178]: 100%
+                - generic [ref=f1e179]: 50%
+                - generic [ref=f1e180]: 0%
+            - generic [ref=f1e183]:
+              - generic [ref=f1e184]: 00:00
+              - generic [ref=f1e185]: 06:00
+              - generic [ref=f1e186]: 12:00
+              - generic [ref=f1e187]: 18:00
+              - generic [ref=f1e188]: 24:00
+          - generic [ref=f1e189]:
+            - generic [ref=f1e190]: AI 鏅鸿兘鍒嗘瀽
+            - paragraph [ref=f1e194]: 褰撳墠浣滅墿闀垮娍鑹ソ锛屽湡澹ゅ鎯呴�傚疁锛屾湭鏉�3澶╂棤鏄庢樉闄嶉洦锛屽缓璁�傛椂鐏屾簤锛屼繚璇佷綔鐗╃ǔ浜ч珮浜с��
+    - generic [ref=f1e195]:
+      - generic [ref=f1e196]: 漏 2026 绉嶆涓氭暟瀛楀寲骞冲彴 鐗堟潈鎵�鏈�
+      - generic [ref=f1e197]: 椴両CP澶�2026001234鍙�-1
+      - generic [ref=f1e198] [cursor=pointer]: 闅愮鏀跨瓥
+      - generic [ref=f1e199]: "|"
+      - generic [ref=f1e200] [cursor=pointer]: 鐢ㄦ埛鍗忚
+  - generic [ref=f1e204]:
+    - generic [ref=f1e205]:
+      - heading "娆㈣繋鍥炴潵" [level=2] [ref=f1e206]
+      - paragraph [ref=f1e207]:
+        - generic [ref=f1e208]: 鐧诲綍绉嶆涓氭暟瀛楀寲骞冲彴锛屽紑鍚櫤鎱х妞�
+    - generic [ref=f1e210]:
+      - textbox "璇疯緭鍏ョ敤鎴峰悕" [ref=f1e216]: admin
+      - generic [ref=f1e222]:
+        - textbox "璇疯緭鍏ュ瘑鐮�" [ref=f1e223]: admin123
+        - generic [ref=f1e224] [cursor=pointer]
+    - generic [ref=f1e232]:
+      - checkbox "璁颁綇璐﹀彿" [ref=f1e233] [cursor=pointer]
+      - generic [ref=f1e234] [cursor=pointer]: 璁颁綇璐﹀彿
+    - button "login" [ref=f1e235] [cursor=pointer]: 鐧诲綍
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-06-42-806Z.yml b/.playwright-mcp/page-2026-08-25T09-06-42-806Z.yml
new file mode 100644
index 0000000..14f79d0
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-06-42-806Z.yml
@@ -0,0 +1,94 @@
+- generic [ref=f1e4]:
+  - generic [ref=f1e5]:
+    - generic [ref=f1e6]:
+      - generic [ref=f1e7]:
+        - generic:
+          - button [ref=f1e8] [cursor=pointer]
+          - button [ref=f1e10] [cursor=pointer]
+          - button [ref=f1e12] [cursor=pointer]
+          - button [ref=f1e14] [cursor=pointer]
+          - button [ref=f1e16] [cursor=pointer]
+          - button [ref=f1e18] [cursor=pointer]
+          - button [ref=f1e22] [cursor=pointer]
+        - button [ref=f1e24] [cursor=pointer]
+      - button [ref=f1e31] [cursor=pointer]
+    - button [ref=f1e35] [cursor=pointer]
+    - button "light" [ref=f1e236] [cursor=pointer]
+  - generic [ref=f1e50]:
+    - generic [ref=f1e79]:
+      - generic [ref=f1e88]:
+        - generic [ref=f1e89]: 鏅�
+        - strong [ref=f1e90]: 26.8掳C
+      - generic [ref=f1e94]:
+        - generic [ref=f1e95]: 婀垮害
+        - strong [ref=f1e96]: 68%
+      - generic [ref=f1e104]:
+        - generic [ref=f1e105]: 闄嶉洦姒傜巼
+        - strong [ref=f1e106]: 20%
+      - generic [ref=f1e111]:
+        - generic [ref=f1e112]: 灞变笢鐪�
+        - strong [ref=f1e113]: 娴庡崡甯�
+    - generic [ref=f1e114]:
+      - generic [ref=f1e115]:
+        - generic [ref=f1e125]:
+          - generic [ref=f1e126]: 绉嶆涓氭暟瀛楀寲骞冲彴
+          - generic [ref=f1e127]: AGRICULTURE DIGITAL PLATFORM
+        - generic [ref=f1e128]: 鏁板瓧璧嬭兘鍐滀笟 路 绉戞妧寮曢鏈潵
+      - generic [ref=f1e132]:
+        - generic "骞冲彴杩愯姒傝" [ref=f1e133]:
+          - generic [ref=f1e139]:
+            - text: 绉嶆闈㈢Н
+            - generic [ref=f1e140]: 12,580浜�
+            - generic [ref=f1e141]: 杈冩槰鏃� 鈫� 2.35%
+          - generic [ref=f1e148]:
+            - text: 鍦ㄧ嚎璁惧
+            - generic [ref=f1e149]: 1,286鍙�
+            - generic [ref=f1e150]: 杈冩槰鏃� 鈫� 5.21%
+          - generic [ref=f1e156]:
+            - text: 浠婃棩鐏屾簤
+            - generic [ref=f1e157]: 328浜�
+            - generic [ref=f1e158]: 杈冩槰鏃� 鈫� 1.15%
+          - generic [ref=f1e164]:
+            - text: AI 棰勮
+            - generic [ref=f1e165]: 6鏉�
+            - generic [ref=f1e166]: 杈冩槰鏃� 鈫� 12.50%
+        - generic [ref=f1e167]:
+          - generic [ref=f1e168]:
+            - generic [ref=f1e169]: 鍦熷¥澧掓儏鐩戞祴
+            - generic [ref=f1e170]:
+              - strong [ref=f1e173]: 68.5%
+              - generic [ref=f1e174]: 鍦熷¥婀垮害
+            - img [ref=f1e175]:
+              - generic [ref=f1e177]:
+                - generic [ref=f1e178]: 100%
+                - generic [ref=f1e179]: 50%
+                - generic [ref=f1e180]: 0%
+            - generic [ref=f1e183]:
+              - generic [ref=f1e184]: 00:00
+              - generic [ref=f1e185]: 06:00
+              - generic [ref=f1e186]: 12:00
+              - generic [ref=f1e187]: 18:00
+              - generic [ref=f1e188]: 24:00
+          - generic [ref=f1e189]:
+            - generic [ref=f1e190]: AI 鏅鸿兘鍒嗘瀽
+            - paragraph [ref=f1e194]: 褰撳墠浣滅墿闀垮娍鑹ソ锛屽湡澹ゅ鎯呴�傚疁锛屾湭鏉�3澶╂棤鏄庢樉闄嶉洦锛屽缓璁�傛椂鐏屾簤锛屼繚璇佷綔鐗╃ǔ浜ч珮浜с��
+    - generic [ref=f1e195]:
+      - generic [ref=f1e196]: 漏 2026 绉嶆涓氭暟瀛楀寲骞冲彴 鐗堟潈鎵�鏈�
+      - generic [ref=f1e197]: 椴両CP澶�2026001234鍙�-1
+      - generic [ref=f1e198] [cursor=pointer]: 闅愮鏀跨瓥
+      - generic [ref=f1e199]: "|"
+      - generic [ref=f1e200] [cursor=pointer]: 鐢ㄦ埛鍗忚
+  - generic [ref=f1e204]:
+    - generic [ref=f1e205]:
+      - heading "娆㈣繋鍥炴潵" [level=2] [ref=f1e206]
+      - paragraph [ref=f1e207]:
+        - generic [ref=f1e208]: 鐧诲綍绉嶆涓氭暟瀛楀寲骞冲彴锛屽紑鍚櫤鎱х妞�
+    - generic [ref=f1e210]:
+      - textbox "璇疯緭鍏ョ敤鎴峰悕" [ref=f1e216]: admin
+      - generic [ref=f1e222]:
+        - textbox "璇疯緭鍏ュ瘑鐮�" [ref=f1e223]: admin123
+        - generic [ref=f1e224] [cursor=pointer]
+    - generic [ref=f1e232]:
+      - checkbox "璁颁綇璐﹀彿" [ref=f1e233] [cursor=pointer]
+      - generic [ref=f1e234] [cursor=pointer]: 璁颁綇璐﹀彿
+    - button "login" [disabled]: 鐧诲綍
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-06-50-446Z.yml b/.playwright-mcp/page-2026-08-25T09-06-50-446Z.yml
new file mode 100644
index 0000000..15a975d
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-06-50-446Z.yml
@@ -0,0 +1,98 @@
+- generic [ref=f1e237]:
+  - complementary [ref=f1e239]:
+    - generic [ref=f1e240]:
+      - generic [ref=f1e241] [cursor=pointer]
+      - link "宸ヤ笟AI鏅洪�犲钩鍙� 宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f1e246] [cursor=pointer]:
+        - /url: javascript:void 0
+        - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f1e249]
+        - generic [ref=f1e250]: 宸ヤ笟AI鏅洪�犲钩鍙�
+      - menu [ref=f1e253]:
+        - menuitem "棣栭〉" [ref=f1e254] [cursor=pointer]
+        - listitem [ref=f1e259]:
+          - generic [ref=f1e260] [cursor=pointer]: 鍩虹鏁版嵁
+        - listitem [ref=f1e268]:
+          - generic [ref=f1e269] [cursor=pointer]: 浠撳偍鐗╂祦
+        - listitem [ref=f1e277]:
+          - generic [ref=f1e278] [cursor=pointer]: 涓�琚嬩竴鐮佺鐞�
+        - listitem [ref=f1e284]:
+          - generic [ref=f1e285] [cursor=pointer]: 璐ㄩ噺绠$悊
+        - listitem [ref=f1e291]:
+          - generic [ref=f1e292] [cursor=pointer]: 绯荤粺绠$悊
+      - generic [ref=f1e299] [cursor=pointer]
+  - generic [ref=f1e304]:
+    - generic [ref=f1e305]:
+      - banner [ref=f1e306]:
+        - button [ref=f1e307] [cursor=pointer]
+        - button [ref=f1e310] [cursor=pointer]
+        - navigation "breadcrumb" [ref=f1e315]:
+          - list [ref=f1e316]:
+            - listitem [ref=f1e317]:
+              - link "棣栭〉" [disabled] [ref=f1e318]
+        - generic [ref=f1e323]:
+          - generic [ref=f1e325] [cursor=pointer]:
+            - generic [ref=f1e329]: 鎼滅储
+            - generic [ref=f1e330]: Ctrl K
+          - button [ref=f1e332] [cursor=pointer]
+          - button "light" [ref=f1e337] [cursor=pointer]
+          - button [ref=f1e346] [cursor=pointer]
+          - button [ref=f1e352] [cursor=pointer]
+          - button [ref=f1e355] [cursor=pointer]
+          - button [ref=f1e361] [cursor=pointer]:
+            - button [ref=f1e363]
+          - button "宸ヤ綔鍙�" [ref=f1e367] [cursor=pointer]
+          - button "鐞嗗憳" [ref=f1e371] [cursor=pointer]
+      - generic [ref=f1e378]:
+        - generic [ref=f1e379]: 棣栭〉
+        - generic [ref=f1e398]:
+          - button [ref=f1e399] [cursor=pointer]
+          - generic [ref=f1e406] [cursor=pointer]
+          - generic [ref=f1e410] [cursor=pointer]
+    - main [ref=f1e417]:
+      - generic [ref=f1e420]:
+        - generic [ref=f1e421]:
+          - generic [ref=f1e431] [cursor=pointer]:
+            - generic [ref=f1e432]: 鍝佺鎬绘暟
+            - generic [ref=f1e433]: "1"
+          - generic [ref=f1e444] [cursor=pointer]:
+            - generic [ref=f1e445]: MES 鍝佺
+            - generic [ref=f1e446]: "0"
+          - generic [ref=f1e457] [cursor=pointer]:
+            - generic [ref=f1e458]: 鍝佺鍒嗙被
+            - generic [ref=f1e459]: "1"
+          - generic [ref=f1e468] [cursor=pointer]:
+            - generic [ref=f1e469]: 璁¢噺鍗曚綅
+            - generic [ref=f1e470]: "1"
+        - generic [ref=f1e472]:
+          - generic [ref=f1e480] [cursor=pointer]:
+            - generic [ref=f1e481]: 浜х嚎
+            - generic [ref=f1e482]: "1"
+          - generic [ref=f1e494] [cursor=pointer]:
+            - generic [ref=f1e495]: 鐢熶骇鎵规
+            - generic [ref=f1e496]: "2"
+          - generic [ref=f1e505] [cursor=pointer]:
+            - generic [ref=f1e506]: 琚嬬爜
+            - generic [ref=f1e507]: "101"
+          - generic [ref=f1e518] [cursor=pointer]:
+            - generic [ref=f1e519]: 鎵樼洏鐮�
+            - generic [ref=f1e520]: "10"
+        - generic [ref=f1e522]:
+          - generic [ref=f1e526]:
+            - generic [ref=f1e527]: 琚嬬爜鐢熸垚瓒嬪娍
+            - generic [ref=f1e529]:
+              - generic [ref=f1e530] [cursor=pointer]:
+                - generic [ref=f1e531]:
+                  - radio "杩� 7 澶�" [checked]
+                - generic [ref=f1e532]: 杩� 7 澶�
+              - generic [ref=f1e533] [cursor=pointer]:
+                - generic [ref=f1e534]:
+                  - radio "杩� 30 澶�"
+                - generic [ref=f1e535]: 杩� 30 澶�
+          - generic [ref=f1e540]: 鎵规鐘舵�佸垎甯�
+          - generic [ref=f1e549]: 琚嬬爜鐘舵�佸垎甯�
+        - generic [ref=f1e558]:
+          - generic [ref=f1e559]: 蹇嵎鍏ュ彛
+          - generic [ref=f1e563]:
+            - generic [ref=f1e564]: 鍝佺绠$悊
+            - generic [ref=f1e572]: 鍝佺鍒嗙被
+            - generic [ref=f1e580]: 鎵规鐢熶骇
+            - generic [ref=f1e589]: 璧嬬爜绠$悊
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-07-17-780Z.yml b/.playwright-mcp/page-2026-08-25T09-07-17-780Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-07-17-780Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-07-28-054Z.yml b/.playwright-mcp/page-2026-08-25T09-07-28-054Z.yml
new file mode 100644
index 0000000..0de1c4c
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-07-28-054Z.yml
@@ -0,0 +1,98 @@
+- generic [ref=f2e7]:
+  - complementary [ref=f2e9]:
+    - generic [ref=f2e10]:
+      - generic [ref=f2e11] [cursor=pointer]
+      - link "宸ヤ笟AI鏅洪�犲钩鍙� 宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f2e16] [cursor=pointer]:
+        - /url: javascript:void 0
+        - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f2e19]
+        - generic [ref=f2e20]: 宸ヤ笟AI鏅洪�犲钩鍙�
+      - menu [ref=f2e23]:
+        - menuitem "棣栭〉" [ref=f2e24] [cursor=pointer]
+        - listitem [ref=f2e29]:
+          - generic [ref=f2e30] [cursor=pointer]: 鍩虹鏁版嵁
+        - listitem [ref=f2e38]:
+          - generic [ref=f2e39] [cursor=pointer]: 浠撳偍鐗╂祦
+        - listitem [ref=f2e47]:
+          - generic [ref=f2e48] [cursor=pointer]: 涓�琚嬩竴鐮佺鐞�
+        - listitem [ref=f2e54]:
+          - generic [ref=f2e55] [cursor=pointer]: 璐ㄩ噺绠$悊
+        - listitem [ref=f2e61]:
+          - generic [ref=f2e62] [cursor=pointer]: 绯荤粺绠$悊
+      - generic [ref=f2e69] [cursor=pointer]
+  - generic [ref=f2e74]:
+    - generic [ref=f2e75]:
+      - banner [ref=f2e76]:
+        - button [ref=f2e77] [cursor=pointer]
+        - button [ref=f2e80] [cursor=pointer]
+        - navigation "breadcrumb" [ref=f2e85]:
+          - list [ref=f2e86]:
+            - listitem [ref=f2e87]:
+              - link "棣栭〉" [disabled] [ref=f2e88]
+        - generic [ref=f2e93]:
+          - generic [ref=f2e95] [cursor=pointer]:
+            - generic [ref=f2e99]: 鎼滅储
+            - generic [ref=f2e100]: Ctrl K
+          - button [ref=f2e102] [cursor=pointer]
+          - button "dark" [active] [ref=f2e107] [cursor=pointer]
+          - button [ref=f2e116] [cursor=pointer]
+          - button [ref=f2e122] [cursor=pointer]
+          - button [ref=f2e125] [cursor=pointer]
+          - button [ref=f2e131] [cursor=pointer]:
+            - button [ref=f2e133]
+          - button "宸ヤ綔鍙�" [ref=f2e137] [cursor=pointer]
+          - button "鐞嗗憳" [ref=f2e141] [cursor=pointer]
+      - generic [ref=f2e148]:
+        - generic [ref=f2e149]: 棣栭〉
+        - generic [ref=f2e168]:
+          - button [ref=f2e169] [cursor=pointer]
+          - generic [ref=f2e176] [cursor=pointer]
+          - generic [ref=f2e180] [cursor=pointer]
+    - main [ref=f2e187]:
+      - generic [ref=f2e190]:
+        - generic [ref=f2e191]:
+          - generic [ref=f2e201] [cursor=pointer]:
+            - generic [ref=f2e202]: 鍝佺鎬绘暟
+            - generic [ref=f2e203]: "1"
+          - generic [ref=f2e214] [cursor=pointer]:
+            - generic [ref=f2e215]: MES 鍝佺
+            - generic [ref=f2e216]: "0"
+          - generic [ref=f2e227] [cursor=pointer]:
+            - generic [ref=f2e228]: 鍝佺鍒嗙被
+            - generic [ref=f2e229]: "1"
+          - generic [ref=f2e238] [cursor=pointer]:
+            - generic [ref=f2e239]: 璁¢噺鍗曚綅
+            - generic [ref=f2e240]: "1"
+        - generic [ref=f2e242]:
+          - generic [ref=f2e250] [cursor=pointer]:
+            - generic [ref=f2e251]: 浜х嚎
+            - generic [ref=f2e252]: "1"
+          - generic [ref=f2e264] [cursor=pointer]:
+            - generic [ref=f2e265]: 鐢熶骇鎵规
+            - generic [ref=f2e266]: "2"
+          - generic [ref=f2e275] [cursor=pointer]:
+            - generic [ref=f2e276]: 琚嬬爜
+            - generic [ref=f2e277]: "101"
+          - generic [ref=f2e288] [cursor=pointer]:
+            - generic [ref=f2e289]: 鎵樼洏鐮�
+            - generic [ref=f2e290]: "10"
+        - generic [ref=f2e292]:
+          - generic [ref=f2e296]:
+            - generic [ref=f2e297]: 琚嬬爜鐢熸垚瓒嬪娍
+            - generic [ref=f2e299]:
+              - generic [ref=f2e300] [cursor=pointer]:
+                - generic [ref=f2e301]:
+                  - radio "杩� 7 澶�" [checked]
+                - generic [ref=f2e302]: 杩� 7 澶�
+              - generic [ref=f2e303] [cursor=pointer]:
+                - generic [ref=f2e304]:
+                  - radio "杩� 30 澶�"
+                - generic [ref=f2e305]: 杩� 30 澶�
+          - generic [ref=f2e310]: 鎵规鐘舵�佸垎甯�
+          - generic [ref=f2e319]: 琚嬬爜鐘舵�佸垎甯�
+        - generic [ref=f2e328]:
+          - generic [ref=f2e329]: 蹇嵎鍏ュ彛
+          - generic [ref=f2e333]:
+            - generic [ref=f2e334]: 鍝佺绠$悊
+            - generic [ref=f2e342]: 鍝佺鍒嗙被
+            - generic [ref=f2e350]: 鎵规鐢熶骇
+            - generic [ref=f2e359]: 璧嬬爜绠$悊
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-07-53-861Z.yml b/.playwright-mcp/page-2026-08-25T09-07-53-861Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-07-53-861Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-08-01-907Z.yml b/.playwright-mcp/page-2026-08-25T09-08-01-907Z.yml
new file mode 100644
index 0000000..99b9ade
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-08-01-907Z.yml
@@ -0,0 +1,94 @@
+- generic [ref=f5e4]:
+  - generic [ref=f5e5]:
+    - generic [ref=f5e6]:
+      - generic [ref=f5e7]:
+        - generic:
+          - button [ref=f5e8] [cursor=pointer]
+          - button [ref=f5e12] [cursor=pointer]
+          - button [ref=f5e14] [cursor=pointer]
+          - button [ref=f5e16] [cursor=pointer]
+          - button [ref=f5e18] [cursor=pointer]
+          - button [ref=f5e20] [cursor=pointer]
+          - button [ref=f5e22] [cursor=pointer]
+        - button [ref=f5e24] [cursor=pointer]
+      - button [ref=f5e31] [cursor=pointer]
+    - button [ref=f5e35] [cursor=pointer]
+    - button "dark" [ref=f5e41] [cursor=pointer]
+  - generic [ref=f5e50]:
+    - generic [ref=f5e79]:
+      - generic [ref=f5e88]:
+        - generic [ref=f5e89]: 鏅�
+        - strong [ref=f5e90]: 26.8掳C
+      - generic [ref=f5e94]:
+        - generic [ref=f5e95]: 婀垮害
+        - strong [ref=f5e96]: 68%
+      - generic [ref=f5e104]:
+        - generic [ref=f5e105]: 闄嶉洦姒傜巼
+        - strong [ref=f5e106]: 20%
+      - generic [ref=f5e111]:
+        - generic [ref=f5e112]: 灞变笢鐪�
+        - strong [ref=f5e113]: 娴庡崡甯�
+    - generic [ref=f5e114]:
+      - generic [ref=f5e115]:
+        - generic [ref=f5e125]:
+          - generic [ref=f5e126]: 绉嶆涓氭暟瀛楀寲骞冲彴
+          - generic [ref=f5e127]: AGRICULTURE DIGITAL PLATFORM
+        - generic [ref=f5e128]: 鏁板瓧璧嬭兘鍐滀笟 路 绉戞妧寮曢鏈潵
+      - generic [ref=f5e132]:
+        - generic "骞冲彴杩愯姒傝" [ref=f5e133]:
+          - generic [ref=f5e139]:
+            - text: 绉嶆闈㈢Н
+            - generic [ref=f5e140]: 12,580浜�
+            - generic [ref=f5e141]: 杈冩槰鏃� 鈫� 2.35%
+          - generic [ref=f5e148]:
+            - text: 鍦ㄧ嚎璁惧
+            - generic [ref=f5e149]: 1,286鍙�
+            - generic [ref=f5e150]: 杈冩槰鏃� 鈫� 5.21%
+          - generic [ref=f5e156]:
+            - text: 浠婃棩鐏屾簤
+            - generic [ref=f5e157]: 328浜�
+            - generic [ref=f5e158]: 杈冩槰鏃� 鈫� 1.15%
+          - generic [ref=f5e164]:
+            - text: AI 棰勮
+            - generic [ref=f5e165]: 6鏉�
+            - generic [ref=f5e166]: 杈冩槰鏃� 鈫� 12.50%
+        - generic [ref=f5e167]:
+          - generic [ref=f5e168]:
+            - generic [ref=f5e169]: 鍦熷¥澧掓儏鐩戞祴
+            - generic [ref=f5e170]:
+              - strong [ref=f5e173]: 68.5%
+              - generic [ref=f5e174]: 鍦熷¥婀垮害
+            - img [ref=f5e175]:
+              - generic [ref=f5e177]:
+                - generic [ref=f5e178]: 100%
+                - generic [ref=f5e179]: 50%
+                - generic [ref=f5e180]: 0%
+            - generic [ref=f5e183]:
+              - generic [ref=f5e184]: 00:00
+              - generic [ref=f5e185]: 06:00
+              - generic [ref=f5e186]: 12:00
+              - generic [ref=f5e187]: 18:00
+              - generic [ref=f5e188]: 24:00
+          - generic [ref=f5e189]:
+            - generic [ref=f5e190]: AI 鏅鸿兘鍒嗘瀽
+            - paragraph [ref=f5e194]: 褰撳墠浣滅墿闀垮娍鑹ソ锛屽湡澹ゅ鎯呴�傚疁锛屾湭鏉�3澶╂棤鏄庢樉闄嶉洦锛屽缓璁�傛椂鐏屾簤锛屼繚璇佷綔鐗╃ǔ浜ч珮浜с��
+    - generic [ref=f5e195]:
+      - generic [ref=f5e196]: 漏 2026 绉嶆涓氭暟瀛楀寲骞冲彴 鐗堟潈鎵�鏈�
+      - generic [ref=f5e197]: 椴両CP澶�2026001234鍙�-1
+      - generic [ref=f5e198] [cursor=pointer]: 闅愮鏀跨瓥
+      - generic [ref=f5e199]: "|"
+      - generic [ref=f5e200] [cursor=pointer]: 鐢ㄦ埛鍗忚
+  - generic [ref=f5e204]:
+    - generic [ref=f5e205]:
+      - heading "娆㈣繋鍥炴潵" [level=2] [ref=f5e206]
+      - paragraph [ref=f5e207]:
+        - generic [ref=f5e208]: 鐧诲綍绉嶆涓氭暟瀛楀寲骞冲彴锛屽紑鍚櫤鎱х妞�
+    - generic [ref=f5e210]:
+      - textbox "璇疯緭鍏ョ敤鎴峰悕" [ref=f5e216]: admin
+      - generic [ref=f5e222]:
+        - textbox "璇疯緭鍏ュ瘑鐮�" [ref=f5e223]: admin123
+        - generic [ref=f5e224] [cursor=pointer]
+    - generic [ref=f5e232]:
+      - checkbox "璁颁綇璐﹀彿" [ref=f5e233] [cursor=pointer]
+      - generic [ref=f5e234] [cursor=pointer]: 璁颁綇璐﹀彿
+    - button "login" [ref=f5e235] [cursor=pointer]: 鐧诲綍
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-20-39-383Z.yml b/.playwright-mcp/page-2026-08-25T09-20-39-383Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-20-39-383Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-44-56-418Z.yml b/.playwright-mcp/page-2026-08-25T09-44-56-418Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-44-56-418Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-25T09-50-51-027Z.yml b/.playwright-mcp/page-2026-08-25T09-50-51-027Z.yml
new file mode 100644
index 0000000..0947cbf
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-25T09-50-51-027Z.yml
@@ -0,0 +1,78 @@
+- generic [ref=f16e4]:
+  - generic [ref=f16e5]:
+    - generic [ref=f16e6]:
+      - generic [ref=f16e7]:
+        - generic:
+          - button [ref=f16e8] [cursor=pointer]
+          - button [ref=f16e12] [cursor=pointer]
+          - button [ref=f16e14] [cursor=pointer]
+          - button [ref=f16e16] [cursor=pointer]
+          - button [ref=f16e18] [cursor=pointer]
+          - button [ref=f16e20] [cursor=pointer]
+          - button [ref=f16e22] [cursor=pointer]
+        - button [ref=f16e24] [cursor=pointer]
+      - button [ref=f16e31] [cursor=pointer]
+    - button [ref=f16e35] [cursor=pointer]
+    - button "dark" [ref=f16e41] [cursor=pointer]
+  - generic [ref=f16e51]:
+    - generic [ref=f16e52]:
+      - generic [ref=f16e62]:
+        - generic [ref=f16e63]: 绉嶆涓氭暟瀛楀寲骞冲彴
+        - generic [ref=f16e64]: AGRICULTURE DIGITAL PLATFORM
+      - generic [ref=f16e65]: 鏁板瓧璧嬭兘鍐滀笟 路 绉戞妧寮曢鏈潵
+    - generic [ref=f16e69]:
+      - generic "骞冲彴杩愯姒傝" [ref=f16e70]:
+        - generic [ref=f16e76]:
+          - text: 绉嶆闈㈢Н
+          - generic [ref=f16e77]: 12,580浜�
+          - generic [ref=f16e78]: 杈冩槰鏃� 鈫� 2.35%
+        - generic [ref=f16e85]:
+          - text: 鍦ㄧ嚎璁惧
+          - generic [ref=f16e86]: 1,286鍙�
+          - generic [ref=f16e87]: 杈冩槰鏃� 鈫� 5.21%
+        - generic [ref=f16e93]:
+          - text: 浠婃棩鐏屾簤
+          - generic [ref=f16e94]: 328浜�
+          - generic [ref=f16e95]: 杈冩槰鏃� 鈫� 1.15%
+        - generic [ref=f16e101]:
+          - text: AI 棰勮
+          - generic [ref=f16e102]: 6鏉�
+          - generic [ref=f16e103]: 杈冩槰鏃� 鈫� 12.50%
+      - generic [ref=f16e104]:
+        - generic [ref=f16e105]:
+          - generic [ref=f16e106]: 鍦熷¥澧掓儏鐩戞祴
+          - generic [ref=f16e107]:
+            - strong [ref=f16e110]: 68.5%
+            - generic [ref=f16e111]: 鍦熷¥婀垮害
+          - img [ref=f16e112]:
+            - generic [ref=f16e114]:
+              - generic [ref=f16e115]: 100%
+              - generic [ref=f16e116]: 50%
+              - generic [ref=f16e117]: 0%
+          - generic [ref=f16e120]:
+            - generic [ref=f16e121]: 00:00
+            - generic [ref=f16e122]: 06:00
+            - generic [ref=f16e123]: 12:00
+            - generic [ref=f16e124]: 18:00
+            - generic [ref=f16e125]: 24:00
+        - generic [ref=f16e126]:
+          - generic [ref=f16e127]: AI 鏅鸿兘鍒嗘瀽
+          - paragraph [ref=f16e131]: 褰撳墠浣滅墿闀垮娍鑹ソ锛屽湡澹ゅ鎯呴�傚疁锛屾湭鏉�3澶╂棤鏄庢樉闄嶉洦锛屽缓璁�傛椂鐏屾簤锛屼繚璇佷綔鐗╃ǔ浜ч珮浜с��
+  - generic [ref=f16e135]:
+    - generic [ref=f16e136]:
+      - heading "娆㈣繋鍥炴潵" [level=2] [ref=f16e137]
+      - paragraph [ref=f16e138]:
+        - generic [ref=f16e139]: 鐧诲綍绉嶆涓氭暟瀛楀寲骞冲彴锛屽紑鍚櫤鎱х妞�
+    - generic [ref=f16e141]:
+      - textbox "璐﹀彿" [ref=f16e147]:
+        - /placeholder: 璇疯緭鍏ョ敤鎴峰悕
+        - text: admin
+      - generic [ref=f16e153]:
+        - textbox "瀵嗙爜" [ref=f16e154]:
+          - /placeholder: 璇疯緭鍏ュ瘑鐮�
+          - text: admin123
+        - button "鍒囨崲瀵嗙爜鍙鎬�" [ref=f16e155] [cursor=pointer]
+    - generic [ref=f16e163]:
+      - checkbox "璁颁綇璐﹀彿" [ref=f16e164] [cursor=pointer]
+      - generic [ref=f16e165] [cursor=pointer]: 璁颁綇璐﹀彿
+    - button "login" [ref=f16e166] [cursor=pointer]: 鐧诲綍
\ No newline at end of file
diff --git a/docs/mes_product_sales_scan_integration.md b/docs/mes_product_sales_scan_integration.md
new file mode 100644
index 0000000..6acfb10
--- /dev/null
+++ b/docs/mes_product_sales_scan_integration.md
@@ -0,0 +1,76 @@
+# MES 閿�鍞嚭搴撴壂鐮佹嫞璐� - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- 閿�鍞嚭搴撳崟璇︽儏椤�
+- 閿�鍞嚭搴撴嫞璐ч〉
+- 搴撳瓨鍙拌处鏌ヨ椤�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. 閿�鍞嚭搴撳崟杩涘叆鈥滃緟鎷h揣鈥濈姸鎬佸悗锛屽墠绔壂鎻忚鐮佹垨鎵樼洏鐮併��
+2. 鎵弿鍐呭璋冪敤鎵爜鎺ュ彛锛屽悗绔瘑鍒爜绫诲瀷骞跺叧鑱旂敓浜ф壒娆°�佺墿鏂欏強搴撳瓨璁板綍銆�
+3. 鎵爜缁撴灉涓殑搴撳瓨璁板綍銆佹壒娆°�佷粨搴撱�佸簱鍖恒�佸簱浣嶅拰鏁伴噺甯﹀叆閿�鍞嚭搴撴槑缁嗐��
+4. 鎵弿瀹屾垚鍚庣户缁皟鐢ㄥ師鏈夆�滄墽琛屾嫞璐р�濇帴鍙o紝缁熶竴鍒涘缓搴撳瓨鍗犵敤锛涙壂鐮佹帴鍙d笉鐩存帴鎵e噺搴撳瓨銆�
+5. 鍑哄簱鍗曞畬鎴愭椂鐢卞師鏈夆�滄墽琛屽嚭搴撯�濇帴鍙f墸鍑忓簱瀛橈紝骞舵洿鏂板簱瀛樼姸鎬併��
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/mes/wm/product-sales/scan` | 鎵弿琚嬬爜鎴栨墭鐩樼爜骞剁敓鎴愰攢鍞嚭搴撴槑缁� |
+| PUT | `/mes/wm/product-sales/stock?id={id}` | 鎵ц鎷h揣骞跺垱寤哄簱瀛樺崰鐢� |
+| PUT | `/mes/wm/product-sales/finish?id={id}` | 瀹屾垚鍑哄簱骞舵墸鍑忓簱瀛� |
+
+**鎵爜璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| salesId | Long | 鏄� | 閿�鍞嚭搴撳崟 ID锛屽崟鎹繀椤诲浜庡緟鎷h揣鐘舵�� |
+| scanContent | String | 鏄� | 琚嬬爜鎴栨墭鐩樼爜 |
+| quantity | BigDecimal | 鍚� | 鏈鎷h揣鏁伴噺锛屼笉濉椂浣跨敤閿�鍞鏁伴噺 |
+
+**鎵爜鍝嶅簲瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| scanType | String | `BAG` 琚嬬爜锛宍PALLET` 鎵樼洏鐮� |
+| codeId | Long | 鐮佽褰� ID |
+| itemId銆乥atchId銆乥atchCode | Long/Long/String | 鐗╂枡鍜屾壒娆′俊鎭� |
+| materialStockId | Long | 鍏宠仈搴撳瓨璁板綍 ID |
+| availableQuantity | BigDecimal | 褰撳墠搴撳瓨鏁伴噺 |
+| scanQuantity銆乷utboundQuantity | BigDecimal | 鏈鎵弿鏁伴噺鍜屽嚭搴撴暟閲� |
+| detailId | Long | 鐢熸垚鐨勯攢鍞嚭搴撴槑缁� ID |
+| warehouseId銆乴ocationId銆乤reaId | Long | 搴撳瓨鎵�鍦ㄤ粨搴撱�佸簱鍖恒�佸簱浣� |
+| alreadyScanned | Boolean | 閲嶅鎵弿鏃朵负 true锛屽苟杩斿洖宸叉湁鏄庣粏 ID |
+| palletExpanded | Boolean | 鎵樼洏灞曞紑鏍囪瘑 |
+| bagCount銆乮nboundBagCount | Integer | 鎵樼洏琚嬬爜鎬绘暟銆佸凡绱琚嬬爜鏁� |
+| message | String | 鎿嶄綔鎻愮ず |
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| scanType銆乻canContent | 鎵爜缁撴灉鍖� | 鏄剧ず璇嗗埆绫诲瀷鍜屽師濮嬬爜鍊� |
+| itemCode銆乮temName銆乥atchCode | 鏄庣粏琛� | 浠庢壂鐮佺粨鏋滃甫鍏ワ紝涓嶅厑璁稿墠绔嚜琛屾敼鍐� |
+| materialStockId銆佷粨搴撱�佸簱鍖恒�佸簱浣� | 鏄庣粏鏁版嵁 | 淇濆瓨搴撳瓨鍏宠仈锛岀敤浜庢嫞璐у拰鍑哄簱鏍¢獙 |
+| availableQuantity | 鎵爜缁撴灉鍖� | 鐢ㄤ簬鎻愮ず褰撳墠搴撳瓨鏁伴噺 |
+| stockState | 搴撳瓨鍙拌处 | `10` 鏆傚瓨搴撱�乣20` 鍚堟牸搴撱�乣30` 宸插嚭搴� |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 琚嬬爜鎵弿 | 鎸夎鐮佸叧鑱旀壒娆″拰鐗╂枡锛屽苟鐢熸垚甯� `bagCodeId` 鐨勬槑缁� |
+| 鎵樼洏鎵弿 | 鍏宠仈鎵樼洏鍙婂叾琚嬬爜锛岀敓鎴愬甫 `palletCodeId` 鐨勬槑缁嗭紝骞惰繑鍥炲睍寮�缁熻 |
+| 閲嶅鎵弿 | 鍚屼竴閿�鍞嚭搴撳崟閲嶅鎵弿鍚屼竴鐮佹椂涓嶉噸澶嶇敓鎴愭槑缁嗭紝杩斿洖宸叉湁鏄庣粏 |
+| 鏁伴噺瓒呴檺 | 鎵弿鏁伴噺涓嶅緱瓒呰繃搴撳瓨鍙敤鏁伴噺锛屼篃涓嶅緱瓒呰繃閿�鍞鍓╀綑鏁伴噺 |
+| 搴撳瓨鍙樻洿 | 鎵爜鍙敓鎴愭槑缁嗭紱鎷h揣鏃跺崰鐢紝瀹屾垚鍑哄簱鏃舵墸鍑忓簱瀛� |
+| 搴撳瓨鐘舵�� | 鏂板缓搴撳瓨涓烘殏瀛樺簱锛涘叆搴撳悗鏈夋暟閲忎负鍚堟牸搴擄紱鏁伴噺鎵e噺鑷抽浂涓哄凡鍑哄簱 |
+
+## 娉ㄦ剰浜嬮」
+
+- 鎵爜鎺ュ彛鍙兘鐢ㄤ簬寰呮嫞璐х姸鎬佺殑閿�鍞嚭搴撳崟銆�
+- 鎵樼洏鍐呰鐮佸睍寮�鐨勫叿浣撴槑缁嗘暟閲忓簲浠ユ帴鍙h繑鍥炵殑 `bagCount` 鍜� `inboundBagCount` 涓哄噯銆�
+- 閲嶅鎵爜鍝嶅簲鐨勯儴鍒嗙墿鏂欏拰搴撳瓨瀛楁鍙兘涓虹┖锛屽墠绔簲浼樺厛浣跨敤 `detailId` 鏌ヨ宸叉湁鏄庣粏銆�
+- 鍚庣鎺ュ彛鍙樻洿涓嶄慨鏀� `mom-pro2-before` 鍓嶇椤圭洰銆�
diff --git a/img/img.png b/img/img.png
new file mode 100644
index 0000000..ba59fc9
--- /dev/null
+++ b/img/img.png
Binary files differ
diff --git a/img/img_1.png b/img/img_1.png
new file mode 100644
index 0000000..5a10871
--- /dev/null
+++ b/img/img_1.png
Binary files differ
diff --git a/sql/mysql/mes_wm_sales_outbound_traceability.sql b/sql/mysql/mes_wm_sales_outbound_traceability.sql
new file mode 100644
index 0000000..8f707d1
--- /dev/null
+++ b/sql/mysql/mes_wm_sales_outbound_traceability.sql
@@ -0,0 +1,25 @@
+-- 鍑哄簱娴侀�氱鐞嗭細閿�鍞嚭搴撲笌琚嬬爜/鎵樼洏鐮佸叧鑱旓紙鏃犵鎴峰瓧娈碉級
+-- 鎵ц鍓嶈纭鐩爣鏁版嵁搴撲负 mom-thzy锛屽苟閫愭潯鎵ц銆�
+
+ALTER TABLE mes_wm_product_sales_detail
+  ADD COLUMN bag_code_id bigint DEFAULT NULL COMMENT '琚嬬爜缂栧彿' AFTER area_id;
+ALTER TABLE mes_wm_product_sales_detail
+  ADD COLUMN pallet_code_id bigint DEFAULT NULL COMMENT '鎵樼洏鐮佺紪鍙�' AFTER bag_code_id;
+ALTER TABLE mes_wm_product_sales_detail
+  ADD INDEX idx_sales_detail_bag_code (bag_code_id);
+ALTER TABLE mes_wm_product_sales_detail
+  ADD INDEX idx_sales_detail_pallet_code (pallet_code_id);
+
+ALTER TABLE mes_pro_bag_code
+  ADD COLUMN sales_id bigint DEFAULT NULL COMMENT '鏈�杩戦攢鍞嚭搴撳崟缂栧彿' AFTER inbound_line_code;
+ALTER TABLE mes_pro_bag_code
+  ADD COLUMN outbound_time datetime DEFAULT NULL COMMENT '鏈�杩戦攢鍞嚭搴撴椂闂�' AFTER sales_id;
+ALTER TABLE mes_pro_bag_code
+  ADD INDEX idx_bag_code_sales (sales_id);
+
+ALTER TABLE mes_pro_pallet
+  ADD COLUMN sales_id bigint DEFAULT NULL COMMENT '鏈�杩戦攢鍞嚭搴撳崟缂栧彿' AFTER status;
+ALTER TABLE mes_pro_pallet
+  ADD COLUMN outbound_time datetime DEFAULT NULL COMMENT '鏈�杩戦攢鍞嚭搴撴椂闂�' AFTER sales_id;
+ALTER TABLE mes_pro_pallet
+  ADD INDEX idx_pallet_sales (sales_id);
diff --git a/sql/mysql/mes_wm_stock_state_init.sql b/sql/mysql/mes_wm_stock_state_init.sql
new file mode 100644
index 0000000..f56bd96
--- /dev/null
+++ b/sql/mysql/mes_wm_stock_state_init.sql
@@ -0,0 +1,32 @@
+-- 浠撳偍搴撳瓨鐘舵�佸垵濮嬪寲锛堟棤绉熸埛瀛楁锛�
+SET @stock_state_exists = (
+  SELECT COUNT(*)
+  FROM information_schema.columns
+  WHERE table_schema = DATABASE()
+    AND table_name = 'mes_wm_material_stock'
+    AND column_name = 'stock_state'
+);
+SET @stock_state_sql = IF(
+  @stock_state_exists = 0,
+  'ALTER TABLE mes_wm_material_stock ADD COLUMN stock_state tinyint NOT NULL DEFAULT 20 COMMENT ''搴撳瓨鐘舵�侊細10鏆傚瓨搴擄紝20鍚堟牸搴擄紝30宸插嚭搴�'' AFTER in_transit_quantity',
+  'SELECT 1'
+);
+PREPARE stock_state_stmt FROM @stock_state_sql;
+EXECUTE stock_state_stmt;
+DEALLOCATE PREPARE stock_state_stmt;
+
+SET @stock_state_index_exists = (
+  SELECT COUNT(*)
+  FROM information_schema.statistics
+  WHERE table_schema = DATABASE()
+    AND table_name = 'mes_wm_material_stock'
+    AND index_name = 'idx_stock_state_query'
+);
+SET @stock_state_index_sql = IF(
+  @stock_state_index_exists = 0,
+  'CREATE INDEX idx_stock_state_query ON mes_wm_material_stock (stock_state, item_id, batch_id, warehouse_id, receipt_time)',
+  'SELECT 1'
+);
+PREPARE stock_state_index_stmt FROM @stock_state_index_sql;
+EXECUTE stock_state_index_stmt;
+DEALLOCATE PREPARE stock_state_index_stmt;
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 2e7dc10..8be7fce 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
@@ -30,6 +30,9 @@
     @Schema(description = "渚涘簲鍟嗙紪鍙�")
     private Long vendorId;
 
+    @Schema(description = "搴撳瓨鐘舵�侊細10-鏆傚瓨搴擄紝20-鍚堟牸搴擄紝30-宸插嚭搴�")
+    private Integer stockState;
+
     @Schema(description = "寮�濮嬫椂闂达紙鍔ㄦ�佺洏鐐圭敤锛�")
     private LocalDateTime startTime;
 
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 b5a18ac..6549016 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
@@ -48,6 +48,9 @@
     @Schema(description = "渚涘簲鍟嗙紪鍙�", example = "1")
     private Long vendorId;
 
+    @Schema(description = "搴撳瓨鐘舵�侊細10-鏆傚瓨搴擄紝20-鍚堟牸搴擄紝30-宸插嚭搴�", example = "20")
+    private Integer stockState;
+
     @Schema(description = "鏄惁鍐荤粨", example = "false")
     private Boolean frozen;
 
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 8552e20..5cec30c 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
@@ -101,6 +101,10 @@
     @ExcelProperty("鍏ュ簱鏃堕棿")
     private LocalDateTime receiptTime;
 
+    @Schema(description = "搴撳瓨鐘舵�侊細10-鏆傚瓨搴擄紝20-鍚堟牸搴擄紝30-宸插嚭搴�", example = "20")
+    @ExcelProperty("搴撳瓨鐘舵��")
+    private Integer stockState;
+
     @Schema(description = "鏄惁鍐荤粨", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
     @ExcelProperty("鏄惁鍐荤粨")
     private Boolean frozen;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java
index 21ed7b7..7704cda 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java
@@ -14,6 +14,8 @@
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesSaveReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesShippingReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesScanReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesScanRespVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO;
 import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesService;
@@ -122,6 +124,14 @@
         return success(productSalesService.checkProductSalesQuantity(id));
     }
 
+    @PostMapping("/scan")
+    @Operation(summary = "鎵爜鎷h揣")
+    @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:stock')")
+    public CommonResult<MesWmProductSalesScanRespVO> scanProductSales(
+            @Valid @RequestBody MesWmProductSalesScanReqVO reqVO) {
+        return success(productSalesService.scanProductSales(reqVO));
+    }
+
     @PutMapping("/stock")
     @Operation(summary = "鎵ц鎷h揣")
     @Parameter(name = "id", description = "缂栧彿", required = true)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanReqVO.java
new file mode 100644
index 0000000..04d71a8
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 閿�鍞嚭搴撴壂鐮佹嫞璐� Request VO")
+@Data
+public class MesWmProductSalesScanReqVO {
+
+    @Schema(description = "閿�鍞嚭搴撳崟ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "閿�鍞嚭搴撳崟ID涓嶈兘涓虹┖")
+    private Long salesId;
+
+    @Schema(description = "鎵弿鍐呭锛堣鐮佹垨鎵樼洏鐮侊級", requiredMode = Schema.RequiredMode.REQUIRED, example = "PC2026081920-0001")
+    @NotEmpty(message = "鎵弿鍐呭涓嶈兘涓虹┖")
+    private String scanContent;
+
+    @Schema(description = "鏈鍑哄簱鏁伴噺锛堜负绌哄垯鍙栬琚嬬爜/鏁存墭鍏ㄩ儴鏁伴噺锛�", example = "50")
+    private BigDecimal quantity;
+
+}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanRespVO.java
new file mode 100644
index 0000000..aec512f
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanRespVO.java
@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 閿�鍞嚭搴撴壂鐮佹嫞璐� Response VO")
+@Data
+public class MesWmProductSalesScanRespVO {
+
+    @Schema(description = "璇嗗埆绫诲瀷锛歅ALLET-鎵樼洏鐮侊紝BAG-琚嬬爜", example = "BAG")
+    private String scanType;
+
+    @Schema(description = "鎵弿鐨勭爜缂栧彿", example = "12")
+    private Long codeId;
+
+    @Schema(description = "鎵弿鍐呭锛堣鐮佹垨鎵樼洏鐮侊級", example = "PC2026081920-0001")
+    private String scanContent;
+
+    @Schema(description = "鐗╂枡ID", example = "1")
+    private Long itemId;
+
+    @Schema(description = "鐗╂枡缂栫爜", example = "ITEM001")
+    private String itemCode;
+
+    @Schema(description = "鐗╂枡鍚嶇О", example = "绋荤")
+    private String itemName;
+
+    @Schema(description = "鎵规ID", example = "1")
+    private Long batchId;
+
+    @Schema(description = "鎵规鍙�", example = "PC2026081920")
+    private String batchCode;
+
+    @Schema(description = "搴撳瓨璁板綍ID", example = "1")
+    private Long materialStockId;
+
+    @Schema(description = "鍙嚭搴撴暟閲�", example = "50.00")
+    private BigDecimal availableQuantity;
+
+    @Schema(description = "鏈/鏈墭瀹為檯鏁伴噺", example = "50.00")
+    private BigDecimal scanQuantity;
+
+    @Schema(description = "鏈鍑哄簱鏁伴噺", example = "50.00")
+    private BigDecimal outboundQuantity;
+
+    @Schema(description = "鏄惁宸叉壂鎻忚繃锛堝箓绛夎繑鍥炲凡鏈夋槑缁嗭級", example = "false")
+    private Boolean alreadyScanned;
+
+    @Schema(description = "鐢熸垚鐨勯攢鍞嚭搴撴槑缁咺D锛堝箓绛夎繑鍥炴椂浜︽湁鍊硷級", example = "100")
+    private Long detailId;
+
+    @Schema(description = "浠撳簱ID", example = "1")
+    private Long warehouseId;
+
+    @Schema(description = "搴撳尯ID", example = "1")
+    private Long locationId;
+
+    @Schema(description = "搴撲綅ID", example = "1")
+    private Long areaId;
+
+    @Schema(description = "鏄惁鎵樼洏灞曞紑锛堟墭鐩樼爜蹇呬负 true锛�", example = "false")
+    private Boolean palletExpanded;
+
+    @Schema(description = "缁戝畾鐨勮鐮佹暟閲忥紙鎵樼洏灞曞紑鏃惰繑鍥烇級", example = "100")
+    private Integer bagCount;
+
+    @Schema(description = "宸茬疮鍔犲嚭搴撶殑琚嬬爜鏁伴噺锛堟墭鐩樺睍寮�鏃惰繑鍥烇級", example = "0")
+    private Integer inboundBagCount;
+
+    @Schema(description = "鎿嶄綔淇℃伅鎻愮ず", example = "鎵爜鎴愬姛")
+    private String message;
+
+}
\ No newline at end of file
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 d010580..50e4df7 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
@@ -36,5 +36,7 @@
     private Long inboundEventId;
     private String inboundDeviceCode;
     private String inboundLineCode;
+    private Long salesId;
+    private LocalDateTime outboundTime;
     private String remark;
 }
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 4cdc673..c246328 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
@@ -69,6 +69,14 @@
      */
     private Integer status;
     /**
+     * 鏈�杩戦攢鍞嚭搴撳崟缂栧彿
+     */
+    private Long salesId;
+    /**
+     * 鏈�杩戦攢鍞嚭搴撴椂闂�
+     */
+    private java.time.LocalDateTime outboundTime;
+    /**
      * 澶囨敞
      */
     private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java
index e387678..ed87830 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java
@@ -113,6 +113,11 @@
     // ==================== 鐘舵�� ====================
 
     /**
+     * 搴撳瓨鐘舵�侊細10-鏆傚瓨搴擄紝20-鍚堟牸搴擄紝30-宸插嚭搴�
+     */
+    private Integer stockState;
+
+    /**
      * 鏄惁鍐荤粨
      */
     private Boolean frozen;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java
index d5aa12a..3ad3273 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java
@@ -93,6 +93,14 @@
      */
     private Long areaId;
     /**
+     * 琚嬬爜缂栧彿
+     */
+    private Long bagCodeId;
+    /**
+     * 鎵樼洏鐮佺紪鍙�
+     */
+    private Long palletCodeId;
+    /**
      * 澶囨敞
      */
     private String remark;
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 e167d16..226c82a 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
@@ -131,6 +131,15 @@
                    @Param("toStatus") Integer toStatus, @Param("cancelTime") LocalDateTime cancelTime,
                    @Param("cancelReason") String cancelReason);
 
+    @Update("UPDATE mes_pro_bag_code SET sales_id = #{salesId}, outbound_time = #{outboundTime}, update_time = NOW() "
+            + "WHERE id = #{id} AND deleted = 0")
+    void markOutbound(@Param("id") Long id, @Param("salesId") Long salesId,
+                      @Param("outboundTime") LocalDateTime outboundTime);
+
+    @Update("UPDATE mes_pro_bag_code SET sales_id = NULL, outbound_time = NULL, update_time = NOW() "
+            + "WHERE id = #{id} AND deleted = 0")
+    void clearOutbound(@Param("id") Long id);
+
     @Select("SELECT COUNT(*) FROM mes_pro_bag_code WHERE batch_id = #{batchId} " +
             "AND deleted = 0 AND status <> 30")
     int selectEffectiveCountByBatchId(@Param("batchId") Long batchId);
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 8e2b856..293487b 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
@@ -49,4 +49,13 @@
     @Select("SELECT IFNULL(MAX(pallet_no), 0) FROM mes_pro_pallet WHERE batch_id = #{batchId}")
     Integer selectMaxPalletNo(@Param("batchId") Long batchId);
 
+    @org.apache.ibatis.annotations.Update("UPDATE mes_pro_pallet SET sales_id = #{salesId}, outbound_time = #{outboundTime}, update_time = NOW() "
+            + "WHERE id = #{id} AND deleted = 0")
+    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 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/wm/materialstock/MesWmMaterialStockMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
index 38a7df2..44636f3 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
@@ -32,6 +32,7 @@
                 .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId())
                 .eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId())
                 .eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId())
+                .eqIfPresent(MesWmMaterialStockDO::getStockState, reqVO.getStockState())
                 .eqIfPresent(MesWmMaterialStockDO::getFrozen, reqVO.getFrozen());
         wrapper.ne(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO)
                 .orderByAsc(MesWmMaterialStockDO::getReceiptTime);
@@ -177,6 +178,7 @@
                 .eqIfPresent(MesWmMaterialStockDO::getItemId, reqVO.getItemId())
                 .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId())
                 .eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId())
+                .eqIfPresent(MesWmMaterialStockDO::getStockState, reqVO.getStockState())
                 .likeIfPresent(MesWmMaterialStockDO::getBatchCode, reqVO.getBatchCode())
                 .geIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getStartTime())
                 .leIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getEndTime())
@@ -187,6 +189,14 @@
     /**
      * 鎸夌墿鏂欑紪鍙锋壒閲忔煡璇㈠簱瀛樿褰曪紙鐢ㄤ簬鐗╂枡闇�姹傚簱瀛樻牎楠岋級
      */
+    default List<MesWmMaterialStockDO> selectListByItemAndBatch(Long itemId, Long batchId) {
+        return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+                .eq(MesWmMaterialStockDO::getItemId, itemId)
+                .eqIfPresent(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();
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java
index cac3187..878783d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java
@@ -22,6 +22,18 @@
         return selectList(MesWmProductSalesDetailDO::getSalesId, salesId);
     }
 
+    default MesWmProductSalesDetailDO selectBySalesIdAndBagCodeId(Long salesId, Long bagCodeId) {
+        return selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MesWmProductSalesDetailDO>()
+                .eq(MesWmProductSalesDetailDO::getSalesId, salesId)
+                .eq(MesWmProductSalesDetailDO::getBagCodeId, bagCodeId));
+    }
+
+    default MesWmProductSalesDetailDO selectBySalesIdAndPalletCodeId(Long salesId, Long palletCodeId) {
+        return selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MesWmProductSalesDetailDO>()
+                .eq(MesWmProductSalesDetailDO::getSalesId, salesId)
+                .eq(MesWmProductSalesDetailDO::getPalletCodeId, palletCodeId));
+    }
+
     default void deleteByLineId(Long lineId) {
         delete(MesWmProductSalesDetailDO::getLineId, lineId);
     }
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 0e8a332..033f956 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
@@ -716,6 +716,16 @@
     ErrorCode WM_PRODUCT_SALES_LINE_NOTICE_LINE_OQC_MISMATCH = new ErrorCode(1_040_714_033,
             "鍑哄簱琛� OQC 妫�楠屾爣璇嗕笌鍙戣揣閫氱煡鍗曡涓嶄竴鑷�");
 
+    // ========== MES 閿�鍞嚭搴�-鎵爜鎷h揣锛�1-040-714-100锛� ==========
+    ErrorCode WM_PRODUCT_SALES_SCAN_BAG_NOT_EXISTS = new ErrorCode(1_040_714_100, "鎵弿鐨勮鐮佷笉瀛樺湪鎴栧凡浣滃簾");
+    ErrorCode WM_PRODUCT_SALES_SCAN_PALLET_NOT_EXISTS = new ErrorCode(1_040_714_101, "鎵弿鐨勬墭鐩樼爜涓嶅瓨鍦ㄦ垨宸蹭綔搴�");
+    ErrorCode WM_PRODUCT_SALES_SCAN_PALLET_NOT_BOUND = new ErrorCode(1_040_714_102, "鎵弿鐨勬墭鐩樼爜鏈粦瀹氫换浣曡鐮侊紝鏃犳硶鍑哄簱");
+    ErrorCode WM_PRODUCT_SALES_SCAN_BAG_NOT_INBOUND = new ErrorCode(1_040_714_103, "琚嬬爜灏氭湭鍏ュ簱锛屾棤娉曞嚭搴�");
+    ErrorCode WM_PRODUCT_SALES_SCAN_BAG_NO_BATCH = new ErrorCode(1_040_714_104, "琚嬬爜鏃犲叧鑱旂敓浜ф壒娆★紝鏃犳硶鍑哄簱");
+    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, "璇ヨ鐮佸凡鎵弿鍑哄簱锛岃鍕块噸澶嶆壂鎻�");
+
     // ========== MES 浠撳簱绠$悊-鏉傞」鍑哄簱鍗曪紙1-040-715-000锛� ==========
     ErrorCode WM_MISC_ISSUE_NOT_EXISTS = new ErrorCode(1_040_715_000, "鏉傞」鍑哄簱鍗曚笉瀛樺湪");
     ErrorCode WM_MISC_ISSUE_CODE_DUPLICATE = new ErrorCode(1_040_715_001, "鏉傞」鍑哄簱鍗曠紪鐮佸凡瀛樺湪");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmStockStateEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmStockStateEnum.java
new file mode 100644
index 0000000..a32f150
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmStockStateEnum.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.mes.enums.wm;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum MesWmStockStateEnum {
+
+    TEMP(10, "鏆傚瓨搴�"),
+    QUALIFIED(20, "鍚堟牸搴�"),
+    OUT(30, "宸插嚭搴�");
+
+    private final Integer state;
+    private final String name;
+}
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 1769303..c498951 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
@@ -126,4 +126,19 @@
      */
     List<MesProBagCodeDO> getBagCodeListByBatchId(Long batchId);
 
+    /**
+     * 鏍囪琚嬬爜涓哄凡鍑哄簱锛堣褰曢攢鍞嚭搴撳崟缂栧彿鍜屽嚭搴撴椂闂达級
+     *
+     * @param id      琚嬬爜缂栧彿
+     * @param salesId 閿�鍞嚭搴撳崟缂栧彿
+     */
+    void markOutbound(Long id, Long salesId);
+
+    /**
+     * 娓呴櫎琚嬬爜鐨勫嚭搴撴爣璁帮紙鍙栨秷鍑哄簱鍗曟椂浣跨敤锛�
+     *
+     * @param id 琚嬬爜缂栧彿
+     */
+    void clearOutbound(Long id);
+
 }
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 8966276..2f69f53 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
@@ -343,6 +343,16 @@
         return bagCodeMapper.selectListByBatchId(batchId);
     }
 
+    @Override
+    public void markOutbound(Long id, Long salesId) {
+        bagCodeMapper.markOutbound(id, salesId, LocalDateTime.now());
+    }
+
+    @Override
+    public void clearOutbound(Long id) {
+        bagCodeMapper.clearOutbound(id);
+    }
+
     // ==================== 绉佹湁鏂规硶 ====================
 
     /**
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 2dfb6e6..9407667 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
@@ -87,4 +87,19 @@
      */
     void updatePalletBagCount(Long palletId, Integer bagCount);
 
+    /**
+     * 鏍囪鎵樼洏鐮佷负宸插嚭搴擄紙璁板綍閿�鍞嚭搴撳崟缂栧彿鍜屽嚭搴撴椂闂达級
+     *
+     * @param id      鎵樼洏鐮佺紪鍙�
+     * @param salesId 閿�鍞嚭搴撳崟缂栧彿
+     */
+    void markOutbound(Long id, Long salesId);
+
+    /**
+     * 娓呴櫎鎵樼洏鐮佺殑鍑哄簱鏍囪锛堝彇娑堝嚭搴撳崟鏃朵娇鐢級
+     *
+     * @param id 鎵樼洏鐮佺紪鍙�
+     */
+    void clearOutbound(Long id);
+
 }
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 285f8f7..66e33ed 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
@@ -221,4 +221,14 @@
         palletMapper.updateById(new MesProPalletDO().setId(palletId).setBagCount(bagCount));
     }
 
+    @Override
+    public void markOutbound(Long id, Long salesId) {
+        palletMapper.markOutbound(id, salesId, java.time.LocalDateTime.now());
+    }
+
+    @Override
+    public void clearOutbound(Long id) {
+        palletMapper.clearOutbound(id);
+    }
+
 }
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 8ad1a45..50c9faa 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
@@ -128,6 +128,8 @@
     MesWmMaterialStockDO getMaterialStockByCompositeKey(Long itemId, Long warehouseId, Long locationId, Long areaId,
                                                          Long batchId, Long vendorId);
 
+    List<MesWmMaterialStockDO> getMaterialStockListByItemAndBatch(Long itemId, Long batchId);
+
     /**
      * 鏇存柊搴撳瓨鏁伴噺
      *
@@ -137,6 +139,8 @@
      */
     void updateMaterialStockQuantity(Long id, BigDecimal quantity, boolean checkFlag);
 
+    void updateMaterialStockState(Long id, Integer stockState);
+
     /**
      * 搴撲綅娣锋斁瑙勫垯鏍¢獙
      *
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 f8f4734..d609a27 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
@@ -18,6 +18,7 @@
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper;
 import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
 import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
@@ -186,6 +187,7 @@
                 .batchId(batchId).batchCode(batchCode).vendorId(vendorId)
                 .quantity(BigDecimal.ZERO) // 鍒濆鏁伴噺涓� 0锛岀敱 updateMaterialStockQuantity 鏇存柊
                 .receiptTime(receiptTime != null ? receiptTime : LocalDateTime.now())
+                .stockState(MesWmStockStateEnum.TEMP.getState())
                 .frozen(false)
                 .build();
         materialStockMapper.insert(newStock);
@@ -201,6 +203,11 @@
     }
 
     @Override
+    public List<MesWmMaterialStockDO> getMaterialStockListByItemAndBatch(Long itemId, Long batchId) {
+        return materialStockMapper.selectListByItemAndBatch(itemId, batchId);
+    }
+
+    @Override
     public void updateMaterialStockQuantity(Long id, BigDecimal quantity, boolean checkFlag) {
         // 鏇存柊搴撳瓨鏁伴噺锛圡apper 灞� CAS 闃茶礋搴撳瓨锛沜heckFlag=false 鏃跺厑璁歌礋鏁帮級
         int updatedRows = materialStockMapper.updateQuantity(id, quantity, checkFlag);
@@ -210,6 +217,11 @@
     }
 
     @Override
+    public void updateMaterialStockState(Long id, Integer stockState) {
+        materialStockMapper.updateById(new MesWmMaterialStockDO().setId(id).setStockState(stockState));
+    }
+
+    @Override
     public void checkAreaMixingRule(Long areaId, Long itemId, Long batchId) {
         // 1.1 鏍¢獙搴撲綅蹇呴』瀛樺湪
         MesWmWarehouseAreaDO area = areaService.validateWarehouseAreaExists(areaId);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java
index cf2d409..003c54a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java
@@ -4,6 +4,8 @@
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesSaveReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesShippingReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesScanReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesScanRespVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO;
 import jakarta.validation.Valid;
 
@@ -80,6 +82,8 @@
      */
     void stockProductSales(Long id);
 
+    MesWmProductSalesScanRespVO scanProductSales(@Valid MesWmProductSalesScanReqVO reqVO);
+
     /**
      * 濉啓杩愬崟锛堝緟濉啓杩愬崟 鈫� 寰呮墽琛屽嚭搴擄級
      *
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 9338217..c2a2cc6 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
@@ -9,6 +9,15 @@
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesSaveReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesShippingReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesScanReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesScanRespVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper;
+import cn.iocoder.yudao.module.mes.service.pro.bagcode.MesProBagCodeService;
+import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO;
@@ -24,6 +33,7 @@
 import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
 import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
 import cn.iocoder.yudao.module.mes.service.wm.salesnotice.MesWmSalesNoticeService;
+import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
 import cn.iocoder.yudao.module.mes.service.wm.stockreserve.MesWmStockReserveService;
 import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
 import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
@@ -58,6 +68,14 @@
     private MesWmProductSalesMapper productSalesMapper;
     @Resource
     private MesWmProductSalesLineMapper productSalesLineMapper;
+    @Resource
+    private MesWmProductSalesDetailMapper productSalesDetailMapper;
+    @Resource
+    private MesProBagCodeService bagCodeService;
+    @Resource
+    private MesProPalletService palletService;
+    @Resource
+    private MesProBatchService wmBatchService;
 
     @Resource
     private MesWmProductSalesLineService productSalesLineService;
@@ -200,6 +218,66 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
+    public MesWmProductSalesScanRespVO scanProductSales(MesWmProductSalesScanReqVO reqVO) {
+        MesWmProductSalesDO sales = validateProductSalesExists(reqVO.getSalesId());
+        if (ObjUtil.notEqual(MesWmProductSalesStatusEnum.APPROVING.getStatus(), sales.getStatus())) {
+            throw exception(WM_PRODUCT_SALES_CANNOT_PICK);
+        }
+        MesProPalletDO pallet = palletService.getPalletByCode(reqVO.getScanContent());
+        MesProBagCodeDO bag = pallet == null ? bagCodeService.getBagCodeByCode(reqVO.getScanContent()) : null;
+        if (pallet == null && bag == null) {
+            throw exception(WM_MATERIAL_STOCK_NOT_EXISTS);
+        }
+        Long codeId = pallet != null ? pallet.getId() : bag.getId();
+        MesWmProductSalesDetailDO existed = pallet != null
+                ? productSalesDetailMapper.selectBySalesIdAndPalletCodeId(reqVO.getSalesId(), codeId)
+                : productSalesDetailMapper.selectBySalesIdAndBagCodeId(reqVO.getSalesId(), codeId);
+        if (existed != null) {
+            return new MesWmProductSalesScanRespVO().setScanType(pallet != null ? "PALLET" : "BAG")
+                    .setCodeId(codeId).setScanContent(reqVO.getScanContent()).setAlreadyScanned(true)
+                    .setDetailId(existed.getId()).setOutboundQuantity(existed.getQuantity()).setMessage("璇ョ爜宸叉壂鎻�");
+        }
+        Long batchId = pallet != null ? pallet.getBatchId() : bag.getBatchId();
+        MesProBatchDO batch = wmBatchService.getBatch(batchId);
+        if (batch == null) {
+            throw exception(WM_TRANSACTION_BATCH_NOT_EXISTS);
+        }
+        List<MesWmProductSalesLineDO> lines = productSalesLineService.getProductSalesLineListBySalesId(reqVO.getSalesId());
+        MesWmProductSalesLineDO line = lines.stream().filter(item -> ObjUtil.equal(item.getItemId(), batch.getItemId())).findFirst().orElse(null);
+        if (line == null) {
+            throw exception(WM_PRODUCT_SALES_DETAIL_ITEM_MISMATCH);
+        }
+        BigDecimal quantity = reqVO.getQuantity();
+        if (quantity == null) {
+            quantity = line.getQuantity();
+        }
+        List<MesWmMaterialStockDO> stocks = materialStockService.getMaterialStockListByItemAndBatch(batch.getItemId(), batchId);
+        BigDecimal outboundQuantity = quantity;
+        MesWmMaterialStockDO stock = stocks.stream().filter(item -> item.getQuantity().compareTo(outboundQuantity) >= 0).findFirst().orElse(null);
+        if (stock == null) {
+            throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
+        }
+        BigDecimal scanned = productSalesDetailService.getProductSalesDetailListByLineId(line.getId()).stream()
+                .map(MesWmProductSalesDetailDO::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
+        if (scanned.add(quantity).compareTo(line.getQuantity()) > 0) {
+            throw exception(WM_PRODUCT_SALES_LINE_QUANTITY_INVALID);
+        }
+        MesWmProductSalesDetailDO detail = new MesWmProductSalesDetailDO().setLineId(line.getId())
+                .setSalesId(reqVO.getSalesId()).setItemId(batch.getItemId()).setQuantity(quantity)
+                .setMaterialStockId(stock.getId()).setBatchId(batchId).setBatchCode(batch.getCode())
+                .setWarehouseId(stock.getWarehouseId()).setLocationId(stock.getLocationId()).setAreaId(stock.getAreaId())
+                .setBagCodeId(pallet == null ? codeId : null).setPalletCodeId(pallet != null ? codeId : null);
+        productSalesDetailMapper.insert(detail);
+        return new MesWmProductSalesScanRespVO().setScanType(pallet != null ? "PALLET" : "BAG")
+                .setCodeId(codeId).setScanContent(reqVO.getScanContent()).setItemId(batch.getItemId())
+                .setBatchId(batchId).setBatchCode(batch.getCode()).setMaterialStockId(stock.getId())
+                .setAvailableQuantity(stock.getQuantity()).setScanQuantity(quantity).setOutboundQuantity(quantity)
+                .setAlreadyScanned(false).setDetailId(detail.getId()).setWarehouseId(stock.getWarehouseId())
+                .setLocationId(stock.getLocationId()).setAreaId(stock.getAreaId()).setMessage("鎵爜鎴愬姛");
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
     public void stockProductSales(Long id) {
         // 鏍¢獙瀛樺湪
         MesWmProductSalesDO sales = validateProductSalesExists(id);
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 031dc5d..98c781b 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
@@ -14,6 +14,7 @@
 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.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.service.mdm.MesMdmItemService;
 import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
@@ -124,6 +125,10 @@
         // 2.3 鏇存柊搴撳瓨鏁伴噺
         boolean checkFlag = ObjUtil.defaultIfNull(reqDTO.getCheckFlag(), true);
         materialStockService.updateMaterialStockQuantity(materialStock.getId(), reqDTO.getQuantity(), checkFlag);
+        MesWmMaterialStockDO updatedStock = materialStockService.getMaterialStock(materialStock.getId());
+        BigDecimal newQuantity = updatedStock.getQuantity();
+        materialStockService.updateMaterialStockState(updatedStock.getId(), newQuantity.signum() <= 0
+                ? MesWmStockStateEnum.OUT.getState() : MesWmStockStateEnum.QUALIFIED.getState());
 
         // 3. 鎻掑叆浜嬪姟娴佹按
         MesWmTransactionDO transaction = MesWmTransactionDO.builder()

--
Gitblit v1.9.3