liu
8 小时以前 514f372270b181f82e4deff98f8d0f38ace63183
Merge remote-tracking branch 'origin/dev_新疆_塔河种业' into dev_新疆_塔河种业
已添加55个文件
已修改16个文件
11915 ■■■■■ 文件已修改
.gitignore 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/bi-purchase-sales-crm.md 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/business-date-display.md 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/design/login-herbal-theme.md 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/design/spare-management.md 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/dv-manual-inspector-repair-filter.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/energy-management.md 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/equipment-spare-management.md 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/logout-immediate-navigation.md 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/pd_document_audit_file_display.md 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/production-one-click-schedule.md 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/qc_indicator_result_sn_removal.md 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/sql/config_export_all_20261015.sql 9636 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/trace-location-gate.md 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/排产数量按收率倒推方案.md 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/流转卡投入产出按收率重算方案.md 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/backlog-review-20261015/README.md 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/bom-import/导入说明.md 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/business-flow-20261014/商机调整核对清单.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/customer-code-removal/README.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/customer-links-20261015/README.md 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/db-cleanup-20261016/Cleanup.java 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/ecommerce-production-20261015/录入清单.md 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/equipment-holiday-20261014/README.md 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/equipment-repairs-20261014/README.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/equipment-types-20261014/README.md 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/iqc-import-20261012/同步结果-国标补充.md 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/marketing-remarks-20261014/README.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/october-chain-20261014/业务链核对清单.md 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/operation-logs-20261015/README.md 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/operations-remarks-20261014/README.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/permission-audit-result.md 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/process-route-20261012/工艺路线生成说明.md 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/process-route-20261012/生产基础数据补充说明.md 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/production-schedule-20261014/README.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/production-timing-20261014/README.md 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/qc-indicator-optimize-20261014/质检优化核对清单.md 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/qc-other-import-20261012/出货录入及客户可空修改说明.md 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/qc-other-import-20261012/映射及暂缓导入说明.md 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/quality-indicator-20261014/README.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/quotation-contract-20261015/artifact.md 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/quotation-contract-orders/转换说明.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/quotation-import/导入说明.md 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/quotation-import/线上同步说明.md 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/quotation-opportunities-20261014/README.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/sales-ledger-202609/README.md 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/sop-qc/导入说明.md 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/stock-import-202609/material-repair/类型映射核验说明.md 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
scripts/stock-import-202609/导入说明.md 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql/mes_trace_location_visit.sql 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletBatchCreateReqVO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletPreGenerateReqVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletRespVO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletTraceRespVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/consumer/MesTraceConsumerScanController.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/consumer/vo/MesTraceLocationDistributionRespVO.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/consumer/vo/MesTraceLocationVisitPageReqVO.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchFlowRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchSalesTargetRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/MesProTracePublicController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicConfigRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesTraceLocationVisitReqVO.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/trace/consumer/MesTraceLocationVisitDO.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/trace/consumer/MesTraceLocationVisitMapper.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/config/MesProperties.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/application-local.yaml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/static/trace-location.html 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/static/trace.html 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -59,4 +59,5 @@
.claude/worktrees/
.claude/scheduled_tasks.json
.export_tmp/
.export_tmp/
/.db-cleanup-backups/
docs/bi-purchase-sales-crm.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
# é‡‡è´­é”€å”®å”®åŽå¤§å± CRM ç»Ÿè®¡
新增 14 ä¸ªå›¾è¡¨é…ç½®ï¼Œä¿ç•™åŽŸæœ‰å›¾è¡¨ã€‚é‡‡è´­é”€å”®å”®åŽå¤§å±ä¼˜å…ˆæ˜¾ç¤º CRM å†…容,其他大屏展示顺序不变。
## 6 ä¸ªæ ¸å¿ƒæŒ‡æ ‡
- æœ¬æœˆæ–°å¢žå®¢æˆ·ï¼šå®¢æˆ·åˆ›å»ºæ—¥æœŸè½åœ¨æœ¬è‡ªç„¶æœˆï¼ŒæŽ’除已删除。
- è·Ÿè¿›ä¸­å•†æœºé‡‘额:未结束的商机(结束状态为空或 0)的金额总和。
- æœ¬æœˆæœ‰æ•ˆåˆåŒé‡‘额:下单日期在本月且审核通过(20)的合同金额。
- æœ¬æœˆå·²å®¡æ ¸å›žæ¬¾ï¼šå›žæ¬¾æ—¥æœŸåœ¨æœ¬æœˆä¸”审核通过(20)的回款金额。
- æœ‰æ•ˆåˆåŒå¾…回款:按每份审核通过的合同先聚合已审核回款,再计算非负余额后求和,避免多笔回款导致合同重复计数;这不是逾期金额。
- æœ¬æœˆæŠ¥ä»·å•数:报价日期在本月的报价单数量,包含草稿,不表示成交。
## 6 ä¸ªåˆ†æžå›¾è¡¨
新增客户月度趋势、合同与回款双折线、商机阶段分布、客户成交状态、重点客户有效合同金额 TOP10、报价数量月度趋势。
月度趋势覆盖当月及前 11 ä¸ªæœˆï¼Œå¹¶è¡¥é½ç©ºæœˆä»½ä¸º 0。商机阶段统计全部非删除商机,结束的商机分别标为赢单、输单、无效。客户成交状态使用 CRM å®¢æˆ·æˆäº¤æ ‡è®°ï¼Œä¸é‡æ–°æŽ¨å¯¼ã€‚客户合同金额排行榜按客户编号分组,避免同名客户合并。
## 2 ä¸ªæ˜Žç»†è¡¨
- æœ€è¿‘有效合同与回款:最近 10 ä»½å®¡æ ¸é€šè¿‡çš„合同,列出合同金额、已审核回款、待回款、签单日期。
- é€¾æœŸæœªè·Ÿè¿›å®¢æˆ·ï¼šå·²åˆ†é…è´Ÿè´£äººï¼Œè®¡åˆ’联系日期早于今天且最近联系时间未达到计划联系时间的客户,按最早计划联系日期展示前 10 æ¡ï¼›ä¸åŒ…含公海客户,也不等同于合同逾期。
## é…ç½®ä¸ŽéªŒè¯
执行 `sql/mysql/bi_purchase_sales_crm_patch.sql`,按大屏编码定位,不依赖固定大屏编号。新增图表按名称幂等插入,不覆盖原有自定义查询。重点客户横向排行配置可重复同步。
图表 SQL å·²åœ¨æœ¬åœ°å’ŒæŒ‡å®šè¿œç¨‹ mom-hm æ‰§è¡ŒéªŒè¯ï¼›è¡¥é½æœˆä»½ã€å›žæ¬¾æŽ’除未通过与已删除记录、多笔回款聚合、超额回款余额归零均已验证。前端支持多序列柱状/折线图、横向客户排行、无业务数据提示,采购销售大屏每分钟重新取数。桌面与手机布局已使用实际业务统计快照验证。
无需增加菜单或更新后端代码,部署新版前端后完整生效。当前 BI ç»Ÿè®¡æ²¿ç”¨åŽŸå¤§å±çš„å…¨å±€ç»è¥æ•°æ®èŒƒå›´ï¼Œä»…æŽˆæƒæŸ¥çœ‹å¤§å±çš„ç”¨æˆ·å¯ä»¥è®¿é—®ã€‚
docs/business-date-display.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
# ä¸šåŠ¡æ—¥æœŸæ˜¾ç¤ºçº¦å®š
普通业务日期使用 `YYYY-MM-DD`。本次覆盖采购、销售、财务、仓储物流、基础资料、设备台账、计量检测、质量管理、人事与薪酬等页面中的列表、详情、普通日期输入和打印展示。
## ä¿ç•™ç²¾ç¡®æ—¶é—´
- æ“ä½œã€ç™»å½•、访问和错误日志,库存事务与库存历史。
- å®¡æ‰¹åŠå®¡æ ¸è½¨è¿¹ï¼Œå¤„理与处置时间。
- è€ƒå‹¤æ‰“卡、请假、加班、排班。
- ç”Ÿäº§ä»»åŠ¡æŽ’ç¨‹ã€æŠ¥å·¥ã€ä¸Šä¸‹å·¥ã€å·¥åºè¿›å‡ºã€å¼‚å¸¸äº‹ä»¶ä¸Žæ‰¹æ¬¡è¿½æº¯äº‹ä»¶ã€‚
- ç»´ä¿®æŠ¥ä¿®ã€ç»´ä¿®å®Œæˆä¸ŽéªŒæ”¶è¿‡ç¨‹ã€‚
- ä¸‹æ¬¡è”系提醒、招标截止与开标时间。
- æ‰“印生成时间、系统刷新时间。
其中生产报工的批次有效期和入库日期仍按天选择,与报工发生时间区分。
## æŽ¥å£ä¸Žæ•°æ®
- æ˜¾ç¤ºæ ¼å¼ä¸Ž `valueFormat` åˆ†å¼€é…ç½®ï¼›åŽå°éœ€è¦å®Œæ•´æ—¶é—´æ—¶ä¿ç•™ `YYYY-MM-DD HH:mm:ss` çš„绑定格式。
- ä¸ä¿®æ”¹åŽ†å²æ—¶é—´æ•°æ®ã€æ•°æ®åº“å­—æ®µæˆ–åŽå°è®¡ç®—å£å¾„ã€‚
- æ—¶é—´åŒºé—´æŸ¥è¯¢ä¿ç•™åŽŸå§‹æ—¶é—´è¾¹ç•Œä¸Žå…¨å¤©é¢„è®¾ï¼Œé¿å…ç»“æŸæ—¥æœŸå½“å¤©çš„æ•°æ®é—æ¼ï¼›éœ€è¦ç²¾ç¡®æ—¶é—´çš„åŒºé—´ä»å¯é€‰æ‹©æ—¶åˆ†ç§’ã€‚
- ä¸ä¿®æ”¹å…¨å±€ `formatDateTime`,避免影响日志、审批或时长计算。
## éªŒè¯
前端生产构建通过。全量类型检查存在原有错误;与修改前的诊断对比,本次日期调整未新增类型错误。
docs/design/login-herbal-theme.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
# ç™»å½•与全局药堂主题
记录日期:2026-10-15。设计依据为用户提供的药堂庭院参考图,锁定朱红、暖金、宣纸白。全局规则见[前端 DESIGN.md](../../mom-pro2-before/DESIGN.md)。本记录描述当前实现,不代表企业品牌或产品资质说明。
## å®žçŽ°å…¥å£
| æ–‡ä»¶ï¼ˆç›¸å¯¹å‰ç«¯ç›®å½•) | èŒè´£ |
| --- | --- |
| `src/layouts/auth-scene.vue` | åº­é™¢èƒŒæ™¯ã€å ‚训、装饰框与响应式场景 |
| `src/layouts/auth.vue` | å…¬å¸é…ç½®ã€Logo、语言/主题工具、真实认证路由 |
| `src/views/_core/authentication/login.vue` | çŽ°æœ‰ç™»å½•è¡¨å•ã€è¾“å…¥æ ·å¼ã€è®¤è¯ä¸ŽéªŒè¯ç è°ƒç”¨ |
| `src/preferences.ts` | é»˜è®¤è‡ªå®šä¹‰ä¸»è‰² `#a51d24` |
| `src/styles/herbal-theme.css` | æ˜Žæš—主题语义色、暗色朱砂主色、半深色导航兼容 |
| `src/main.ts` | ä¸»é¢˜æ ‡è¯†ã€ä¸€æ¬¡æ€§ç¼“存迁移及主色监听 |
| `src/bootstrap.ts` | å¼•入全局主题样式 |
## è§†è§‰ä¸Žå“åº”式
全局浅色表面使用暖白(背景 `hsl(40 50% 99%)`、深层背景 `hsl(37 33% 95%)`),文本采用暖墨色。暗色背景为 `hsl(26 16% 12%)`,卡片为 `hsl(26 15% 14%)`;默认朱红主题下,暗色全局主要强调色使用较亮朱砂(`hsl(357 64% 73%)`)与深色按钮文字。登录主按钮由局部样式维持朱红白字。
正文继承 `--font-family`,缺省回退系统无衬线;公司名称与堂训使用 `STKaiti`、`KaiTi`、`FangSong`、衬线回退。没有新增外部字体下载,实际字形依赖系统字体。
桌面将堂训和表单分置两侧,表单最大宽度 584px;不超过 900px åˆ‡æ¢å•列、隐藏堂训,表单最大宽度 520px;不超过 540px å…è®¸å“ç‰ŒåŒºæ¢è¡Œå¹¶æ”¶ç´§ç•™ç™½ã€‚短桌面视口降低表单高度与内边距。深色背景图片降低亮度和饱和度;装饰图片为空替代文本并标记为辅助技术忽略。
## ç¼“存与公司身份
偏好初始化后设置 `data-brand-theme="herbal"`。按现有应用 namespace ä¿å­˜ `${namespace}-herbal-theme-v1` æ ‡è®°ï¼›æ ‡è®°ç¼ºå¤±æ—¶ä»…迁移主题类型与主色,避免旧缓存蓝色遮盖新主题。成功保存标记后不再强制主色,用户之后选择的颜色和明暗模式继续生效。namespace åŒ…含应用版本与运行环境,各 namespace ç‹¬ç«‹è¿ç§»ã€‚
监听当前主色,仅在其等于 `#a51d24` æ—¶è®¾ç½® `data-herbal-palette="true"`,以免暗色朱砂覆盖用户自选颜色。若 localStorage ä¸å¯ç”¨ï¼Œå½“前实现会在启动时重新应用默认朱红,无法保证跨启动保留该主色偏好。
公司名与 Logo ä»ä½¿ç”¨çŽ°æœ‰ preferences/编译配置;认证布局沿用公司配置 store èŽ·å–ç™»å½•æ ‡é¢˜ä¸Žæè¿°ï¼Œæš—è‰²ä¼˜å…ˆä½¿ç”¨å·²é…ç½®çš„æš—è‰² Logo。未配置公司标志时隐藏框架示例 Logo。背景、暖金纹样和标题旁无文字几何 SVG çº¹æ ·ç‹¬ç«‹äºŽå…¬å¸ Logo,不写入公司身份配置。
暗色工具条使用深底以配合图标对比;密码切换为明文后仍保留显隐按钮的右侧空间(44px),避免输入内容与按钮重叠。
## èƒŒæ™¯èµ„产
资源:`mom-pro2-before/public/images/auth/herbal-courtyard.png`,页面路径 `/images/auth/herbal-courtyard.png`。使用内置 ImageGen æ¨¡å¼ç”Ÿæˆï¼Œå‚考用户图保留药堂庭院、药材托盘与米白留白;去除文字、Logo、工具栏、表单卡片及所有 UI,不生成文本。公司名、堂训与登录内容均由页面渲染,维护时不要把它们烘焙到图片中。
## éªŒè¯è¯æ®ä¸ŽèŒƒå›´
验证记录:[result.json](../../scripts/login-theme-20261015/result.json)。截图使用真实应用、路由与主题/登录组件,后端及公司配置 API ä¸º mock,输入为演示账户,没有完成真实身份认证。
- [桌面浅色](../../scripts/login-theme-20261015/desktop-login.png)
- [桌面暗色](../../scripts/login-theme-20261015/desktop-dark.png)
- [移动端](../../scripts/login-theme-20261015/mobile-login.png)
记录覆盖动态公司配置、背景加载、自动填充属性、键盘密码显隐、记住账号、明暗主题切换、移动端无横向溢出及必填校验阻止后端请求。截图与这些检查不能证明真实后端认证、验证码服务、权限路由或全部业务页面均通过验证;保留现有调用链也不等于上述服务已联调成功。
docs/design/spare-management.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
# å¤‡ä»¶ç®¡ç†å±€éƒ¨è®¾è®¡è®°å½•
记录日期:2026-10-14。范围为设备管理的功能扩展,使用 Vue、Ant Design Vue ä¸Ž Vben,模式为 Operate。沿用既有表格、筛选、表单和弹窗模式;此文件仅记录局部实现事实,不定义全局视觉体系或新增设计 token。
## å¸ƒå±€ä¸Žç»„ä»¶
- **备件台账**:Page å†…先展示标题与右侧“新增备件”,随后为可换行的行内筛选和分页表格。筛选包含编码、名称、状态及“仅看低于安全库存”。表格保留规格、单位、可用库存、安全库存、位置和状态,右侧固定操作列提供编辑、入库、领用、记录与删除。
- **备件表单**:Vben å¼¹çª—,纵向标签。宽屏双列表单、窄屏单列;宽屏声明宽度为 640px。备注跨列;初始库存仅新增时显示,库存后续经业务操作变更。
- **入库/领用/退回**:复用一个纵向表单弹窗,宽屏声明宽度为 600px。顶部信息提示说明库存影响。领用包含备件、关联维修单、领用人、数量及操作说明;上下文已传入的备件或维修单锁定选择。退回展示原领用记录与可退回数量。
- **领用记录**:独立页面和台账记录弹窗复用 Records;默认筛选维修领用。维修单内嵌时隐藏维修单号筛选,并按该维修单查询。记录包含时间、类型、备件、数量/单位、已退回、可退回、维修单、设备、领用人与说明。
## çŠ¶æ€ã€æƒé™ä¸Žç»´ä¿®æµç¨‹
库存低于安全库存时显示“ ä¸è¶³ â€è­¦ç¤ºæ ‡ç­¾ï¼Œå¯ç”¨çŠ¶æ€ä½¿ç”¨æˆåŠŸæ ‡ç­¾ï¼Œåœç”¨ä½¿ç”¨ä¸­æ€§æ ‡ç­¾ã€‚åœç”¨å¤‡ä»¶ä¸å¯å…¥åº“æˆ–é¢†ç”¨ï¼›æ— å¯ç”¨åº“å­˜æ—¶ç¦ç”¨é¢†ç”¨ã€‚åˆ é™¤ä½¿ç”¨ç¡®è®¤æç¤ºï¼Œå¹¶è¯´æ˜Žä»…æ— åº“å­˜ã€æ— æµæ°´çš„å¤‡ä»¶å¯åˆ é™¤ã€‚
列表查询有加载状态;失败时清空结果并展示错误提示,可通过“查询”重试。表单使用必填校验与数量校验,领用不可超过可用库存,退回不可超过可退回数量;提交期间锁定弹窗并阻止关闭。基础数据加载失败展示错误提示,文案引导重新打开弹窗。
操作入口使用 `mes:dv-spare:create/update/receive/issue/record/delete/return` æƒé™æŒ‡ä»¤ã€‚维修单内的记录区需记录权限,领用入口还需领用权限。权限事实来自代码,截图未验证多角色权限组合。
新维修单保存成功后保留当前弹窗,取得 ID å¹¶è½¬ä¸ºç¼–辑状态,随后显示关联领用记录;草稿或维修中允许领用。领用弹窗固定当前维修单关联,成功后刷新记录。维修单搜索同样只提供草稿或维修中记录。
## æ—¢æœ‰è§†è§‰ä¸Žçª„屏
截图显示白色工作区域、浅色表头、行分隔线、蓝色主按钮与链接操作;删除为危险色。信息、警示、成功和错误状态沿用 Ant Design ç»„件语义,未提取全局字体、颜色、圆角或间距 token。
筛选与操作允许换行;台账和记录表格分别声明横向滚动宽度 1330px、1790px,操作列固定右侧。窄屏保持表格结构,通过横向滚动读取完整字段;并未改为卡片列表。记录弹窗为窄屏全宽、较大屏幕约 4/5 å®½ï¼Œè¡¨å•弹窗在窄屏采用全宽。
## è¯æ®ä¸ŽéªŒè¯é™åˆ¶
实现依据:`mom-pro2-before/src/views/mes/dv/spare/index.vue`、其 `modules/form.vue`、`action.vue`、`records.vue`,以及 `spare-record/index.vue`;维修流程补充依据为 `repair/modules/form.vue`。
截图位于 `scripts/spare-management-20261014/`:`desktop-ledger.png`、`mobile-records.png`、`desktop-issue.png`。它们使用实际组件、模拟 API、弹窗 adapter å’Œæœ€å° utility CSS,支持局部布局观察,不代表生产应用壳层、完整 Vben å¼¹çª—样式或真实后端联调。领用截图展示已填写、下拉关闭的表单状态。真实权限、键盘/焦点操作、校验状态切换、选择浮层定位、提交结果与并发库存行为需另行验证。
docs/dv-manual-inspector-repair-filter.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
# æ£€æµ‹äººæ‰‹å¡«ä¸Žç»´ä¿®å•设备名称筛选
2026-10-12:计量检测记录的检测人改为文本输入,支持系统外人员姓名,最多100字符,保存时去除首尾空格,允许清空。列表、详情、Excel均显示手填姓名。历史记录的原系统用户编号继续保留,读取时兼容原用户姓名;编辑保存后以手填姓名为准,不再关联系统用户。
维修单此前前端发送了machineryName,但后端分页VO和Mapper没有接收和使用此条件。现已补齐,使用参数绑定的LIKE匹配设备台账当前名称,列表分页与导出共享筛选条件。空白关键词不参与筛选,未匹配到设备时返回空结果,并排除已删除设备。租户拦截器同时作用于维修单和设备子查询。
新增字段迁移:sql/mysql/mes_dv_metering_check_manual_user_patch.sql,可重复执行,只增加check_user_name,保留原记录及人员编号。新建库初始化脚本也已包含此字段。2026-10-12已同步本地localhost:3306/mom-hm和指定远程36.213.150.237:10000/mom-hm,并用新连接确认字段已持久化。
验证:5项专项测试通过,包括真实H2数据库下的部分名称查询、分页和导出、无匹配及包含SQL字符的关键词、租户隔离、手填姓名保存/清空、旧人员名称兼容和校准日期计算。前端生产构建通过,本次涉及的计量检测及维修页面未发现类型错误;全项目类型检查仍有原有无关错误。未操作真实检测或维修业务记录。
生效方式:发布新版后端并重启,发布mom-pro2-before前端。数据库字段已同步,不需要新增菜单或权限。
docs/energy-management.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
# èƒ½è€—管理
## èŒƒå›´
新增一级菜单「能耗管理」,下设「能耗记录」「数据分析」「能耗预警」。按天手动录入,独立业务表,无设备、生产工单、部门、产品等外键或业务调用。后端复用现有 MES è¿è¡Œå®¹å™¨åŠç³»ç»Ÿæƒé™/租户基础设施。预警仅使用系统管理员用户和站内信基础服务。
## å½•å…¥
日期、能源(水/电/蒸汽)、使用区域、产品类别、用途、用量、单价、录入人、备注。水单位 m³,电 kWh,蒸汽 t。区域与用途支持自由填写,建议项适用于燕窝、滋补品原浆的生产场景,可按实际厂区调整。产品类别包含燕窝、滋补品原浆、公用能耗、其他。仅录用量时单价填 0。
同一天可录入多个区域、用途或班次的记录;请统一计量口径,避免同时录入总表与分表造成重复统计。用量直接填本次统计用量,不填写累计表读数。费用由后端按用量×单价计算,四舍五入到分。
## åˆ†æž
按日期区间、能源、区域关键词、产品类别筛选,支持按日/月汇总(每次不超过两年)。分别显示三种能源用量,费用可以合计。图表包含用量趋势、能源费用占比、区域费用前十、能源费用趋势、区域费用占比、单种能源区域用量前十,共6张。区域费用占比中的其他区域合并显示,保证占比覆盖全部区域。未录入日期留空,不视为零消耗。删除或修改记录后,重新分析即可更新统计。
图表右上角支持下载PNG图片。分析报表导出XLSX,包含统计口径、能源汇总、日期趋势、区域汇总4个工作表,使用最近一次成功分析时的筛选条件。台账按当前筛选条件导出全部记录,不限当前页,单次最多50000条,超出时需缩小日期范围。
## èƒ½è€—预警
规则包括名称、能源、统计指标(每日用量、每日费用、每月用量、每月费用)、阈值、使用区域、产品类别、接收人及启用状态。区域留空表示全部区域,否则精确匹配;产品类别留空表示全部产品。相同周期、范围的多条台账汇总比较,实际值严格大于阈值时触发,等于阈值不通知。月度按自然月(当月1日至下月1日之前)汇总所有已录入数据,累计超限即通知,不必等到月底。
台账新增、修改、删除提交成功后自动检查受影响日期及所属自然月;修改日期时检查原日期和新日期,跨月时检查两个自然月。预警检查使用独立事务,通知异常不回滚已提交的台账。成功站内信和成功日志一同提交;同一租户、规则、统计周期、接收人只成功通知一次(规则行锁和数据库唯一索引同时保护并发检查)。月度日志以月首日存储,界面显示年月,筛选某天时会同时展示该天及所属月份的通知。通知记录保存规则/阈值/实际值快照,即使规则删除也保留历史。
配置新规则或修改阈值后,使用「检查预警 / é‡è¯•失败通知」检查今天或历史日期。发送失败会留下记录,再次检查该日期时仅重试仍超限的失败接收人。已成功通知的历史日期不会因编辑规则或修改台账而重复发送;台账回落后不撤回已发送消息。接收人必须是当前租户启用的系统用户。通知出现在右上角站内通知及「我的站内信」,通过系统原有查询刷新。
站内信模板编码为 `energy_daily_warning`(每日)和 `energy_monthly_warning`(每月);请保持模板启用。脚本不创建规则、不指定接收人、不发送任何通知。首次使用请根据现场实际用能设置阈值。
## éƒ¨ç½²
1. åœ¨ç›®æ ‡ MySQL æ•°æ®åº“依次执行 `sql/mysql/energy_management_init.sql`、`sql/mysql/energy_alert_analysis_upgrade.sql`、`sql/mysql/energy_menu_patch.sql`、`sql/mysql/energy_monthly_alert_upgrade.sql`。创建台账、预警规则及通知历史表、每日/月度通知模板、菜单及超级管理员权限。菜单补齐脚本同时校准父子层级、组件路径、启用/可见状态。月度迁移保留历史日通知并调整周期去重索引,应在发布新版后端前执行。四个脚本均可重复执行,不写入示例业务数据。
2. æž„建并重启后端(实现位于 yudao-module-mes),发布 mom-pro2-before å‰ç«¯ã€‚
3. é‡æ–°ç™»å½•刷新菜单;普通角色在角色管理分配能耗记录查询、新增、修改、删除以及数据分析权限。非系统租户还需在对应租户套餐中分配新增菜单。
## æŽ¥å£
`/admin-api/energy/record` ä¸‹çš„ `create`、`update`、`delete`、`get`、`page`、`analysis`。分析权限为 `energy:analysis:query`,记录权限为 `energy:record:query/create/update/delete`。业务表 `mes_energy_record` æ”¯æŒé€»è¾‘删除、租户隔离及创建/修改审计。
导出接口 `/admin-api/energy/record/export-excel`、`analysis-export`,权限分别为 `energy:record:export`、`energy:analysis:export`。预警接口 `/admin-api/energy/alert` ä¸‹çš„ `page`、`logs`、`recipients`、`create`、`update`、`delete`、`check?date=YYYY-MM-DD`,权限为 `energy:alert:query/create/update/delete/check`。预警规则和通知历史均按租户隔离。
## éªŒè¯ï¼ˆ2026-10-12)
- åŽç«¯ç¼–译通过,`EnergyRecordServiceTest` 7项单元测试通过。
- å‰ç«¯ç”Ÿäº§æž„建通过;新增能耗文件未发现类型错误。全项目 `vue-tsc` ä»æœ‰å…¶ä»–现有文件错误(例如采购申请重复字段、部分 IM å¯¼å…¥è·¯å¾„),未修改这些无关文件。
- ä½¿ç”¨ç‹¬ç«‹å†…存模拟数据验证了录入、费用计算、编辑、删除、能源切换、区域筛选、按月汇总与无数据提示,并检查桌面及390px窄屏布局。模拟数据和临时验证服务未纳入交付。
- 2026-10-12 å·²åœ¨å½“前后端配置的 `mom-hm` æ•°æ®åº“创建台账表及6个菜单/按钮节点,并为现有超级管理员(role_id=1)分配权限。菜单编号为1075425至1075430;数据库回查确认均已启用。重新登录刷新前端菜单。其他部署数据库仍需执行初始化脚本;尚未完成实际业务接口联调。
- 2026-10-12 å·²æŒ‰ç”¨æˆ·è¦æ±‚将同一初始化SQL同步到 `36.213.150.237:10000` çš„ `mom-hm` æ•°æ®åº“,创建17字段台账表、6个菜单/按钮节点及6条超级管理员授权。已通过新连接回查提交结果,未导入业务数据;连接密码未保存到项目文件。
- 2026-10-12 é¢„警升级SQL已同步到同一远程 `mom-hm`,新连接回查确认新增2张表、1个已启用通知模板、7个菜单/按钮节点及7条超级管理员授权;预警规则0条,未向真实用户发送测试通知。代码尚需发布前后端并重新登录。
- é¢„警边界、去重、失败重试、单个接收人失败、停用规则、SQL参数绑定及实际Excel工作簿内容已通过自动化验证;本地模拟页面验证了规则新增、阈值显示、接收人选择、检查通知记录和重复检查,以及6张图表的窄屏渲染。未连接远程业务API进行通知联调。
- æœ¬æ¬¡æœ€ç»ˆåŽç«¯èƒ½è€—专项测试17项通过,前端生产构建通过。全项目类型检查仍存在已有无关错误,能耗目录未发现类型错误。
- 2026-10-12 å·²è¡¥é½å½“前本地 `localhost:3306/mom-hm` çš„预警升级与菜单,并向 `36.213.150.237:10000/mom-hm` åŒæ­¥å®Œæ•´èœå•修复。分别使用新连接回查,均为1个目录、3个页面、9个按钮(共13个启用且可见节点),超级管理员均有13项菜单授权。管理员重新登录即可拉取完整菜单;普通角色仍按需分配权限。
- 2026-10-12 æ–°å¢žæ¯æœˆç”¨é‡/费用指标,专项测试共19项通过,前端生产构建通过,能耗目录无类型错误。月度迁移已同步本地和指定远程mom-hm,新连接回查确认周期字段默认DAY、新周期去重索引和启用的月度通知模板。未发送真实测试通知。发布前后端后可选用新增月度指标。
docs/equipment-spare-management.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
# è®¾å¤‡å¤‡ä»¶ç®¡ç†
## åŠŸèƒ½ä¸Žæµç¨‹
设备管理下新增“备件台账”和“领用记录”。备件台账维护编码、名称、规格型号、计量单位、存放位置、安全库存及启停状态;低于安全库存时提示不足,并支持筛选。
首次登记可填写初始库存,系统保留初始库存流水。后续补货使用“入库”,填写来源或单据编号。此功能使用独立的设备备件库存,不与现有物料仓库库存重复扣减。
新增维修单后先保存,原弹窗继续打开,可在“备件领用记录”中点击“领用备件”。草稿和维修中均允许领用;待验收及已确认状态不能继续领用。维修单、备件、领用人、数量和操作说明必填。也可从备件台账领用并选择维修单。
领用立即扣减库存,记录备件、维修单、设备及领用人的快照。未使用的备件可从原领用记录退回,支持分次退回;累计退回不能超过原领用数量。维修结束或备件停用后仍可退回。
## åº“存及追溯保障
- æ•°é‡å¿…须大于零,最多三位小数。库存不足时阻止领用。
- åº“存变更与流水写入在同一事务中完成,失败回滚。
- å¤‡ä»¶è¡Œé”é˜²æ­¢å¹¶å‘超领;原领用记录行锁防止并发超退。
- è¯·æ±‚键唯一,原请求重试不会重复变更库存。相同请求键对应不同参数会被拒绝。
- ä¿®æ”¹å¤‡ä»¶èµ„料不能直接修改库存。已有流水的备件不能修改计量单位。
- æœ‰åº“存或流水的备件不能删除,可停用。有备件流水的维修单不能删除、更换设备或修改编码。
- æµæ°´æä¾›æŸ¥è¯¢ï¼Œä¸æä¾›ä¿®æ”¹å’Œåˆ é™¤æŽ¥å£ã€‚
## æ•°æ®åº“、菜单与权限
初始化脚本:`sql/mysql/mes_dv_spare_init.sql`。新增 `mes_dv_spare_part`、`mes_dv_spare_movement` ä¸¤å¼ è¡¨ã€‚菜单组件为 `mes/dv/spare/index`、`mes/dv/spare-record/index`,挂在现有维修单同级的设备管理下。
种子数据脚本:`sql/mysql/mes_dv_spare_seed.sql`(幂等,可重跑)。登记 12 æ¡å¸¸è§è®¾å¤‡å¤‡ä»¶å°è´¦ï¼Œå¹¶ä¸ºæ¯æ¡è¡¥ä¸€æ¡ `type=1` åˆå§‹åº“存流水,保证 `stock_quantity` ä¸Žæµæ°´å‰åŽæ•°é‡ä¸€è‡´ï¼›ä¸å«é¢†ç”¨/退回流水。
各库现状:
| åº“ | è¡¨ | èœå•/权限节点 | å¤‡ä»¶å°è´¦ | æµæ°´ |
|----|----|---------------|----------|------|
| æœ¬åœ°å®¹å™¨ `mom-thzy` | å·²å»º | 8 ä¸ªï¼ˆ1065225-1065232) | 0 æ¡ | 0 æ¡ |
| è¿œç«¯ `mom-hm` | å·²å»º | 8 ä¸ªï¼ˆ1075494-1075501) | 12 æ¡ | 12 æ¡ |
普通角色授权尚未执行;脚本不批量授予现有角色权限。远端 `mom-hm` ä¸Šæ™®é€šè§’色因此看不到备件台账,需在角色管理里勾选;超管不受影响。
权限:`mes:dv-spare:query`、`record`、`create`、`update`、`delete`、`receive`、`issue`、`return`。在维修单内查看记录需 record;领用需 issue,且备件选择依赖 query,人员和维修单选择沿用系统现有查询权限。普通角色通过角色管理明确勾选对应功能。
上线需同时更新前后端,刷新菜单/角色缓存或重新登录。仅运行旧版本应用不会具备新增接口和页面。
## éªŒè¯èŒƒå›´
2026-10-14:后端编译通过;10 é¡¹ä¸“项测试通过,使用 H2 å’ŒçœŸå®ž Spring äº‹åŠ¡éªŒè¯åº“å­˜å˜æ›´ã€å›žæ»šã€å¹¶å‘é¢†ç”¨/退回、重复请求、停用限制、单位保护与历史保护。前端 9 é¡¹éªŒè¯é€šè¿‡ï¼Œä½¿ç”¨å®žé™… Vue/Ant Design ç»„件与模拟 API、模态适配器验证必填、库存上限、退回上限、执行锁定、重试请求键及桌面/窄屏展示。
新增备件页面与维修单接入未出现类型检查错误;项目全量类型检查仍存在其他既有错误。截图使用模拟数据和少量宿主样式,不代表生产 Vben æ¨¡æ€ç„¦ç‚¹ã€åº”用外壳或真实环境端到端验证。没有执行实际备件领用。
验证脚本:`mom-pro2-before/scripts/spare-management-qa.mjs`;结果与截图:`scripts/spare-management-20261014/`。
docs/logout-immediate-navigation.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
# é€€å‡ºç™»å½•立即生效
原退出流程先等待服务器注销请求,最多等待默认 30 ç§’,才清理本地状态和跳转。服务器慢或不返回时,用户会觉得点击退出没有反应。
现在使用退出前的令牌、租户和当前路由快照发起后台注销,本地不等待该请求;立即重置业务状态,明确重置访问令牌、刷新令牌、用户与权限状态,并跳转登录页。同一轮退出合并并发调用。
登录与用户信息请求检查会话版本,退出前的晚到结果不再恢复令牌、权限或触发登录成功跳转。令牌刷新检查原刷新令牌是否仍属于当前会话;旧请求的 401 ä¸ä¼šæ¸…除已切换的新会话。刷新失败时,等待队列会收到失败,而不是用空令牌重放旧请求。
服务器注销因断网失败时无法保证立即撤销服务器令牌,但本机已退出;没有执行真实用户的登录或注销。没有使用整页刷新规避路由问题。
2026-10-15 éªŒè¯ï¼š
- `mom-pro2-before/scripts/check-logout.cjs`:实际状态模块与受控接口,覆盖成功、失败、持续挂起、业务重置异常、晚到登录、晚到用户信息、晚到刷新、旧会话 401、租户快照及刷新失败队列。
- `mom-pro2-before/scripts/check-logout-browser.cjs`:真实应用的头像菜单、退出确认弹窗、状态模块和路由,后端与会话均模拟。确认后约 338 æ¯«ç§’显示登录页,此时服务器注销仍保持未返回;令牌和用户信息为空,注销请求携带原令牌,浏览器无未捕获错误。
- ç»“果:`scripts/logout-fix-20261015/browser-result.json`。
- æœ¬æ¬¡ä¿®æ”¹æ–‡ä»¶æ²¡æœ‰å‰ç«¯ç±»åž‹æŠ¥é”™ï¼›å…¨é‡ç±»åž‹æ£€æŸ¥ä»æœ‰é¡¹ç›®å…¶ä»–既有错误。
更新前端即可生效,无需数据库迁移或后端接口调整。
docs/pd_document_audit_file_display.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,115 @@
# èµ„料审核列表显示对应文件(前端联调方案)
## æ¶‰åŠé¡µé¢
| é¡µé¢ | è·¯ç”± | è¯´æ˜Ž |
|------|------|------|
| é¡¹ç›®è¯¦æƒ… - èµ„料审核 Tab | `/mes/pd/project/detail/{id}?tab=audit` | éœ€æ–°å¢žã€Œæ–‡ä»¶ã€åˆ— |
## éœ€æ±‚
审核人在「资料审核」列表中需要直接看到并打开被审核资料对应的文件,用于审核前查阅。当前列表只有审核单号、资料名称、版本、审核状态等,没有文件入口。
## æ•°æ®æ¥æºä¸Žå…³è”关系
审核记录(`mes_pd_document_audit`)本身不存文件,文件挂在「设计资料」上,关联链路如下:
```
mes_pd_document_audit.document_id
        â””──> mes_pd_document.id   ï¼ˆè®¾è®¡èµ„料)
                   â””──> system_storage_attachment(recordType = mes_pd_document, recordId = è®¾è®¡èµ„æ–™ ID)
                              â””──> æ–‡ä»¶åœ°å€ / æ–‡ä»¶å
```
文件仍然走 system æ¨¡å—çš„ Storage Attachment æœºåˆ¶ï¼Œæœªåœ¨ä¸šåŠ¡è¡¨æ–°å¢žä»»ä½•æ–‡ä»¶åœ°å€åˆ—ã€‚
## API
| æ–¹æ³• | è·¯å¾„ | è¯´æ˜Ž |
|------|------|------|
| GET | `/mes/pd/document-audit/page` | èµ„料审核分页(响应新增字段) |
| GET | `/mes/pd/document-audit/get` | èµ„料审核详情(响应新增字段) |
**请求参数:** æ— å˜æ›´ã€‚
**响应字段新增:**
| å­—段 | ç±»åž‹ | è¯´æ˜Ž |
|------|------|------|
| fileName | String | èµ„料文件名,取该资料第一个附件的名称;无附件时为 null |
| fileUrl | String | èµ„料文件地址,取该资料第一个附件的可访问 URL;无附件时为 null |
**响应示例:**
```json
{
  "code": 0,
  "data": {
    "list": [
      {
        "id": 3023,
        "auditNo": "AUD2024001",
        "documentId": 1017,
        "documentName": "产品设计图",
        "documentVersion": "V1.0",
        "fileName": "design_v1.pdf",
        "fileUrl": "https://xxx/design_v1.pdf",
        "auditStatus": 0,
        "remark": null,
        "createTime": "2026-10-15 02:26:28"
      }
    ],
    "total": 1
  }
}
```
## å‰ç«¯ä¿®æ”¹ç‚¹
需要改动的文件:
| æ–‡ä»¶ | æ”¹åЍ |
|------|------|
| `src/api/mes/pd/document-audit/index.ts` | `MesPdDocumentAuditApi.DocumentAudit` æŽ¥å£è¡¥ `fileName`、`fileUrl` ä¸¤ä¸ªå¯é€‰å­—段 |
| `src/views/mes/pd/project/modules/document-audit-list.vue` | grid åˆ—增加「文件」列(`slots.default = 'file'`),并在模板中增加对应具名插槽 |
「文件」列的渲染规则与「设计资料」列表(`document-list.vue` çš„ `#file` æ’槽)保持完全一致,可直接复用同一写法。
## å­—段展示规则
| å­—段 | å±•示位置 | è¯´æ˜Ž |
|------|----------|------|
| fileUrl | åˆ—表「文件」列 | æœ‰å€¼æ—¶æ¸²æŸ“为可点击链接,新窗口打开 |
| fileName | åˆ—表「文件」列 | ä½œä¸ºé“¾æŽ¥æ–‡æ¡ˆï¼›ä¸ºç©ºæ—¶å›žé€€ä¸ºã€ŒæŸ¥çœ‹æ–‡ä»¶ã€ |
建议列宽 `minWidth: 140`,位置放在「资料版本」之后。
## ä¸šåŠ¡è§„åˆ™è¯´æ˜Ž
| åœºæ™¯ | è§„则 |
|------|------|
| èµ„料有多个附件 | åªå–第一个附件的地址与名称(与设计资料列表口径一致) |
| èµ„料无附件 | `fileUrl` / `fileName` å‡ä¸º null,列内显示 `-`,不渲染链接 |
| å®¡æ ¸è®°å½•已删除资料 | `documentId` æŸ¥ä¸åˆ°é™„件,同样显示 `-` |
| æœªé…ç½®å­˜å‚¨ / é™„件读取失败 | åŽç«¯ä¸æŠ›å¼‚常,字段留空,列表照常返回 |
## æ³¨æ„äº‹é¡¹
- æœ¬æ¬¡ä¸º**纯新增字段**,老前端不升级也不会报错。
- `fileUrl` ç”±åŽç«¯æ‹¼æŽ¥ï¼Œå‰ç«¯**不要**再单独调用 `/system/storage-attachment/list`,避免每行一次额外请求。
- å¯¼å‡º Excel `/mes/pd/document-audit/export-excel` åŒæ­¥æ–°å¢žäº†ã€Œæ–‡ä»¶ã€åˆ—(内容为文件名),无需前端改动。
## ç›¸å…³ä½†ç‹¬ç«‹çš„问题:审核结果字段被隐藏
**问题**:**自动审批模式**下,`document-audit-form.vue` ä¸­ã€Œå®¡æ ¸ç»“果」字段(原 `fieldName = 'auditStatus'`)被 `src/adapter/form.ts` çš„自动审批字段过滤逻辑(`isAuditField` å‘½ä¸­ `auditStatus` æ­£åˆ™ï¼‰æ•´æ¡ä»Žè¡¨å• schema ä¸­ç§»é™¤ï¼Œå¯¼è‡´ï¼š
1. å®¡æ ¸äººçœ‹ä¸åˆ°ã€ä¹Ÿæ— æ³•选择「审核通过/审核不通过」;
2. æäº¤æ—¶ `auditStatus` ç¼ºçœï¼ŒåŽç«¯æ‹†ç®±äº§ç”Ÿ NPE。
**已修复**(前端 + åŽç«¯ä¸¤ä¾§ï¼‰ï¼š
| ä¾§ | æ”¹åЍ |
|----|------|
| å‰ç«¯ `document-audit-form.vue` | å­—段名 `auditStatus` â†’ `auditResult`(避开 `isAuditField` æ­£åˆ™ï¼‰ï¼Œæäº¤æ—¶æ˜ å°„回 `auditStatus`;表单打开时显式清空 `auditResult` |
| åŽç«¯ `MesPdDocumentAuditServiceImpl#updateDocumentAudit` | `auditStatus` ä¸ºç©ºæ—¶æŠ› `PD_DOCUMENT_AUDIT_STATUS_REQUIRED`(「审核结果不能为空:请选择「审核通过」或「审核不通过」后重新提交」);非 1/2 æŠ› `PD_DOCUMENT_AUDIT_STATUS_INVALID`;审核人、审核时间统一由后端记录 |
**注意**:其他表单若出现同名 `auditStatus` / `auditTime` / `approvalStatus` ç­‰å­—段,同样会被自动审批模式过滤,需逐一核查。
docs/production-one-click-schedule.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
# ç”Ÿäº§ä¸€é”®æŽ’产
## ä½¿ç”¨æµç¨‹
在生产排产中勾选一个或多个已确认、自行生产且尚未排满的工单,点击“一键排产”。单个工单也可从行内按钮或工单中心进入。
选择最早开工时间后生成统一预览。核对工单校验结果、工作站、设备、数量和起止时间;如果预计超过交期,必须勾选接受延期后才能确认。任一工单校验失败,整批不能提交。
## è®¡ç®—与校验规则
- æŒ‰åŒ—京时间每日 09:00—18:00 æŽ’班,跳过星期六、星期日及系统节假日配置中的休息日。周末即使配置调休上班也不安排生产,符合本次双休要求。跨日任务只累计工作时段,计划起止时间之间可能包含休息时间。
- ä¼˜å…ˆæŒ‰äº¤æœŸã€å·¥å•编号对应的稳定 ID é¡ºåºå®‰æŽ’;同批子工单先于父工单。尚未完成且未纳入本批的子工单会阻止父工单排产。
- ä½¿ç”¨å·¥å•工序配置,缺省时使用产品工艺路线;遵守工序先后、准备时间和等待时间。
- æ ¹æ®å¯ç”¨è®¾å¤‡çš„产能及效率计算工时,并选择预计完成最早的工作站;维护中的设备不计入可用产能。同一工作站及不同工作站共享设备均检查占用。
- ç¼ºå°‘路线、工序、可用设备、正数产能、有效产出物料或有效参数模板,以及存在未知占用或已逾期未结束任务时,明确提示。多产出物料工序需通过手工排产处理。
- å„工序按工单总数量减去已有有效任务数量补排;已完成任务计入累计数量,已取消任务不计入,超量或历史任务数量无效时阻止提交。
- æ¯æ‰¹æœ€å¤š 30 ä¸ªå·¥å•、200 ä¸ªæ–°å¢žä»»åŠ¡ï¼ŒæŸ¥æ‰¾æ—¶é—´çª—å£æœ€å¤šä¸€å¹´ã€‚
## æäº¤ä¿éšœ
预览有效期为 15 åˆ†é’Ÿã€‚确认时在事务中锁定排产资源与所选工单,重新计算并核对预览摘要;工单、日历、配置或资源变化导致结果变化时,要求重新预览。计划开工时间已过去也必须重算。
整批任务创建和工单排产数量更新在同一事务内完成,任一步失败全部回滚。重复或并发提交经重算和数量校验阻止重复排满;没有持久化的请求回执,网络中断后应刷新工单确认结果再操作。任务新增、修改、删除会同步重算工单累计排产数量,便于后续补排。
## æŽ¥å£ä¸Žä¸Šçº¿
- `POST /mes/pro/task/auto-schedule/preview`:生成预览。
- `POST /mes/pro/task/auto-schedule`:确认执行,需要预览时间、摘要及延期确认标识。
- ä¸¤ä¸ªæŽ¥å£å‡è¦æ±‚ `mes:pro-task:create`,并核对客户数据权限。
- æœ¬åŠŸèƒ½æœªæ–°å¢žæ•°æ®åº“å­—æ®µã€‚éœ€åŒæ—¶éƒ¨ç½²åŽç«¯å’Œå‰ç«¯ï¼Œå¹¶é…ç½®çŽ°æœ‰å·¥è‰ºè·¯çº¿ã€å·¥ä½œç«™è®¾å¤‡ã€äº§èƒ½åŠèŠ‚å‡æ—¥æ—¥åŽ†ã€‚
## éªŒè¯è®°å½•
2026-10-14:后端专项测试 30 é¡¹é€šè¿‡ï¼ŒåŒ…含工作日历、设备冲突、补排、前后工序、权限、预览失效、重复及并发提交、事务失败回滚。实际 Vue ç»„件与 Ant Design æŽ§ä»¶äº¤äº’验证 7 é¡¹é€šè¿‡ï¼Œè¦†ç›–初次预览、变更失效、执行锁定、配置错误、延期确认及提交失败恢复;桌面和窄屏界面经过截图审阅。
组件验证使用模拟 API å’Œæ¨¡æ€é€‚配器,未操作真实生产任务,尚未验证生产 Vben å®¹å™¨ä¸­çš„焦点行为及真实环境端到端流程。项目全量前端类型检查仍存在既有错误,本次新增排产组件及排产入口未报告类型错误。
组件验证结果及截图位于 `scripts/one-click-schedule-20261014/`,复现脚本为 `mom-pro2-before/scripts/one-click-schedule-qa.mjs`。
docs/qc_indicator_result_sn_removal.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
# è´¨æ£€æŒ‡æ ‡ç»“果(检测结果)物料 SN å­—段移除 - å‰ç«¯è”调方案
## èƒŒæ™¯
检验指标结果(检测结果)中的「物资SN」字段不再需要,前后端一并移除。数据库列 `mes_qc_indicator_result.sn` ä¿ç•™ï¼ˆä¸å†è¯»å†™ï¼‰ï¼Œé¿å…åŽ†å²æ•°æ®ä¸¢å¤±ï¼ŒåŽç»­å¦‚éœ€å¯å†å¯ç”¨ã€‚
## æ¶‰åŠé¡µé¢
- è´¨æ£€ç®¡ç† â†’ æ£€éªŒç»“果(检测结果)列表页
- è´¨æ£€ç®¡ç† â†’ æ£€éªŒç»“果新增/编辑/详情弹窗
## API
接口未新增/删除,仅请求与响应结构移除 `sn` å­—段。
| æ–¹æ³• | è·¯å¾„ | è¯´æ˜Ž |
|------|------|------|
| POST | /mes/qc/indicator-result/create | æ–°å¢žæ£€éªŒç»“æžœ |
| PUT | /mes/qc/indicator-result/update | ä¿®æ”¹æ£€éªŒç»“æžœ |
| DELETE | /mes/qc/indicator-result/delete | åˆ é™¤æ£€éªŒç»“æžœ |
| GET | /mes/qc/indicator-result/get-detail | æŸ¥è¯¢æ£€éªŒç»“果明细 |
| GET | /mes/qc/indicator-result/page | æ£€éªŒç»“果分页查询 |
## å­—段变更
| å­—段 | ä½ç½® | å˜æ›´å‰ | å˜æ›´åŽ |
|------|------|--------|--------|
| sn | è¯·æ±‚体(create/update) | ç‰©èµ„SN,字符串 | å·²ç§»é™¤ï¼Œå‰ç«¯ä¸å†æäº¤ |
| sn | å“åº”体(get-detail/page) | ç‰©èµ„SN,字符串 | å·²ç§»é™¤ï¼ŒåŽç«¯ä¸å†è¿”回 |
**响应示例(get-detail):**
```json
{
  "code": 0,
  "data": {
    "id": 1,
    "code": "SPL-001",
    "qcId": 1,
    "qcType": 1,
    "remark": "无",
    "items": [
      { "indicatorId": 1, "value": "3.14", "remark": "无" }
    ]
  }
}
```
## å‰ç«¯ä¿®æ”¹ç‚¹
| æ–‡ä»¶ | ä½ç½® | è¯´æ˜Ž |
|------|------|------|
| src/views/mes/qc/indicatorresult/components/data.ts | è¡¨å• schema | ç§»é™¤ã€Œç‰©èµ„ SN」表单项 |
| src/views/mes/qc/indicatorresult/components/data.ts | è¡¨æ ¼åˆ—定义 | ç§»é™¤ã€Œç‰©èµ„SN」列 |
| src/views/mes/qc/indicatorresult/components/form.vue | è¯¦æƒ…回填 | ç§»é™¤ `sn` å›žå¡«èµ‹å€¼ |
| src/api/mes/qc/indicatorresult/index.ts | æŽ¥å£ç±»åž‹ | ç§»é™¤ `sn` å­—段声明 |
> ä¸Šè¿°å‰ç«¯æ”¹åŠ¨å·²åŒæ­¥å®Œæˆã€‚
## æ³¨æ„äº‹é¡¹
- æ•°æ®åº“列 `mes_qc_indicator_result.sn` **保留**,后端 DO/VO å·²ä¸å†æ˜ å°„该列,历史数据不受影响。
- å‰ç«¯å¦‚有其它页面引用该字段(如导出、打印模板),需一并清理。
- åŽç«¯ AI è¾…助判定(`MesQcAiServiceImpl`)已同步移除 SN å…¥å‚,AI åˆ¤å®šé€»è¾‘不受影响。
docs/sql/config_export_all_20261015.sql
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
docs/trace-location-gate.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
# è¿½æº¯ç½‘址定位授权入口
旧追溯页的“追溯网址”文字仍显示标签印刷所用的 `mes.trace-base-url`,点击后进入同目录的 `trace-location.html?code=...`。授权页以原追溯页的品牌页面为背景。用户主动点击“开启定位并继续”,只有浏览器返回当前位置、且服务端成功保存记录后才在新网址中显示产品追溯内容。定位视图沿用原有背景和版式,把已有真实数据按“生产信息、仓储信息、物流信息”组织;没有来源数据的字段不臆造。直接打开不带追溯码的新网址也可以授权后进入手动查询。拒绝授权、定位失败或保存失败会停留在授权页并给出重试提示。刷新新网址需重新获取位置。
后台“消费者扫码统计”新增“定位授权访问”区块,沿用 `mes:trace-consumer-scan:query` æƒé™ï¼Œå¯æŒ‰æ—¶é—´å’Œè¿½æº¯ç æŸ¥è¯¢ï¼Œæ˜¾ç¤ºè®¿é—®æ¬¡æ•°ã€åæ ‡ã€ç²¾åº¦ã€æ—¶é—´ï¼Œå¹¶å¯æ‰“开地图;热门位置将经纬度分别保留两位小数后聚合(最多 20 å¤„)。记录与原有按 IP æŽ¨æ–­çœå¸‚的扫码事件分开存储,避免影响原统计口径。
## ä¸Šçº¿æ­¥éª¤
1. æ‰§è¡Œ `sql/mysql/mes_trace_location_visit.sql`。
2. éƒ¨ç½²åŽç«¯å’Œç®¡ç†ç«¯ï¼Œç¡®ä¿æ–°é™æ€æ–‡ä»¶ `trace-location.html` ä¸Ž `trace.html` åœ¨ç›¸åŒå…¬å¼€è·¯å¾„下;`/prod/` ä»£ç†åº”把 `/public/mes/trace/location-visit` è½¬å‘到后端。
3. ç»™å…¬ä¼—访问入口配置有效域名和 HTTPS è¯ä¹¦ï¼Œå¹¶æŠŠ `mes.trace-base-url` æ”¹æˆå¯¹åº”çš„ HTTPS è¿½æº¯é¡µåœ°å€ã€‚旧地址 `http://1.95.78.124:9008/prod/trace.html` è‹¥ä»ä¸º HTTP,普通浏览器无法调用 Geolocation API,授权页会明确提示必须使用 HTTPS。已经印制的旧二维码仍会打开 HTTP,需在服务器上将 HTTP è¯·æ±‚跳转到新 HTTPS åŸŸåï¼Œå¹¶ä¿ç•™ `code` å‚数。
浏览器定位必须获得用户授权;服务端接收的坐标来自客户端,不能用它作为防伪或到场证明。现有公开 `/public/mes/trace/query` æŽ¥å£ä»å¯ç›´æŽ¥æŸ¥è¯¢ï¼Œå®šä½é™åˆ¶åªä½œç”¨äºŽæ–°å¢žçš„“追溯网址”点击路径。若业务要求所有产品追溯查询都强制定位,需要另行改造二维码入口和公开查询接口的鉴权流程。
本地启动使用 `application-local.yaml` æ—¶ï¼Œ`mes.trace-location-required=false`,授权页读取公开配置后直接显示定位视图,便于通过 HTTP è°ƒè¯•。默认值为 `true`,生产 profile ä¸é…ç½®æ­¤é¡¹æ—¶ä»è¦æ±‚定位;配置接口失败时前端也不会自动跳过。
docs/ÅŲúÊýÁ¿°´ÊÕÂʵ¹ÍÆ·½°¸.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,130 @@
# ç”Ÿäº§æŽ’产数量按工序收率倒推 â€” éœ€æ±‚与方案
## ä¸€ã€èƒŒæ™¯ä¸Žé—®é¢˜
一键排产(`MesProBatchScheduleService`)当前对**每一道工序**都按工单数量排产:
```java
// MesProBatchScheduleService.build() ç¬¬ 238、291 è¡Œ
var remaining = order.getQuantity().subtract(assigned);   // å·²æŽ’量从「订单量」里扣
...
best.setQuantity(remaining);                              // æ¯é“工序都排订单量
```
实测(远端 `mom-hm`,工单 WO_20260927001,6 é“工序,订单量 100):每道工序的任务数量都是 100。
这不符合实际:末道工序产出成品,数量才等于订单量;前面各道工序要克服本级损耗,产出量必须大于订单量,越靠前越大。
## äºŒã€è§„则定义
### 2.1 æ”¶çއ
- æ”¶çއ `yield_rate` è¡¨ç¤º**本道工序的产出 / æœ¬é“工序的投入**,取值 (0, 1]。
- ç»´æŠ¤ä½ç½®ï¼š**工艺路线工序级**(`mes_pro_route_process`),在「工艺路线 â†’ å·¥åºé…ç½®ã€é‡Œç»´æŠ¤ï¼›å·¥å•生成工序时复制到 `mes_pro_work_order_process`。
- ä¸€é”®æŽ’产读取顺序与现有工序来源一致:工单工序 â†’ å›žé€€å·¥è‰ºè·¯çº¿å·¥åºã€‚
- å­—段为空时按 `1.0` å¤„理(不放大),保证历史数据与未维护收率的工序行为不变。
### 2.2 å€’推公式
设工单工序按 `sort` å‡åºä¸º `p₁ â€¦ pₙ`,各自收率为 `r₁ â€¦ rₙ`,订单量为 `Q`。
任务数量口径 = **该工序的产出量**:
```
target(pₙ) = Q                                    // æœ«é“ = è®¢å•量
target(páµ¢) = CEIL( Q / (rᵢ₊₁ Ã— rᵢ₊₂ Ã— â€¦ Ã— rₙ) )     // å‰é¢å„道逐级放大后向上取整
```
含义:`páµ¢` å¿…须产出足够量,使得经过后面每道工序各自的损耗后,末道仍能拿到 `Q`。数量一律为**整数件**,向上取整以保证前道产出足够覆盖后方累计损耗。
### 2.3 ç¤ºä¾‹
订单量 `Q = 100`,6 é“工序,统一收率 98%:
| å·¥åºï¼ˆsort å€’序) | è®¡ç®— | æŽ’产数量 |
|---|---|---|
| p₆(末道) | 100 | 100 |
| p₅ | ceil(100 / 0.98) | 103 |
| p₄ | ceil(100 / 0.98²) | 105 |
| p₃ | ceil(100 / 0.98³) | 107 |
| p₂ | ceil(100 / 0.98⁴) | 109 |
| p₁ | ceil(100 / 0.98⁵) | 111 |
首道约为订单量的 **1.11 å€**(n=6、98%)。
## ä¸‰ã€æ”¹åŠ¨æ¸…å•
### 3.1 æ•°æ®åº“(远端 mom-hm)
```sql
ALTER TABLE mes_pro_route_process
  ADD COLUMN yield_rate DECIMAL(10,6) NULL COMMENT '工序收率(产出/投入,0~1)' AFTER param_template_id;
ALTER TABLE mes_pro_work_order_process
  ADD COLUMN yield_rate DECIMAL(10,6) NULL COMMENT '工序收率(产出/投入,0~1)' AFTER param_template_id;
-- çŽ°æœ‰è¡Œç»Ÿä¸€åˆå§‹åŒ– 98%
UPDATE mes_pro_route_process       SET yield_rate = 0.980000 WHERE yield_rate IS NULL;
UPDATE mes_pro_work_order_process  SET yield_rate = 0.980000 WHERE yield_rate IS NULL;
```
### 3.2 åŽç«¯
| æ–‡ä»¶ | æ”¹åЍ |
|---|---|
| `MesProRouteProcessDO` | åŠ  `yieldRate` |
| `MesProRouteProcessSaveReqVO` / `RespVO` | åŠ  `yieldRate` |
| `MesProWorkOrderProcessDO` | åŠ  `yieldRate` |
| `MesProWorkOrderProcessSaveReqVO` / `RespVO` | åŠ  `yieldRate` |
| `MesProWorkOrderProcessServiceImpl#getProcessListByProductId` | å¤åˆ¶æ—¶å¸¦ä¸Š `yieldRate` |
| `MesProBatchScheduleService#build` | æ–°å¢ž `calcTargetQuantities()`,`remaining = target - å·²æŽ’量`;`processes()` å›žé€€è·¯çº¿å·¥åºæ—¶ä¹Ÿå¸¦ `yieldRate` |
`calcTargetQuantities` é€»è¾‘(工序已按 sort å‡åºï¼‰ï¼š
```java
int n = processes.size();
BigDecimal cum = BigDecimal.ONE;              // åŽé“累计收率积
BigDecimal[] targets = new BigDecimal[n];
for (int i = n - 1; i >= 0; i--) {
    targets[i] = quantity.divide(cum, 0, RoundingMode.CEILING);   // æ•´æ•°ä»¶ï¼Œå‘上取整
    BigDecimal r = processes.get(i).getYieldRate() == null
        ? BigDecimal.ONE : processes.get(i).getYieldRate();
    cum = cum.multiply(r);
}
```
### 3.3 å‰ç«¯ï¼ˆéœ€ç¡®è®¤ï¼‰
- å·¥è‰ºè·¯çº¿å·¥åºé…ç½®è¡¨å•(`views/mes/pro/route/data.ts`)加「收率」输入框,百分数展示,`0 < æ”¶çއ â‰¤ 1`。
### 3.4 æ•°æ®ä¿®æ­£ï¼ˆæœ¬æ¬¡ä¸€æ¬¡æ€§ï¼‰
- èŒƒå›´ï¼šè¿œç«¯ `mom-hm` çŽ°æœ‰ 60 ä¸ªå·¥å• / 604 æ¡ä»»åŠ¡ï¼ˆæ¯ä¸ªå·¥åºæ°å¥½ 1 æ¡ä»»åŠ¡ï¼Œæ— åŒå·¥åºå¤šä»»åŠ¡ï¼‰ã€‚
- è§„则:按所在工单的工序顺序与收率重算 `quantity`。
- 604 æ¡ä»»åŠ¡å½“å‰çŠ¶æ€å‡ä¸ºã€Œå·²å®Œæˆã€(status=4),`produced_quantity = quantity`。
## å››ã€å¾…确认的边界处理
重算已完成任务时,以下字段是否同步调整,直接决定历史数据一致性:
| å­—段 | å»ºè®® | è¯´æ˜Ž |
|---|---|---|
| `quantity` | **必改** | æœ¬æ¬¡ç›®æ ‡ |
| `produced_quantity` | åŒæ¯”改 | ä¿æŒ produced = quantity,否则任务显示已完成却产出≠排产 |
| `qualify_quantity` | åŒæ¯”改 | åˆæ ¼æ•°åŒæ­¥ |
| `duration` / `start_time` / `end_time` | ä¸æ”¹ | æ—¶é•¿æŒ‰æ•°é‡/产能算,数量变时长本应变;但历史任务时间是**实际发生**记录,改动会破坏甘特图与生产实迹 |
## äº”、影响与风险
- æ”¶çŽ‡å€’æŽ¨åªå½±å“ã€Œä¸€é”®æŽ’äº§ã€ç”Ÿæˆçš„æ•°é‡ï¼›æ‰‹å·¥æŽ’äº§ç”±ç”¨æˆ·è‡ªè¡Œå¡«å†™ï¼Œä¸å—å½±å“ã€‚
- æ•°é‡å˜å¤§åŽï¼ŒæŽ’产时长变长,可能导致交期延后(`result.getWarnings()` ä¸­çš„延期提示会触发),属预期行为。
- å‰ç«¯å·¥åºè¡¨æ ¼è‹¥æ–°å¢žæ”¶çŽ‡åˆ—ï¼Œéœ€åŒæ­¥è°ƒæ•´åˆ—å®½ä¸Žè¡¨å•æ ¡éªŒã€‚
## å…­ã€æ‰§è¡Œè®°å½•(2026-10-15)
- **字段**:远端 `mom-hm` çš„ `mes_pro_route_process`(687 è¡Œï¼‰ã€`mes_pro_work_order_process`(928 è¡Œï¼‰å·²åŠ  `yield_rate`,并统一初始化为 `0.98`。
- **数据**:604 æ¡ä»»åŠ¡ï¼ˆ60 ä¸ªå·¥å•)的 `quantity` / `produced_quantity` / `qualify_quantity` å·²æŒ‰ 98% å€’推重算并**向上取整为整数**;末道工序保持订单量,首道最大(如 WO_20260927001:100 â†’ 111 / 109 / 107 / 105 / 103 / 100)。校验:604 æ¡å…¨éƒ¨ä¸ºæ•´æ•°ã€æœ«é“数量与订单量完全一致。
- **时长**:604 æ¡ä»»åŠ¡ `duration` åŽŸæœ¬å…¨éƒ¨ä¸º NULL,且设备未绑定工作站(`mes_dv_machinery.workstation_id` å…¨ç©ºï¼‰ï¼Œæ•…时长未参与重算。
- **备份与脚本**:`scripts/yield-rate-schedule-20261015/`(`task-before.tsv`、`task-after.tsv`、`work-order-process.tsv`、`applied.sql`)。
- **初始化脚本**:`docs/sql/config_export_all_20261015.sql`(两张表的 DDL å·²å« `yield_rate`)。
- **待用户操作**:重启后端使算法改动生效;前端需 `pnpm typecheck` æˆ–启动 dev server å¤æ ¸ã€‚
docs/Á÷ת¿¨Í¶Èë²ú³ö°´ÊÕÂÊÖØËã·½°¸.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
# æµè½¬å¡å·¥åºè®°å½•「投入 / äº§å‡ºã€æŒ‰æ”¶çŽ‡é‡ç®— â€” éœ€æ±‚与方案
## ä¸€ã€èƒŒæ™¯ä¸Žé—®é¢˜
`/mes/pro/card`(生产流转卡)页面的工序记录表里,"投入数量 / äº§å‡ºæ•°é‡"与同一工单的生产任务数量对不上。
实测(远端 `mom-hm`,工单 WO_20260927001 / 6 é“工序 / è®¢å•量 100):
| | ç¬¬1道 | ç¬¬2道 | ç¬¬3道 | ç¬¬4道 | ç¬¬5道 | ç¬¬6道 |
|---|---|---|---|---|---|---|
| ç”Ÿäº§ä»»åŠ¡ `quantity`(已按收率倒推) | 111 | 109 | 107 | 105 | 103 | 100 |
| æµè½¬å¡å·¥åº æŠ•å…¥ / äº§å‡º | 100/100 | 100/100 | 100/100 | 100/100 | 100/100 | 100/100 |
原因:604 æ¡æµè½¬å¡å·¥åºè®°å½•是当日用 `scripts/pro-card-backfill-20261015/` **按报工记录**补录的,规则为"产出 = æŠ¥å·¥æ•°é‡ã€æŠ•å…¥ = ä¸Šé“产出(首道 = å·¥å•计划数量)"。补录发生在**收率倒推之前**,当时报工数量都是 100;随后生产任务被重算为 111/109/…/100,流转卡便与工序流转、与生产任务分叉。
## äºŒã€å£å¾„定义(已确认)
设工单工序按 `sort` å‡åºä¸º `p₁…pₙ`,各道收率 `r₁…rₙ`,工单计划数量 `Q`:
```
产出(páµ¢) = CEIL( Q / (rᵢ₊₁ Ã— rᵢ₊₂ Ã— â€¦ Ã— rₙ) )          // ä¸Žç”Ÿäº§ä»»åŠ¡æ•°é‡å®Œå…¨ä¸€è‡´
投入(p₁) = CEIL( äº§å‡º(p₁) / r₁ )                        // é¦–道要克服本级损耗
投入(páµ¢) = äº§å‡º(pᵢ₋₁)                                   // i â‰¥ 2:本道投入 = ä¸Šé“产出
不合格品(páµ¢) = 0                                        // å›ºå®šä¸º 0(2026-10-15 æŒ‰ç”¨æˆ·è¦æ±‚,投入/产出不受影响)
```
- æ•°é‡ä¸€å¾‹ä¸ºæ•´æ•°ä»¶ï¼Œå‘上取整。
- æ”¶çŽ‡ä¸ºç©ºæˆ– â‰¤ 0 æ—¶æŒ‰ `1.0` å¤„理(不放大),与一键排产口径一致。
- äº§å‡ºé‡å…¬å¼ä¸Ž `MesProBatchScheduleService#calcTargetQuantities` ç›¸åŒï¼Œä¿è¯æµè½¬å¡äº§å‡º = ç”Ÿäº§ä»»åŠ¡æ•°é‡ã€‚
## ä¸‰ã€ç¤ºä¾‹ï¼ˆQ=100,6 é“工序,统一收率 98%)
| å·¥åºï¼ˆsort å‡åºï¼‰ | æŠ•å…¥ | äº§å‡º | ä¸åˆæ ¼å“ |
|---|---|---|---|
| p₁(首道) | 114 | 111 | 0 |
| p₂ | 111 | 109 | 0 |
| p₃ | 109 | 107 | 0 |
| p₄ | 107 | 105 | 0 |
| p₅ | 105 | 103 | 0 |
| p₆(末道) | 103 | 100 | 0 |
投入/产出按收率逐级倒推,流转卡末道产出 = ç”Ÿäº§ä»»åŠ¡æ•°é‡ï¼›ä¸åˆæ ¼å“æ•°é‡ç»Ÿä¸€ä¸º 0。
## å››ã€æ”¹åŠ¨æ¸…å•
### 4.1 åŽç«¯ï¼šæ–°å¡è‡ªåŠ¨ç”Ÿæˆå·¥åºè®°å½•
| æ–‡ä»¶ | æ”¹åЍ |
|---|---|
| `MesProCardProcessService` / `Impl` | æ–°å¢ž `createCardProcessBatch(List<MesProCardProcessDO>)` æ‰¹é‡æ’å…¥ |
| `MesProCardServiceImpl#createCard` | å»ºå¡åŽæŒ‰å·¥å•工序 + æ”¶çŽ‡ç”Ÿæˆå·¥åºè®°å½•ï¼›åŠ  `@Transactional` |
| `MesProCardServiceImpl#updateCard` | ç”Ÿäº§è®¢å•变更时,删除原工序记录并按新工单重建 |
生成规则:
- å·¥åºæ¥æºï¼š`mes_pro_work_order_process`(按 `sort` å‡åºï¼‰ï¼Œå·¥å•未维护工序则跳过,留待手工维护。
- `进入/出工序时间`、`工位`、`操作人` ç•™ç©ºï¼ˆç”Ÿäº§å°šæœªå‘生,后续填写);`ipqc_id`、`remark` ç•™ç©ºã€‚
### 4.2 è¡¥å½•脚本
- `scripts/pro-card-backfill-20261015/generate.mjs`:改为按 `mes_pro_work_order_process.yield_rate` å€’推投入/产出/不合格,不再直接取报工数量;快照 `wop.tsv` è¡¥å……收率列。
### 4.3 åŽ†å²æ•°æ®é‡ç®—ï¼ˆä¸€æ¬¡æ€§ï¼‰
- èŒƒå›´ï¼šè¿œç«¯ `mom-hm` çŽ°æœ‰ 60 å¼ æµè½¬å¡ / 604 æ¡å·¥åºè®°å½•(604 æ¡å…¨éƒ¨èƒ½åŒ¹é…åˆ°åŒå·¥å•的工序配置,收率全为 0.98)。
- åªæ”¹ `input_quantity` / `output_quantity` / `unqualified_quantity`;`input_time` / `output_time` / `workstation_id` / `user_id` ä¸ºå®žé™…发生记录,保持不变。
## äº”、边界与风险
- æµè½¬å¡å·¥åºè®°å½•仅在流转卡模块内使用(`MesProCardProcessDO` æ— å…¶ä»–模块引用),重算不影响报工、扣料、库存。
- æ•°é‡å˜å¤§åŽå¡ç‰‡ä¸Žç”Ÿäº§ä»»åŠ¡ä¸€è‡´ï¼Œä¸å†å‡ºçŽ°"卡上产出 < ä»»åŠ¡æŽ’äº§"的观感问题。
- æ–°å»ºæµè½¬å¡å³äº§ç”Ÿå·¥åºè®°å½•,草稿态仍可逐条编辑/删除(原有行为不变)。
## å…­ã€æ‰§è¡Œè®°å½•
### 6.1 åŽç«¯æ”¹åŠ¨ï¼ˆå·²å®Œæˆï¼Œç¼–è¯‘é€šè¿‡ï¼‰
`mvn compile -pl yudao-module-mes -am -q` é€šè¿‡ã€‚涉及文件:
- `MesProCardProcessService` / `Impl`:新增 `createCardProcessBatch(List<MesProCardProcessDO>)` æ‰¹é‡æ’入。
- `MesProCardServiceImpl`:`createCard` / `updateCard` åŠ  `@Transactional`;建卡后调用 `generateCardProcesses` æŒ‰å·¥å•工序 + æ”¶çŽ‡ç”Ÿæˆå·¥åºè®°å½•ï¼›æ¢å·¥å•æ—¶å…ˆåˆ æ—§è®°å½•å†é‡å»ºã€‚
- ç”Ÿæˆå£å¾„与 `MesProBatchScheduleService#calcTargetQuantities` ä¸€è‡´ï¼Œä¿è¯æµè½¬å¡äº§å‡º = ç”Ÿäº§ä»»åŠ¡æ•°é‡ã€‚
> ç”Ÿæ•ˆéœ€**重启后端**服务。
### 6.2 åŽ†å²æ•°æ®é‡ç®—ï¼ˆå·²å®Œæˆå¹¶æ ¡éªŒï¼‰
- è„šæœ¬ï¼š`scripts/pro-card-yield-recalc-20261015/recalc.sql`(临时表规避 errno 1093)。
- å¤‡ä»½ï¼š`task-before.tsv`(重算前 604 è¡Œï¼‰ï¼›`task-after.tsv`(重算后 604 è¡Œï¼‰ã€‚
- æ ¡éªŒç»“果(远端 `mom-hm`):
  - æœ«é“产出 = å·¥å•数量:0 æ¡ä¸ç¬¦
  - ä¸åˆæ ¼ = æŠ•å…¥ âˆ’ äº§å‡ºï¼š0 æ¡ä¸ç¬¦
  - æŠ•å…¥ < äº§å‡ºï¼š0 æ¡ï¼ˆæ— è´Ÿä¸åˆæ ¼ï¼‰
  - æŠ•å…¥ = ä¸Šé“产出(首道除外):0 æ¡æ–­é“¾
  - å¡ç‰‡äº§å‡º = ç”Ÿäº§ä»»åŠ¡ `quantity`:604 æ¡å…¨éƒ¨ä¸€è‡´
- ç¤ºä¾‹ WO_20260927001(Q=100,6 é“,收率 0.98):投入 114/111/109/107/105/103,产出 111/109/107/105/103/100,不合格 3/2/2/2/2/3。
### 6.3 è¡¥å½•脚本改造(已完成)
`scripts/pro-card-backfill-20261015/generate.mjs`:
- `wop.tsv` å¿«ç…§å¢žåŠ ç¬¬ 4 åˆ— `yield_rate`(`SELECT work_order_id, process_id, sort, yield_rate FROM mes_pro_work_order_process WHERE deleted=0`)。
- æŠ•å…¥ / äº§å‡ºæ”¹ä¸ºæŒ‰æ”¶çŽ‡å€’æŽ¨ï¼ˆä¸ŽåŽç«¯ã€é‡ç®— SQL åŒå£å¾„),不再直接取报工数量。
- é‡è·‘生成器输出与远端库现状逐行比对:604/604 å®Œå…¨ä¸€è‡´ã€‚
### 6.4 ä¸åˆæ ¼å“æ•°é‡æ”¹ä¸º 0(2026-10-15 è¿½åŠ ï¼‰
按用户要求,流转卡工序记录的**不合格品数量统一固定为 0**(投入、产出仍按收率口径重算,不变):
- åŽç«¯ `MesProCardServiceImpl#generateCardProcesses`:`unqualifiedQuantity(BigDecimal.ZERO)`;编译通过。
- é‡ç®— SQL è¿½åŠ ï¼š`UPDATE mes_pro_card_process SET unqualified_quantity = 0 WHERE deleted = 0;`(604 è¡Œï¼Œå·²æ ¡éªŒ `SUM(unqualified_quantity <> 0) = 0`)。
- è¡¥å½•脚本 `generate.mjs`:`unq` å›ºå®šè¾“出 0;重跑 604 è¡Œå…¨éƒ¨ä¸º 0。
- ç¤ºä¾‹ WO_20260927001:投入 114/111/109/107/105/103,产出 111/109/107/105/103/100,不合格 0/0/0/0/0/0。
scripts/backlog-review-20261015/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
# CRM å¾…办事项检查与修复
检查了待办入口、8 ç±»å¾…办组件、复用表格列、关联 API,以及相关后端列表和数量条件。没有更改远程业务数据。
修复范围:
- åˆåŒå¾…办客户、商机、签约人跳转分别使用 customerId、businessId、signContactId;无关联 ID æ—¶é˜»æ­¢è·³è½¬ã€‚签约人插槽名统一为 signContactName。补齐合同状态、关联订单插槽;没有流程实例不展示“查看审批”。保留上次补齐的合同编号插槽。
- å¾…进入公海调用现有 put-pool-remind-page æŽ¥å£ï¼Œä¸å†æŸ¥è¯¢æ™®é€šå…¬æµ·åˆ—表。3 ç±»å®¢æˆ·å¾…办补齐签订合同数量/金额列。
- å›žæ¬¾è®¡åˆ’期数跳转回款计划详情,纠正“合同状态”筛选标签。计划和回款待办固定初始负责人场景为 1,与数量接口一致。
- å·²æœ‰å…³è”回款的计划隐藏创建回款按钮,并在处理函数再次拦截;创建回款、审核按钮加入与主列表相同的权限控制。创建成功、审核成功后刷新列表和父页面角标。
- å›žæ¬¾å¾…办补齐开票列,合同编号读取实际返回的 contract.no,并保留 contractNo å…¼å®¹ï¼›ç¼ºå¤±å…³è”显示占位符。
- å„类数量独立并发加载,单个失败不阻断其他数量;首次挂载/激活产生的重叠调用合并。
- åŽç«¯å›žæ¬¾æé†’数量条件与列表“未回款且已达提醒日期”对齐,包含提醒日期等于今天的记录,不再要求回款逾期。待审核回款数量引用 CrmReceivableDO.auditStatus,移除错误的合同实体引用。
验证:
- `mvn -o -pl yudao-module-crm -am -DskipTests compile -q` ç¼–译通过。
- `node scripts/backlog-review-20261015/verify.cjs` é€šè¿‡ã€‚使用实际 Vue ç»„件脚本进行针对性验证(依赖 API、路由和表格使用替身),覆盖 8 ç±»å¾…办 Vue ç¼–译、所有复用列插槽、关联实体 ID è·¯ç”±ã€åˆ†é¡µæŸ¥è¯¢å‚数、公海提醒接口、重复回款拦截、操作后刷新、计数接口部分失败与请求合并。结果见 verification.json。
- å‰åŽç«¯æ”¹åŠ¨çš„ Git diff ç©ºç™½æ£€æŸ¥é€šè¿‡ã€‚前端全量 typecheck å­˜åœ¨æ­¤å‰å·²å‘现的其他模块错误,本次未重跑。
尚未部署,未执行浏览器端到端或真实后端接口联调;发布前后端后生效。
scripts/bom-import/µ¼Èë˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
# MES ç‰©æ–™ BOM å¯¼å…¥ç»“æžœ
导入日期:2026-10-12。业务表:`mom-hm.mes_md_product_bom`。
| é¡¹ç›® | è¿œç¨‹ mom-hm | æœ¬åœ° mom-hm |
| --- | ---: | ---: |
| å·²æ ¸éªŒç»„成关系 | 657 | 642 |
| çˆ¶ç‰©æ–™æ•°ï¼ˆåŒ…括下一级半成品) | 81 | 80 |
| æ–°å¢žå…³ç³» | 654 | 639 |
| æ›´æ–°å·²æœ‰ç”¨é‡ | 2 | 2 |
| ä¿ç•™å·²æœ‰ç›¸åŒå…³ç³» | 1 | 1 |
| åˆå¹¶é‡å¤æºè¡Œ | 33 | 33 |
| æœªå½•入源行 | 0 | 15 |
来源为用户提供的 `传渠产品BOMxml(1).xlsx`(37 ä¸ªå·¥ä½œè¡¨ã€342 æ¡ç»„成行)及 `电商产品BOM(1).xls`(3 ä¸ªå·¥ä½œè¡¨ã€348 æ¡ç»„成行),合计 690 è¡Œã€‚原始文件未改动。
电商产品按源表父物料编码匹配。传渠成品与现有 TC0001~TC0037 å¯¹åº”,逐项核对名称;黑果枸杞120克使用传渠 TC0020,电商同名产品使用源表 U2100201,避免混用。子物料均按编码精确匹配。
红枣单碗、鱼胶单碗、150克单碗、100克单碗等二级组成分别关联其上一级表格中对应的 71500052、71500051、71500050、74001507、74001508,避免把单碗配方直接作为整盒用量。
相同父子物料和用量的重复记录合并,不累加;各原始行均可通过 source-lines.json、计划文件和重复行清单追溯。BOM å¤‡æ³¨ä¿ç•™åŽŸæ–‡ä»¶ã€å·¥ä½œè¡¨ã€è¡Œå·ã€åŽŸå§‹æ•°é‡å’Œå•ä½ã€‚
9 æ¡æºè¡Œç¼ºå°‘单位,其中 4 æ¡ç”±åŒç¼–码其他源行确认,另外 5 æ¡ç»ç”¨æˆ·ç¡®è®¤é‡‡ç”¨ç³»ç»ŸåŸºæœ¬å•位。冻干枸杞200克的铝箔袋、原料用量经用户确认分别从 1 æ›´æ–°ä¸º 25 ä¸ªã€ä»Ž 1 æ›´æ–°ä¸º 0.21 kg。
数据库数量字段保留 6 ä½å°æ•°ã€‚5 æ¡ç”¨é‡ç»å•位换算后需要 7 ä½å°æ•°ï¼Œå·²æŒ‰ 6 ä½å››èˆäº”入,原值保留在备注和清单中:
| çˆ¶ç‰©æ–™ | å­ç‰©æ–™ | æ¢ç®—后原值 kg | å­˜å‚¨å€¼ kg |
| --- | --- | ---: | ---: |
| Q2100202 | 61902677 | 0.0000572 | 0.000057 |
| Q2100202 | 63000389 | 0.0003815 | 0.000382 |
| Q2100202 | 61902682 | 0.0000763 | 0.000076 |
| Q2100202 | 61900948 | 0.0001908 | 0.000191 |
| TC0015 | 61900948 | 0.0021428 | 0.002143 |
远程所有提取行均已覆盖。本地 TC0020 ä¸ºå·²åˆ é™¤è®°å½•,保留其删除状态,相应 15 æ¡ç»„成未录入;详情见 local-待核对.csv。
验证包括源行覆盖、父子编码及名称、单位、数量精度、半成品层级、BOM çŽ¯è·¯ã€é‡å¤å…³ç³»ã€äº‹åŠ¡å†…å†…å®¹åŠé‡å¤å†™å…¥æ£€æŸ¥ã€‚æäº¤åŽé‡æ–°ä»Žä¸¤ä¸ªæ•°æ®åº“è¯»å–ï¼Œé€æ¡æ¯”è¾ƒçˆ¶å­é¡¹ä¸Žæ•°é‡ï¼Œé€šè¿‡ã€‚
导入前 snapshot.xml æ–‡ä»¶ä¿ç•™ç›¸å…³ç‰©æ–™ä¸ŽåŽŸå§‹ BOM,post-snapshot.xml ä¸ºæäº¤åŽå›žè¯»ã€‚实际提交数量见 local-result.txt、remote-result.txt。
scripts/business-flow-20261014/ÉÌ»úµ÷ÕûºË¶ÔÇåµ¥.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
# å•†æœºæµç¨‹å’Œå…³è”调整
已同步远程 mom-hm。
- ç”µå•†ã€ç”µå­å•†åŠ¡åŠ399零号店:10条,电销流程。
- å…¶ä½™å•†æœºï¼š687条,标准直销流程。
- åç§°æˆ–客户含北京同仁堂的商机:463条,逻辑删除。
- è§£é™¤4张报价、10张合同的商机绑定,保留业务单据及其销售、生产、质检、库存关联。
- å•†å“æ˜Žç»†ã€è”系人关联、跟进关联及商机权限同时清理。
- åŽŸæœ‰ç»“æŸçŠ¶æ€ã€ç¼–å·ã€å®¢æˆ·ã€å•ä»·ã€é‡‘é¢ã€æ•°é‡ä¸Žåº“å­˜ä¿æŒä¸å˜ã€‚
- æäº¤å‰äº‹åŠ¡æ ¸éªŒä¸Žæäº¤åŽç‹¬ç«‹è¿žæŽ¥å¤æ ¸é€šè¿‡ï¼›æŠ¥ä»·ä¸ŽåˆåŒçš„å•†æœºå­—æ®µåœ¨çŽ°æœ‰ä¿å­˜æŽ¥å£ä¸­ä¸ºå¯é€‰ã€‚
scripts/customer-code-removal/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
# å®¢æˆ·ç¼–码字段移除
已从前端列表、详情、客户选择器、接口类型,以及后端响应和导出模型中移除客户编码。客户名称、客户 ID、关联关系和统一社会信用代码保留。共修改 34 ä¸ªæºæ–‡ä»¶ï¼›å…·ä½“修改前后内容记录于 changes.json,未修改数据库业务记录。
验证结果:
- MES æ¨¡å—及依赖离线编译通过:`mvn -o -pl yudao-module-mes -am -DskipTests compile -q`。
- ä¿®æ”¹æ–‡ä»¶çš„ TypeScript、Vue è¯­æ³•检查通过;客户选择器按名称查询、单选和多选结构保留;Java æ¨¡åž‹å…¶ä»–字段保持不变。结果见 verification.json。
- æºç ä¸­æœªå‘现客户编码相关字段残留;Git diff ç©ºç™½æ£€æŸ¥é€šè¿‡ã€‚
- å‰ç«¯å…¨é‡ typecheck æœªé€šè¿‡ï¼Œå­˜åœ¨ IM å¯¼å…¥è·¯å¾„、采购申请重复字段等既有问题。
当前仅完成源代码修改与验证,尚未部署。需要发布前后端后才会在运行系统中生效。
scripts/customer-links-20261015/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
# ç”Ÿäº§åŠå…³è”业务客户关系修复
2026-10-15 11:09:13 å·²æäº¤è‡³ 36.213.150.237:10000 / mom-hm;11:09:32 ç‹¬ç«‹è¿žæŽ¥æ ¸éªŒé€šè¿‡ã€‚
补齐 5 å¼ ç”Ÿäº§å·¥å•、57 æ¡ç”Ÿäº§ä»»åŠ¡ã€51 ä¸ªç”Ÿäº§æ‰¹æ¬¡ï¼Œå…± 113 å¤„ client_id。工单由销售来源编号和主计划双重确认;任务继承工单;生产批次继承工单及任务。销售客户使用既有电商、北京同仁堂健康(大连)海洋食品有限公司,库存生产沿用已有工单的“总公司”归属。未新建客户,不通过产品名称猜测客户。
修改前备份见 locked-before-20261015-110913.json,依据及明细见 plan.json、客户关联修复清单.csv;事务提交和独立核验结果分别见 result.json、verification.json。全字段比较确认只有目标 client_id æ”¹åŠ¨ï¼ŒåŽŸæœ‰åˆ›å»º/更新时间、操作人、状态、金额、数量等保持不变。主计划、工单、任务客户缺失均为 0,销售→主计划→工单→任务→生产批次一致。
其余营销、发货通知、销售出库客户有效且无上下游冲突。生产领料、生产入库和过程检验本身没有 client_id å­—段,沿工单获得客户,修复后能够正常解析。
51 å¼ ç‹¬ç«‹å‡ºè´§æ£€éªŒå•没有销售单或生产订单关联,不能唯一认定客户,已向用户询问对应关系,清单见“待确认客户的出货检验单.csv”。829 ä¸ªæ²¡æœ‰é”€å”®æˆ–生产订单归属的库存批次保持客户为空;未转客户的线索不做客户强绑。
代码中主计划生成工单已带入 clientId,任务创建已继承工单 clientId,本次缺项来自历史业务数据,未修改相关源码。完成的是数据库及控制器客户读取路径核对,未声称执行页面端到端测试。
## ç‹¬ç«‹å‡ºè´§æ£€éªŒå•后续绑定
用户明确回复“参考其他数据帮我绑定一下”后,于 2026-10-15 11:14:33 å¯¹ä¸Šè¿° 51 å¼ æ£€éªŒå•完成客户推定绑定。顺序为同物料历史销售、同名产品(可跨规格)、同系列产品历史销售、检验单 BJTRT ä¼ä¸šæ ‡è¯†ä¸Žæ—¢æœ‰å®¢æˆ·åç§°å‚考匹配;不是原始客户证明。共 1 æ¡åŒç‰©æ–™ã€11 æ¡åŒåã€31 æ¡åŒç³»åˆ—、8 æ¡ä¼ä¸šæ ‡è¯†æŽ¨å®šã€‚未混填销售单 ID、检验来源或结论。
分配为电商 25 å¼ ã€åŒ—京同仁堂健康药业股份有限公司 13 å¼ ã€åŒ—京同仁堂健康(大连)海洋食品有限公司 7 å¼ ã€åŒ—京同仁堂健康药业电子商务有限公司 6 å¼ ã€‚全部客户为既有有效档案。结果见 oqc-binding-result.json,匹配依据及候选见 oqc-binding-plan.json,“出货检验客户匹配清单.csv”便于复核。旧“待确认”清单为当时快照,当前已完成绑定。
事务内和独立连接都做了全字段校验,只有指定 51 å¼  client_id å˜åŒ–,其余 79 å¼ æ£€éªŒå•及所有业务时间、结果、数量、状态、来源字段保持不变;当前全部 130 å¼ å‡ºè´§æ£€éªŒå•客户有效且无空缺,核验见 oqc-binding-verification.json。
scripts/db-cleanup-20261016/Cleanup.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,178 @@
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.sql.Types;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.GZIPOutputStream;
/** One-time cleanup of the requested modules in mom-thzynew. No credentials are stored here. */
public class Cleanup {
    private static final String DB = "mom-thzynew";
    private static final String URL = "jdbc:mysql://1.95.78.124:9000/" + DB
            + "?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&connectTimeout=5000";
    private static final List<String> PRESERVED = List.of(
            "mes_wm_warehouse", "mes_wm_warehouse_area", "mes_wm_warehouse_location", "mes_pro_line");
    private static boolean selected(String table) {
        if (PRESERVED.contains(table)) return false;
        return table.startsWith("crm_")
                || table.startsWith("erp_sale_")
                || table.startsWith("mes_wm_")
                || table.startsWith("mes_qc_")
                || table.startsWith("mes_pro_bag_code")
                || table.startsWith("mes_pro_batch")
                || table.equals("mes_pro_pallet")
                || table.equals("mes_pro_scan_event")
                || table.equals("mes_trace_consumer_scan_event")
                || table.equals("mes_trace_cross_region_warning")
                || table.equals("mes_trace_event")
                || table.equals("mes_trace_integrity_record");
    }
    private static String password() throws IOException {
        String yaml = Files.readString(Path.of("yudao-server/src/main/resources/application-thzy.yaml"));
        return Arrays.stream(yaml.split("\\R")).map(String::trim)
                .filter(line -> line.startsWith("password:"))
                .findFirst().orElseThrow().substring("password:".length()).trim();
    }
    private static List<String> tables(Connection connection) throws Exception {
        List<String> result = new ArrayList<>();
        try (Statement statement = connection.createStatement();
             ResultSet rows = statement.executeQuery("SELECT table_name FROM information_schema.tables "
                     + "WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE' ORDER BY table_name")) {
            while (rows.next()) {
                String table = rows.getString(1);
                if (selected(table)) result.add(table);
            }
        }
        return result;
    }
    private static long count(Connection connection, String table) throws Exception {
        try (Statement statement = connection.createStatement();
             ResultSet rows = statement.executeQuery("SELECT COUNT(*) FROM `" + table + "`")) {
            rows.next();
            return rows.getLong(1);
        }
    }
    private static String hex(byte[] bytes) {
        StringBuilder result = new StringBuilder(bytes.length * 2);
        for (byte value : bytes) result.append(String.format("%02X", value & 0xff));
        return result.toString();
    }
    private static String literal(ResultSet row, ResultSetMetaData meta, int column) throws Exception {
        Object value = row.getObject(column);
        if (value == null) return "NULL";
        int type = meta.getColumnType(column);
        if (type == Types.BINARY || type == Types.VARBINARY || type == Types.LONGVARBINARY
                || type == Types.BLOB || type == Types.BIT || type == Types.BOOLEAN) {
            return "0x" + hex(row.getBytes(column));
        }
        if (type == Types.TINYINT || type == Types.SMALLINT || type == Types.INTEGER
                || type == Types.BIGINT || type == Types.FLOAT || type == Types.REAL
                || type == Types.DOUBLE || type == Types.DECIMAL || type == Types.NUMERIC) {
            return row.getString(column);
        }
        return "CONVERT(0x" + hex(row.getString(column).getBytes(StandardCharsets.UTF_8)) + " USING utf8mb4)";
    }
    private static void backup(Connection connection, List<String> tables, Path destination) throws Exception {
        Files.createDirectories(destination.getParent());
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
                new GZIPOutputStream(Files.newOutputStream(destination)), StandardCharsets.UTF_8))) {
            writer.write("-- Data backup before requested cleanup of " + DB + "\n");
            writer.write("-- Restore only after reviewing target schema and current data.\n");
            writer.write("SET NAMES utf8mb4;\n");
            for (String table : tables) {
                writer.write("-- " + table + "\n");
                try (Statement statement = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY,
                        ResultSet.CONCUR_READ_ONLY)) {
                    statement.setFetchSize(Integer.MIN_VALUE);
                    try (ResultSet rows = statement.executeQuery("SELECT * FROM `" + table + "`")) {
                        ResultSetMetaData meta = rows.getMetaData();
                        StringBuilder columns = new StringBuilder();
                        for (int i = 1; i <= meta.getColumnCount(); i++) {
                            if (i > 1) columns.append(',');
                            columns.append('`').append(meta.getColumnName(i)).append('`');
                        }
                        while (rows.next()) {
                            writer.write("INSERT INTO `" + table + "` (" + columns + ") VALUES (");
                            for (int i = 1; i <= meta.getColumnCount(); i++) {
                                if (i > 1) writer.write(',');
                                writer.write(literal(rows, meta, i));
                            }
                            writer.write(");\n");
                        }
                    }
                }
            }
        }
    }
    public static void main(String[] args) throws Exception {
        if (args.length < 1 || !List.of("audit", "backup", "delete").contains(args[0])) {
            throw new IllegalArgumentException("Usage: Cleanup audit|backup|delete [backup-path]");
        }
        try (Connection connection = DriverManager.getConnection(URL, "root", password())) {
            if (!DB.equals(connection.getCatalog())) throw new IllegalStateException("Wrong database");
            List<String> tables = tables(connection);
            long total = 0;
            for (String table : tables) {
                long rows = count(connection, table);
                total += rows;
                if (rows > 0 || args[0].equals("audit")) System.out.println(table + "\t" + rows);
            }
            System.out.println("TABLES=" + tables.size() + " ROWS=" + total);
            for (String preserved : PRESERVED) System.out.println("PRESERVED " + preserved + "=" + count(connection, preserved));
            if (args[0].equals("audit")) return;
            if (args.length != 2) throw new IllegalArgumentException("Backup path required");
            Path backupPath = Path.of(args[1]).toAbsolutePath();
            if (args[0].equals("backup")) {
                if (Files.exists(backupPath)) throw new IllegalStateException("Backup already exists");
                backup(connection, tables, backupPath);
                System.out.println("BACKUP=" + backupPath + " BYTES=" + Files.size(backupPath));
                return;
            }
            if (!Files.isRegularFile(backupPath) || Files.size(backupPath) == 0) {
                throw new IllegalStateException("Backup is missing or empty");
            }
            if (total != 53982 || count(connection, "mes_wm_warehouse") != 5
                    || count(connection, "mes_wm_warehouse_area") != 3
                    || count(connection, "mes_wm_warehouse_location") != 4
                    || count(connection, "mes_pro_line") != 3) {
                throw new IllegalStateException("Database changed since backup; aborting cleanup");
            }
            connection.setAutoCommit(false);
            try {
                for (String table : tables) {
                    try (Statement statement = connection.createStatement()) {
                        System.out.println("DELETED " + table + "=" + statement.executeUpdate("DELETE FROM `" + table + "`"));
                    }
                }
                for (String table : tables) {
                    if (count(connection, table) != 0) throw new IllegalStateException("Not empty: " + table);
                }
                connection.commit();
            } catch (Exception failure) {
                connection.rollback();
                throw failure;
            }
            System.out.println("COMMITTED " + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        }
    }
}
scripts/ecommerce-production-20261015/¼ÈëÇåµ¥.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
# 10月15日至月底生产及销售录入清单
客户:总公司;合计:2,062,353.18元;4组销售单据,13项产品。
回款:11月30日一次月结,仅建立回款计划。
今天:蜜桃味营养素饮品包装部分完成800盒,尚未形成末道成品;其余12工单待排产,不提前报工。
| äº§å“ | æ•°é‡ | å•位 | è®¡åˆ’开工 | äº¤æœŸ | å·¥å• |
|---|---:|---|---|---|---|
|γ-氨基丁酸营养素饮品(蜜桃味)|19216|盒|2026-10-15|2026-10-23|WO_20261015004|
|γ-氨基丁酸酸枣仁饮品(桃子味)|30000|盒|2026-10-20|2026-10-23|WO_20261015005|
|血蛋白营养素饮|10000|盒|2026-10-22|2026-10-27|WO_20261015006|
|血红素铁红枣饮|7992|盒|2026-10-19|2026-10-21|WO_20261015007|
|红黑枸杞原浆礼盒-1800ml(30ml*60袋)|3033|盒|2026-10-20|2026-10-22|WO_20261015008|
|黑红枸杞原浆-30ml|100000|袋|2026-10-21|2026-10-30|WO_20261015009|
|枸杞原浆-300ml|1400|盒|2026-10-16|2026-10-19|WO_20261015010|
|黑枸杞250克(50克*5)|168|盒|2026-10-19|2026-10-21|WO_20261015011|
|黑枸杞 å¤§æžœ 500克(250克*2)特优级|666|套|2026-10-22|2026-10-26|WO_20261015012|
|黑果枸杞-250克甲级|1800|瓶|2026-10-26|2026-10-28|WO_20261015013|
|黑果枸杞-90克|90|瓶|2026-10-27|2026-10-29|WO_20261015014|
|雪菊|180|瓶|2026-10-28|2026-10-30|WO_20261015015|
|桑椹原浆|1000|盒|2026-10-16|2026-10-16|WO_20261015016|
以下产品现有BOM不完整,未套用其他规格或虚构投料:血蛋白营养素饮、血红素铁红枣饮、黑红枸杞原浆-30ml、黑果枸杞-90克、雪菊、桑椹原浆。
原表中的项目号、进度备注均保留在对应单据;168盒、90瓶、180瓶等小批量保持原数,没有为了凑数量上调。
价格按表列结算单价及金额执行,未额外假设税率或追加税款。
新增了表内原编码缺失的3款成品;规范了相关成品的包装单位和规格,历史单据数量金额未改动。
工作日校对参考:https://www.gov.cn/zhengce/content/202511/content_7047090.htm
scripts/equipment-holiday-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
# å›½åº†ç‚¹æ£€ä¿å…»æ¢å¤æœªå®Œæˆ
按用户要求处理2026-10-01 00:00:00至2026-10-08 00:00:00(不含末端)的记录。2026-10-14 20:55:49已提交并读回核验:943条点检状态20改为10(待点检),616条保养状态4改为0(待保养),清空4065行点检check_status/check_result及672行保养status/result,保留项目及记录关联关系。
按剩余有效完成记录重算受影响设备最近点检、保养时间。最近点检均有假期后的有效记录,无需改变;11台最近保养时间回退到假期前最后完成的记录。保留check_time/mainten_time作为原记录日期和待处理日期,没有另设完成时间列。方案为周期性启用配置,非单次完成单据,386份方案及设备/项目关联保持不变。无来源明确关联本批次的有效维修工单,独立维修数据不变。
操作人244李万娟。既有创建人、责任人、创建时间、其他日期记录、设备类型与其他设备业务字段不变。locked-before.json保存事务前所有有效mes_dv业务数据,result.json包含完整目标记录及明细ID和设备日期变更。事务内逐字段校验,提交后再次读取验证;未虚构考勤、重新完成或真实执行情况。
scripts/equipment-repairs-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
# ä¸¤æ¡è®¾å¤‡ç»´ä¿®å•
按用户明确要求“造两条数据”,于北京时间2026-10-14 22:42:16新增两份维修单及各一条明细;生成依据保存在执行结果generated_at_user_request字段,不另向界面备注追加过程说明。
RP_20260922001:半自动旋盖机,2026-09-22 09:15报修、11:10维修完成、11:40验收;关联传动及定位部件点检项目26,处理定位部件松动及异响。
RP_20261013001:电子感应封口机,2026-10-13 09:30报修、10:55维修完成、11:20验收;关联冷却风扇点检项目213,处理风扇积尘和散热问题。
两份按现有维修单口径为已确认(4)、通过(1),报修创建人、维修人、验收人、明细创建人及修改人均243赵磊(设备部启用账号)。业务时刻均09:00–18:00内,工作日且不在中秋/国庆假期,日期依次递增且不超过执行时刻,设备及项目的创建时间早于维修日期。未关联不存在的报修来源单,没有创建耗料或调整库存。
locked-before-20261014-224216.json为执行前备份,result.json含ID、编号及所有业务时刻。事务内与提交后核验原有记录完全不变。
scripts/equipment-types-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
# è®¾å¤‡ç±»åž‹æ•´ç†
按用户要求,于北京时间2026-10-14 20:25:21整理mom-hm设备类型为两个启用根类型:生产设备26(编码SCSB)、其他设备27(编码QTSB)。原有9个车间类型逻辑删除,134台有效设备重新绑定,106台生产设备、28台其他设备。设备未删除,名称、编码、规格、车间、工作站、状态、备注、效率、创建人及创建时间均不变;修改人244李万娟,已核实生产管理员角色。
分类依据为逐项核对的名称及用途。直接加工、清洗原料、配制、提取、灭菌、包装、成品输送、在线金属检测等归生产设备;空调、除湿、压缩空气、供水、冷却、除尘、洗衣、清洁、叉车、成品存储及独立检测仪器等归其他设备。中间液体储罐和乙醇工艺储罐归生产设备,独立密封性测试仪和电导率仪归其他设备。
before.json为只读预览,locked-before.json为完整事务前备份(包含逻辑删除历史行),result.json含每台设备新旧类型映射。已检查数据库只有设备台账引用类型,全部有效设备均关联有效类型,无悬空引用;事务内及提交后读回验证通过。
scripts/iqc-import-20261012/ͬ²½½á¹û-¹ú±ê²¹³ä.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
# æ¥æ–™æ£€éªŒåŠé£Ÿå“å›½æ ‡è¡¥å……结果
目标库:36.213.150.237:10000 / mom-hm。处理日期:2026-10-12。
59行来源数据累计导入40张检验单、441条检验明细;此次新增14张、185条明细。来料日期均为检测日期前15天。检验单保留草稿状态;合格数量与总体结论来自原表,未生成或伪造实测数值。
物料:新增山梨糖醇、丹参粉2项;按名称及包装规格复用已有物料5项,未因编码不同重复新建。固体山梨糖醇与山梨糖醇液分别保留。
本次依据官方CFSA标准正文补充13个方案、177项检验要求(共新增147个可复用指标),启用12个;香精方案仍停用。另8个未明确适用标准的方案保持停用。所有限值以文本方式保留,条件项须按适用范围、产品形态及检验日期人工判断。
## å·²è¡¥å……方案
|物料|执行标准|项目数|状态|
|---|---|---:|---|
|DL-苹果酸|GB 25544-2010|13|启用|
|乳酸链球菌素|GB 1886.231-2023|13|启用|
|木糖醇|GB 1886.234-2016|12|启用|
|乳酸钙|GB 1886.21-2016|18|启用|
|山梨糖醇|GB 1886.187-2016|13|启用|
|柠檬酸钙|GB 1903.14-2016|9|启用|
|柠檬酸锌|GB 1903.49-2020|17|启用|
|甘油|GB 29950-2013|12|启用|
|甜菊糖苷|GB 1886.355-2022|12|启用|
|葡萄糖酸亚铁|GB 1903.10-2015|12|启用|
|赤藓糖醇|GB 26404-2011|11|启用|
|黄原胶|GB 1886.41-2025|18|启用|
|食用香精|GB 30616-2020|17|停用|
木糖醇和山梨糖醇第1号修改单自2026-08-18实施,历史检验不追溯使用例外。赤藓糖醇此次使用GB 26404-2011,新版GB 1886.390-2026在2027-02-18才实施。柠檬酸钙按四水合物适用范围;乳酸钙与柠檬酸锌保留各水合形态分支;判定前须核对COA、标签和适用范围。
## æš‚缓行(19行)
|Excel行|编号|名称|暂缓原因|
|---:|---|---|---|
|3|T202609023|L-赖氨酸来料检验|方案未启用来料检验;GB 1903.1-2015针对L-盐酸赖氨酸;现有名称未证明盐酸盐形态,不直接套用,待COA/标签确认。|
|20|T202609011|甜橙香精来料检验|方案未启用来料检验;待补产品类型/型号、批准对照品及其相对密度/折光指数;暂缓检验单导入。|
|22|Y202609003|甜菜根浓缩粉来料检验|方案未启用来料检验;未检得可直接对应该浓缩粉的食品安全产品国标;待工艺、配方及产品执行标准。|
|23|Y202609026|白燕丝A2来料检验|方案未启用来料检验;待确认净燕窝/血燕及加工形态、产地、供应商执行标准;不套用即食燕窝指标。|
|30|Y202609031|黑果枸杞原浆来料检验|方案未启用来料检验;待确认原浆加工工艺、配方、杀菌方式及产品执行标准;不套用干果枸杞指标。|
|31|Y202609032|黑果枸杞原浆-经济型来料检验|方案未启用来料检验;待确认原浆加工工艺、配方、杀菌方式及产品执行标准;不套用干果枸杞指标。|
|32|Y202607039|丹参粉来料检验|方案未启用来料检验;待确认普通食品/保健食品用途、原料适用依据及产品标准;不将药典标准直接当作食品国标。|
|37|Y202608014|山药粉来料检验|方案未启用来料检验;待确认生粉/熟粉/固体饮料/淀粉或提取物形态及产品标准;不套用其他类别限值。|
|38|Y202608021|山药粉来料检验|方案未启用来料检验;待确认生粉/熟粉/固体饮料/淀粉或提取物形态及产品标准;不套用其他类别限值。|
|39|Y202608006|桂圆粉来料检验|编号重复:按用户要求暂不导入这两行|
|41|Y202607016|甜菜根浓缩粉来料检验|方案未启用来料检验;未检得可直接对应该浓缩粉的食品安全产品国标;待工艺、配方及产品执行标准。|
|43|Y202608027|白燕丝A2来料检验|方案未启用来料检验;待确认净燕窝/血燕及加工形态、产地、供应商执行标准;不套用即食燕窝指标。|
|44|Y202608039|白燕丝A2来料检验|方案未启用来料检验;待确认净燕窝/血燕及加工形态、产地、供应商执行标准;不套用即食燕窝指标。|
|51|Y202608050|花生衣粉来料检验|方案未启用来料检验;GB 1886.323-2021是食品添加剂花生衣红,不是花生衣粉;待原料用途、工艺及产品标准。|
|56|Y202608001|黑果枸杞-带柄(中果)来料检验|方案未启用来料检验;0006S属于待确认的企业标准编号,需完整企业标准及版本;不从编号推定国标指标。|
|57|Y202608002|黑果枸杞-带柄(小果)来料检验|方案未启用来料检验;0006S属于待确认的企业标准编号,需完整企业标准及版本;不从编号推定国标指标。|
|58|Y202608041|黑果枸杞-带柄来料检验|方案未启用来料检验;0006S属于待确认的企业标准编号,需完整企业标准及版本;不从编号推定国标指标。|
|59|Y202608006|黑果枸杞原浆来料检验|编号重复:按用户要求暂不导入这两行;方案未启用来料检验;待确认原浆加工工艺、配方、杀菌方式及产品执行标准;不套用干果枸杞指标。|
|60|Y202608042|黑果枸杞原浆来料检验|方案未启用来料检验;待确认原浆加工工艺、配方、杀菌方式及产品执行标准;不套用干果枸杞指标。|
## æ ¸å¯¹ä¸Žç•™æ¡£
正式PDF、标准发布时间/实施日期、官网详情链接保存在standards目录。国标技术要求表及修改单已渲染检查。数据库事务提交后已复核方案状态、177条关联项及标准文本、40张单据日期;新增14张单据执行标准字段已逐条核对。
[国标指标明细](national-standards-review.csv) Â· [暂缓清单](skipped-rows.csv) Â· [国标落库SQL](national-standards-executed.sql) Â· [新增检验单SQL](executed-import.sql) Â· [执行标准字段SQL](national-iqc-execute-standard.sql)
[官方食品安全国家标准检索平台](https://sppt.cfsa.net.cn:8086/db)
scripts/marketing-remarks-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
# è¥é”€å¤‡æ³¨æ•´ç†
按用户“非真实交易不要出现”“整个营销都帮我优化一下”的要求,于北京时间2026-10-14 21:52:10完成mom-hm营销业务备注整理。仅处理remark字段,创建人、金额、日期、更新日期、单据状态和关联关系均不变;修改人291朱莉。跟进正文和其他非备注字段不改。
扫描所有有remark的有效CRM业务表及ERP销售订单/明细。去除纯业务链演示说明、台账补录、文件来源及导入过程说明;纯说明备注置空。保留付款状态、票号、渠道及原业务内容,统一发票称谓、标点,修复已知括号错误。商机原业务备注主要为尾部标点规范,没有重写其业务进展。回款计划明确保留“计划日期待确认”,合并开票明确保留“单张金额待核对”,缺发票附件仍标注待补充。
共调整1761条:商机1142、线索44、客户308、合同25、报价26、报价明细80、开票21、回款5、回款计划26、销售订单5、销售订单明细79。联系人148条业务备注和销售目标等无需要清理的内容未修改。
preview.json为只读扫描;locked-before-20261014-215210.json为事务前完整备份;result.json记录逐条原文与新文。原演示/补录来源保存在备份,本次只是备注展示调整,不把演示单据重新认定为真实交易。事务内逐字段比较和提交后全量读回核验通过。
scripts/october-chain-20261014/ÒµÎñÁ´ºË¶ÔÇåµ¥.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
# 10月8日至14日业务链补充清单
已写入指定远程 `mom-hm`。日期采用 2026-10-08、09、12、14,避开双休日。编号与业务名称已规范化,备注保留补录来源;生成的检验结果保留样例标识。
## è¥é”€è‡³å‡ºåº“的四条链
每条链包括商机、跟进、报价、合同、销售订单、生产主计划、工单、工序任务与参数、报工、来料及过程检验、产出、成品入库、出货检验、销售出库和两期回款计划。未录入实际回款。
### 2026-10-08 Â· æ´žç‡•窝即食碗装燕窝(900克(150克*6))
- å®¢æˆ·ï¼šåŒ—京同仁堂健康药业股份有限公司;数量:200 ç›’。
- æŠ¥ä»·ï¼š`BJ-202610-L001`;合同:`HT-202610-L001`。
- é”€å”®å•号:`26000492`;金额:90,174.00 å…ƒã€‚
- ä¸»è®¡åˆ’:`MPS20261008001`;生产工单:`WO_20261008001`。
- æœ€ç»ˆæˆå“æ‰¹æ¬¡ï¼š`BT_20261008013`,可在质量批次追溯中查询。
- å·¥åºä»»åŠ¡/报工:各 10 æ¡ï¼›å›žæ¬¾è®¡åˆ’:2 æœŸï¼Œæ€»é¢ä¸ŽåˆåŒä¸€è‡´ã€‚
### 2026-10-09 Â· å³é£Ÿå°ç½æ´žç‡•窝(360克(30克×12))
- å®¢æˆ·ï¼šåŒ—京同仁堂健康药业电子商务有限公司;数量:200 ç›’。
- æŠ¥ä»·ï¼š`BJ-202610-L002`;合同:`HT-202610-L002`。
- é”€å”®å•号:`26000493`;金额:54,014.00 å…ƒã€‚
- ä¸»è®¡åˆ’:`MPS20261009001`;生产工单:`WO_20261009001`。
- æœ€ç»ˆæˆå“æ‰¹æ¬¡ï¼š`BT_20261009013`,可在质量批次追溯中查询。
- å·¥åºä»»åŠ¡/报工:各 10 æ¡ï¼›å›žæ¬¾è®¡åˆ’:2 æœŸï¼Œæ€»é¢ä¸ŽåˆåŒä¸€è‡´ã€‚
### 2026-10-12 Â· æž¸æžåŽŸæµ†ï¼ˆ300ml)
- å®¢æˆ·ï¼šåŒ—京同仁堂健康药品经营有限公司;数量:200 ä¸ªã€‚
- æŠ¥ä»·ï¼š`BJ-202610-L003`;合同:`HT-202610-L003`。
- é”€å”®å•号:`26000494`;金额:3,842.00 å…ƒã€‚
- ä¸»è®¡åˆ’:`MPS20261012001`;生产工单:`WO_20261012001`。
- æœ€ç»ˆæˆå“æ‰¹æ¬¡ï¼š`BT_20261012008`,可在质量批次追溯中查询。
- å·¥åºä»»åŠ¡/报工:各 3 æ¡ï¼›å›žæ¬¾è®¡åˆ’:2 æœŸï¼Œæ€»é¢ä¸ŽåˆåŒä¸€è‡´ã€‚
### 2026-10-14 Â· é»‘枸杞原浆(1.8L)
- å®¢æˆ·ï¼šåŒ—京同仁堂健康(大连)海洋食品有限公司;数量:200 ä¸ªã€‚
- æŠ¥ä»·ï¼š`BJ-202610-L004`;合同:`HT-202610-L004`。
- é”€å”®å•号:`26000495`;金额:35,708.00 å…ƒã€‚
- ä¸»è®¡åˆ’:`MPS20261014001`;生产工单:`WO_20261014001`。
- æœ€ç»ˆæˆå“æ‰¹æ¬¡ï¼š`BT_20261014008`,可在质量批次追溯中查询。
- å·¥åºä»»åŠ¡/报工:各 3 æ¡ï¼›å›žæ¬¾è®¡åˆ’:2 æœŸï¼Œæ€»é¢ä¸ŽåˆåŒä¸€è‡´ã€‚
## ä¸šåŠ¡äººå‘˜
营销:朱莉(291);生产:李万娟(244)、张慧清(273);质量:华生菁(289)、罗军(290);仓库:李万娟(244,参考已有仓库单据);能源:赵磊(243)。
## èƒ½æº
4 æ¡ç‹¬ç«‹è®°å½•,覆盖水、电、蒸汽;单价参考既有台账,用量为演示补充,不与工单建立关联。
- 2026-10-08:WATER,原浆调配区,用量 32.600,金额 169.52 å…ƒã€‚
- 2026-10-09:ELECTRICITY,燕窝加工区,用量 1268.500,金额 1052.86 å…ƒã€‚
- 2026-10-12:STEAM,原浆杀菌区,用量 1.850,金额 458.80 å…ƒã€‚
- 2026-10-14:ELECTRICITY,动力站,用量 1586.200,金额 1316.55 å…ƒã€‚
## æ ¸éªŒä¸Žä¿æŠ¤
- 4 æ¡æˆå“æ‰¹æ¬¡å‡èƒ½è¿½æº¯åˆ°åŽŸæ–™æ¥æ–™æ‰¹æ¬¡ã€æ¥æ–™æ£€éªŒå’Œå…¨éƒ¨å·¥åºï¼Œå¹¶æŸ¥åˆ°é”€å”®åŽ»å‘åŠå‡ºè´§æ£€éªŒã€‚
- 16 ä¸ªç‹¬ç«‹åŽŸæ–™æ‰¹æ¬¡ã€26 ä¸ªå·¥åºæ‰¹æ¬¡ã€124 æ¡åº“存流水;新增库存入出平衡,原有库存未改动。
- 24 å¼ è´¨æ£€å•均有指标明细和样例检验结果。
- æ–°å¢ž 3 ä¸ªé€‚用检验方案,备注保留补录来源,不改原质量标准与工艺/BOM主数据。
- æŠ¥ä»·ã€åˆåŒã€é”€å”®é‡‘额一致;8 æ¡å›žæ¬¾è®¡åˆ’总额按合同校验,计划日期也避开双休日。
- æ•°æ®åº“事务演练、提交后新连接复核均通过。
scripts/operation-logs-20261015/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
# æ“ä½œæ—¥å¿—补充
目标:36.213.150.237:10000 / mom-hm。2026-10-15 09:25:34 æäº¤ï¼›09:26:31 ä½¿ç”¨ç‹¬ç«‹è¿žæŽ¥éªŒè¯é€šè¿‡ã€‚
新增 922 æ¡æ—¥å¿—,涉及 31 ç±»ä¸šåŠ¡ï¼Œæ˜¾ç¤ºä¸šåŠ¡æ—¶é—´ä¸º 2026-09-01 è‡³ 2026-10-14。大批量客户、物料、任务、报工、点检、保养等按方案上限抽取代表记录;不是全量补齐。重复业务日志、非工作日、未来时间、非九至十八点及人员无法匹配的记录跳过,明细见 plan.json。
- IP å‡ä¸ºç”¨æˆ·æŒ‡å®šçš„ 118.213.155.222。extra ä¸­æ³¨æ˜Ž IP æ¥æºï¼Œä¸å£°ç§°æ¥è‡ªåŽŸå§‹ç½‘ç»œè¯·æ±‚ã€‚
- è´¨é‡ä½¿ç”¨ inspector_user_id;营销使用 owner_user_id æˆ– sale_user_id;报工、点检、保养、维修使用各自业务人员字段。生产管理、生产领料入库和 MDM/MES åŸºç¡€æ•°æ®æŒ‰æ­¤å‰ç”¨æˆ·è¦æ±‚归属生产管理员。来源建档人保留在 extra。
- å‘¨å…­å‘¨æ—¥å…¨éƒ¨ä¸æŽ’,含调休工作日;9 æœˆ 25—27 æ—¥ã€10 æœˆ 1—7 æ—¥ä¸æŽ’。依据:[国务院办公厅 2026 å¹´éƒ¨åˆ†èŠ‚å‡æ—¥å®‰æŽ’](https://www.beijing.gov.cn/zhengce/zhengcefagui/202511/t20251104_4258873.html)。
- åŽŸä¸šåŠ¡æ—¶é—´ç²¾ç¡®åˆ°ç§’çš„ä¿æŒä¸å˜ï¼›106 æ¡åªæœ‰æ—¥æœŸæˆ–零点的记录在同一天分配展示时刻,并在 extra æ ‡æ³¨æ—¥æœŸç²¾åº¦å’Œ display_time_assigned,不认定为真实请求时刻。
- æ–°æ—¥å¿—有“业务记录补充”类型及 reconstructed æ¥æºæ ‡è¯†ï¼Œrequest_method、request_url、user_agent ç•™ç©ºã€‚actual recorded_at ä¸ŽåŽ†å²æ˜¾ç¤ºæ—¶é—´åˆ†åˆ«ä¿å­˜ã€‚
- åŽŸæœ‰ 1954 æ¡æ—¥å¿—全部字段不变;业务表不修改。backup ä¸º locked-before-20261015-092534.json。
执行前锁定并校验源单据,事务内逐字段验证新增日志后提交。独立回读验证结果见 verification.json;业务及人员分布见 result.json;可查看“日志补充清单.csv”。防重依据 trace_id、来源表/业务 ID å’Œå·²æœ‰åˆ›å»ºè®°å½•。
## æ˜¾ç¤ºæ–‡æ¡ˆè°ƒæ•´
后续按用户要求,将本批 922 æ¡æ—¥å¿—çš„ sub_type å’Œ action æ”¹ä¸ºè‡ªç„¶ä¸šåŠ¡æè¿°ï¼Œä¾‹å¦‚â€œé”€å”®æŠ¥ä»·â€â€œæ¥æ–™æ£€éªŒâ€â€œç”Ÿäº§æŠ¥å·¥â€ï¼Œå†…å®¹ä½¿ç”¨å½“å‰ä¸šåŠ¡å•æ®ã€è´Ÿè´£äººã€æ—¥æœŸã€é‡‘é¢æˆ–æ•°é‡ã€‚æ˜¾ç¤ºå†…å®¹ä¸å†åŒ…å«â€œè¡¥å……â€â€œè¡¥å½•â€â€œéžåŽŸå§‹â€ç­‰è¯´æ˜Žï¼Œä¸æŽ¨æ–­å®¡æ‰¹ã€åˆæ ¼æˆ–å®Œæˆç­‰äº‹å®žã€‚æ‰©å±•å­—æ®µ extra ä¸­çš„ reconstructed、日期精度、IP æ¥æºç­‰ä¿¡æ¯ä¿æŒåŽŸå€¼ï¼›æ“ä½œäººã€æ—¶é—´ã€IP å’Œå…¶ä»–所有字段保持不变。变更及备份路径见 display-result.json、display-changes.json。
scripts/operations-remarks-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
# ç”Ÿäº§ã€è´¨é‡ã€ä»“库备注整理
按用户承接营销备注整理的要求,于北京时间2026-10-14 22:01:51完成mom-hm备注展示调整,生产181、质量514、仓库2274,共2969条。仅修改remark及修改人,不改创建人、创建/更新时间、数量、金额、参数值、检验结果、状态、库存或业务关联。质量修改人289,其他MES业务修改人244,已核实启用。
清除纯业务链演示和补录说明,纯说明置空。生产参数说明改为“参数值待现场核验;工艺限值保持原要求”,样例检验结果说明改为“检测结果待复核,不作为放行依据”;保留需补标准、暂停检验等实际要求,不重新认定检验或放行依据。路线保留实际配方以客户工艺文件为准。
库存保留期初汇总批次、跨生产批次汇总、生产日期有效期检验信息待补充、规格差异、原编码归并及换算系数。历史销售等量补库存保持“历史销售库存等量调整;补入后出库,净库存不变;使用库存汇总批次”。当前SKU包装1:1说明明确限定当前SKU,不修改主单位或换算主数据。
preview.json为只读扫描,locked-before-20261014-220151.json为完整事务前备份,result.json保存逐条新旧备注。原演示和补录性质保存在备份,本次备注整理不证明实际生产、检验或物流已发生。已做事务内全字段差异校验和提交后全量读回校验。
scripts/permission-audit-result.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
# èœå•与接口权限排查结果(2026-10-12)
已扫描后端 Controller æƒé™ã€å‰ç«¯æƒé™æ ‡è¯†ã€çŽ°æœ‰èœå•æƒé™ï¼Œå¹¶æ ¸å¯¹æ´»åŠ¨é¡µé¢è°ƒç”¨çš„æŽ¥å£ã€‚æ­¤æŠ¥å‘Šæ˜¯é™æ€ä¸€è‡´æ€§æ ¸æŸ¥ç»“æžœï¼Œä¸ç­‰åŒäºŽé€è§’è‰²æµè§ˆå™¨éªŒæ”¶ã€‚
## å·²æ‰§è¡Œ
- æœ¬åœ°åŠè¿œç¨‹ `36.213.150.237:10000/mom-hm` å‡å·²æ‰§è¡Œ `sql/mysql/menu_permission_consistency_patch.sql`。
- è¿œç¨‹ä¿®æ­£ 15 æ¡èœå•记录,新增 53 æ¡ç¼ºå¤±æƒé™ï¼Œæ–°å¢ž 69 æ¡è¶…级管理员菜单授权;68 ä¸ªç›®æ ‡æƒé™æ ‡è¯†å‡å­˜åœ¨ä¸”启用。
- æœ¬åœ°è®¡é‡å•位权限此前已修正,本次修正另外 13 æ¡èœå•记录,并新增 53 æ¡æƒé™ã€69 æ¡è¶…级管理员授权。
- ä¿ç•™åŽŸèœå• ID å’ŒåŽŸæœ‰è§’è‰²å…³è”ã€‚è¦†ç›–è®¡é‡å•ä½ã€å·¥è‰ºå‚æ•°/模板、委外领料完成、退供应商完成、移库、项目归档、销售报价转合同等标识不一致问题。
- è¡¥é½å·²æœ‰é¡µé¢å¯¹åº”的查询、导入、导出、完成等权限。新增权限自动授权范围仅为超级管理员。
- ç”¨æˆ· 244 çš„角色 166 ä»æœ‰ `mdm:unit:import`、`mdm:unit:export`。
- æœ¬åœ° Redis åˆ é™¤äº†ä¸Šè¿°è®¡é‡å•位权限的 2 æ¡æ—§æƒé™èœå•缓存。远程 Redis æ²¡æœ‰è¿žæŽ¥ä¿¡æ¯ï¼Œæœªæ¸…理,远程应用须刷新权限缓存或重启。
- æœ¬åœ°å’Œè¿œç¨‹é‡å¤æ‰§è¡Œ SQL å‡å½±å“ 0 è¡Œï¼Œå¹‚等验证通过。
- å‰ç«¯ä¿®æ”¹çš„ 14 ä¸ª Vue æ¨¡æ¿ç¼–译通过;首页权限 5 ä¸ªåœºæ™¯ä¸Žé€€å‡ºç™»å½•回归脚本通过。
## æŸ¥è¯¢æŽˆæƒè¡¥å……
用户于 2026-10-12 æ˜Žç¡®å›žå¤â€œå…è®¸è¡¥å……”后,已执行 `sql/mysql/menu_page_query_role_grants_pending.sql`,向已持有对应页面权限的角色补授该页查询权限,包括薪资、社保、考勤数据。本地新增 7 æ¡è§’色菜单授权,远程新增 17 æ¡ï¼›ä¸¤åº“均核对待补授权为 0,重复执行影响 0 è¡Œã€‚保留已有授权及删除记录,不扩大到尚未持有该页面权限的角色。
## å…¶ä»–发现
静态接口匹配另发现部分旧 ERP、AI é¡µé¢åŠè®¾è®¡é¡¹ç›®ä»»åŠ¡ã€å›¾çº¸è¯„å®¡ã€BOM、版本变更页面调用的接口,在当前后端没有对应实现;通知模板导出、工资发放导出、旧 MES ç‰©æ–™å¯¼å…¥æ¨¡æ¿ä¹Ÿå­˜åœ¨æŽ¥å£ç¼ºå¤±å€™é€‰ã€‚这些不能用增加菜单权限修复,需单独确认功能是否保留并实现接口。完整原始核查记录见 `permission-api-audit.json` å’Œ `permission-audit-report.json`;解析器无法解析的动态调用仍需人工验收。
前端标识修改需要部署后并重新登录才能更新按钮权限;SQL åŒæ­¥æœ¬èº«ä¸ä¼šéƒ¨ç½²å‰ç«¯ä»£ç ã€‚
scripts/process-route-20261012/¹¤ÒÕ·ÏßÉú³É˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
# å·¥åºåŽ»é‡å’Œå·¥è‰ºè·¯çº¿ç”Ÿæˆç»“æžœ
已同步至 36.213.150.237:10000 / mom-hm,并在事务提交后核对路线工序顺序、后继工序及全部标记。
26 ä»½é™„件去重后为 24 ä»½è§„程;新增 46 ä¸ªå·¥åºã€575 æ¡å¸¦æ¥æºçš„工序操作说明、28 æ¡è·¯çº¿å’Œ 421 æ¡è·¯çº¿å·¥åºã€‚
## è´¨æ£€ä¸Žé¢†æ–™è®¾ç½®
- åŽŸæ–‡æµç¨‹å›¾ä¸­çš„å…¨éƒ¨ 90 ä¸ªæ˜Ÿå·æŽ§åˆ¶ç‚¹å·²è®¾ç½® `check_flag=1`(需要质检),并在备注保留 `*原文关键控制点`。
- æˆå“æ£€éªŒå’Œé‡‘属探测也设置需要质检,共 122 ä¸ªè·¯çº¿å·¥åºã€‚
- å…¨éƒ¨ 421 ä¸ªè·¯çº¿å·¥åºå‡ä¸º `backflush_flag=0`:非倒冲、手动领料。
- ç³»ç»Ÿ `key_flag` æ˜¯å”¯ä¸€äº§å‡ºå·¥åºï¼Œç”¨äºŽç´¯è®¡å·¥å•产量和生成产出单,并非原文多处关键控制点字段。每条路线仅选内包装或热灌装为产出关键工序;所有星号控制点独立标记需要质检。这样避免多个工序重复累计成品产量。
## è·¯çº¿çŠ¶æ€ä¸ŽèŒƒå›´
28 æ¡è·¯çº¿å‡æŒ‰ç³»ç»Ÿæ–°å»ºè§„则保存为未启用(status=1),可在生产管理的工艺路线中查看、编辑。工序主数据为启用状态。
袋装与瓶装的后处理不同,沙棘原浆罐头、黑果枸杞原浆罐头、桑葚原浆及燕窝肽饮品分别生成两条路线;两份黑果枸杞规程类别/版本不同,分别保留。
未绑定产品或新建物料:产品名称、规格、包装及物料类型存在多候选,系统还限制每个产品只能绑定一条路线。候选产品列在 `产品候选及待核实事项.csv`,没有沿用质检任务中的随机选择规则。BOM ç”¨é‡ã€æ‰¹æ¬¡äº§é‡åŠç”Ÿäº§æ€»ç”¨æ—¶æœªå¡«é€ ã€‚
原有测试路线及其产品关系保持原样;未生成生产工单或过程检验单,未修改此前来料、出货检验数据。
## å·²ä¿ç•™çš„差异
- å³é£Ÿè—œéº¦ç²‰ R åž‹ï¼šæµç¨‹å›¾åŠè´¨é‡ç›‘控表混合40min,正文混合30min;保留冲突,未替用户选定生产设定值。
- å³é£Ÿè—œéº¦ç²‰ B åž‹ï¼šæµç¨‹å›¾æœ‰æµ¸æ³¡ã€æ²¥å¹²ã€é«˜æ¸©æ€èŒã€ç²‰ç¢Žã€è¿‡ç­›å’Œé‡‘属探测,正文未完整展开前处理;按图保留步骤并标注待核实。
- çº¢é»‘枸杞原浆:红枸杞、黑果枸杞各自制浆后合流。系统只支持一条后继工序链,采用两项复合工序保存各支线说明;显示顺序不表示将红枸杞半成品投到黑枸杞前处理线上。
- é»‘果枸杞玫瑰果膏:图中预热后过40目筛,正文未单列,已保留过滤步骤。
- å†»å¹²æž¸æžæ–‡ä»¶ä»Žå·²å†»å¹²åŽŸæ–™çš„åŒ…è£…å¼€å§‹ï¼Œæœªè™šæž„å†»å¹²åŠ å·¥æ­¥éª¤ã€‚
- äººå‚葛根枳椇子玉米低聚肽饮品原文未列冷却风干,未从其他产品复制补入。
## ç³»ç»Ÿç”Ÿæˆæ¸…单
| è·¯çº¿ID | æ¥æºç¼–号 | äº§å“åŠåŒ…装 | å·¥åºæ•° | æ˜Ÿå·è´¨æ£€æ•° |
| ---: | --- | --- | ---: | ---: |
| 2 | STP-SG-003-01 | æœ‰æœºé»‘果枸杞 | 13 | 2 |
| 3 | STP-DY-007-00 | é»‘果枸杞 | 13 | 2 |
| 4 | STP-SG-002-04 | å†»å¹²æž¸æž | 8 | 0 |
| 5 | STP-GT-015-04 | æ²™æ£˜åŽŸæµ†ç½å¤´ï¼ˆè¢‹è£…ï¼‰ | 20 | 5 |
| 6 | STP-GT-015-04 | æ²™æ£˜åŽŸæµ†ç½å¤´ï¼ˆç“¶è£…ï¼‰ | 20 | 5 |
| 7 | STP-GT-016-04 | é»‘果枸杞原浆罐头(袋装) | 20 | 0 |
| 8 | STP-GT-016-04 | é»‘果枸杞原浆罐头(瓶装) | 20 | 0 |
| 9 | STP-GY-001-06 | å³é£Ÿè—œéº¦ç²‰R型 | 8 | 0 |
| 10 | STP-DY-001-02 | é»‘果枸杞袋泡茶 | 13 | 2 |
| 11 | STP-GT-009-07 | æž¸æžåŽŸæµ†ç½å¤´ | 19 | 5 |
| 12 | STP-GY-002-05 | å³é£Ÿè—œéº¦ç²‰B型 | 14 | 0 |
| 13 | STP-SG-001-09 | é»‘果枸杞 | 13 | 2 |
| 14 | STP-GT-010-05 | é»‘果枸杞玫瑰果膏 | 18 | 3 |
| 15 | STP-FB-005-00 | é“æ£å±±è¯ç²‰ | 11 | 3 |
| 16 | STP-YL-006-00 | æ¡‘葚原浆(袋装) | 13 | 0 |
| 17 | STP-YL-006-00 | æ¡‘葚原浆(瓶装) | 13 | 0 |
| 18 | STP-YL-016-00 | çº¢é»‘枸杞原浆 | 15 | 5 |
| 19 | STP-YL-008-00 | ç›Šç”Ÿå…ƒè¥¿æ¢…饮 | 15 | 5 |
| 20 | STP-YL-010-00 | Î³-氨基丁酸酸枣仁饮品(桃子味) | 15 | 5 |
| 21 | STP-YL-015-00 | äººå‚枸杞原浆 | 19 | 5 |
| 22 | STP-YL-018-00 | é»‘果枸杞桑葚原浆 | 20 | 5 |
| 23 | STP-YL-009-00 | Î³-氨基丁酸营养素饮品(蜜桃味) | 15 | 5 |
| 24 | STP-YL-012-00 | è“èŽ“å¶é»„ç´ DHA饮品 | 15 | 4 |
| 25 | STP-YL-017-00 | äººå‚葛根枳椇子玉米低聚肽饮品 | 17 | 6 |
| 26 | STP-YL-011-00 | è¥¿æ¢…原浆 | 13 | 6 |
| 27 | STP-YL-007-00 | ç‡•窝肽γ-氨基丁酸鱼胶原蛋白肽饮品(袋装) | 13 | 5 |
| 28 | STP-YL-007-00 | ç‡•窝肽γ-氨基丁酸鱼胶原蛋白肽饮品(瓶装) | 13 | 5 |
| 29 | STP-YL-013-00 | DHA藻油饮品 | 15 | 5 |
## æ˜Žç»†å’Œå®¡è®¡
- [去重工序清单](去重工序清单.csv)
- [工艺路线生成结果](工艺路线生成结果.csv)
- [路线与工序明细](工艺路线与工序明细.csv)
- [产品候选和待核实事项](产品候选及待核实事项.csv)
- `documents.json`:原文件路径、SHA256 åŠæ­£æ–‡ã€‚各 `提取文本.txt`、XML å’Œæµç¨‹å›¾ PNG ä¸ºæ ¸å¯¹ä¸­é—´æ–‡ä»¶ã€‚
- `route-plan-with-ids.json`:路线、工序、原文证据、标记与系统ID。
- `before-route-import.json`:同步前相关系统数据快照。
- `route-import-executed.sql`:实际执行的 SQL。
- `route-import-result.json`:提交后验证结果。
scripts/process-route-20261012/Éú²ú»ù´¡Êý¾Ý²¹³ä˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
# ç”Ÿäº§åŸºç¡€æ•°æ®è¡¥å……结果
已同步数据库:`mom-hm`。来源为本次生产工艺规程、现有产品及BOM、现有车间和系统参数类型。
| é¡¹ç›® | æ•°é‡ |
| --- | ---: |
| äº§å“åŠå°åŒ…装半成品路线绑定 | 97 |
| å·²ä½¿ç”¨è·¯çº¿ï¼ˆå«å®Œæ•´ç”Ÿäº§ã€åŒ…装段、小包装路线) | 46 |
| æœ¬æ¬¡æ–°å¢žè·¯çº¿å˜ä½“ | 23 |
| äº§å“BOM工序投入 | 470 |
| ç”Ÿäº§åŸºç¡€å‚æ•° | 21 |
| å‚数模板 | 63 |
| æ¨¡æ¿å‚数明细 | 99 |
| è·¯çº¿å·¥åºæ¨¡æ¿ç»‘定 | 643 |
| å·¥åºé€šç”¨å‚数绑定 | 68 |
| å·¥ä½œç«™ | 46 |
| è¡¥å……计量单位 | 8 |
## äº§å“ã€æŠ•入与产出
按名称、规格和BOM包装/配方证据匹配,符合条件的多个产品均已绑定。一个产品只绑定一条路线。
BOM投入保留原比例,每个直接BOM用料只安排到一个工序。已灌装半成品进入包装路线,原料和配方用料进入制造路线。小包装半成品另有生产路线,省略外盒段。
产出随生产工单产品编码和单位对应。系统空产出配置会原生回退到工单产品;没有将多种成品编码写成固定首项,也没有将整盒工单切换成单袋物料而保留错误数量。
未自动绑定 7 ä¸ªäº§å“ï¼š
- Q2100072 é»‘果枸杞 200克(100克*2):已绑定现有路线1;保留既有绑定,候选为STP-SG-001-09。
- Q2100197 çº¢é»‘枸杞原浆 1.8L:BOM是红、黑两种30ml袋拼装,不是文档红黑混合原浆;缺拼装规程。
- Q2100228 çº¢é»‘枸杞原浆 1.8L:BOM分别使用红、黑包装膜,属于两种原浆拼装;缺拼装规程。
- Q2100314 é»‘红枸杞原浆 é»‘果枸杞原浆30ml,红枸杞原浆30ml:规格明确红原浆30ml和黑原浆30ml两种,不是混合原浆。
- 12101914 æœ‰æœºé»‘果枸杞原浆 1.44L(60ml*24):有机黑果枸杞原浆缺有机原浆规程,不能套用有机干果或非有机原浆。
- 74000488 é»‘果枸杞(银标240g)(内购专用) ï¼š240g可匹配两份黑果枸杞规程,缺小包装和产品执行标准,暂不选版本。
- 74000565 æž¸æžæ²™æ£˜åŽŸæµ†ç½å¤´ 300ml(30ml/袋×10):枸杞沙棘混合原浆无对应配方规程。
另有 42 ä¸ªå·²ç»‘定产品/半成品未找到自身制造BOM,未虚构投入。24个产品使用已封装半成品BOM,已绑定包装段。即食藜麦粉B型暂未找到明确对应产品,规程路线及参数模板已保留。
## å‚数与模板
沿用系统数值参数类型,生产要求模板类型1、自检要求类型2。单位复用现有MDM计量单位;补充摄氏度、分钟、秒、兆帕、转/分钟、毫米、百分比、目。
温度、时间、压力、灌装净含量等明确工艺要求保存在模板参数备注,保留来源规程。带星号工序的明确数值记录项设置必填,未明确的通用记录项不虚构限值。
| å·¥åº | æ–‡æ¡£è¦æ±‚示例 |
| --- | --- |
| å¾®æ³¢æ€èŒ | æœ‰æœºåŠSG黑果55~65℃、13~15min;DY黑果及袋泡茶50~60℃ |
| çœŸç©ºè„±æ°” | -0.07MPa |
| å‡è´¨ | 18~20MPa |
| çž¬æ—¶ç­èŒ | 100℃、30s |
| çƒ­çŒè£… | â‰¥87℃;各饮品分别按30/35/50ml或工单小包装规格记录 |
| æ°´æµ´ç­èŒ | 90℃;30min与40min分别模板,按产品规程绑定 |
| é¢„热保温 | 85℃、30min |
| æžœè†æå–过滤 | 80±5℃,2次、每次15min,120目 |
| å±±è¯ç²‰è¿‡ç­› | 80目 |
R型藜麦粉混合30/40min冲突没有选择统一执行值。B型前处理高温杀菌数值仅见流程图,模板标为待核实。
现有模板表没有结构化上下限字段,也没有默认生产实测值字段;标准写在备注,实际值由现场填写,系统不会据此自动判定超限。
## å·¥ä½œç«™
严格按一个去重工序对应一个工作站建立46个工作站,工序名称相同不因产品或车间重复建立。参考现有车间的岗位职责归属,全部关联已有虚拟线边仓、库区和库位。
工作站已启用;实体地址、设备、人员未虚构,待现场资料补录。现有车间保持不变。
| çŽ°æœ‰è½¦é—´ | å·¥ä½œç«™æ•° |
| --- | ---: |
| ç½å¤´é£Ÿå“ï¼ˆçŒè£…)车间 | 13 |
| é£Ÿå“è½¦é—´ | 8 |
| æå–车间 | 9 |
| æå–前处理车间 | 10 |
| ç”Ÿäº§è½¦é—´ | 6 |
## æ ¡éªŒä¸Žå½“前状态
事务写入并校验:一工序一工作站、产品唯一绑定、BOM用料无重复且比例一致、单位及模板关联有效、原工序质检标志完整保留、全部非倒冲。
所有本次工艺路线仍停用,保留手动领料;缺少制造BOM、计量比例及文档参数冲突项见清单。没有生成新的生产工单、报工实测值、领料单或库存流水。
## æ–‡ä»¶
- äº§å“è·¯çº¿åŒ¹é…æ˜Žç»†.csv
- å·¥åºæŠ•入匹配明细.csv
- å·¥åºäº§å‡ºåŒ¹é…æ˜Žç»†.csv
- äº§å“ç»‘定及投入待核实清单.csv
- å·¥ä½œç«™ä¸Žå·¥åºè½¦é—´å¯¹åº”.csv
- ç”Ÿäº§å‚数定义.csv
- ç”Ÿäº§å‚数模板明细.csv
- è·¯çº¿å·¥åºå‚数模板绑定.csv
- binding-import-result.json、parameter-station-import-result.json:校验结果
- before-binding-import.json、before-parameter-station-import.json:写入前快照
- binding-import-executed.sql、parameter-station-import-executed.sql:实际执行SQL(不含口令)
scripts/production-schedule-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
# ç”Ÿäº§éƒ¨é—¨æŽ’班
已于北京时间2026-10-14 20:06:30向指定mom-hm库写入并核验。范围2026-09-01至2026-10-14,生产部119及下级生产车间126的45名启用用户;操作人244李万娟,已核实生产管理员角色166。
按用户要求09:00–18:00单白班、固定双休、节假日不排班。排除中秋9月25日至27日及国庆10月1日至7日;9月20日、10月10日虽然官方为调休上班日,仍依用户固定双休要求不排班。官方来源:https://www.beijing.gov.cn/cs/gncs/zcwj/202603/t20260327_4568275.html ã€‚
新建生产类型字典值5(原类型只有注塑、投料工、组装、仓库)、生产白班组、45个成员、9月和10月截至14日两份已确认计划,班次均09:00–18:00。按系统原生班组日历存储26条班组排班,对应1170人次,不是1170条考勤或报工,不推断实际到岗情况。
完整执行前备份locked-before.json,执行关联关系及排除日期result.json。事务内保护既有记录、部门和用户不变;提交后重新读取并核验26天日期集合、成员集合、计划状态及班次时间,无重复日期,不包含周末或假期。
scripts/production-timing-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
# éœ€è¦ç”Ÿäº§è®¢å•的时间间隔调整
北京时间2026-10-14 23:40:18提交,23:41:15独立读回核验通过。仅处理明细need_production=1所属8张有效销售订单,不以production_status完成标记代替需要生产条件。分档数量按销售订单total_count,含多个需生产产品的订单按整单安排,并行工单分别保持工序先后顺序。
采用工作日口径,09:00–18:00内安排执行时刻,生产工序分钟分配另避开12:00–13:00;固定双休,排除2026-09-25至27日中秋及10-01至07日国庆。9月20日、10月10日按用户此前固定双休口径仍不安排。假日来源为国务院2026年放假安排:https://www.beijing.gov.cn/cs/gncs/zcwj/202603/t20260327_4568275.html ã€‚任务范围跨休息日时,仅在工作时段分配生产分钟,所有记录的起止及执行时刻均在工作日。预计有效期、保质期等非实际执行日期保留原值。
|销售订单|总数量|工作日周期|订单日期|出库日期|
|---|---:|---:|---|---|
|26000111|99|3|2026-10-09|2026-10-13|
|26000427|14|2|2026-10-12|2026-10-13|
|26000442|10037|10|2026-09-22|2026-10-13|
|26000458|6018|8|2026-09-24|2026-10-13|
|26000492|200|3|2026-10-08|2026-10-12|
|26000493|200|4|2026-10-09|2026-10-14|
|26000494|200|3|2026-10-12|2026-10-14|
|26000495|200|3|2026-10-12|2026-10-14|
用户明确确认26000495关联报价、合同由10月14日前移至10月12日,分别09:05、09:10,销售订单09:20;相关产品明细创建时间同步。报价与合同关联商机已为空,不恢复此前删除的商机。其他报价、合同及营销数据不改。
共调整49张表2401条记录,均仅改变日期时间字段,不改修改人/创建人、编号、数量、金额、状态、检验结果、参数值、任何ID或关联关系。覆盖9份主计划、9张工单、83道任务/报工、相关来料和过程/出货质检、出入库单及明细、190笔库存流水和专用批次/库存时间。强关联沿订单、主计划、工单、任务、反馈、来源单、检验ID等遍历,不按物料名称模糊扩展。
原有共享期初库存及全订单共用的等量补库存单据保持原样;其入库流水早于调整后的对应出库。仅对全部相关流水都在同一目标链内的专用库存/批次同步时间。逐库存对照调整前后的流水最低累计量,未产生新的先出后入缺口,库存数量始终未改变。
snapshot.json为规划时快照,plan.json保存逐字段修改前后值和每单工作日期集合;locked-before-20261014-234018.json为提交前完整有效数据备份;result.json为提交结果;verification.json为独立连接读回核验。校验包含整单分档周期、MPS/工单/工序/报工先后、先来料后检验再入库、生产完成后出货检验及出库、非目标记录完全不变、日期不超执行时刻。没有新增、删除或变更审计操作日志;本次为用户要求的业务展示时间整理,不证明真实生产或现场检验已发生。
scripts/qc-indicator-optimize-20261014/ÖʼìÓÅ»¯ºË¶ÔÇåµ¥.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
# è´¨æ£€æ£€æµ‹é¡¹ã€æ–¹æ¡ˆä¸ŽæŠ¥å‘Šä¼˜åŒ–
已同步远程 `mom-hm`,原始快照、变更SQL及逐项标准核对表在同目录保存。
- åˆ†ç»„:感官与性状、理化与物性、营养与活性成分、微生物、污染物与重金属、农兽药残留;保留甲醇专项分组。
- ç»“果类型:205个浮点、6个整数、69个文本、7个无结果值的分组项。
- 22种检测单位:百分比、质量分数、污染物浓度、微生物计数及物性单位;不改产品包装单位。
- æ ‡å‡†ä¸Šä¸‹é™æŒ‰çŽ°æœ‰SOP/国标资料原文提取;标准品/试剂纯度、分级、抽样方案及检出条件不合并成一个通用验收限值。
- åŽŸæ¥åªæœ‰â€œåˆæ ¼ã€æ­£å¸¸â€ç­‰æ–‡å­—çš„æ•°å€¼é¡¹ï¼Œä¿ç•™åŽŸæ–‡åˆ°å¤‡æ³¨åŠå¤‡ä»½ï¼Œæ•°å€¼ç•™ç©ºå¾…è¡¥å½•æˆ–ç¡®è®¤ï¼Œä¸ç”Ÿæˆå‡çš„å®žæµ‹æ•°å­—ã€‚
- 12份有效来源报告重新生成;1份来源已删除的报告保留原冻结数据。物料报告模板升级到v1.2,显示完整标准要求并改善列宽,保留原版本。
- 6份旧PDF附件关联作废,实体文件保留;重新导出PDF即可取得更新报告。
- 4份报告(ID 5、13、15、18)有现存数值超出对应标准,见“报告异常与待核对.csv”,需人工复核;原质检单人工结论未改动。
- åŽŸé”€å”®ã€ç”Ÿäº§ã€åº“å­˜ã€è´¨é‡å•å¤´çš„æ•°é‡å’ŒçŠ¶æ€æœªå˜ï¼Œç‹¬ç«‹è¿žæŽ¥æ ¸éªŒé€šè¿‡ã€‚
- åŽç«¯28项相关测试、实际报告渲染和前端生产构建通过;报告判定和数值输入的代码修复需发布新版前后端后生效。
scripts/qc-other-import-20261012/³ö»õ¼Èë¼°¿Í»§¿É¿ÕÐÞ¸Ä˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
# å‡ºè´§æ£€éªŒå½•入及客户可空修改
目标数据库:36.213.150.237:10000 / mom-hm。
原表 496 è¡Œï¼Œå·²å½•å…¥ 220 å¼ å‡ºè´§æ£€éªŒå•(ID 1–220),生成 3,866 æ¡æ–¹æ¡ˆæ£€éªŒæ˜Žç»†ï¼›276 è¡Œæš‚缓。提交后已逐单核对原表编号、日期、数量、汇总结论、检测人员、物料和选定方案,并核对明细数量。
## å½•入规则
- å¤ç”¨å…ˆå‰æŒ‰æ£€éªŒå•名称与系统方案名称模糊匹配、多个候选随机选择后保存的映射,没有重新抽取。
- å®¢æˆ·å…¨éƒ¨ä¿å­˜ä¸ºç©ºï¼Œæ²¡æœ‰è™šæž„客户或来源出货单。
- ä¿ç•™åŽŸè¡¨æ£€æµ‹æ—¥æœŸã€å‡ºè´§æ—¥æœŸå’Œæ•°é‡ã€‚æ¥æ–™æ—¥æœŸæå‰çº¦ 15 å¤©çš„规则仅适用于来料单。
- æ‰€æœ‰æ–°å•据为草稿,原表仅提供汇总结论,没有添加虚构的实测指标结果或完成审批。
- ä½¿ç”¨çš„ 9 ä¸ªå·²å¯ç”¨æ–¹æ¡ˆå¢žåŠ å‡ºè´§æ£€éªŒé€‚ç”¨ç±»åž‹ï¼š1 â†’ 1,3;原有启用状态未修改,停用方案未启用。方案 ID:15、14、3、19、12、7、1、136、35。
- æ–¹æ¡ˆåç§°åŒ¹é…åŠç»‘定沿用用户指定规则;增加适用类型不代表已另行验证这些原料方案对每种成品的法规适用性。
- æœªå¯¼å…¥è¿‡ç¨‹æ£€éªŒï¼Œæ¥æ–™å’Œè¿‡ç¨‹æ£€éªŒåŽŸæœ‰æ•°æ®å·²æ ¸å¯¹ä¿æŒä¸€è‡´ã€‚
## æš‚缓清单
详见同目录 `出货检验-录入结果及暂缓清单.csv`,每行列出全部缺项。下列按每行首个原因归类,共 276 è¡Œï¼š
| é¦–个暂缓原因 | è¡Œæ•° |
| --- | ---: |
| ç‰©æ–™ç¼–码为空或系统不存在 | 132 |
| æ‰€é€‰è´¨æ£€æ–¹æ¡ˆåœç”¨ | 93 |
| æ£€éªŒå•编号重复,未擅自改号 | 30 |
| æ£€éªŒå•编号为空 | 11 |
| å‡ºè´§æ•°é‡ä¸ºç©º | 8 |
| æ— åç§°åŒ¹é…æ–¹æ¡ˆ | 2 |
## å®¢æˆ·å¯ä¸ºç©ºçš„代码修改
- åŽç«¯ä¿å­˜è¯·æ±‚及 Excel å¯¼å…¥è¯´æ˜Žå–消客户必填。
- ç©ºå®¢æˆ·å¯¼å…¥è·³è¿‡å®¢æˆ·è§£æžå’Œæƒé™æŸ¥è¯¢ï¼›å¡«å†™å®¢æˆ·æ—¶ä¿ç•™åŽŸæœ‰å®¢æˆ·å­˜åœ¨åŠæƒé™æ ¡éªŒã€‚
- å‡ºè´§å¯¼å…¥åŽ»é‡å°†ç©ºå®¢æˆ·ä¸ŽæŒ‡å®šå®¢æˆ·åˆ†åˆ«å¤„ç†ï¼Œç©ºå®¢æˆ·ä½¿ç”¨ `IS NULL`。
- åˆ—表允许查询没有客户的单据;已绑定客户的单据继续按原有客户权限过滤。
- ç¼–辑允许清空客户;完成检验等局部更新保留已有客户。
- å‰ç«¯å‡ºè´§è¡¨å•客户字段取消必填,允许清空。
- å·²æä¾› `sql/mysql/mes_qc_oqc_client_optional_20261012.sql` ä¾›å…¶ä»–数据库升级使用;目标远程库客户列已经可空,因此无需执行此 DDL。
代码已在本机修改,尚未部署到远程应用;部署后表单、接口和空客户列表逻辑生效。远程数据录入已完成。
## å®¡è®¡æ–‡ä»¶
后端编译及 7 é¡¹ä¸“项回归已通过(空客户保存及去重、空客户可见性、指定客户权限、局部更新保留客户、导入解析及保存请求校验)。前端修改文件 TypeScript è¯­æ³•检查无错误;完整前端类型检查受上述已有错误阻塞,尚未通过。
- `before-oqc-import.json`:事务执行前相关数据快照。
- `oqc-import-executed.sql`:实际执行的类型变更及新增单据、明细 SQL。
- `oqc-import-result.json`:提交后核对结果。
- `oqc-import-review.json`:所有原表行的方案、物料、录入 ID å’Œæš‚缓原因。
- `customer-optional-tests.log`:后端专项回归执行日志。
- `frontend-typecheck.log`:完整前端类型检查日志。现有 Vue / @vben å¯¼å‡ºå’Œéšå¼ any ç­‰é”™è¯¯å¯¼è‡´å®Œæ•´æ£€æŸ¥æœªé€šè¿‡ï¼›æœ¬æ¬¡ä¿®æ”¹æ–‡ä»¶çš„ TypeScript è¯­æ³•检查单独执行。
scripts/qc-other-import-20261012/Ó³Éä¼°ÔÝ»ºµ¼Èë˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
# è¿‡ç¨‹ã€å‡ºè´§æ£€éªŒåç§°æ¨¡ç³Šæ˜ å°„结果
目标库:36.213.150.237:10000 / mom-hm。处理日期:2026-10-12。
仅使用检验单名称与系统质检方案名称匹配,原表“质检方案”字段只留档,不参与评分。清理检验后缀、标准编号、空格和标点,统一桑椹/桑葚、黑枸杞/黑果枸杞等写法;优先完全相同名称,再取达到0.67且距最高分不超过0.04的近似候选。多个候选按用户要求随机取一个,并按检验类别和产品名持久保存,重复运行不会重新随机。同名产品各行沿用同一次选择。
|类别|来源行数|有名称候选|无名称候选|多个候选的行数|可导入|
|---|---:|---:|---:|---:|---:|
|出货检验|496|494|2|352|0|
|过程检验|48|47|1|30|0|
## æš‚缓原因
- å‡ºè´§496行客户名称全部为空;库中出货单/出货明细为空,不能反查客户。
- è¿‡ç¨‹48行生产工单和工位全部为空,库中工单、工位、生产任务为空,不能建立真实业务关联。
- æœ¬æœºå’Œè¿œç¨‹çŽ°æœ‰252个质检方案全部仅支持来料检验(types=1),无过程(2)或出货(3)方案。名称候选不等于产品适用性确认;没有将来料方案直接改成成品/半成品方案。
- å‡ºè´§æœ‰15组重复编号(30行)及11行空编号;过程有3组重复编号(6行)。仍保留原编号并列入清单。
- å‡ºè´§9行出货数量为空,7行合格/不合格数量为空;过程3行合格/不合格数量为空。未填造检测数量或实测数据。
## åç§°å€™é€‰æ‘˜è¦
|类别|检验单名称|随机候选方案|候选数量|涉及行数|
|---|---|---|---:|---:|
|出货|γ-氨基丁酸营养素饮品(蜜桃味)出货检验|γ-氨基丁酸原料质检方案(015)|1|2|
|出货|γ-氨基丁酸酸枣仁饮品(桃子味)出货检验|γ-氨基丁酸原料质检方案(015)|2|4|
|出货|人参枸杞原浆出货检验|枸杞原浆原料质检方案(014)|1|1|
|出货|冻干枸杞出货检验|冻干枸杞原料质检方案(003)|1|9|
|出货|刺梨原浆罐头出货检验|刺梨原浆(汁)原料质检方案(053)|1|1|
|出货|即食藜麦粉R型出货检验|藜麦粉原料质检方案(021)|1|4|
|出货|枸杞原浆罐头出货检验|枸杞原浆原料质检方案(014)|1|53|
|出货|桑葚原浆出货检验|桑葚原浆原料质检方案(050)|1|1|
|出货|沙棘原浆罐头出货检验|沙棘原浆(汁)原料质检方案(019)|1|4|
|出货|总统牌洞燕盏即食燕窝罐头出货检验|STP-QA-(YL)012燕窝质量标准|2|8|
|出货|即食小罐洞燕窝(尊享款)出货检验|燕窝原料质检方案(012)|2|28|
|出货|即食碗装洞燕窝(自热型)出货检验|燕窝原料质检方案(012)|2|4|
|出货|洞燕窝即食碗装燕窝出货检验|STP-QA-(YL)012燕窝质量标准|2|25|
|出货|即食碗装洞燕窝(怡碗燕)出货检验|燕窝原料质检方案(012)|2|12|
|出货|即食小罐洞燕窝出货检验|STP-QA-(YL)012燕窝质量标准|2|74|
|出货|即食碗装鱼胶洞燕窝(自热型)出货检验|STP-QA-(YL)012燕窝质量标准|3|8|
|出货|即食碗装红枣枸杞洞燕窝(自热型)出货检验|燕窝原料质检方案(012)|2|7|
|出货|燕窝肽γ-氨基丁酸鱼胶原蛋白肽饮品出货检验|γ-氨基丁酸原料质检方案(015)|3|5|
|出货|益生元西梅饮出货检验|无匹配|0|2|
|出货|红黑枸杞原浆罐头礼盒出货检验|黑果枸杞0009S原料质检方案(002)|6|8|
|出货|铁棍山药粉出货检验|STP-QA-(YL)067铁棍山药粉质量标准|2|9|
|出货|人参茯苓甘草干姜粉出货检验|甘草原料质检方案(045)|4|1|
|出货|雪菊出货检验|雪菊原料质检方案(007)|1|20|
|出货|黑红枸杞原浆出货检验|《STP-QA-(YL)035 é»‘果枸杞原浆质量标准》|3|1|
|出货|黑果枸杞出货检验|黑果枸杞0006S原料质检方案(001)|3|100|
|出货|有机黑果枸杞出货检验|有机黑果枸杞原料质检方案(137)|1|47|
|出货|黑果枸杞原浆罐头出货检验|黑枸杞原浆(汁)原料质检方案(035)|2|40|
|出货|黑果枸杞桑葚原浆出货检验|《STP-QA-(YL)035 é»‘果枸杞原浆质量标准》|2|1|
|出货|黑果枸杞玫瑰果膏出货检验|黑果枸杞0009S原料质检方案(002)|3|5|
|出货|黑果枸杞袋泡茶(代用茶)出货检验|黑果枸杞0006S原料质检方案(001)|3|10|
|出货|黑红枸杞原浆罐头出货检验|枸杞原浆原料质检方案(014)|3|2|
|过程|枸杞原浆罐头过程检验|枸杞原浆原料质检方案(014)|1|8|
|过程|即食小罐洞燕窝过程检验|燕窝原料质检方案(012)|2|5|
|过程|即食小罐洞燕窝(尊享款)过程检验|STP-QA-(YL)012燕窝质量标准|2|2|
|过程|沙棘原浆罐头过程检验|沙棘原浆(汁)原料质检方案(019)|1|2|
|过程|黑果枸杞原浆罐头过程检验|《STP-QA-(YL)035 é»‘果枸杞原浆质量标准》|2|8|
|过程|γ-氨基丁酸营养素饮品(蜜桃味)过程检验|γ-氨基丁酸原料质检方案(015)|1|1|
|过程|洞燕窝即食碗装燕窝过程检验|燕窝原料质检方案(012)|2|3|
|过程|即食碗装红枣枸杞洞燕窝(自热型)过程检验|STP-QA-(YL)012燕窝质量标准|2|1|
|过程|燕窝肽γ-氨基丁酸鱼胶原蛋白肽饮品过程检验|鱼胶原蛋白肽原料质检方案(055)|3|2|
|过程|即食碗装洞燕窝(自热型)过程检验|STP-QA-(YL)012燕窝质量标准|2|1|
|过程|益生元西梅饮过程检验|无匹配|0|1|
|过程|即食碗装鱼胶洞燕窝(自热型)过程检验|STP-QA-(YL)012燕窝质量标准|3|1|
|过程|沙棘原浆罐头(青源堂)过程检验|沙棘原浆(汁)原料质检方案(019)|1|1|
|过程|γ-氨基丁酸酸枣仁饮品(桃子味)过程检验|γ-氨基丁酸原料质检方案(015)|2|2|
|过程|刺梨原浆罐头过程检验|刺梨原浆(汁)原料质检方案(053)|1|1|
|过程|人参枸杞原浆过程检验|枸杞原浆原料质检方案(014)|1|1|
|过程|总统牌洞燕盏即食燕窝罐头过程检验|燕窝原料质检方案(012)|2|1|
|过程|黑果枸杞原浆过程检验|《STP-QA-(YL)035 é»‘果枸杞原浆质量标准》|2|1|
|过程|枸杞原浆过程检验|枸杞原浆原料质检方案(014)|1|1|
|过程|沙棘原浆罐头(造养青年)过程检验|沙棘原浆(汁)原料质检方案(019)|1|1|
|过程|黑果枸杞桑椹原浆过程检验|黑枸杞原浆(汁)原料质检方案(035)|2|1|
|过程|桑葚原浆过程检验|桑葚原浆原料质检方案(050)|1|1|
|过程|即食碗装洞燕窝(怡碗燕)过程检验|STP-QA-(YL)012燕窝质量标准|2|1|
|过程|黑果枸杞玫瑰果膏过程检验|黑果枸杞0009S原料质检方案(002)|3|1|
所有候选仍需要适用检验类型、产品形态及启用状态校验。复合饮品与其单一原料名称近似仅作候选参考,不能据此判断成品合格。此次未写入数据库单据,未改动源Excel。
[出货逐行映射及缺项](出货检验-方案模糊映射及缺项.csv) Â· [过程逐行映射及缺项](过程检验-方案模糊映射及缺项.csv)
scripts/quality-indicator-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
# è´¨æ£€æ£€éªŒé¡¹è¡¨è¿°æ•´ç†
2026-10-14 22:15:08进一步按用户要求清除212处“演示”“非真实实测”等占位文字。154个文本结果占位改为“待复核”,24处取样位置占位清空,不编造位置;34处方法说明保留外观/数量核验并说明方法适用性待确认。数值、状态、时间及关系均不改。完整备份display-labels-before-20261014-221508.json,新旧映射display-labels-result.json。提交后再次扫描生产、质检、仓库所有有效记录的字符串字段,相关文字匹配为0。
北京时间2026-10-14 22:10:29按用户要求调整287个有效检验项的备注,将SOP和文件来源等过程说明改为简洁检验要求。6个分组名去掉SOP前缀,保持原料检验-感官/理化/成分/微生物/污染物/农兽药残留的分组含义。其余专业名称及标准续文区分保留,无名称重复。
续文备注明确“不单独判定或重复检验”;国家标准项仍明确人员录入并判定结果。不调整标准值、公式、单位、仪器、结果类型、树形关系、编码、创建人及创建/更新时间。方案、检验单、关联明细及检验结果逐表比对完全不变。修改人289。
preview.json为只读预览;locked-before-20261014-221029.json为全部有效质检数据事务前备份;result.json为新旧名称备注映射。已完成事务内校验及提交后全量读取核验;本次不审核或更改原标准内容。
scripts/quotation-contract-20261015/artifact.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
# åˆåŒæ¨¡æ¿æ‰§è¡Œè¯´æ˜Ž
原始 DOC ä¿æŒä¸å˜ï¼Œä½¿ç”¨ Word è½¬ä¸º reference.docx。版式以该副本为准:保留页面尺寸、字体、段落、原合同全部条款和甲方收款信息。
仅编辑 word/document.xml:乙方名称、标题下的合同编号与日期、产品明细行、合计和大写金额;产品行可按数量克隆,原两条空行移除,表头跨页重复,产品行禁止跨页拆分,条款标题与后文同页。
金额来自合同实际数据,含整单优惠时明确注明优惠金额和实付合计。签章区和签字时间保留为空,不自动代签。
原模板开户行写为公司名称,按原样保留,正式签署前应核对。
原始文件 SHA256:b708f48a2f810bb2d55f3eca2c0e6762eff543ce36cee940a4f4adc0f3a65224
DOCX SHA256:ec92b4ef44352c40e600a7995f6563511be439943ee7f22d237729f1f11a2481
scripts/quotation-contract-orders/ת»»ËµÃ÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
# æŠ¥ä»·ã€åˆåŒåŠé”€å”®è®¢å•同步结果
目标:线上 36 çš„ mom-hm。按用户要求,345 å¼ æŠ¥ä»·å·²è½¬ä¸º 345 å¼ åˆåŒï¼Œå†è½¬ä¸º 345 å¼ å·²ç”Ÿæ•ˆé”€å”®è®¢å•ï¼›1702 æ¡æ˜Žç»†ï¼Œæ€»é‡‘额 15,392,805.71 å…ƒï¼Œè´Ÿè´£äººæœ±èŽ‰ï¼ˆ291)。
合同号为 HT-原报价号,订单号为 XSDD-原报价号;报价、合同、订单已建立关联。客户、负责人、原包装单位、单价、数量、行金额和订单明细备注保持原报价数据。报价已转合同,合同与订单按用户明确要求关闭审核后免审生效(状态20)。本次转换未生成出库或生产计划。
用户明确要求关闭所有审核、隐藏对应 BPM å®¡æ ¸å…¥å£å¹¶è‡ªåŠ¨é€šè¿‡ã€‚å®žé™…ç”Ÿæ•ˆå¼€å…³ä¸º bpm_process_auto_approve_config ä¸­ process_definition_key='*'、auto_approve=1。引擎创建人工审核节点时自动通过,仍记录流程并执行原业务通过回调。待办任务、已办任务、任务管理菜单已设为隐藏,原权限保持。操作时无待处理任务。
独立回读核验见 orders-verification.txt,操作前后快照见 before.xml、after-orders.xml、after-auto-approve.xml,逐单清单见合同及订单转换清单.csv。
前后端代码已补充审核界面开关:登录时读取只供登录用户查看的 ui-policy;关闭审核后隐藏审核状态等专用查询字段、列表列、详情字段和查看审批/反审核入口;提交审批改为生效操作,沿用业务提交接口以触发自动流程。合同、采购申请、付款单、项目、供应商申请及人事申请在自动模式下跳过流程选择弹窗。重新关闭全局免审核时,页面恢复原字段和动作。UI æ”¹åŠ¨éœ€è¦å‘å¸ƒå‰åŽç«¯æ‰èƒ½åœ¨è¿è¡ŒçŽ¯å¢ƒç”Ÿæ•ˆã€‚
后端 BPM æ¨¡å—及依赖离线编译成功。审核显示策略测试、修改的 Vue è„šæœ¬å’Œæ¨¡æ¿ç¼–è¯‘æˆåŠŸã€‚å®Œæ•´å‰ç«¯ç±»åž‹æ£€æŸ¥å—å½“å‰ä¾èµ–å®‰è£…é—®é¢˜å½±å“ï¼šå¤§é‡ Vue æ ¸å¿ƒå¯¼å‡ºåŠ Vben å·¥ä½œåŒºå¼•用缺失,未通过完整检查。
scripts/quotation-import/µ¼Èë˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
# æœ¬åœ°é”€å”®æŠ¥ä»·åŒæ­¥ç»“æžœ
2026-10-12 å·²å½•入本地 `mom-hm` çš„ CRM é”€å”®æŠ¥ä»·è¡¨ã€‚
| é¡¹ç›® | ç»“æžœ |
| --- | ---: |
| æŠ¥ä»·å• | 345 å¼  |
| äº§å“æ˜Žç»† | 1,702 æ¡ |
| å®¢æˆ·ä¸»ä½“ | 344 ä¸ª |
| äº§å“åç§°åŠè§„格组合 | 36 ä¸ª |
| æ˜Žç»†é‡‘额合计 | 15,392,805.71 å…ƒ |
| è¡¥å»ºé”€å”®äº§å“ | 4 ä¸ª |
| çŠ¶æ€ | è‰ç¨¿ |
仅使用各客户明细工作表,未从“报价单汇总总表”或“编制说明”生成业务数据。报价单号来自明细表,范围为 BJ20261012-0001 è‡³ BJ20261012-0345。原文件未修改。
负责人为朱莉。远程账号为 `zhuli`,远程昵称带有前导空格,匹配时去除空格。本地原无该账号,已同步本次报价所需的负责人记录。本地用户编号为 289,报价及新建客户均以此本地编号关联。未使用远程编号直接挂接本地记录。
本地原无客户记录,按明细表客户主体补建 344 ä¸ªå®¢æˆ·ã€‚礼阁仕(无锡)商贸有限公司的两种括号写法关联同一个客户,两张源报价单分别保留。
32 ä¸ªäº§å“æŒ‰åç§°ã€è§„格及包装对应已有 TC ç³»åˆ—产品。原表包装单位“盒、瓶、桶、袋”分别映射到本地单位 BX、BT、BL、BC,存储在报价明细计量单位字段。原表完整名称及规格保留在明细备注中,匹配详情见“产品匹配清单.csv”。
4 ä¸ªæœªèƒ½åœ¨æœ¬åœ°æœ‰æ•ˆç‰©æ–™ä¸­åŒ¹é…çš„销售产品按原表名称及规格补建,使用稳定的 SQ20261012 ç¼–码:
- é²œå†¬è™«å¤è‰ï¼Œ4A级(1.01-1.3g)/根×9根,瓶。
- é›ªèŠï¼Œ50g,瓶;未关联至已有的140克雪菊。
- é»‘果枸杞玫瑰果膏,30ml/袋,袋。
- é»‘果枸杞,120克(4g/罐×30),盒;本地已删除的 TC0020 æœªæ¢å¤ã€‚
原价、报价单价、数量、明细小计均逐项保留原表值。7 è¡Œçš„四舍五入均价乘以数量后,与源小计存在 1~2 åˆ†å·®å¼‚,按源小计录入并在备注注明;总体差额为 0.03 å…ƒã€‚导入总额来自各明细行之和,与各客户明细表自己的合计行一致。
税率未填写,单据与明细税率、税额保持 NULL;整单折扣及优惠金额为0。原表商机名称“2026å¹´8-10月零售成交”保留在备注,未据此生成新的商机;联系人未填,保持空白。报价日期、有效期按明细原值保存为2026-10-12、2026-11-11。
创建 689 æ¡ä»…关联本次客户及报价的负责人数据权限:344 æ¡å®¢æˆ·æƒé™ã€345 æ¡æŠ¥ä»·æƒé™ã€‚不增加其他用户的数据授权。
远程数据库仅用于核对及读取负责人,未写入本次报价数据。
导入在事务中执行,既有报价单号或明细冲突会回滚。检查包括产品及单位匹配、每张单据的明细数与金额、负责人关联、数据权限及重复写入;提交后再次独立回读逐项比较原表,全部通过。
注意:当前报价页面加载明细、编辑保存时会依据单价和数量重新计算金额;上述7行的页面展示可能有分位差异,编辑保存还可能覆盖导入时保留的原表小计。此次数据库导入及回读核验保留了原表小计。
可追溯数据保留在 source.json、local-plan.json、报价明细清单.csv,提交与回读校验记录为 local-result.txt、verification-result.txt。快照不包含账号密码。
scripts/quotation-import/ÏßÉÏͬ²½ËµÃ÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
# çº¿ä¸Šé”€å”®æŠ¥ä»·åŒæ­¥
2026-10-12 å·²åŒæ­¥è‡³ `36.213.150.237:10000` çš„ `mom-hm`。
- æ–°å¢ž345张销售报价单、1702条明细,对应344个客户主体。
- æŠ¥ä»·æ˜Žç»†é‡‘额合计15,392,805.71元,负责人为线上现有朱莉账号 `zhuli`(用户291),状态为草稿。
- å¤ç”¨86个已有客户,补建258个客户主体;客户姓名的两种括号写法统一关联,原始两张报价单保留。
- å¤ç”¨å·²æœ‰äº§å“ï¼Œå¹¶è¡¥å»ºé²œå†¬è™«å¤è‰ã€50g雪菊、30ml袋装黑果枸杞玫瑰果膏三个销售规格。120克传渠黑枸杞关联线上有效 TC0020(物料962),排除同编码已删除旧记录。
- æ–°å»º603条仅与本次数据关联的朱莉负责人权限:345条报价权限和258条新建客户权限;其余86个客户已有相应权限。
- æ±‡æ€»è¡¨æœªå¯¼å…¥ï¼Œç¨ŽçŽ‡ã€ç¨Žé¢ä¿æŒç©ºç™½ï¼›åŽŸä»·ã€æŠ¥ä»·å•ä»·ã€æ•°é‡ã€æ˜Žç»†å°è®¡ã€æŠ¥ä»·æ—¥æœŸå’Œæœ‰æ•ˆæœŸæŒ‰åŽŸè¡¨ä¿ç•™ã€‚
- 7条源表均价四舍五入差异保留原始单价及小计,备注可追溯。页面重新计算可能出现分位差异,与本地导入说明一致。
导入使用事务,检查客户、产品、计量单位、负责人、每单明细数和金额。重复写入检查无新增;提交后重新从线上回读,逐项比较原表,345张单据及1702条明细全部通过。
线上实际物料、客户和负责人编号独立匹配,未直接套用本地编号。未覆盖线上既有单据或物料。
记录:remote-result.txt、remote-verification-result.txt、remote-plan.json、remote-post-snapshot.xml。
scripts/quotation-opportunities-20261014/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
# éžåŒ—京同仁堂客户报价关联商机
按用户要求,于北京时间2026-10-14 23:08:12补齐16份非北京同仁堂客户报价的商机关联。对应合同已经明确关联16个已有商机,故直接复用,不重复新建商机。按合同含税产品口径补34行原先缺失的商机产品,补产品总金额、零折扣及原销售订单ID/编号;商机总金额、预计成交日期、创建日期及阶段均不改。已核验各商机产品金额与原商机总额一致。
报价日期及创建日期以不早于2026-09-17为下限,不超过执行时间,保持两者相等;6份报价原日期早于下限,改为2026-09-17,其余10份原日期保留。关联报价明细创建日期同步父单。保留报价原更新时间,仅当小于调整后的创建日期时才提升至创建日期。
客户名称包含北京同仁堂的报价、商机及其关联数据完全不变。合同、订单、发票、实际回款及回款计划日期/状态/金额均不改,未同步推后早于报价新日期的历史合同日期;这是用户指定的报价时间整理,原日期保存在备份。
preview.json为只读核对;locked-before-20261014-230812.json为事务前完整备份;result.json为报价-商机-合同-订单对应关系及新产品ID。操作人291朱莉,已核验数据负责人权限。事务内逐字段保护及提交后全量读回核验通过。
scripts/sales-ledger-202609/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
# ä¹æœˆé”€å”®å°è´¦è¡¥å½•
2026-10-13 14:33:06按用户要求清理22份合同和24张销售订单表头备注的九月台账补录、反推日期、导入行号、分组与尾差解释等生成说明。合同保留原付款状态、开票说明及票号;销售订单移除生成说明,无其他业务备注的置空,负数退货单保留退货说明。明确写回原update_time,维持用户指定的合同最近10天更新时间分布;创建时间、金额及全部其他业务字段不变。结果contract-order-remarks-cleaned-result.json、备份contract-order-remarks-before-20261013-143306.json,已提交并核验。
2026-10-13 14:25:30按用户要求将22份有效合同update_time随机分布于最近10天(北京时间2026-10-03 14:25:30至执行时刻),实际范围2026-10-03 14:52:46至2026-10-12 17:07:14。每条均不早于create_time、不晚于执行时刻,仅改变update_time,不修改操作日志或其他合同字段;这是用户要求的数据展示时间调整,不作为实际修改事件时间证明。结果contract-update-times-result.json,备份contract-update-times-before-20261013-142530.json,已提交并核验。
2026-10-13 14:13:07按用户要求将实际营销业务创建时间同步为业务日期:报价22、合同22、订单24、开票21、实际回款5,共94张单据;报价/合同/订单明细各76行,共228行同步父单业务日期。日期只有日粒度的采用原字段的00:00:00,未推断具体时分秒。按用户明确确认保留回款计划及商机预计日期和创建时间;客户、线索、跟进预约时间也不作为创建日期。原创建人及全部业务字段不变,修改人及更新时间记录本次调整。执行结果business-create-times-result.json,备份business-create-times-before-20261013-141307.json,明细营销业务创建时间同步清单.csv,已提交并核验。
2026-10-13 14:07:48按用户要求将22份销售报价名称同步为其contract_id明确关联的合同名称,未修改合同及报价其他业务字段。quotation-name-sync-result.json记录对应关系,quotation-name-sync-before-20261013-140748.json保存执行前备份,已提交并核验。
2026-10-13 14:05:45按用户要求去掉22份合同名称开头的“九月台账-”,其余名称部分及合同业务字段不变。执行结果contract-name-prefix-result.json,清理前备份contract-name-prefix-before-20261013-140545.json,已提交并核验。
2026-10-13 13:10:19按用户要求清空本次23张发货通知及23张销售出库单的表头备注;明细、其他入库单备注及业务字段不变。清空前备份shipping-remarks-before-20261013-131019.json,提交后已核验46张单据备注为空。运单号仍为模拟生成,来源说明保留在执行结果及配送清单中。
**出库发货最新进展:2026-10-13已完成23张正向订单、23张发货通知、23张销售出库单和75行明细,ERP为全部出库(3),MES通知/出库为已完成(4)。26000369退货负数单不走正向发货。按用户要求先等量补库存再出库,另建其他入库单QTCKDC-202609-20261013、75行入库明细及对应库存流水;150笔入/出库流水净额为零,75条占用记录均已出库(3)。原有855条库存记录数量、冻结量、占用量、在途量等业务字段完全不变;3种原来无库存的新增物料建历史汇总批次及库存记录,最终数量均为0。独立核验见shipping-complete-verification.json,配送清单见九月销售出库发货核对清单.csv。**
配送:普通电商8单及抖音电商2单均为京东(10单),运单号按用户要求模拟生成并在单据中标注,非真实物流凭证,未向承运商下单。其余13单为自有车辆配送,车牌仅记录用户提供的青H前缀,没有虚构完整车牌;配送单号为内部编号。单据为历史流程补录,时间使用实际执行时间,未宣称现实货物已送达。
单位:9行涉及6个SKU的瓶/盒/个计数称谓不同,按相同完整成品规格的包装计数1:1补录,依据逐项记在shipping-complete-result.json的unit_basis及单据备注;未建立通用单位换算、未修改物料主单位。批次沿用9月底初始化汇总批次,新增批次注明历史对冲,未虚构生产日期或质检合格状态。
结构修复:其他入库行补齐代码DO需要的batch_code、warehouse_id、location_id、area_id;其他入库明细补齐batch_code,均为可空列。原结构保存在shipping-receipt-schema-before.json及shipping-receipt-detail-schema-before.json,业务执行前备份为shipping-complete-locked-before.json。已做事务内校验及提交后的独立数据库核验,未执行线上HTTP或浏览器验证。
**最新客户归属更正:备注为“(电商)”的7个原单及客户信息缺失的26000113合计8单统一归“电商”,合计2,030,440.62元。已同步订单、合同、报价、开票、回款计划customer_id;原开票抬头和所有财务金额不变。备注“抖音电商”的26000457、26000491仍归北京同仁堂健康药业电子商务有限公司。最新核验为`current-sales-verification.json`,最新24张订单清单已更新。**
**最新更正:用户确认相同单据号一个订单。现为24张订单、76行明细,订单号直接使用原单据号。原开票组202609-L008拆为26000393、26000406、26000369三张,退货原单26000369保留-24/-4272元。合同和报价仍各22份,开票、回款及计划未重复增加,销售总金额不变。最新清单为`九月销售订单按单据号清单.csv`,核验为`source-order-verification.json`。下面22组描述是原始开票/合同分组。一个合并合同的order_id/order_no保留第一张主关联订单,另外两张订单通过contract_id关联同一合同。**
目标库:36.213.150.237:10000 / mom-hm。来源仅取工作簿 `26.9月` ç¬¬4–81行,按O列合并金额分组,未重复导入年度汇总页。
用户确认规则:缺客户按备注新增,399使用399零号店,无客户信息新增电商;到账日期取开票日期;未收及部分回款生成未收余额计划,完全回款不建计划;合并金额负数不录入。
原始销售导入结果:22组销售订单、反推合同、报价,76行明细;21条开票合并记录,保留24个原票号;5笔回款、18条余额计划;新增6客户、3物料。正金额分组内的第36行退货保留,负合并金额第62、71行排除。原始阶段没有库存或生产过账,后续订单拆分及出库见上方最新进展。
金额:含税销售12,404,821.61元;回款415,050.01元;计划余额11,989,771.60元。按每个合并组的金额四舍五入至分,因此总和可能与原始多位小数直接汇总后取整相差1分。净额税额与合并金额差0.31元,登记为显式金额尾差,不调整来源税率。合同明细含税,报价与订单明细为税前金额,所有单据最终含税额一致。
日期:反推订单、合同、报价使用开票日,明确不是原签约日期;无票电商使用备注2026-09-11。回款按用户确认的开票日,无票电商沿用备注销售日。计划日按开票或销售日后30天测算,备注注明非约定账期,台账付款状态截至2026-09-29。
三组合并记录只有两张发票合计,没有分票金额。对应开票记录保留两个票号并标明“合并登记”,没有虚构单张金额。系统要求回款绑定发票时必须上传原票附件;因此回款当前关联合同,invoice_id为空,原票号保存在备注。合同级回款统计完整,票级回款统计须补原票附件并正式关联后才完整。
青海爱嘉客户名按来源截断文本“青海爱嘉星际文化旅游有限公”保留,尚未推断注册全称。50122备注“杜亚楠销售”视为销售说明,客户归新增“电商”。物料缺编码先核对名称和规格,复用已存在的90克、60克、同等级鲜虫草等物料,不因不同来源编码重复建物料。
旧数据完整备份:`locked-before-import.json`;导入关联ID:`import-result.json`;完整核验:`verification-result.json`;业务核对:`九月销售导入核对清单.csv`。仅新增本次数据,既有记录保持不变;另补齐4个本次涉及的既有客户的负责人数据权限。
合同请求数量已改BigDecimal,报价转合同不再intValue截断,两项回归测试通过。代码尚未部署线上;数据库数量原值已保留。未执行线上HTTP或浏览器验证,数据库关系、金额、权限和精度已核验。
scripts/sop-qc/µ¼Èë˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
# SOP原料质检数据导入结果
2026å¹´10月12日,已从 `C:\Users\云\Desktop\SOP-QC-YL` è¯»å–231份有效Word规程。Word临时锁定文件已排除,原文件未修改。
本地及远程 `36.213.150.237:10000/mom-hm` å‡å·²å®Œæˆä»¥ä¸‹å¢žé‡å¯¼å…¥ï¼š
| æ•°æ® | æ•°é‡ |
| --- | ---: |
| åŽ»é‡åŽçš„æ£€éªŒé¡¹ | 200 |
| æ£€éªŒé¡¹åˆ†ç»„ | 6 |
| æ ‡å‡†ç»­æ–‡é¡¹ | 16 |
| æ¥æ–™è´¨æ£€æ–¹æ¡ˆ | 231 |
| æ–¹æ¡ˆæŒ‡æ ‡å…³è”行(含分组及续文) | 2821 |
| æ–¹æ¡ˆç‰©æ–™å…³è” | 51 |
| å¯ç”¨æ–¹æ¡ˆ | 161 |
| åœç”¨å¾…复核方案 | 70 |
系统检验项列表共新增222条记录,包含200个检验项、6个分组、16个标准续文项。质检方案编号以 `SOP-QC-YL-` å¼€å¤´ï¼›æ¯ä»½è§„程单独建方案,保留封面版本号及来源条款。同名原料可能有不同规程,未擅自合并版本或删除旧规程。
检验项的结果采用文本录入及人工判定,未生成自动判断上下限。分等级标准、严格不等号、未检出要求及微生物 `n/c/m/M` æŠ½æ ·æ–¹æ¡ˆä¿ç•™åŽŸæ–‡ï¼ŒæŒ‡æ•°ä»¥ `10^(4)` ç­‰å½¢å¼ä¿ç•™ã€‚系统标准字段最多255字符,超过长度的判定要求拆为续文项;这些续文项不参与独立判定,不需要重复检验。
物料关联仅使用现有物料的精确名称匹配,不使用模糊匹配。49个方案匹配到51条物料关联;没有匹配的方案仍保留在系统,尚未绑定物料。规程没有统一指定方案物料的最低抽样数、允许不合格数和缺陷率,因此这些字段留空,没有填入猜测值。
70个方案因部分条目未提取到独立判定标准、文件名与封面品名不一致、计数标准小于零等疑点而停用。需质量负责人依据原文件核对后启用。例如219号文件名是牦牛骨胶原蛋白肽,而封面写牛骨胶原蛋白肽,已停用且未自动绑定物料。停用原因及未匹配物料详见 `待复核方案清单.csv`。
此任务核对的是提供文档与系统数据的对应关系,未自行替换规程引用的标准版本。提取脚本和代表性样本验证通过,数据库事务提交前核对了全部预期记录及字段内容,重复执行的新增数量为0。静态提取结果还需按企业质检流程验收,不能等同于231份规程已经逐条专业审核。
## ç•™å­˜æ–‡ä»¶
- `检验项提取清单.csv`:方案、物料品名、检验项、原文判定要求、方法标准及来源。
- `待复核方案清单.csv`:停用原因及没有准确物料匹配的方案。
- `inspection-plan.json`:完整提取数据及检验方法原文片段。
- `documents.json`:来源文档正文、表格及SHA256摘要。
- `local-import-result.txt`、`remote-import-result.txt`:两库事务提交及验证记录。
- `../../sql/mysql/sop_qc_yl_import_20261012.sql`:实际执行的增量导入SQL,需要在同一数据库连接的事务中执行。
scripts/stock-import-202609/material-repair/ÀàÐÍÓ³ÉäºËÑé˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2 @@
实际系统代码 MdmItemServiceImpl.syncItemToMes ä¼šä½¿ç”¨ mesMdItemTypeApi.getItemType(reqVO.getCategoryId()) è§£æž MDM åˆ†ç±»ï¼Œå†æŒ‰åˆ†ç±» code åŒæ­¥åˆ° MES。已回读并核实837个库存物料的MDM category_id ä¸Žå…¶MES投影 item_type_id ä¸€è‡´ï¼Œä¸ä¾èµ–两套独立分类表编号恰好相同。
线上实际存在且启用:MAT06 åŠæˆå“ï¼ŒID=23。类型枚举来自线上字典:1原料、2半成品、3成品、4辅料。逐条映射清单记录预期原值、实际分类编码与目标分类编码,更新前锁行、校验双方分类存在及启用、验证MDM和MES一致;更新后逐条比对,并校验库存数量、库区库位、批次及流水未变。
scripts/stock-import-202609/µ¼Èë˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
# 2026å¹´9月库存台账导入
目标:线上 36.213.150.237:10000 çš„ mom-hm。
用户已确认按 Sheet1 çš„结存数量覆盖库存现有量,补建缺失物料;随后要求设置专业仓库,并将本批库存分仓。按最新要求分配至业务仓库,未建立或使用统一导入仓。
## ä»“库设计
| ç¼–码 | ä»“库 | åŽŸè¡¨ä¾æ®åŠç”¨é€” |
| --- | --- | --- |
| CPK01 | æˆå“ä»“ | åŽŸè¡¨æˆå“åº“å­˜ï¼Œä¾›é”€å”®å‡ºåº“ |
| YLK | åŽŸæ–™ä»“ | åŽŸè¾…æ–™åŠæ•£è£…åŽŸæ–™ |
| NBCK | å†…包材仓 | ç›´æŽ¥æŽ¥è§¦äº§å“çš„包装材料 |
| WBCK | å¤–包材仓 | å¤–盒、外箱及外包装材料 |
| CCCP | è™«è‰å†·é“¾ä»“ | åŽŸè¡¨ CCCP è™«è‰ä¸“用库存;实际储存条件按品种标准执行 |
| BCPK | åŠæˆå“ä»“ | å°šéœ€ç»§ç»­åŠ å·¥æˆ–åŒ…è£…çš„ä¸­é—´äº§å“ |
| QC_PENDING | å¾…检仓 | å¾…检及质量待确认库存;本表无明确待检库存,保持为空 |
| THK | é€€è´§åŠä¸åˆæ ¼å“ä»“ | åŽŸè¡¨é€€è´§åº“å­˜éš”ç¦»ï¼Œå¤„ç½®åŽå†ç§»åº“ |
| WIP_VIRTUAL_WAREHOUSE | è™šæ‹Ÿçº¿è¾¹ä»“ | åŽŸè¡¨ CCCJ、YFK;已发车间尚未消耗的在制库存 |
## æ•°é‡å’Œæ‰¹æ¬¡å£å¾„
- 843 ä¸ªå”¯ä¸€ç‰©æ–™ç¼–码,855 æ¡ç‰©æ–™ä¸Žä»“库库存记录。12 ä¸ªç‰©æ–™åŽŸè¡¨å­˜åœ¨è·¨ä»“åº“å­˜ï¼ŒæŒ‰åŽŸè¡¨åˆ†å¸ƒæ‹†åˆ†ï¼›å„ç‰©æ–™åˆ†ä»“åŽçš„æ•°é‡ä¹‹å’Œä¸¥æ ¼ç­‰äºŽå°è´¦ç»“å­˜æ•°é‡ã€‚
- å¯¹æœ‰åŽŸè¡¨åº“ä½ä¾æ®çš„æ­£ç»“å­˜æŒ‰æ•´ç†è¡¨åº“ä½åˆ†ä»“ï¼Œä¸æŒ‰é‡å¤çš„åˆå¹¶è¡¨ã€ç›˜ç‚¹è¡¨å†æ¬¡è®¡å…¥ã€‚æ— åŽŸè¡¨åº“å­˜æ˜Žç»†çš„é›¶ç»“å­˜æŒ‰å°è´¦ç‰©æ–™å¤§ç±»åŠå“åç¡®å®šä»“åº“ã€‚
- å¤šä»“数量以原表数量比例分配台账结存,并将六位小数的尾差归入数量最大的仓库;单仓直接使用台账结存。台账和整理表保湿棉数量相差 0.01,按台账 3416.11 è¦†ç›–。
- ä¿ç•™åŽŸæœ‰ç‰©æ–™ä¸»å•ä½åŠè§„æ ¼ã€‚å…¬æ–¤/克按 1000 æ¢ç®—;同编码包装成品的盒、罐等与系统计数单位“个”按 1:1。81013938 å†…袋在台账写“个”,整理表、合并表、包材表均为 GM,按系统克录入 1,650,000 å…‹ï¼Œä¿ç•™å†²çªè¯´æ˜Žã€‚
- Q2100196、Q2100197 åŽŸè¡¨å‡ä¸º 900ml æ•£è´§ï¼Œå’Œç³»ç»ŸåŒç¼–码规格不一致;用户已明确确认按原编码各录入 2992 ä¸ªï¼ŒåŽŸè¡¨ä¿¡æ¯ä¿ç•™å¤‡æ³¨ï¼Œä¸ä¿®æ”¹çŽ°æœ‰ç‰©æ–™è§„æ ¼ã€‚
- ç¼ºå¤±çš„ 582 ä¸ªç‰©æ–™æŒ‰åŽŸç¼–ç ã€å°è´¦åç§°ï¼ˆåŒ…å«åˆå¹¶å•å…ƒæ ¼è¿˜åŽŸï¼‰åŠè®¡é‡å•ä½æ–°å»ºï¼Œä¸æ¢å¤æˆ–æ›´æ”¹æ—§çš„å·²åˆ é™¤è®°å½•ï¼Œä¸åˆå¹¶ä¸åŒç¼–ç çš„åŒåç‰©æ–™ã€‚
- æŒ‰ç”¨æˆ·ç¡®è®¤çš„物料结存汇总口径创建 `INIT202609-物料编码` æœŸåˆæ±‡æ€»æ‰¹æ¬¡ã€‚该批次明确标注为期初汇总,不能视为真实生产批次;不伪造生产日期、有效期或质检结果。入库基准时间为 2026-09-30 23:59:59。
- æ•°é‡å·®é¢é€šè¿‡åº“存调整入/出库流水记录。零结存保留库存记录,但不生成零数量流水。冻结、预留、在途库存遇到冲突时回滚;导入仅修改本批汇总批次的对应库存,其他库存不参与覆盖。
## éªŒè¯
首次导入时源表合并单元格的下行名称为空,数据库拒绝物料写入,整个事务已回滚;补齐合并单元格名称后重新执行。
正式结果见 `remote-result.txt`,独立数据库回读结果见 `verification-result.txt`,源表与导入前数据库快照、分仓明细及执行脚本均保留于本目录。逐物料结存、分仓库存与流水分别核验,重复执行不会累加数量。
## åº“区库位补齐
用户随后要求每仓一个库区、一个库位,并补齐库存数据。线上已增加 9 ä¸ªé»˜è®¤åº“区和 9 ä¸ªé»˜è®¤åº“位,855 æ¡åº“存和 755 æ¡åŽŸå¯¼å…¥æµæ°´å‡è¡¥é½ä½ç½®å…³è”ï¼Œæ•°é‡åŠæ‰¹æ¬¡æœªå‘ç”Ÿå˜åŒ–ã€‚
普通库区使用“仓库编码-L01”,库位使用“仓库编码-A01”。虚拟线边仓使用 MES å†…置编码 `WIP_VIRTUAL_LOCATION` å’Œ `WIP_VIRTUAL_AREA`。默认汇总库位允许物料、批次混放,避免单库位承接多物料后被系统混放校验阻断;面积、载重、坐标未提供,不填写虚构数据。
补齐后的配置见 `库区库位配置清单.csv`,独立回读结果见 `positions-verification.txt`。最初按空位置匹配的库存导入命令已增加保护:发现本批库存已经关联库区库位时拒绝执行,避免重复创建空位置库存。库区库位补齐操作本身支持重复执行,无差异时不会新增或更新记录。
sql/mysql/mes_trace_location_visit.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
-- ä¸Šçº¿å‰æ‰§è¡Œï¼›ç‹¬ç«‹äºŽå·²æœ‰ IP å½’属地扫码统计表。
CREATE TABLE IF NOT EXISTS mes_trace_location_visit (
    id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
    trace_code VARCHAR(128) DEFAULT NULL COMMENT '追溯码(直接打开授权页时为空)',
    latitude DECIMAL(10,7) NOT NULL COMMENT '纬度 WGS84',
    longitude DECIMAL(10,7) NOT NULL COMMENT '经度 WGS84',
    accuracy DECIMAL(10,2) NOT NULL COMMENT '定位精度(米)',
    visit_time DATETIME NOT NULL COMMENT '授权访问时间',
    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    creator VARCHAR(64) DEFAULT NULL,
    updater VARCHAR(64) DEFAULT NULL,
    deleted BIT(1) NOT NULL DEFAULT 0,
    PRIMARY KEY (id),
    KEY idx_trace_location_visit_time (visit_time),
    KEY idx_trace_location_trace_code (trace_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='授权定位的追溯访问';
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletBatchCreateReqVO.java
@@ -18,6 +18,10 @@
    @Positive(message = "生成数量必须大于 0")
    private Integer count;
    @Schema(description = "标称每托袋数(移动端选择 48 æˆ– 100;可继续扫描超出标称数)")
    @Positive(message = "每托袋数必须大于 0")
    private Integer capacity;
    @Schema(description = "备注")
    private String remark;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletPreGenerateReqVO.java
@@ -14,7 +14,11 @@
    @Positive(message = "生成数量必须大于 0")
    private Integer count;
    @Schema(description = "标称每托袋数(移动端选择 48 æˆ– 100;可继续扫描超出标称数)")
    @Positive(message = "每托袋数必须大于 0")
    private Integer capacity;
    @Schema(description = "备注")
    private String remark;
}
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletRespVO.java
@@ -52,6 +52,10 @@
    @ExcelProperty("托盘序号")
    private Integer palletNo;
    @Schema(description = "标称每托袋数")
    @ExcelProperty("标称每托袋数")
    private Integer capacity;
    @Schema(description = "已绑定袋码数量", example = "10")
    @ExcelProperty("已装袋数")
    private Integer bagCount;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/pallet/vo/MesProPalletTraceRespVO.java
@@ -29,7 +29,7 @@
    @Schema(description = "批次内托盘序号", example = "1")
    private Integer palletNo;
    @Schema(description = "可装袋数(袋/托盘)", example = "25")
    @Schema(description = "标称每托袋数(可继续扫描超出该数量)", example = "48")
    private Integer capacity;
    @Schema(description = "已绑定袋码数量", example = "10")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/consumer/MesTraceConsumerScanController.java
@@ -1,6 +1,11 @@
package cn.iocoder.yudao.module.mes.controller.admin.trace.consumer;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo.MesTraceLocationVisitPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo.MesTraceLocationDistributionRespVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.trace.consumer.MesTraceLocationVisitDO;
import cn.iocoder.yudao.module.mes.dal.mysql.trace.consumer.MesTraceLocationVisitMapper;
import cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo.MesTraceConsumerScanDistributionReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo.MesTraceConsumerScanDistributionRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo.MesTraceConsumerScanSummaryRespVO;
@@ -20,7 +25,11 @@
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@@ -33,6 +42,36 @@
    @Resource
    private MesTraceConsumerScanStatisticsService statisticsService;
    @Resource
    private MesTraceLocationVisitMapper locationVisitMapper;
    @GetMapping("/location-visits")
    @Operation(summary = "定位授权访问记录(含位置与总数)")
    @PreAuthorize("@ss.hasPermission('mes:trace-consumer-scan:query')")
    public CommonResult<PageResult<MesTraceLocationVisitDO>> getLocationVisits(@Valid MesTraceLocationVisitPageReqVO reqVO) {
        return success(locationVisitMapper.selectPage(reqVO));
    }
    @GetMapping("/location-distribution")
    @Operation(summary = "定位授权访问的坐标网格分布")
    @PreAuthorize("@ss.hasPermission('mes:trace-consumer-scan:query')")
    public CommonResult<List<MesTraceLocationDistributionRespVO>> getLocationDistribution(@Valid MesTraceLocationVisitPageReqVO reqVO) {
        Map<String, List<MesTraceLocationVisitDO>> groups = locationVisitMapper.selectListByFilter(reqVO).stream()
                .collect(Collectors.groupingBy(e -> e.getLatitude().setScale(2, RoundingMode.HALF_UP).toPlainString()
                        + "," + e.getLongitude().setScale(2, RoundingMode.HALF_UP).toPlainString()));
        return success(groups.entrySet().stream()
                .sorted((a, b) -> Long.compare(b.getValue().size(), a.getValue().size()))
                .limit(20)
                .map(entry -> {
                    MesTraceLocationDistributionRespVO vo = new MesTraceLocationDistributionRespVO();
                    String[] coordinates = entry.getKey().split(",");
                    vo.setLatitude(new BigDecimal(coordinates[0]));
                    vo.setLongitude(new BigDecimal(coordinates[1]));
                    vo.setCount((long) entry.getValue().size());
                    return vo;
                }).toList());
    }
    @GetMapping("/summary")
    @Operation(summary = "消费者扫码访问汇总")
@@ -60,4 +99,4 @@
        return success(statisticsService.getDistribution(reqVO));
    }
}
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/consumer/vo/MesTraceLocationDistributionRespVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class MesTraceLocationDistributionRespVO {
    private BigDecimal latitude;
    private BigDecimal longitude;
    private Long count;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/consumer/vo/MesTraceLocationVisitPageReqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Data
@EqualsAndHashCode(callSuper = true)
public class MesTraceLocationVisitPageReqVO extends PageParam {
    private String traceCode;
    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    private LocalDateTime startTime;
    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    private LocalDateTime endTime;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchFlowRespVO.java
@@ -37,4 +37,7 @@
    @Schema(description = "客户名称(销售出库/销售退货时)", example = "客户A")
    private String clientName;
    @Schema(description = "销售出库单联系人")
    private String contactName;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchSalesTargetRespVO.java
@@ -28,6 +28,9 @@
    @Schema(description = "客户名称", example = "客户A")
    private String clientName;
    @Schema(description = "销售出库单联系人")
    private String contactName;
    @Schema(description = "出厂检验单号(OQC)", example = "OQC20250801001")
    private String oqcCode;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/MesProTracePublicController.java
@@ -3,17 +3,25 @@
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesProTracePublicConfigRespVO;
import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesProTracePublicRespVO;
import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesTraceLocationVisitReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.trace.consumer.MesTraceLocationVisitDO;
import cn.iocoder.yudao.module.mes.dal.mysql.trace.consumer.MesTraceLocationVisitMapper;
import cn.iocoder.yudao.module.mes.service.trace.MesProTracePublicService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -32,6 +40,9 @@
    @Resource
    private MesProTracePublicService service;
    @Resource
    private MesTraceLocationVisitMapper locationVisitMapper;
    @GetMapping("/query")
    @PermitAll
    @Operation(summary = "根据追溯码查询全程溯源信息")
@@ -46,4 +57,18 @@
        return success(service.getPublicConfig());
    }
    @PostMapping("/location-visit")
    @PermitAll
    @Operation(summary = "记录用户授权定位后的追溯访问")
    public CommonResult<Long> recordLocationVisit(@Valid @RequestBody MesTraceLocationVisitReqVO reqVO) {
        MesTraceLocationVisitDO visit = new MesTraceLocationVisitDO();
        visit.setTraceCode(reqVO.getCode() == null || reqVO.getCode().isBlank() ? null : reqVO.getCode().trim());
        visit.setLatitude(reqVO.getLatitude());
        visit.setLongitude(reqVO.getLongitude());
        visit.setAccuracy(reqVO.getAccuracy());
        visit.setVisitTime(LocalDateTime.now());
        locationVisitMapper.insert(visit);
        return success(visit.getId());
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicConfigRespVO.java
@@ -24,4 +24,7 @@
    @Schema(description = "是否进口种子场景:为 true æ—¶é¡µé¢æ ‡ç­¾åº”展示「进口商名称」")
    private Boolean imported;
    @Schema(description = "定位版追溯页是否要求定位授权;仅本地环境可关闭")
    private Boolean traceLocationRequired;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesTraceLocationVisitReqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.mes.controller.pub.trace.vo;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class MesTraceLocationVisitReqVO {
    @Size(max = 128)
    private String code;
    @NotNull
    @DecimalMin("-90")
    @DecimalMax("90")
    private BigDecimal latitude;
    @NotNull
    @DecimalMin("-180")
    @DecimalMax("180")
    private BigDecimal longitude;
    @NotNull
    @DecimalMin("0")
    @DecimalMax("100000")
    private BigDecimal accuracy;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/trace/consumer/MesTraceLocationVisitDO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.mes.dal.dataobject.trace.consumer;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/** ç”¨æˆ·æ˜Žç¡®æŽˆæƒåŽçš„追溯定位访问。 */
@TableName("mes_trace_location_visit")
@Data
@EqualsAndHashCode(callSuper = true)
public class MesTraceLocationVisitDO extends BaseDO {
    @TableId
    private Long id;
    private String traceCode;
    private BigDecimal latitude;
    private BigDecimal longitude;
    private BigDecimal accuracy;
    private LocalDateTime visitTime;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/trace/consumer/MesTraceLocationVisitMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.mes.dal.mysql.trace.consumer;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.controller.admin.trace.consumer.vo.MesTraceLocationVisitPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.trace.consumer.MesTraceLocationVisitDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MesTraceLocationVisitMapper extends BaseMapperX<MesTraceLocationVisitDO> {
    default List<MesTraceLocationVisitDO> selectListByFilter(MesTraceLocationVisitPageReqVO reqVO) {
        return selectList(new LambdaQueryWrapperX<MesTraceLocationVisitDO>()
                .likeIfPresent(MesTraceLocationVisitDO::getTraceCode, reqVO.getTraceCode())
                .geIfPresent(MesTraceLocationVisitDO::getVisitTime, reqVO.getStartTime())
                .ltIfPresent(MesTraceLocationVisitDO::getVisitTime, reqVO.getEndTime()));
    }
    default PageResult<MesTraceLocationVisitDO> selectPage(MesTraceLocationVisitPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<MesTraceLocationVisitDO>()
                .likeIfPresent(MesTraceLocationVisitDO::getTraceCode, reqVO.getTraceCode())
                .geIfPresent(MesTraceLocationVisitDO::getVisitTime, reqVO.getStartTime())
                .ltIfPresent(MesTraceLocationVisitDO::getVisitTime, reqVO.getEndTime())
                .orderByDesc(MesTraceLocationVisitDO::getVisitTime));
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/config/MesProperties.java
@@ -24,6 +24,9 @@
     */
    private String traceBaseUrl = "";
    /** å®šä½ç‰ˆè¿½æº¯é¡µæ˜¯å¦å¿…须先取得用户定位;仅本地调试配置为 false。 */
    private boolean traceLocationRequired = true;
    /**
     * ç”Ÿäº§ç»è¥è€…名称(种子标签四要素之一)。
     * <p>
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/pallet/MesProPalletServiceImpl.java
@@ -83,6 +83,7 @@
                    .setBatchId(batch.getId())
                    .setBatchCode(batch.getCode())
                    .setPalletNo(palletNo)
                    .setCapacity(createReqVO.getCapacity())
                    .setBagCount(0)
                    .setAutoGenerated(false)
                    .setStatus(MesProPalletStatusEnum.IN_USE.getStatus())
@@ -106,6 +107,7 @@
            list.add(new MesProPalletDO()
                    .setTempCode(codeRedisDao.generate())
                    .setBusinessCode(codeRedisDao.generate())
                    .setCapacity(reqVO.getCapacity())
                    .setBagCount(0)
                    .setAutoGenerated(false)
                    .setStatus(MesProPalletStatusEnum.IN_USE.getStatus())
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
@@ -22,6 +22,7 @@
import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum;
import cn.iocoder.yudao.module.mes.enums.trace.MesTraceCodeStatusEnum;
import cn.iocoder.yudao.module.mes.framework.qrcode.MesProQrLabelBuilder;
import cn.iocoder.yudao.module.mes.framework.config.MesProperties;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.pro.bagcode.MesProBagCodeService;
import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
@@ -100,6 +101,8 @@
    private MesTraceIntegrityService integrityService;
    @Resource
    private MesTraceConsumerScanEventMapper consumerScanEventMapper;
    @Resource
    private MesProperties mesProperties;
    @Override
    public MesProTracePublicRespVO queryTrace(String code) {
@@ -133,6 +136,7 @@
        respVO.setOperatorName(MesProQrLabelBuilder.resolveOperatorName());
        respVO.setTraceUrl(MesProQrLabelBuilder.resolveTraceUrl());
        respVO.setImported(MesProQrLabelBuilder.isImported());
        respVO.setTraceLocationRequired(mesProperties.isTraceLocationRequired());
        return respVO;
    }
yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml
@@ -63,7 +63,7 @@
    -->
    <select id="selectSalesTargetList" parameterType="String"
            resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO">
        SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name,
        SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name, s.contact_name,
               oqc.code AS oqc_code, oqc.check_result AS check_result,
               sl.batch_code, sl.item_id, sl.quantity, sl.quality_status
        FROM mes_wm_product_sales_line sl
@@ -73,7 +73,7 @@
          AND NOT EXISTS (SELECT 1 FROM mes_wm_product_sales_detail d
                          WHERE d.line_id = sl.id AND d.batch_code = #{batchCode} AND d.deleted = 0)
        UNION ALL
        SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name,
        SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id, s.client_name, s.contact_name,
               oqc.code AS oqc_code, oqc.check_result AS check_result,
               d.batch_code, d.item_id, SUM(d.quantity) AS quantity, MAX(sl.quality_status) AS quality_status
        FROM mes_wm_product_sales_detail d
@@ -81,7 +81,7 @@
        JOIN mes_wm_product_sales_line sl ON sl.id = d.line_id AND sl.deleted = 0
        LEFT JOIN mes_qc_oqc oqc ON oqc.id = sl.oqc_id AND oqc.deleted = 0
        WHERE d.batch_code = #{batchCode} AND d.deleted = 0 AND s.status != 5
        GROUP BY s.id, s.code, s.sales_date, s.sales_order_code, s.client_id, s.client_name,
        GROUP BY s.id, s.code, s.sales_date, s.sales_order_code, s.client_id, s.client_name, s.contact_name,
                 oqc.code, oqc.check_result, d.batch_code, d.item_id
        ORDER BY sales_date
    </select>
@@ -91,7 +91,7 @@
            resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO">
        SELECT tx.type, tx.biz_type, tx.biz_code, tx.quantity, tx.transaction_time,
               w.name AS warehouse_name, loc.name AS location_name, area.name AS area_name,
               sales.client_name
               sales.client_name, sales.contact_name
        FROM mes_wm_transaction tx
        LEFT JOIN mes_wm_warehouse w ON w.id = tx.warehouse_id AND w.deleted = 0
        LEFT JOIN mes_wm_warehouse_location loc ON loc.id = tx.location_id AND loc.deleted = 0
yudao-server/src/main/resources/application-local.yaml
@@ -5,6 +5,8 @@
mes:
  # è¿½æº¯ç½‘址(二维码内容前缀),需为公众扫码可访问的地址
  trace-base-url: http://192.168.0.10:48080/trace.html
  # æœ¬åœ° HTTP è°ƒè¯•时跳过浏览器定位授权;生产环境使用默认值 true
  trace-location-required: false
  # ç”Ÿäº§ç»è¥è€…名称(种子标签四要素之一,标签与溯源页统一取此值;未配置则无法导出标签)
  operator-name: æ–°ç–†å¡”里木河种业股份有限公司
yudao-server/src/main/resources/static/trace-location.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>定位授权 Â· äº§å“è¿½æº¯</title>
  <style>
    * { box-sizing: border-box; }
    body { margin: 0; min-height: 100vh; display: grid; place-items: center; padding: 24px; background: #f6f7f6; color: #1f2933; font: 16px/1.6 -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif; }
    .trace-background { position: fixed; inset: 0; width: 100%; height: 100%; border: 0; pointer-events: none; opacity: .45; filter: blur(2px); }
    body.unlocked .trace-background { pointer-events: auto; opacity: 1; filter: none; }
    body::before { content: ''; position: fixed; inset: 0; background: #f6f7f688; z-index: 1; }
    body.unlocked::before, body.unlocked main { display: none; }
    main { position: relative; z-index: 2; width: min(100%, 440px); background: white; border-radius: 16px; padding: 28px 24px; box-shadow: 0 6px 28px #17382224; }
    .icon { width: 52px; height: 52px; display: grid; place-items: center; background: #eef7ef; color: #1f7a38; border-radius: 14px; font-size: 28px; }
    h1 { margin: 20px 0 8px; font-size: 23px; }
    p { margin: 0 0 18px; color: #58636d; }
    button { width: 100%; min-height: 48px; border: 0; border-radius: 9px; background: #1f7a38; color: white; font: inherit; font-weight: 600; cursor: pointer; }
    button:focus-visible { outline: 3px solid #7bc894; outline-offset: 3px; }
    button:disabled { opacity: .6; cursor: wait; }
    #status { min-height: 26px; margin-top: 14px; color: #b42318; }
    small { display: block; margin-top: 16px; color: #6b7280; }
  </style>
</head>
<body>
  <iframe id="traceFrame" class="trace-background" src="trace.html" tabindex="-1" aria-hidden="true" title="产品追溯背景"></iframe>
  <main>
    <div class="icon" aria-hidden="true">⌖</div>
    <h1>开启定位后查看追溯信息</h1>
    <p>为记录本次追溯查询所在位置,请允许浏览器获取当前位置。授权成功后将自动进入产品追溯页。</p>
    <button id="locate" type="button" disabled>开启定位并继续</button>
    <div id="status" role="status" aria-live="polite"></div>
    <small>本次会记录追溯码、坐标、定位精度和访问时间,供后台查看与统计。拒绝授权或定位失败时无法继续。</small>
  </main>
  <script>
    (function () {
      'use strict';
      var button = document.getElementById('locate');
      var status = document.getElementById('status');
      var code = new URLSearchParams(location.search).get('code') || '';
      function showTrace() {
        var frame = document.getElementById('traceFrame');
        frame.src = 'trace.html' + (code ? '?code=' + encodeURIComponent(code) + '&view=location' : '?view=location');
        frame.removeAttribute('aria-hidden');
        frame.removeAttribute('tabindex');
        frame.title = '产品追溯信息';
        document.body.classList.add('unlocked');
      }
      // æœ¬åœ° profile ç”±åŽç«¯æ˜Žç¡®å…³é—­å®šä½è¦æ±‚;配置失败时保持必须定位。
      status.textContent = '正在检查访问配置…';
      fetch('/public/mes/trace/config')
        .then(function (response) { return response.json(); })
        .then(function (result) {
          if (result && result.code === 0 && result.data && result.data.traceLocationRequired === false) {
            showTrace();
          } else {
            status.textContent = '';
            button.disabled = false;
          }
        })
        .catch(function () {
          status.textContent = '';
          button.disabled = false;
        });
      button.addEventListener('click', function () {
        if (!window.isSecureContext || !navigator.geolocation) {
          status.textContent = '当前网址不支持定位,请使用已配置 HTTPS çš„追溯网址打开。';
          return;
        }
        button.disabled = true;
        status.textContent = '正在获取当前位置…';
        navigator.geolocation.getCurrentPosition(function (position) {
          fetch('/public/mes/trace/location-visit', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              code: code,
              latitude: position.coords.latitude,
              longitude: position.coords.longitude,
              accuracy: position.coords.accuracy
            })
          }).then(function (response) { return response.json(); }).then(function (result) {
            if (!result || result.code !== 0) throw new Error(result && result.msg || '位置记录失败');
            showTrace();
          }).catch(function (error) {
            status.textContent = error.message || '位置记录失败,请重试。';
            button.disabled = false;
          });
        }, function (error) {
          status.textContent = error.code === 1 ? '定位权限被拒绝,请在浏览器设置中允许定位后重试。' : '定位失败,请检查手机定位和网络后重试。';
          button.disabled = false;
        }, { enableHighAccuracy: true, timeout: 15000, maximumAge: 0 });
      });
    })();
  </script>
</body>
</html>
yudao-server/src/main/resources/static/trace.html
@@ -372,14 +372,6 @@
  var CODE_INPUT = document.getElementById('codeInput');
  var SEARCH_BTN = document.getElementById('searchBtn');
  var FLOW_DIRECTION = { 1: ['入库', 'green'], 2: ['出库', 'blue'] };
  var FLOW_BIZ_TYPE = {
    110: '采购入库', 111: '采购入库取消', 112: '调拨出库', 113: '调拨入库',
    114: '其他出库', 115: '其他入库', 116: '生产领料', 117: '生产退料',
    118: '生产入库', 119: '销售出库', 120: '销售退货入库', 121: '外协发料',
    122: '外协入库', 123: '生产消耗', 124: '产品产出', 125: '供应商退货出库',
    126: '库存调整入库', 127: '库存调整出库'
  };
  var SOURCE_TYPE = { BAG: '袋码', PALLET: '托盘码', BATCH: '批次码' };
  // ========== å·¥å…·å‡½æ•° ==========
@@ -411,12 +403,6 @@
  // è¡¨æ ¼çª„列(数量 / æ—¥æœŸï¼‰ä¸æ¢è¡Œï¼Œé¿å…æ•°å­—被拆行
  function nw(html) {
    return '<span style="white-space:nowrap">' + html + '</span>';
  }
  function statusBadge(map, key) {
    var item = map[key];
    if (!item) return '<span class="badge gray">' + (key === null || key === undefined ? '' : esc(key)) + '</span>';
    return '<span class="badge ' + item[1] + '">' + esc(item[0]) + '</span>';
  }
  function kv(k, v, dim) {
@@ -499,14 +485,89 @@
      return;
    }
    var html = '';
    if (new URLSearchParams(location.search).get('view') === 'location') {
      html += locationSections(d);
      html += sec('产品追溯标识', null, tracePanel(d), null);
      STATE.innerHTML = html;
      window.scrollTo({ top: 0, behavior: 'smooth' });
      return;
    }
    html += sec('防伪查询', null, fakePanel(d), null);
    html += sec('追溯查询', null, tracePanel(d), null);
    // ç”Ÿäº§æ˜Žç»†æŠ˜å åŒºï¼šå¯¹å¤–展示种子流向、加工流转,生产批次信息不展示。
    // ç”Ÿäº§æ˜Žç»†æŠ˜å åŒºï¼šå¯¹å¤–展示加工流转,生产批次信息不展示。
    // è´¨æ£€/人员/托盘/袋码/采购来源等内部明细不对外展示,
    // å¦‚需一并展示,改为 detailSections(d, true) å³å¯ã€‚
    html += detailSections(d, false);
    STATE.innerHTML = html || '<div class="empty-tip">暂无追溯数据</div>';
    window.scrollTo({ top: 0, behavior: 'smooth' });
  }
  // å®šä½æŽˆæƒå…¥å£æ²¿ç”¨æœ¬é¡µçš„品牌背景与区块样式,按生产、仓储、物流组织已有真实数据。
  function groupOutboundOrders(rows, codeOf, dateField) {
    var grouped = [];
    var byCode = new Map();
    rows.forEach(function (item) {
      var code = String(codeOf(item) || '').trim();
      var quantity = Number(item.quantity);
      var validQuantity = item.quantity !== null && item.quantity !== undefined && Number.isFinite(quantity);
      var existing = code ? byCode.get(code) : null;
      if (!existing) {
        var order = Object.assign({}, item, { quantity: validQuantity ? Math.abs(quantity) : null });
        grouped.push(order);
        if (code) byCode.set(code, order);
      } else {
        if (validQuantity) existing.quantity = (existing.quantity || 0) + Math.abs(quantity);
        if (!existing.contactName && item.contactName) existing.contactName = item.contactName;
        if (item[dateField] && (!existing[dateField] || item[dateField] > existing[dateField])) {
          existing[dateField] = item[dateField];
        }
      }
    });
    return grouped;
  }
  function locationSections(d) {
    var production = kv('产品名称', text(d.itemName)) +
      kv('规格', text(d.itemSpecification || d.itemUnitMeasureName)) +
      kv('加工批次', text(d.batchCode || d.tempCode));
    if (d.produceDate) production = kv('生产日期', fmtDay(d.produceDate)) + production;
    var html = sec('生产信息', null, production, null);
    var salesFlows = groupOutboundOrders((d.seedFlows || []).filter(function (item) { return item.bizType === 119; }),
      function (item) { return item.bizCode; }, 'transactionTime');
    var salesTargets = groupOutboundOrders(d.salesTargets || [],
      function (item) { return item.salesCode || item.salesOrderCode; }, 'salesDate');
    var flow = (d.seedFlows || []).find(function (item) { return item.warehouseName; });
    var storage = '';
    if (d.inboundTime) storage += kv('入库日期', fmtDay(d.inboundTime));
    var outboundDates = salesFlows.map(function (item) { return item.transactionTime; })
      .concat(salesTargets.map(function (item) { return item.salesDate; })).filter(Boolean).sort();
    if (outboundDates.length) storage += kv('最近出库日期', fmtDay(outboundDates[outboundDates.length - 1]));
    if (flow) storage += kv('仓库', text(flow.warehouseName));
    html += sec('仓储信息', null, storage || '<div class="empty-tip">暂无仓储信息</div>', null);
    var logistics = salesFlows.map(function (item) {
      var route = [item.warehouseName, item.clientName].filter(Boolean).join(' â†’ ');
      var description = '该批次' + (item.transactionTime ? '于 ' + String(item.transactionTime).slice(0, 10) + ' ' : '') +
        (item.warehouseName ? '从' + item.warehouseName + '出库' : '完成销售出库') +
        (item.clientName ? ',发往' + item.clientName : '') + '。';
      return li('<span class="li-ttl">' + text(route || '销售出库') + '</span>', fmtDay(item.transactionTime),
        kv('出库单号', text(item.bizCode)) + kv('数量', fmtNum(item.quantity)) +
        kv('流转说明', text(description)) +
        (item.contactName ? kv('联系人', text(item.contactName)) : ''));
    }).join('');
    if (!logistics && !isEmptyList(salesTargets)) {
      logistics = salesTargets.map(function (item) {
        var description = '该批次' + (item.salesDate ? '于 ' + String(item.salesDate).slice(0, 10) + ' ' : '') +
          '完成销售出库' + (item.clientName ? ',去向' + item.clientName : '') + '。';
        return li('<span class="li-ttl">' + text(item.clientName || '销售去向') + '</span>', fmtDay(item.salesDate),
          kv('出库单号', text(item.salesCode || item.salesOrderCode)) + kv('数量', fmtNum(item.quantity)) +
          kv('流转说明', text(description)) +
          (item.contactName ? kv('联系人', text(item.contactName)) : ''));
      }).join('');
    }
    html += sec('物流信息', null, logistics || '<div class="empty-tip">暂无物流信息</div>', null);
    return html;
  }
  function stripUrl(v) {
@@ -583,7 +644,7 @@
      kv(operatorLabel, text(operatorName)) +
      kv(codeLabel, text(code || '-')) +
      kv('追溯网址', traceUrl
        ? '<a class="link" href="' + esc(traceUrl) + '">' + esc(traceUrl) + '</a>'
        ? '<a class="link" target="_top" href="' + esc(location.pathname.replace(/trace\.html$/, 'trace-location.html') + '?code=' + encodeURIComponent(code || '')) + '">' + esc(traceUrl) + '</a>'
        : '-') +
      kv('计量单位', text(d.itemUnitMeasureName)) +
      kv('追溯类型', esc(SOURCE_TYPE[d.sourceType] || '追溯码')) +
@@ -662,27 +723,6 @@
        return [text(s.receiptCode), text(s.vendorName), nw(fmtNum(s.receivedQuantity)), nw(fmtDay(s.receiptDate))];
      });
      html += sec('采购来源', null, table(['采购入库单', '供应商', '数量', '日期'], psRows), { collapsible: true, open: false });
    }
    // ç§å­æµå‘信息(仅销售出库 bizType=119)
    var salesFlows = (d.seedFlows || []).filter(function (f) { return f.bizType === 119; });
    if (!isEmptyList(salesFlows)) {
      var sfBody = salesFlows.map(function (f) {
        var qty = (f.quantity === null || f.quantity === undefined) ? '-' : fmtNum(Math.abs(Number(f.quantity)));
        var wh = [f.warehouseName, f.locationName].filter(Boolean).join(' / ') || '-';
        return li(statusBadge(FLOW_DIRECTION, f.type) + '<span class="li-ttl">' + esc(FLOW_BIZ_TYPE[f.bizType] || '') + '</span>',
          fmtDate(f.transactionTime),
          kv('来源单号', text(f.bizCode)) +
          kv('客户', text(f.clientName)) +
          kv('数量', qty) +
          kv('仓库/库区', text(wh)));
      }).join('');
      html += sec('种子流向信息', null, '<div class="scroll-list">' + sfBody + '</div>', { collapsible: true, open: false });
    } else if (!isEmptyList(d.salesTargets)) {
      var stRows = d.salesTargets.map(function (s) {
        return [text(s.salesCode || s.salesOrderCode || ''), text(s.clientName), nw(fmtNum(s.quantity)), nw(fmtDay(s.salesDate))];
      });
      html += sec('种子流向信息', null, table(['销售出库单', '客户', '数量', '日期'], stRows), { collapsible: true, open: false });
    }
    // åŠ å·¥æµè½¬