# 246 Admin:档口入库码后台批量回写与进度反馈 - 类型:需求 - 父级大工单:#14 - 所属 MVP / 版本:#224 - 状态:已完成 - 日期:2026-08-15 - Gitea 工单:http://ilaer.eicp.net:8418/chengma/cmautobuy/issues/246 ## 背景与目标 原“回写顺运宝”在浏览器请求内同步处理,并把 20 条同时当成选择上限。每条记录可能执行 写前读取、删除旧值、写入新值和写后核对,数量增加后页面会长时间等待,也难以区分仍在 执行、请求超时和结果未知。 本工单允许采购员一次提交当前页全部选中记录,页面立即返回;Admin 在后台安全串行回写, 页面可以刷新查看批次进度和逐条结果。 ## 最终方案 - 继续只使用 `syb_inner_code_records` 一张业务表,不新增批次表。MySQL schema v25 增加 `apply_batch_id`、`apply_queued_at`、批次索引,并让状态约束支持 `queued`。 - 提交时使用单个事务把全部选中且仍为 `ready` 的记录改为 `queued`。任一记录状态已变化, 整批回滚,避免部分入队和重复回写。 - HTTP 请求只负责校验顺运宝会话、落库排队和返回页面。Handler 使用单一互斥后台执行器, 每次最多读取 20 条,但每条仍原子领取为 `applying`,逐条执行既有“写前核验、最多一次 写入、写后复读”门禁。 - 页面按 `apply_batch_id` 从业务表聚合进度,使用文字和原生 `progress` 同时显示总数、排队中、 回写中、成功、已存在、跳过、失败、需核对,并用普通 GET 链接手工刷新;模块切换状态会 保留当前批次标识。 - 后台异常时,同批次 `applying` 立即转 `needs_check`,`queued` 恢复 `ready`;Admin 重启时 执行相同安全原则。两种情况都不自动重放真实远端写入。 - 与建单方案一致;实现时进一步补强了“后台进程未退出但执行器异常”的立即状态收敛,避免 必须等到下次重启才能看到 `applying` 的未知结果。 ## 改了哪些 - `admin/repository/mysql_db.go`、`admin/repository/mysql_db_integration_test.go`:追加 v25 迁移、 schema 自检和 v24 升级/重放用例。 - `admin/model/inner_code.go`、`admin/repository/inner_code.go`:增加排队状态、单表批次字段、 原子入队/领取、进度聚合、异常和启动恢复。 - `admin/service/inner_code_apply.go`、`admin/service/inner_code_match.go`、 `admin/service/inner_code_page.go`:实现后台分组消费并让排队记录继续占用已匹配明细。 - `admin/handler/web/inner_code.go`、`admin/handler/web/web.go`:提交后立即重定向,后台批次串行 执行并在异常时收敛状态。 - `admin/templates/inner_code/list.html`、`admin/static/css/app.css`、`admin/static/js/app.js`:增加 可访问的进度区、排队中状态、手工刷新和新的提交反馈。 - `admin/**/*_test.go`:覆盖超过 20 条入队、整批冲突回滚、进度聚合、异常恢复、页面语义和 模块状态保留。 - `docs/admin/03-data-model.md`、`docs/admin/05-ui-specification.md`、 `docs/admin/08-顺运宝接口.md`:同步稳定数据、页面和远端安全约束。 ## 验收结果 | 验收标准 | 结果 | |---|---| | 超过 20 条可一次提交,HTTP 页面不等待远端处理 | 通过:45 条单元测试一次原子入队;Handler 排队后立即 303 | | 后台每次最多读取 20 条,远端仍逐条且最多写一次 | 通过:分组常量和既有写入未知结果不重试测试通过 | | 页面显示批次进度并可手工刷新 | 通过:模板语义、原生 `progress`、刷新链接和状态保留测试通过 | | 重复提交或并发状态变化不会部分入队 | 通过:条件更新、受影响行数校验和事务回滚测试通过 | | 后台异常和 Admin 重启按远端风险区分恢复 | 通过:`applying → needs_check`、`queued → ready` 自动化测试通过 | | MySQL v24 → v25、空库和重复迁移 | 部分通过:用例已编写并通过编译;真实 MySQL 8.4 测试环境未启用 | | 固定 Go 1.23.0 全量检查 | 通过 | | 不新增批次表、不修改 Client | 通过 | ## 测试 - 执行的命令: - `$env:GOTOOLCHAIN='go1.23.0'; go vet ./...; go build ./...; go test ./... -count=1` - `go test ./repository -run 'TestMySQLMigrate_(真实MySQL8|V24升级V25且后台队列状态有效)$' -count=1 -v` - `git diff --check` - 结果:固定 Go 1.23.0 的 vet、全量构建和全量测试通过;格式检查通过。MySQL 定向用例因 未设置 `CMAUTOBUY_MYSQL_TEST=1` 而按安全门禁跳过。 - **没验证到的部分**:当前环境没有名称以 `_test` 结尾的独立 MySQL 8.4 测试库,未实际执行 v24→v25、空库和重复迁移 DDL;未向真实顺运宝发送档口入库码写请求;未在浏览器中人工 观察长批次实时进度。禁止使用生产 `autobuy` 数据库或正式货运单代替这些测试。 ## 遗留问题 上线前必须先备份生产数据库,并在独立 MySQL 8.4 `_test` 库执行 v24→v25 和重复迁移; 真实顺运宝写入需要由用户选择测试货运单人工验收。 ## 相关提交 - `f8f22a1` feat: 档口入库码后台批量回写 (#246)