9 小时以前 1b3fd46c7ccbf636208bcf098c5588441bb71f78
feat(mes): 添加销售出库扫码拣货功能

- 新增销售出库扫码拣货相关错误码定义
- 在袋码和托盘码实体中添加销售出库相关字段
- 实现袋码和托盘码的出库标记和清除功能
- 添加库存状态字段并实现状态更新逻辑
- 新增销售出库扫码拣货控制器接口
- 实现扫码拣货业务逻辑和服务方法
- 添加数据库表结构变更SQL脚本
- 创建扫码拣货请求和响应对象
- 完善销售出库明细中袋码和托盘码关联字段
已删除100个文件
已添加24个文件
已修改22个文件
1061 ■■■■■ 文件已修改
.image/Java监控.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/MySQL.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/OA请假-列表.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/OA请假-发起.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/OA请假-详情.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/Redis.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/01.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/02.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/03.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/04.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/05.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/06.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/07.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/08.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/admin-uniapp/09.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/ai-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/ai-preview.gif 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/bpm-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/crm-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/erp-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/im-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/im-preview-home.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/im-preview-manager.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/infra-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/iot-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/iot-preview.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/mall-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/mall-preview.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/mes-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/mes-preview.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/project-vs.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/ruoyi-vue-pro-architecture.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/ruoyi-vue-pro-biz.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/system-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/wms-feature.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/wms-preview.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/yudao-cloud-architecture.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/common/yudao-roadmap.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/个人中心.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/代码生成.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/令牌管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/任务列表-审批.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/任务列表-已办.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/任务列表-待办.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/任务日志.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/商户信息.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/在线用户.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/大屏设计器-列表.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/大屏设计器-编辑.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/大屏设计器-预览.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/字典数据.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/字典类型.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/定时任务.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/岗位管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/工作流设计器-bpmn.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/工作流设计器-simple.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/应用信息-列表.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/应用信息-编辑.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/应用管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/我的流程-列表.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/我的流程-发起.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/我的流程-详情.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/报表设计器-图形报表.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/报表设计器-打印设计.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/报表设计器-数据报表.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/操作日志.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/支付订单.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/敏感词.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/数据库文档.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/文件管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/文件管理2.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/文件配置.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/日志中心.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/流程模型-列表.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/流程模型-定义.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/流程模型-设计.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/流程表单.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/生成效果.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/用户分组.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/用户管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/登录.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/登录日志.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/短信日志.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/短信模板.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/短信渠道.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/租户套餐.png 补丁 | 查看 | 原始文档 | blame | 历史
.image/租户管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/系统接口.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/菜单管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/表单构建.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/角色管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/访问日志.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/退款订单.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/通知公告.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/部门管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/配置管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/链路追踪.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/错误日志.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/错误码管理.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.image/首页.jpg 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T06-48-56-741Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T07-07-54-966Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T07-11-38-160Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T07-31-24-236Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T08-09-30-148Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T08-47-21-216Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-06-04-966Z.yml 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-06-42-806Z.yml 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-06-50-446Z.yml 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-07-17-780Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-07-28-054Z.yml 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-07-53-861Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-08-01-907Z.yml 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-20-39-383Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-44-56-418Z.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.playwright-mcp/page-2026-08-25T09-50-51-027Z.yml 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/mes_product_sales_scan_integration.md 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
img/img.png 补丁 | 查看 | 原始文档 | blame | 历史
img/img_1.png 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql/mes_wm_sales_outbound_traceability.sql 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql/mes_wm_stock_state_init.sql 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanReqVO.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesScanRespVO.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmStockStateEnum.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.image/Java¼à¿Ø.jpg
Binary files differ
.image/MySQL.jpg
Binary files differ
.image/OAÇë¼Ù-Áбí.jpg
Binary files differ
.image/OAÇë¼Ù-·¢Æð.jpg
Binary files differ
.image/OAÇë¼Ù-ÏêÇé.jpg
Binary files differ
.image/Redis.jpg
Binary files differ
.image/admin-uniapp/01.png
Binary files differ
.image/admin-uniapp/02.png
Binary files differ
.image/admin-uniapp/03.png
Binary files differ
.image/admin-uniapp/04.png
Binary files differ
.image/admin-uniapp/05.png
Binary files differ
.image/admin-uniapp/06.png
Binary files differ
.image/admin-uniapp/07.png
Binary files differ
.image/admin-uniapp/08.png
Binary files differ
.image/admin-uniapp/09.png
Binary files differ
.image/common/ai-feature.png
Binary files differ
.image/common/ai-preview.gif
Binary files differ
.image/common/bpm-feature.png
Binary files differ
.image/common/crm-feature.png
Binary files differ
.image/common/erp-feature.png
Binary files differ
.image/common/im-feature.png
Binary files differ
.image/common/im-preview-home.png
Binary files differ
.image/common/im-preview-manager.png
Binary files differ
.image/common/infra-feature.png
Binary files differ
.image/common/iot-feature.png
Binary files differ
.image/common/iot-preview.png
Binary files differ
.image/common/mall-feature.png
Binary files differ
.image/common/mall-preview.png
Binary files differ
.image/common/mes-feature.png
Binary files differ
.image/common/mes-preview.png
Binary files differ
.image/common/project-vs.png
Binary files differ
.image/common/ruoyi-vue-pro-architecture.png
Binary files differ
.image/common/ruoyi-vue-pro-biz.png
Binary files differ
.image/common/system-feature.png
Binary files differ
.image/common/wms-feature.png
Binary files differ
.image/common/wms-preview.png
Binary files differ
.image/common/yudao-cloud-architecture.png
Binary files differ
.image/common/yudao-roadmap.png
Binary files differ
.image/¸öÈËÖÐÐÄ.jpg
Binary files differ
.image/´úÂëÉú³É.jpg
Binary files differ
.image/ÁîÅÆ¹ÜÀí.jpg
Binary files differ
.image/ÈÎÎñÁбí-ÉóÅú.jpg
Binary files differ
.image/ÈÎÎñÁбí-ÒѰì.jpg
Binary files differ
.image/ÈÎÎñÁбí-´ý°ì.jpg
Binary files differ
.image/ÈÎÎñÈÕÖ¾.jpg
Binary files differ
.image/ÉÌ»§ÐÅÏ¢.jpg
Binary files differ
.image/ÔÚÏßÓû§.jpg
Binary files differ
.image/´óÆÁÉè¼ÆÆ÷-Áбí.jpg
Binary files differ
.image/´óÆÁÉè¼ÆÆ÷-±à¼­.jpg
Binary files differ
.image/´óÆÁÉè¼ÆÆ÷-Ô¤ÀÀ.jpg
Binary files differ
.image/×ÖµäÊý¾Ý.jpg
Binary files differ
.image/×ÖµäÀàÐÍ.jpg
Binary files differ
.image/¶¨Ê±ÈÎÎñ.jpg
Binary files differ
.image/¸Úλ¹ÜÀí.jpg
Binary files differ
.image/¹¤×÷Á÷Éè¼ÆÆ÷-bpmn.jpg
Binary files differ
.image/¹¤×÷Á÷Éè¼ÆÆ÷-simple.jpg
Binary files differ
.image/Ó¦ÓÃÐÅÏ¢-Áбí.jpg
Binary files differ
.image/Ó¦ÓÃÐÅÏ¢-±à¼­.jpg
Binary files differ
.image/Ó¦ÓùÜÀí.jpg
Binary files differ
.image/ÎÒµÄÁ÷³Ì-Áбí.jpg
Binary files differ
.image/ÎÒµÄÁ÷³Ì-·¢Æð.jpg
Binary files differ
.image/ÎÒµÄÁ÷³Ì-ÏêÇé.jpg
Binary files differ
.image/±¨±íÉè¼ÆÆ÷-ͼÐᨱí.jpg
Binary files differ
.image/±¨±íÉè¼ÆÆ÷-´òÓ¡Éè¼Æ.jpg
Binary files differ
.image/±¨±íÉè¼ÆÆ÷-Êý¾Ý±¨±í.jpg
Binary files differ
.image/²Ù×÷ÈÕÖ¾.jpg
Binary files differ
.image/Ö§¸¶¶©µ¥.jpg
Binary files differ
.image/Ãô¸Ð´Ê.jpg
Binary files differ
.image/Êý¾Ý¿âÎĵµ.jpg
Binary files differ
.image/Îļþ¹ÜÀí.jpg
Binary files differ
.image/Îļþ¹ÜÀí2.jpg
Binary files differ
.image/ÎļþÅäÖÃ.jpg
Binary files differ
.image/ÈÕÖ¾ÖÐÐÄ.jpg
Binary files differ
.image/Á÷³ÌÄ£ÐÍ-Áбí.jpg
Binary files differ
.image/Á÷³ÌÄ£ÐÍ-¶¨Òå.jpg
Binary files differ
.image/Á÷³ÌÄ£ÐÍ-Éè¼Æ.jpg
Binary files differ
.image/Á÷³Ì±íµ¥.jpg
Binary files differ
.image/Éú³ÉЧ¹û.jpg
Binary files differ
.image/Óû§·Ö×é.jpg
Binary files differ
.image/Óû§¹ÜÀí.jpg
Binary files differ
.image/怬.jpg
Binary files differ
.image/µÇ¼ÈÕÖ¾.jpg
Binary files differ
.image/¶ÌÐÅÈÕÖ¾.jpg
Binary files differ
.image/¶ÌÐÅÄ£°å.jpg
Binary files differ
.image/¶ÌÐÅÇþµÀ.jpg
Binary files differ
.image/×â»§ÌײÍ.png
Binary files differ
.image/×â»§¹ÜÀí.jpg
Binary files differ
.image/ϵͳ½Ó¿Ú.jpg
Binary files differ
.image/²Ëµ¥¹ÜÀí.jpg
Binary files differ
.image/±íµ¥¹¹½¨.jpg
Binary files differ
.image/½ÇÉ«¹ÜÀí.jpg
Binary files differ
.image/·ÃÎÊÈÕÖ¾.jpg
Binary files differ
.image/Í˿µ¥.jpg
Binary files differ
.image/֪ͨ¹«¸æ.jpg
Binary files differ
.image/²¿ÃŹÜÀí.jpg
Binary files differ
.image/ÅäÖùÜÀí.jpg
Binary files differ
.image/Á´Â·×·×Ù.jpg
Binary files differ
.image/´íÎóÈÕÖ¾.jpg
Binary files differ
.image/´íÎóÂë¹ÜÀí.jpg
Binary files differ
.image/Ê×Ò³.jpg
Binary files differ
.playwright-mcp/page-2026-08-25T06-48-56-741Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.playwright-mcp/page-2026-08-25T07-07-54-966Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.playwright-mcp/page-2026-08-25T07-11-38-160Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.playwright-mcp/page-2026-08-25T07-31-24-236Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.playwright-mcp/page-2026-08-25T08-09-30-148Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.playwright-mcp/page-2026-08-25T08-47-21-216Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.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]: é²ICP备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]: ç™»å½•
.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]: é²ICP备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]: ç™»å½•
.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]: èµ‹ç ç®¡ç†
.playwright-mcp/page-2026-08-25T09-07-17-780Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.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]: èµ‹ç ç®¡ç†
.playwright-mcp/page-2026-08-25T09-07-53-861Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.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]: é²ICP备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]: ç™»å½•
.playwright-mcp/page-2026-08-25T09-20-39-383Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.playwright-mcp/page-2026-08-25T09-44-56-418Z.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
- generic [active]: å·¥ä¸šAI智造平台
.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]: ç™»å½•
docs/mes_product_sales_scan_integration.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
# MES é”€å”®å‡ºåº“扫码拣货 - å‰ç«¯è”调方案
## æ¶‰åŠé¡µé¢
- é”€å”®å‡ºåº“单详情页
- é”€å”®å‡ºåº“拣货页
- åº“存台账查询页
## ä¸šåŠ¡æµç¨‹ä¸Žæ•°æ®å¸¦å…¥
1. é”€å”®å‡ºåº“单进入“待拣货”状态后,前端扫描袋码或托盘码。
2. æ‰«æå†…容调用扫码接口,后端识别码类型并关联生产批次、物料及库存记录。
3. æ‰«ç ç»“果中的库存记录、批次、仓库、库区、库位和数量带入销售出库明细。
4. æ‰«æå®ŒæˆåŽç»§ç»­è°ƒç”¨åŽŸæœ‰â€œæ‰§è¡Œæ‹£è´§â€æŽ¥å£ï¼Œç»Ÿä¸€åˆ›å»ºåº“å­˜å ç”¨ï¼›æ‰«ç æŽ¥å£ä¸ç›´æŽ¥æ‰£å‡åº“å­˜ã€‚
5. å‡ºåº“单完成时由原有“执行出库”接口扣减库存,并更新库存状态。
## API
| æ–¹æ³• | è·¯å¾„ | è¯´æ˜Ž |
|------|------|------|
| POST | `/mes/wm/product-sales/scan` | æ‰«æè¢‹ç æˆ–托盘码并生成销售出库明细 |
| PUT | `/mes/wm/product-sales/stock?id={id}` | æ‰§è¡Œæ‹£è´§å¹¶åˆ›å»ºåº“存占用 |
| PUT | `/mes/wm/product-sales/finish?id={id}` | å®Œæˆå‡ºåº“并扣减库存 |
**扫码请求参数:**
| å‚æ•° | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| salesId | Long | æ˜¯ | é”€å”®å‡ºåº“单 ID,单据必须处于待拣货状态 |
| scanContent | String | æ˜¯ | è¢‹ç æˆ–托盘码 |
| quantity | BigDecimal | å¦ | æœ¬æ¬¡æ‹£è´§æ•°é‡ï¼Œä¸å¡«æ—¶ä½¿ç”¨é”€å”®è¡Œæ•°é‡ |
**扫码响应字段:**
| å­—段 | ç±»åž‹ | è¯´æ˜Ž |
|------|------|------|
| scanType | String | `BAG` è¢‹ç ï¼Œ`PALLET` æ‰˜ç›˜ç  |
| codeId | Long | ç è®°å½• ID |
| itemId、batchId、batchCode | Long/Long/String | ç‰©æ–™å’Œæ‰¹æ¬¡ä¿¡æ¯ |
| materialStockId | Long | å…³è”库存记录 ID |
| availableQuantity | BigDecimal | å½“前库存数量 |
| scanQuantity、outboundQuantity | BigDecimal | æœ¬æ¬¡æ‰«ææ•°é‡å’Œå‡ºåº“数量 |
| detailId | Long | ç”Ÿæˆçš„销售出库明细 ID |
| warehouseId、locationId、areaId | Long | åº“存所在仓库、库区、库位 |
| alreadyScanned | Boolean | é‡å¤æ‰«ææ—¶ä¸º true,并返回已有明细 ID |
| palletExpanded | Boolean | æ‰˜ç›˜å±•开标识 |
| bagCount、inboundBagCount | Integer | æ‰˜ç›˜è¢‹ç æ€»æ•°ã€å·²ç´¯è®¡è¢‹ç æ•° |
| message | String | æ“ä½œæç¤º |
## å­—段展示规则
| å­—段 | å±•示位置 | è¯´æ˜Ž |
|------|----------|------|
| scanType、scanContent | æ‰«ç ç»“果区 | æ˜¾ç¤ºè¯†åˆ«ç±»åž‹å’ŒåŽŸå§‹ç å€¼ |
| itemCode、itemName、batchCode | æ˜Žç»†è¡¨ | ä»Žæ‰«ç ç»“果带入,不允许前端自行改写 |
| materialStockId、仓库、库区、库位 | æ˜Žç»†æ•°æ® | ä¿å­˜åº“存关联,用于拣货和出库校验 |
| availableQuantity | æ‰«ç ç»“果区 | ç”¨äºŽæç¤ºå½“前库存数量 |
| stockState | åº“存台账 | `10` æš‚存库、`20` åˆæ ¼åº“、`30` å·²å‡ºåº“ |
## ä¸šåŠ¡è§„åˆ™è¯´æ˜Ž
| åœºæ™¯ | è§„则 |
|------|------|
| è¢‹ç æ‰«æ | æŒ‰è¢‹ç å…³è”批次和物料,并生成带 `bagCodeId` çš„æ˜Žç»† |
| æ‰˜ç›˜æ‰«æ | å…³è”托盘及其袋码,生成带 `palletCodeId` çš„æ˜Žç»†ï¼Œå¹¶è¿”回展开统计 |
| é‡å¤æ‰«æ | åŒä¸€é”€å”®å‡ºåº“单重复扫描同一码时不重复生成明细,返回已有明细 |
| æ•°é‡è¶…限 | æ‰«ææ•°é‡ä¸å¾—超过库存可用数量,也不得超过销售行剩余数量 |
| åº“存变更 | æ‰«ç åªç”Ÿæˆæ˜Žç»†ï¼›æ‹£è´§æ—¶å ç”¨ï¼Œå®Œæˆå‡ºåº“时扣减库存 |
| åº“存状态 | æ–°å»ºåº“存为暂存库;入库后有数量为合格库;数量扣减至零为已出库 |
## æ³¨æ„äº‹é¡¹
- æ‰«ç æŽ¥å£åªèƒ½ç”¨äºŽå¾…拣货状态的销售出库单。
- æ‰˜ç›˜å†…袋码展开的具体明细数量应以接口返回的 `bagCount` å’Œ `inboundBagCount` ä¸ºå‡†ã€‚
- é‡å¤æ‰«ç å“åº”的部分物料和库存字段可能为空,前端应优先使用 `detailId` æŸ¥è¯¢å·²æœ‰æ˜Žç»†ã€‚
- åŽç«¯æŽ¥å£å˜æ›´ä¸ä¿®æ”¹ `mom-pro2-before` å‰ç«¯é¡¹ç›®ã€‚
img/img.png
img/img_1.png
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);
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;
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;
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;
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;
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 = "扫码拣货")
    @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 = "执行拣货")
    @Parameter(name = "id", description = "编号", required = true)
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;
}
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 = "识别类型:PALLET-托盘码,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 = "生成的销售出库明细ID(幂等返回时亦有值)", 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;
}
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;
}
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;
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;
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;
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);
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);
}
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();
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);
    }
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 é”€å”®å‡ºåº“-扫码拣货(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, "杂项出库单编码已存在");
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;
}
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);
}
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);
    }
    // ==================== ç§æœ‰æ–¹æ³• ====================
    /**
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);
}
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);
    }
}
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);
    /**
     * åº“位混放规则校验
     *
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) {
        // æ›´æ–°åº“存数量(Mapper å±‚ CAS é˜²è´Ÿåº“存;checkFlag=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);
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);
    /**
     * å¡«å†™è¿å•(待填写运单 â†’ å¾…执行出库)
     *
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);
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()