docs: add research donation list Excel parity design

Capture confirmed field mapping, monthly verify number rules, and Web/mini list scope before implementation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-13 12:03:04 +08:00
1 parent 22a6e1f4e4
commit c22c9467f5
1 file changed
+203
@@ -0,0 +1,203 @@
# 科研捐赠列表对齐 Excel「科研表」— 设计
> 日期:2026-10-13
> 状态:待用户审阅
> 参考:`中科兴皖采集大表20260720.xlsx` sheet「科研表」
> 页面:`/#/market/cell-storage/protocol-audit?tab=research_donation`
> 源码:`web-admin/src/views/cell-storage/protocol-audit/DonationProtocolTab.vue`
> 小程序:`mobile-oa-h5` 协议模块 `research_donation` 列表卡片(`list-presenter.js` / `modules/protocol.js`)
> 表:`biz_research_donation`(模型 `backend/app/models/research_donation.py`)
---
## 1. 背景与目标
### 1.1 背景
客户 Excel「科研表」是科研捐赠采集台账。当前 Web「采集协议单 · 科研捐赠」列表列偏少(缺状态、废弃原因、临床字段、附件有无、备注等),且与 Excel 对照不便。小程序协议列表对科研捐赠也未按该台账字段展示。
### 1.2 目标
1. Web 科研捐赠列表列对齐 Excel「科研表」字段映射(见 §3),去掉运费与「是否同存」。
2. 新增业务字段 **当月核量号**(创建时生成,历史不回填),仅列表展示。
3. 小程序科研捐赠列表卡片字段集合与 Web 对齐(布局可折叠/多行,但字段不缺)。
4. 知情同意书 / 传染病检测报告 / 协议书(其他附件)在列表仅显示「有」或「—」。
### 1.3 非目标
- 不改【细胞存储】Tab 列表。
- 详情弹窗、新建/编辑表单不展示当月核量号。
- 不回填历史当月核量号。
- 不展示运费(多协议共享,不适合单行协议列表)。
- 不做 Excel 导入/导出。
- 不改附件上传业务规则,仅列表读现有 URL 字段判断有无。
---
## 2. 已确认决策
| 项 | 结论 |
|----|------|
| 落地方案 | **方案 1**:`biz_research_donation` 新增字段 + 创建时取号 |
| 当月核量号格式 | `YYYYMM` + 三位序号,如 `202508001` |
| 取号年月 | 一律按 **创建时间** 所在年月(不看采集时间) |
| 取号时机 | **创建**科研捐赠单时 |
| 历史数据 | **不回填**;旧单该列显示「—」 |
| 展示范围 | **仅列表**(Web + 小程序科研捐赠列表) |
| 附件列 | 有附件 →「有」;无 →「—」 |
| 年/月/日 | 继续用 **采集日期** 一列(不拆三列) |
| 储存状态 | 用 **协议单状态**(`donationStatus`) |
| 协议书 | 对应附件字段 **其他附件**(`attachmentUrls`) |
| 「台词」 | 按 **胎次**(`birthOrder`)理解 |
| 是否同存 | 科研捐赠列表 **去掉** |
| 运费 | **不展示** |
| 软删占用 | 已占用序号 **不回收**(含 `del_flag=1` 计入已用最大序号) |
---
## 3. Excel「科研表」→ 系统映射
| Excel 字段 | 系统处理 |
|------------|----------|
| 序号 | 列表 UI 行号(已有) |
| 年份 / 月 / 日 | **采集日期**(`sampleCollectTime` 日期部分) |
| 当月核量号 | **新字段** `monthly_verify_no` / API `monthlyVerifyNo` |
| 实验室编码 | 已有:实验室流转编号(样本 `labStorageCode` / 样本编码侧展示,与现网「实验室流转编号」一致) |
| 储存状态 | 协议状态 `donationStatus`(Tag) |
| 废弃原因 | 已有:作废相关描述(优先 `voidDesc`;若列表需补充类型文案可用 `voidType` 字典标签,实现时与现网状态变更字段对齐) |
| 母亲姓名 | 已有 |
| 围产期造血干细胞(Excel 品类/去向混用) | 系统展示 **样本类型**(已有) |
| 采集地区 / 采集医院 | 已有 |
| 分娩时间 / 采集时间 | 已有(分娩时间=`newbornDeliveryTime`,采集时间=`sampleCollectTime`) |
| 市场专员 / 地区经理 / 运输方式 | 已有 |
| 运费 | **不要** |
| 性别 / 新生儿体重 / 分娩方式 / 胎次 / 母血采集时间 | 已有 |
| 知情同意书 | `consentFormUrls` 非空 →「有」 |
| (额外)传染病检测报告 | `infectiousDiseaseReportUrls` 非空 →「有」 |
| (额外)协议书 | `attachmentUrls`(其他附件)非空 →「有」 |
| 备注 | 协议备注 `remark` |
---
## 4. UI 规格
### 4.1 Web(`DonationProtocolTab.vue`)
骨架不变:筛选 → 工具栏 → `el-table` → 分页。
视觉:Fresh Mint;状态用 `el-tag`;操作列 `fixed="right"`,`min-width` ≥ 260。
**表格列(从左到右):**
| 列 | 来源 | 说明 |
|----|------|------|
| 选择 | — | 已有 |
| 序号 | 前端 | 当前页行号 |
| 采集日期 | `sampleCollectTime` | `YYYY-MM-DD`;无则「—」 |
| 当月核量号 | `monthlyVerifyNo` | 空则「—」;建议 monospace |
| 实验室流转编号 | 样本实验室编码 | 与现网一致;无则「—」 |
| 协议状态 | `donationStatus` | Tag;列头可用「协议状态」(对应 Excel 储存状态) |
| 废弃原因 | `voidDesc`(及必要时类型标签) | 无则「—」 |
| 母亲姓名 | `motherName` | |
| 样本类型 | 样本类型名 | |
| 采集地区 | `regionName` | |
| 采集医院 | `hospitalName` | |
| 分娩时间 | `newbornDeliveryTime` | |
| 采集时间 | `sampleCollectTime` | 完整时间 |
| 市场专员 | `salesUserName` | |
| 地区经理 | `regionManagerUserName` | |
| 运输方式 | 运输相关字段 | 与现网一致 |
| 新生儿性别 | `newbornSex` | |
| 新生儿体重 | `newbornWeightGram` | |
| 分娩方式 | `deliveryMode` | |
| 胎次 | `birthOrder` | |
| 母血采集时间 | `maternalBloodCollectTime` | |
| 知情同意书 | 附件有无 | 「有」/「—」 |
| 传染病检测报告 | 附件有无 | 「有」/「—」 |
| 协议书 | 附件有无 | 「有」/「—」 |
| 备注 | `remark` | |
| 操作 | — | 已有 |
宽表允许横向滚动;列均用 `min-width`。
### 4.2 小程序(`mobile-oa-h5`)
- 仅当 `source === 'research_donation'` 时切换卡片字段集(细胞存储卡片不变)。
- 卡片标题/副标题可保留母亲姓名 + 实验室流转编号/样本编码;**fields** 覆盖上表业务字段(除选择/序号/操作)。
- 附件三列同样「有」/「—」。
- 当月核量号展示在靠前字段(建议紧随采集日期或实验室编码之后)。
---
## 5. 数据与后端
### 5.1 字段
表 `biz_research_donation` 新增:
| DB 列 | 类型 | 可空 | 说明 |
|-------|------|------|------|
| `monthly_verify_no` | `VARCHAR(16)` | YES | 当月核量号,如 `202508001`;历史为空 |
ORM / `_donation_to_dict` / 列表聚合响应增加 `monthlyVerifyNo`。
建议索引(租户内按号查询与防重):
- `UNIQUE (tenant_no, monthly_verify_no)` — MySQL 下多行 `NULL` 不冲突,符合历史留空。
SQL 迁移放入 `docs/sql/migrations/2026-10-13-research-donation-monthly-verify-no.sql`。
### 5.2 取号算法
创建捐赠单成功写入前:
1. `ym = create_time` 格式化为 `YYYYMM`(服务器时间与写入 `create_time` 一致)。
2. 在同 `tenant_no` 下查询 `monthly_verify_no` 以 `ym` 为前缀的最大序号(**包含** `del_flag=1`,避免软删回收号)。
3. `next = max_seq + 1`;格式化为三位,拼成 `f"{ym}{next:03d}"`。
4. 写入 `monthly_verify_no`;唯一约束冲突时重试有限次。
并发:优先「查最大 + 唯一索引 + 重试」;若实现中发现冲突频繁,可再评估复用 `biz_biz_no_sequence`(本设计不强制新计数器表)。
### 5.3 列表 API
- Web:`fetchResearchDonationList` 所用列表接口须返回本设计所需字段(含 `monthlyVerifyNo`、附件 URL 或布尔有无、临床/采集/作废字段)。若现网列表已 join party/collection/sample,则补序列化即可;缺字段则在 list DTO 中补齐。
- 小程序:`market` 协议列表 `research_donation` 同源字段对齐,供 `protocolCard` 使用。
- 附件有无:**前端**对列表已有 URL 字段(`consentFormUrls` / `infectiousDiseaseReportUrls` / `attachmentUrls`)判非空即可;若某端列表当前未返回这些字段,则在该端 list 序列化中补齐 URL 字符串(不新增布尔字段)。
### 5.4 不变
- 创建以外路径(编辑、状态变更、转换细胞存储等)**不重算、不修改**当月核量号。
- 详情/表单 API 可带上该字段但 UI 不展示(可选,避免双源;最小改动可只在 list 序列化中输出)。
---
## 6. 测试要点
1. 新建科研捐赠:同月连续创建得到 `…001`、`…002`;跨月前缀变化且序号从 `001` 起。
2. 历史单据:迁移后 `monthlyVerifyNo` 为空,列表显示「—」;新建不受历史空值干扰(从 `001` 或已有最大+1)。
3. 软删后再创建:不复用已删单号。
4. Web 列顺序与有无符合 §4.1;无「是否同存」、无运费。
5. 附件:三类 URL 有/无时分别显示「有」/「—」。
6. 小程序科研捐赠卡片字段与 Web 集合一致;细胞存储卡片回归不变。
---
## 7. 影响面
| 区域 | 文件(预期) |
|------|----------------|
| SQL | `docs/sql/migrations/2026-10-13-research-donation-monthly-verify-no.sql` |
| Model / CRUD | `backend/app/models/research_donation.py`,`backend/app/crud/research_donation.py`(create + list 序列化) |
| Market list(若独立) | `backend/app/services/market_protocol.py` 等科研列表装配 |
| Web 列表 | `DonationProtocolTab.vue`;必要时 `research-donation` API 类型 |
| 小程序 | `mobile-oa-h5/src/market/list-presenter.js`(及对应测试) |
| 测试 | 后端取号单测;前端/小程序列表字段契约测试 |
---
## 8. 验收标准
- [ ] 科研捐赠 Web 列表列与 §4.1 一致,细胞存储 Tab 无回归。
- [ ] 新创建单据有正确当月核量号;历史为空显示「—」。
- [ ] 附件三列仅「有」/「—」。
- [ ] 小程序科研捐赠列表字段对齐;细胞存储卡片不变。
- [ ] 迁移 SQL 与模型字段一致,可通过字段一致性相关检查(若适用)。