12 KiB
科研捐赠协议单 · 一键导入增强(单样本 / 多样本)
日期:2026-07-02
状态:已确认 / 已实现
关联模块:web-admin捐赠协议单新增弹窗(DonationFormDialog.vue)
关联常量:SAMPLE_TYPE_PERINATAL_HSC、SAMPLE_TYPE_UC_MSC(sample-production-reception-fields.ts)
1. 背景与目标
1.1 业务诉求
科研捐赠协议单新增时,左侧「一键导入」支持粘贴客户提供的标准文本,解析后自动填充右侧表单。客户文本存在两种典型场景:
- 单样本:如围产期造血干细胞捐献,仅一种样本类型。
- 多样本:如同一产妇同时采集「围产期造血干细胞」与「脐带间充质干细胞」,文本中含多条不同样本的采集时间字段。
当前实现仅支持首行标题推断一个样本类型、固定快递运输、胎次仅识别阿拉伯数字、时间格式不支持「点」,无法正确导入多样本数据。
1.2 目标
- 根据采集时间字段名推断应创建的样本类型与行数(1 行或 N 行)。
- 正确映射运输方式:快递 →
kdys,顺风车等 →ryxd(人员携带)。 - 胎次支持中文数字(如「二胎」→
2)。 - 中文时间支持
18点05分格式(与12时17分等价)。 - 保持「仅填充空白字段、不覆盖已有值」策略。
- 不改后端表结构;协议级
sampleCollectTime取各样本采集时间中的最早值(已确认:选项 A)。
1.3 非目标(本期不做)
- 样本表增加独立
sample_collect_time字段(方案 B,后续若产品要求再立项)。 - 配置化规则引擎(JSON/YAML 运营可改规则)。
- 细胞存储协议单一键导入(本模块无此功能)。
- 一键导入 UI 布局变更(仍为新增弹窗左侧粘贴区 + 右侧表单)。
2. 客户文本样例
2.1 单样本(捐献)
围产期干细胞(捐献)
产妇姓名:李会
新生儿性别:男
新生儿体重:3900g
新生儿评分: 9
分娩时间:2026年6月22日12时17分
造血干细胞采集时间:2026年6月22日12时18分
母血采集时间:未采集
分娩方式:顺产
胎次:3
采集医护:王天琪
采集医院:利辛县人民医院
运输方式:顺丰快递
销售人员:赵文静
采集医院:利辛县人民医院
期望结果:1 条样本(围产期造血干细胞);运输 kdys + 顺丰;胎次 3。
2.2 多样本(科研脐带)
围产期干细胞(科研脐带)
产妇姓名:陆玲
新生儿性别:男孩
新生儿体重:3700g
分娩时间:2026年3月14日 18点05分
造血干细胞样本采集时间:2026年3月14日 18点06分
脐带采集时间:2026年3月14日 18点08分
母血采集时间:2026年3月14日 19点40分
分娩方式:顺产
胎次:二胎
运输方式:顺风车
销售人员:张慧茹
采集医院:涡阳县中医院
期望结果:2 条样本(围产期造血干细胞、脐带间充质干细胞);协议级 sampleCollectTime = 2026-03-14 18:06(最早);运输 ryxd,不填快递公司;胎次 2。
3. 业务规则
3.1 样本类型推断(优先级)
| 优先级 | 规则 | 说明 |
|---|---|---|
| 1 | 采集时间字段 | 存在且值可解析 → 创建对应样本行(可多条) |
| 2 | 首行标题 | 无采集时间字段时,回退现有 matchCellSampleType(header) 逻辑 |
采集时间字段 → 样本类型映射:
| 字段名(含别名) | 目标类型名 | typeKey |
|---|---|---|
造血干细胞样本采集时间、造血干细胞采集时间、样本采集时间 |
围产期造血干细胞 | hsc |
脐带采集时间 |
脐带间充质干细胞 | uc_msc |
- 同一 typeKey 在文本中多次出现:以首次有效时间为准。
- 字段值为空或「未采集」等占位:不创建该样本行。
- 多样本场景下,首行标题不参与样本类型决定(避免「围产期干细胞(科研脐带)」歧义)。
3.2 协议级样本采集时间(已确认)
- 存储位置:
formData.sampleCollectTime→biz_research_donation_collection.sample_collect_time。 - 多样本:取所有已识别样本采集时间中的最早时间(minute 精度
YYYY-MM-DD HH:mm)。 - 单样本:该样本采集时间写入协议级字段(与现逻辑一致)。
- 若协议级字段已有值:不覆盖(空白才填)。
3.3 运输方式映射
客户文本字段仍为 运输方式;解析结果区分 模式 与 原始标签:
| 客户文本特征 | transportType |
后续处理 |
|---|---|---|
| 含「快递」「顺丰」「圆通」「中通」「韵达」「EMS」等 | kdys |
匹配 expressCompanyId(现有 matchExpressCompany) |
| 含「顺风车」「顺丰车」(后者为笔误)、「自行」「人员携带」「自带」「自送」等 | ryxd |
不填 expressCompanyId;可选后续人工填携带人 |
| 无法识别 | — | warning,不填运输 |
- 多样本时:各样本行复制同一套运输配置(客户数据中通常一致)。
- 仅当样本行
transport.transportType为空时写入。
3.4 胎次
| 输入示例 | 解析结果 |
|---|---|
3 |
3 |
二胎、三胎 |
2、3 |
第二胎 |
2 |
| 无法解析 | warning,不填 |
实现:parseBirthOrder(text) — 先 extractNumericPart;若无阿拉伯数字,再解析中文数字(一~十及「N胎」模式)。
3.5 其他字段(保持 / 微调)
| 字段 | 规则 |
|---|---|
| 新生儿性别 | 扩展识别 男孩→1、女孩→0 |
| 母血采集时间 | 「未采集」等 → 清空(已有) |
| 采集医院重复行 | 首次有效值为准(已有) |
| 母亲 / 医院 / 销售 | 远程匹配(已有) |
| 样本编码 | 每行样本 assignDonationSampleCodeIfMissing(已有) |
3.6 填充策略(不变)
- 仅填空:目标字段为空才写入。
- 样本行:若
formData.samples已有同类型样本且sampleTypeId非空,不重复添加;若为空行可复用。 - 导入完成后:
ElMessage.success列出已填充项;ElMessage.warning列出未匹配项。
4. 技术设计
4.1 解析层结构变更
文件:web-admin/src/utils/donation-standard-import-parse.ts
扩展 DonationStandardImportParsed(或新增子类型):
export type DonationSampleImportHint = {
typeKey: 'hsc' | 'uc_msc'
typeName: string
collectTime?: string // 已解析为标准 datetime-minute
}
export type DonationStandardImportParsed = {
sampleTypeHeader: string
sampleHints: DonationSampleImportHint[] // 新增:0..N
transportModeText?: string // 原始运输方式文本
transportType?: 'kdys' | 'ryxd' // 新增:解析后的系统码
// ... 现有 common 字段保持不变
}
新增 / 导出函数:
| 函数 | 职责 |
|---|---|
parseBirthOrder(text) |
阿拉伯 + 中文胎次 |
resolveTransportType(text) |
运输文本 → kdys | ryxd | null |
matchSampleTypeByExactName(name, types) |
按 typeName 精确匹配(优先于 segment 评分) |
采集时间字段识别:在 KEY_ALIASES 之外,对 key 做 pattern 匹配(支持「造血干细胞样本采集时间」等变体),命中后写入 sampleHints 而非单一 sampleCollectTime。
回退:sampleHints.length === 0 时,保留现有 sampleCollectTime + 首行 matchCellSampleType 行为。
4.2 时间解析增强
文件:web-admin/src/utils/chinese-datetime-parse.ts
- 正则扩展:
[时::点]均视为小时分隔符。 - 例:
2026年3月14日 18点06分→2026-03-14 18:06。
可选新文件:web-admin/src/utils/chinese-numeral-parse.ts
parseChineseNumeral(text: string): number | null— 支持「二」「二胎」「三胎」等;供parseBirthOrder调用。
4.3 填充层变更
文件:web-admin/src/views/research-donation/list/DonationFormDialog.vue — handleStandardImport()
1. parseDonationStandardImportText(text)
2. 并行:母亲 / 医院 / 销售 / 字典预加载(现有)
3. common 字段填空(性别、体重、评分、分娩时间、母血、分娩方式、胎次、医护…)
4. 样本行:
if sampleHints.length > 0:
for each hint:
matchSampleTypeByExactName(hint.typeName)
获取或创建对应样本行
assignDonationSampleCodeIfMissing
sampleCollectTime = min(hint.collectTime) // 最早
else:
现有单样本逻辑(首行 + 一行样本)
5. 运输:
if parsed.transportType === 'kdys': 匹配快递公司
if parsed.transportType === 'ryxd': transportType=ryxd,跳过 expressCompanyId
6. hydrateSampleLookupOptions + 消息反馈
4.4 数据模型(无变更)
| 实体 | 字段 | 说明 |
|---|---|---|
biz_research_donation_collection |
sample_collect_time |
协议级;多样本取最早采集时间 |
biz_research_donation_sample |
— | 无 per-sample 采集时间;本期不加 |
biz_research_donation_sample_transport |
transport_type |
kdys / ryxd |
5. 测试
新建:web-admin/src/utils/donation-standard-import-parse.test.ts(或项目现有 vitest 路径)
| 用例 | 断言 |
|---|---|
| 单样本完整文本(§2.1) | 1 个 hint(hsc);transportType=kdys;birthOrder=3 |
| 多样本完整文本(§2.2) | 2 个 hint(hsc+uc_msc);最早时间 18:06;transportType=ryxd;birthOrder=2 |
| 胎次「二胎」「3」 | 2、3 |
| 时间「18点06分」「12时18分」 | 等价解析 |
| 仅首行无采集时间 | sampleHints 空,回退首行匹配 |
| 运输「顺风车」「顺丰快递」 | ryxd / kdys |
手工验收(/#/market/research-donation/audit 或 list 页新增):
- 粘贴 §2.1 → 1 样本、顺丰、胎次 3。
- 粘贴 §2.2 → 2 样本、人员携带、协议采集时间 18:06、胎次 2。
- 先手动填部分字段再导入 → 已填字段不被覆盖。
6. 改动文件清单
| 文件 | 改动类型 |
|---|---|
web-admin/src/utils/donation-standard-import-parse.ts |
扩展解析:多样本 hints、运输、胎次 |
web-admin/src/utils/chinese-datetime-parse.ts |
支持「点」 |
web-admin/src/utils/chinese-numeral-parse.ts |
新建(可选,也可内联于 parse 文件) |
web-admin/src/views/research-donation/list/DonationFormDialog.vue |
handleStandardImport 多样本 + 运输 |
web-admin/src/utils/donation-standard-import-parse.test.ts |
新建单元测试 |
不改:backend/、docs/sql/、OpenSpec(除非评审要求补充 ui-conventions 条目)。
7. 风险与限制
- 协议级采集时间:多样本各时间不同,列表/采集信息页仅展示一个时间;业务接受「最早时间」代表协议(已确认)。
- 运输携带人:
ryxd模式下客户文本通常不含携带人姓名;导入后可能需人工补全。 - 未知样本类型:若未来出现第三种采集时间字段,需扩展
SAMPLE_COLLECT_TIME_RULES;本期仅 hsc / uc_msc。
8. 验收标准
- §2.1 单样本文本一键导入后,样本 Tab 有 1 行「围产期造血干细胞」,运输为快递运输 + 顺丰。
- §2.2 多样本文本一键导入后,样本 Tab 有 2 行(造血 + 脐带),运输为人员携带,协议采集时间为 18:06。
- 胎次「二胎」解析为 2;「3」解析为 3。
18点06分时间正确解析。- 已有字段不被覆盖;单元测试通过。
9. 决策记录
| 日期 | 决策 | 理由 |
|---|---|---|
| 2026-07-02 | 方案 A:纯前端增强,不改表 | 最小改动、与现架构一致 |
| 2026-07-02 | 协议级 sampleCollectTime 取最早采集时间 |
用户确认选项 A |
| 2026-07-02 | 多样本以采集时间字段为准,首行标题仅作回退 | 避免标题歧义 |