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)。
对主表已有非空时间字段,各插入 1 条历史(from_status 可空或按常识推断;create_by/operator 用协议 update_by):
effective_time → activateexpire_time → expirevoid_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
fetchUpdateCollectionProtocol 写 protocolStatus + 时间描述。在 update_collection_protocol 中,当 protocol_status 实际变更且对应时间字段被写入时,插入历史行(记录 from_status/to_status)。convert_from_storage 写 to_research_* 时同步插历史。change_status 每次成功变更插历史;转细胞存储对称处理。列表排序:change_time ASC, create_time ASC(与 Demo 时间线一致;若产品要最新在上可改为 DESC,前后端统一)。
列(对齐 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。
docs/sql/migrations/2026-10-17-protocol-status-change-log.sqlbiz_collection_protocol / biz_research_donation 回填 INSERTupdate_collection_protocol:状态相关字段写入时 append logconvert_from_storage:append to_researchchange_status(捐赠):append logGET /web/admin/collection-protocols/{id}/status-changesGET /web/admin/research-donations/{id}/status-changesoperatorUserName;租户隔离 + 软删过滤pytest 相关用例通过ProtocolViewDialog:加载历史 + 方案 A 表格DonationViewDialog:同上mobile-oa-h5 protocol module statusChange 区块改为多行记录(非扁平字段)protocol-mobile-parity / mobile-parity-ui 相关断言./scripts/update-graph.sh allassert_protocol_status_transition)