2026-10-17-protocol-status-change-history.md 7.3 KB

采集协议单状态变更记录 · 方案 A 实现计划

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 详情「状态变更记录」改为与「审核记录」一致的表格流水;每次状态变更追加一行,同类型不覆盖。

Architecture: 新增两张追加写历史表(细胞存储 / 科研捐赠),状态变更写路径在更新主表「最新快照字段」的同时插入历史行;详情与移动端只读改为拉历史列表。主表 effective_* / expire_* / void_* / to_research_*(捐赠侧 to_storage_*)保留为最新快照,供列表筛选与兼容旧数据。

Tech Stack: MySQL 5.7 · FastAPI/SQLAlchemy · Vue 3 web-admin · mobile-oa-h5

UI 定稿: docs/demos/2026-10-17-protocol-status-change-records-demo.html 方案 A(表格流水)

范围默认: 细胞存储采集协议单 + 科研捐赠协议单(统一页两个 Tab);移动端详情只读同步。


文件与职责

路径 职责
docs/sql/migrations/2026-10-17-protocol-status-change-log.sql 建表 + 从主表快照回填首条历史
backend/app/models/models.py(或 donation 模型文件) BizProtocolStatusChange / BizDonationStatusChange
backend/app/crud/collection_protocol.py 状态变更时写历史;list 历史 API 支撑
backend/app/crud/research_donation.py change_status / convert_from_storage 写历史;list 历史
backend/app/api/collection_protocol.py GET .../status-changes
backend/app/api/research_donation.py GET .../status-changes
web-admin/.../ProtocolViewDialog.vue 表格替换 data-grid--4
web-admin/.../DonationViewDialog.vue 同上
web-admin/src/api/collection-protocol.ts / research-donation.ts 列表 API
mobile-oa-h5/src/market/modules/protocol.js 状态变更区块改为行列表(或表格字段集)
backend/tests/test_protocol_status_change_history.py(新建) 追加不覆盖 + 回填语义

数据模型

biz_protocol_status_change(细胞存储)

字段顺序:id → 业务字段 → 公共字段(对齐 database-conventions)。

字段 说明
id VARCHAR(64) UUID
collection_protocol_id 协议单 ID
change_type activate / expire / void / to_research
from_status 变更前状态码
to_status 变更后状态码(sxz/ygq/yzf/zky)
change_time 业务时间(表单选择的时间)
change_desc 描述
void_type 作废类型(仅 void,可空)
operator_user_id 操作人
tenant_no … del_flag 公共字段

索引:(tenant_no, collection_protocol_id, del_flag, change_time)。

biz_donation_status_change(科研捐赠)

对称设计:research_donation_id + change_type(activate/expire/void/to_storage)。

回填规则(一次性 SQL)

对主表已有非空时间字段,各插入 1 条历史(from_status 可空或按常识推断;create_by/operator 用协议 update_by):

  • effective_time → activate
  • expire_time → expire
  • void_time → void(带 void_type)
  • to_research_time / to_storage_time → 对应类型

回填后主表快照字段不删不改。


写路径(追加不覆盖)

flowchart LR
  UI[StatusChangeDialog] --> API[update / status-change / convert]
  API --> Snap[更新主表最新快照字段]
  API --> Log[INSERT 历史行]
  Snap --> DB[(MySQL)]
  Log --> DB
  Detail[ViewDialog / Mobile] --> ListAPI[GET status-changes]
  ListAPI --> DB
  1. 细胞存储生效/过期/作废:现有 fetchUpdateCollectionProtocol 写 protocolStatus + 时间描述。在 update_collection_protocol 中,当 protocol_status 实际变更且对应时间字段被写入时,插入历史行(记录 from_status/to_status)。
  2. 转科研:convert_from_storage 写 to_research_* 时同步插历史。
  3. 科研捐赠:change_status 每次成功变更插历史;转细胞存储对称处理。
  4. 纯编辑其它字段(附件等)不写历史。

列表排序:change_time ASC, create_time ASC(与 Demo 时间线一致;若产品要最新在上可改为 DESC,前后端统一)。


前端展示(方案 A)

列(对齐 Demo / 审核记录):

列 来源
序号 index
变更类型 Tag:activate→生效 / expire→过期 / void→作废 / to_research→转科研 / to_storage→转细胞存储
变更时间 changeTime
状态流转 fromLabel → toLabel(用现有 protocolStatusDisplayLabel)
变更说明 changeDesc;作废时前缀「作废类型:xxx;」
操作人 用户昵称

空态:暂无状态变更记录(el-table empty-text)。

去掉现有 data-grid data-grid--4 快照拼盘;hasAnyStatusChange 改为 statusChangeRecords.length > 0。


任务清单

Task 1:建表 SQL + 回填

  • 编写 docs/sql/migrations/2026-10-17-protocol-status-change-log.sql
  • 含两张表 CREATE + 从 biz_collection_protocol / biz_research_donation 回填 INSERT
  • 本地/测试库执行验证行数合理(需在目标库手工执行 migration)

Task 2:后端模型 + CRUD 写历史

  • 增加 SQLAlchemy 模型
  • update_collection_protocol:状态相关字段写入时 append log
  • convert_from_storage:append to_research
  • change_status(捐赠):append log
  • 捐赠转存储路径若有对称写字段,一并 append

Task 3:列表 API

  • GET /web/admin/collection-protocols/{id}/status-changes
  • GET /web/admin/research-donations/{id}/status-changes
  • 返回字段 camelCase;附带 operatorUserName;租户隔离 + 软删过滤
  • 注册路由(已有 router 模块内新增,无需改 main)

Task 4:后端测试

  • 同类型连续两次变更 → 历史 2 行,主表快照为第二次
  • 详情 list API 返回顺序与条数正确(CRUD list 覆盖)
  • pytest 相关用例通过

Task 5:web-admin 详情

  • ProtocolViewDialog:加载历史 + 方案 A 表格
  • DonationViewDialog:同上
  • API 封装

Task 6:移动端只读对齐

  • mobile-oa-h5 protocol module statusChange 区块改为多行记录(非扁平字段)
  • 更新 protocol-mobile-parity / mobile-parity-ui 相关断言

Task 7:验证与图谱

  • 手动:审核页两个 Tab 打开详情,做两次过期类变更,确认两条都在(需先执行 SQL)
  • ./scripts/update-graph.sh all

非目标

  • 不改状态机合法流转规则(仍用 assert_protocol_status_transition)
  • 不删除主表快照列
  • 不在本迭代做历史编辑/删除 UI
  • 不改审核记录表

验收标准

  1. 详情「状态变更记录」为单行表格,不再出现四列网格挤行。
  2. 同类型变更第二次后,历史中仍可见第一次。
  3. 细胞存储与科研捐赠行为一致。
  4. 旧数据经回填后至少能看到各类「最后一次」快照对应的一条历史。