311 lines
15 KiB
Markdown
311 lines
15 KiB
Markdown
# 预产及在途样本 — 功能设计
|
||
|
||
**日期**: 2026-06-23
|
||
**状态**: 已实现
|
||
**界面模式**: P27 衍生列表(只读监控)+ 双分区单页;**列表样式对齐采集协议单列表**
|
||
**参考页**: `web-admin/src/views/cell-storage/protocol/index.vue`(列表壳层与列风格)、`research-donation/list/index.vue`(捐赠侧字段对齐)、`collection_protocol.py` 列表 `_row_to_dict`(样本概要字段)
|
||
|
||
## 1. 需求背景
|
||
|
||
客户在【质检管理】菜单下、【样本接收】上方新增 **【预产及在途样本】** 页面,用于质检人员集中查看接收前的两类待办:
|
||
|
||
| 分区 | 业务含义 | 列表粒度 |
|
||
|------|----------|----------|
|
||
| **上半区 · 在途样本** | 协议下存在 **已采集、未接收** 样本的协议单 | **协议单行**(样本为行内展示字段) |
|
||
| **下半区 · 预产样本** | 协议已建且 **样本未录入** 和/或 **样本未采集** | **协议单行**(样本为行内展示字段) |
|
||
|
||
**已确认展示维度(2026-06-23)**:上下半区均采用 **协议单维度** 展示;样本编码、类型、采集概况、运输/预计到达等作为 **协议行内的概要信息**,不拆成样本级多行。
|
||
|
||
**已确认列表样式**:参照 **【采集协议单】** 列表(`cell-storage/protocol/index.vue`)——`panel-top` + `filter-block` + `list-table`(`stripe`、列居中、`el-tag` 状态)+ `list-pager-bar`;**无**新增/编辑/删除工具栏与勾选列,操作列仅「查看」。
|
||
|
||
**已确认交互**:两个分区列表 **操作列仅「查看」**;按来源打开对应协议查看弹窗(采集 → `ProtocolViewDialog`,捐赠 → `DonationViewDialog`)。**不提供**接收、编辑、跳转样本接收等操作。
|
||
|
||
**已确认数据规则(上半区)**:仅展示 **`sample_status = 'ycj'`(已采集)且尚无有效接收记录** 的样本。
|
||
|
||
## 2. 与现有模块关系
|
||
|
||
- **【样本接收】**:操作入口(登记接收、批量接收、触发质检工单);本页为 **只读看板**,与之互补。
|
||
- **【采集协议单】列表**:列布局、筛选区结构、表格视觉的直接模板(见 §5.2)。
|
||
- **样本采集信息 Tab**:仅作查看弹窗 `handleView` 参考,不作列表列模板。
|
||
- **跨表关联键**:判断是否已接收 SHALL 使用 `tenant_no` + `sample_code`(OpenSpec `api-conventions` § 细胞存储样本跨表关联键),与 `sample_reception.py` 现有逻辑一致。
|
||
|
||
## 3. 数据判定规则
|
||
|
||
> **列表粒度**:先按 §3.1 / §3.2 判定 **协议是否入选**;再在行内挂载 **与本分区相关的样本概要**(`sampleItems` 为过滤后的子集,见 §3.4)。
|
||
|
||
### 3.1 上半区 · 在途(协议入选条件)
|
||
|
||
协议入选当且仅当:在其 `del_flag=0` 的样本子表中,**存在至少一条**同时满足:
|
||
|
||
```
|
||
sample_status = 'ycj'
|
||
AND NOT EXISTS 有效 biz_sample_reception(tenant_no + sample_code)
|
||
```
|
||
|
||
且协议本身:
|
||
|
||
```
|
||
del_flag = 0
|
||
AND tenant_no = 当前用户租户
|
||
AND protocol_status / donation_status NOT IN ('yzf', 'zky', 'zckc', 'ygq')
|
||
```
|
||
|
||
**行内样本展示(`sampleItems`)**:仅包含满足上述「在途」条件的样本行;附带各样本运输字段(`etaTime`、`waybillNo` 等)。
|
||
**行内汇总字段**(复用采集协议单列表逻辑):
|
||
|
||
- `sampleCodes`、`sampleTypeNames`、`labStorageCodes` — 由在途样本拼接
|
||
- `sampleCollectSummary` — 仅统计在途样本,如「2个已采集(待接收)」
|
||
- `etaTimeSummary` — 在途样本中最早的预计到达(用于排序与列展示,实施时命名可调整)
|
||
|
||
**协议级排序**:`etaTimeSummary` 升序(空值靠后)→ 协议 `create_time` 升序。
|
||
|
||
**关键词**:协议号、母亲姓名/电话/身份证、在途样本编码、实验室入库编码。
|
||
|
||
### 3.2 下半区 · 预产(协议入选条件)
|
||
|
||
协议入选当满足 **公共协议条件** 且符合 **下列 A 或 B**:
|
||
|
||
**公共协议条件**:
|
||
|
||
```
|
||
del_flag = 0
|
||
AND tenant_no = 当前用户租户
|
||
AND protocol_status / donation_status IN ('dsx', 'sxz') -- 排除 ygq
|
||
AND NOT IN ('yzf', 'zky', 'zckc')
|
||
```
|
||
|
||
| 子场景 | preDeliveryKind | 入选条件 |
|
||
|--------|-----------------|----------|
|
||
| A · 样本未录入 | `no_sample` | 无任何 `del_flag=0` 样本子表行 |
|
||
| B · 样本未采集 | `uncollected` | 存在 `sample_status` 为空的样本行 |
|
||
|
||
同一协议若同时无样本行与未采集样本不可能并存;若 **仅有未采集样本** 为 `uncollected`;**仅有零样本** 为 `no_sample`。若协议同时含未采集样本与在途样本,**可同时出现在上下两区**(各分区一行,样本概要不同)。
|
||
|
||
**行内样本展示**:
|
||
|
||
- `no_sample`:`sampleItems=[]`,`sampleCollectSummary` 展示「样本未录入」
|
||
- `uncollected`:`sampleItems` 仅含未采集样本;`sampleCollectSummary` 如「2个未采集」
|
||
|
||
**协议级排序**:预产期 `expected_delivery_date` 降序 → 协议 `create_time` 降序。
|
||
|
||
**关键词**:协议号、母亲姓名/电话/身份证、未采集样本编码。
|
||
|
||
### 3.3 数据归属总览(协议维度)
|
||
|
||
| 场景 | 上半区 · 在途 | 下半区 · 预产 |
|
||
|------|---------------|---------------|
|
||
| 协议无样本行 | — | **展示**(`no_sample`) |
|
||
| 仅有未采集样本 | — | **展示**(`uncollected`) |
|
||
| 仅有已采集未接收样本 | **展示** | — |
|
||
| 兼有未采集 + 已采集未接收 | **展示**(在途概要) | **展示**(未采集概要) |
|
||
| 全部样本已接收 | — | — |
|
||
|
||
### 3.4 行内样本概要结构(与采集协议单列表对齐)
|
||
|
||
后端复用 `collection_protocol.list` / `research_donation.list` 的组装方式,统一返回:
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `sampleItems[]` | `{ sampleTypeName, sampleCode, sampleStatus, labStorageCode, transport? }`,**已按分区过滤** |
|
||
| `sampleTypeNames` | 逗号拼接 |
|
||
| `sampleCodes` | 逗号拼接 |
|
||
| `labStorageCodes` | 逗号拼接 |
|
||
| `sampleCollectSummary` | 文字概要(分区语义不同) |
|
||
| `preDeliveryKind` | 仅下半区:`no_sample` / `uncollected`(协议同时仅一种预产态;若仅 `uncollected` 则标 `uncollected`) |
|
||
|
||
上半区在途样本的 `transport.etaTime` 可汇总到列 **预计到达**(多样本取最早或展示「详见概要」,实施取最早一条)。
|
||
|
||
## 4. 后端设计
|
||
|
||
### 4.1 新增 API(推荐独立模块,方案 A)
|
||
|
||
| 接口 | 方法 | 路径 | 说明 |
|
||
|------|------|------|------|
|
||
| 在途样本列表 | GET | `/web/admin/pre-transit-samples/in-transit` | 上半区 |
|
||
| 预产协议列表 | GET | `/web/admin/pre-transit-samples/pre-delivery` | 下半区 |
|
||
|
||
**公共查询参数**:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| page | int | 页码 |
|
||
| pageSize | int | 每页条数(≤100) |
|
||
| keyword | string | 关键词 |
|
||
| sourceType | string | 可选:`cell_storage` / `research_donation`,空=全部 |
|
||
|
||
**在途列表额外参数**(可选一期):
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| etaTimeStart | string | 预计到达开始 YYYY-MM-DD |
|
||
| etaTimeEnd | string | 预计到达结束 YYYY-MM-DD |
|
||
|
||
**权限**:`require_menu_code("biz:preTransitSample:list")`;`apply_data_scope` 挂在 **协议主表**(`BizCollectionProtocol` / `BizResearchDonation`),与采集协议单列表一致。
|
||
|
||
**实现要点**:
|
||
|
||
1. 先查询符合分区条件的 **协议 ID 集合**(采集 + 捐赠 UNION,分页在协议级)。
|
||
2. 批量加载当事人、采集信息、样本、运输、接收记录,组装与 `list_collection_protocols` 同构的协议行。
|
||
3. 按分区规则 **过滤 `sampleItems`** 并生成 `sampleCollectSummary` 等概要字段。
|
||
|
||
**实现文件**:
|
||
|
||
- `backend/app/crud/pre_transit_sample.py` — 协议级查询与行组装(可抽取与 `collection_protocol` 共用的样本概要 helper)
|
||
- `backend/app/api/pre_transit_sample.py` — 路由
|
||
- 注册:`app/api/__init__.py`、`app/main.py`
|
||
|
||
### 4.2 列表响应字段(上下半区均为协议行)
|
||
|
||
在 **采集协议单列表行** 基础上扩展,细胞存储与捐赠 **字段名统一**(捐赠的 `donationStatus` 映射为 `protocolStatus` 展示,`donationNo` 映射为 `docNo` 或保留双字段由前端列模板分支)。
|
||
|
||
**协议主信息**(对齐 `protocol/index.vue` 列):
|
||
|
||
| 字段 | 列名 |
|
||
|------|------|
|
||
| sourceType, sourceTypeLabel | 来源类型(新增,Tag 展示) |
|
||
| protocolStatus | 状态 |
|
||
| registerDate / donationDate | 登记日期 |
|
||
| motherName, motherPhone, motherIdCard | 母亲信息 |
|
||
| fatherName | 父亲姓名 |
|
||
| newbornSex, deliveryMode, newbornWeightGram | 新生儿信息 |
|
||
| regionName, hospitalName | 采集地区/医院 |
|
||
| collectorUserName, salesUserName | 采集专员/销售 |
|
||
| sampleCollectTime | 样本采集时间 |
|
||
| createTime | 创建时间 |
|
||
| expectedDeliveryDate | 预产期(下半区排序用,上半区可展示) |
|
||
|
||
**样本概要**(行内展示,非独立行):
|
||
|
||
| 字段 | 列名建议 |
|
||
|------|----------|
|
||
| sampleTypeNames | 样本类型 |
|
||
| sampleCodes | 样本编码 |
|
||
| labStorageCodes | 实验室入库编码 |
|
||
| sampleCollectSummary | 样本采集概况 |
|
||
| etaTimeSummary | 预计到达(**上半区**) |
|
||
| preDeliveryKindLabel | 预产类型(**下半区**:样本未录入 / 样本未采集) |
|
||
|
||
**查看用 ID**:`collectionProtocolId` 或 `researchDonationId`(二选一有值)、`sourceType`。
|
||
|
||
### 4.3 预产列表响应字段
|
||
|
||
与 §4.2 相同;额外必有 `preDeliveryKind`、`preDeliveryKindLabel`。
|
||
|
||
## 5. 前端设计
|
||
|
||
### 5.1 菜单与路由
|
||
|
||
| 项 | 值 |
|
||
|----|-----|
|
||
| 菜单名 | 预产及在途样本 |
|
||
| 父级 | 质检管理 `QCM00000000000000000000000000001` |
|
||
| 排序 | `order_num = 0`(位于样本接收 `order_num = 1` 之上) |
|
||
| 路由 path | `pre-transit-sample` |
|
||
| 组件 | `/quality-inspection/pre-transit-sample/index` |
|
||
| menuCode | `biz:preTransitSample:list` |
|
||
|
||
同步修改 `web-admin/src/router/modules/sqxp.ts`。
|
||
|
||
### 5.2 页面结构(对齐采集协议单列表)
|
||
|
||
```
|
||
page-container
|
||
└── section.panel
|
||
├── filter-block(结构同 protocol/index.vue:关键词、来源类型、创建时间等;下半区可不单独筛预产类型)
|
||
├── panel-top → h2.title-bar-heading「在途样本」
|
||
├── list-body.list-wrap
|
||
│ ├── el-table.list-table(列布局参照 protocol/index.vue + 来源/样本概要列)
|
||
│ └── pagination.list-pager-bar
|
||
├── panel-top → h2.title-bar-heading「预产样本」
|
||
└── list-body.list-wrap(同上)
|
||
```
|
||
|
||
**与采集协议单列表的差异**:
|
||
|
||
| 采集协议单列表 | 本页 |
|
||
|----------------|------|
|
||
| 有勾选列、新增/批量删除工具栏 | **无**工具栏、无勾选 |
|
||
| 操作:查看 + 更多(编辑/删除) | **仅查看**(`btn-op-item` + View,与协议列表查看按钮一致,不设 `primary` 亦可与协议页保持一致) |
|
||
| 仅细胞存储 | 增加 **来源类型** 列;捐赠行状态 Tag 用 `donationStatusTagType` |
|
||
| 无双分区 | **上下两个独立表格 + 分页** |
|
||
|
||
**表格列(建议顺序)**:序号 → 来源类型 → 状态 → 登记日期 → 母亲姓名 → 母亲电话 → 母亲身份证 → 父亲姓名 → 新生儿性别 → 分娩方式 → 新生儿体重 → 采集地区 → 采集医院 → 采集专员 → 销售 → **样本类型** → **样本编码** → **样本采集概况** → 样本采集时间 → **预计到达**(上半区)/ **预产类型**(下半区)→ 创建时间 → 操作。
|
||
|
||
- 列表:`list-table` + `stripe`;列 `align="center"`;状态/来源用 `el-tag`。
|
||
- **在途列表不对预计到达过期行标红**。
|
||
- 操作列:`fixed="right"`,`min-width ≥ 120`。
|
||
- 两个分区 **独立分页**。
|
||
|
||
**实现建议**:抽取 `ProtocolListTableColumns` 或在本页复制 `protocol/index.vue` 列定义并追加样本概要列,避免与录入页工具栏耦合。
|
||
|
||
### 5.3 查看交互
|
||
|
||
```typescript
|
||
function handleView(row) {
|
||
if (row.sourceType === 'research_donation') {
|
||
// DonationViewDialog :donation-id="row.researchDonationId"
|
||
} else {
|
||
// ProtocolViewDialog :protocol-id="row.collectionProtocolId"
|
||
}
|
||
}
|
||
```
|
||
|
||
挂载组件(默认配置,不展开审核/储存证等扩展 Tab):
|
||
|
||
- `@/views/cell-storage/protocol/ProtocolViewDialog.vue`
|
||
- `@/views/research-donation/list/DonationViewDialog.vue`
|
||
|
||
参照:`SampleCollectionInfoTab.vue`、`DonationSampleCollectionInfoTab.vue` 的 `handleView` 与 `listRow` 摘要传参。
|
||
|
||
### 5.4 API 模块
|
||
|
||
**文件**:`web-admin/src/api/pre-transit-sample.ts`
|
||
|
||
- `fetchPreTransitInTransitList(params)`
|
||
- `fetchPreTransitPreDeliveryList(params)`
|
||
|
||
## 6. 数据库与权限 SQL
|
||
|
||
**文件**:`docs/sql/alter_sys_menu_add_pre_transit_sample.sql`
|
||
|
||
- 新增菜单 C 类型:`biz:preTransitSample:list`
|
||
- 新增按钮 F 类型:`biz:preTransitSample:list`(查询,与菜单 perms 一致即可)
|
||
- 将原「样本接收」`order_num` 调整为 2(若新菜单占 1)或新菜单 0、样本接收保持 1
|
||
|
||
菜单 `id` 使用新 UUID(实施时生成,避免与现有冲突)。
|
||
|
||
## 7. 非目标(一期不做)
|
||
|
||
- 列表导出
|
||
- 从本页直接接收样本
|
||
- 双击行打开查看(可二期加,一期仅按钮)
|
||
- 修改【样本接收】待接收 Tab 的过滤逻辑(保持现网行为)
|
||
|
||
## 8. 测试要点
|
||
|
||
1. 上半区:仅含「存在 ycj 且未接收样本」的协议;行内 `sampleItems` 仅含在途样本;已接收、纯未采集协议不出现。
|
||
2. 下半区:仅 `dsx`/`sxz` 且非 `ygq`;`no_sample` / `uncollected` 协议各一行;同一协议可同时出现在上下区时样本概要不同。
|
||
3. 列表为协议维度,列风格与采集协议单列表一致;样本信息以概要列展示,非样本级多行。
|
||
3. 细胞存储行点查看打开 `ProtocolViewDialog`;捐赠行打开 `DonationViewDialog`。
|
||
4. 租户隔离、数据权限与关键词搜索正确。
|
||
5. 菜单显示在样本接收上方;无权限用户不可访问 API。
|
||
|
||
## 9. 已确认项汇总
|
||
|
||
| # | 项 | 结论 |
|
||
|---|-----|------|
|
||
| 1 | 上半区数据范围 | **仅 `ycj` + 未接收** |
|
||
| 2 | 操作列 | **仅查看** |
|
||
| 3 | 查看目标 | 采集 → 采集协议单;捐赠 → 捐赠协议单 |
|
||
| 4 | 布局 | 上下双分区、分开展示 |
|
||
| 5 | 来源 | 采集协议单 + 捐赠协议单均覆盖 |
|
||
| 6 | 下半区协议状态 | **仅 `dsx` + `sxz`,排除 `ygq` 已过期** |
|
||
| 7 | 在途过期样式 | **不标红、不特殊标记预计到达已过期行** |
|
||
| 8 | 下半区数据范围 | **样本未录入 + 样本未采集** |
|
||
| 9 | 列表粒度 | **上下半区均为协议单维度**;样本为行内概要字段 |
|
||
| 10 | 列表样式 | **参照采集协议单列表**(`protocol/index.vue`) |
|
||
|
||
## 10. 待确认(可选,不阻塞开发)
|
||
|
||
1. 筛选区是否在共用关键词之外,为在途区单独提供「预计到达日期」范围?
|