日期: 2026-06-23
状态: 已实现
界面模式: P27 衍生列表(只读监控)+ 双分区单页;列表样式对齐采集协议单列表
参考页: web-admin/src/views/cell-storage/protocol/index.vue(列表壳层与列风格)、research-donation/list/index.vue(捐赠侧字段对齐)、collection_protocol.py 列表 _row_to_dict(样本概要字段)
客户在【质检管理】菜单下、【样本接收】上方新增 【预产及在途样本】 页面,用于质检人员集中查看接收前的两类待办:
| 分区 | 业务含义 | 列表粒度 |
|---|---|---|
| 上半区 · 在途样本 | 协议下存在 已采集、未接收 样本的协议单 | 协议单行(样本为行内展示字段) |
| 下半区 · 预产样本 | 协议已建且 样本未录入 和/或 样本未采集 | 协议单行(样本为行内展示字段) |
已确认展示维度(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'(已采集)且尚无有效接收记录 的样本。
handleView 参考,不作列表列模板。tenant_no + sample_code(OpenSpec api-conventions § 细胞存储样本跨表关联键),与 sample_reception.py 现有逻辑一致。列表粒度:先按 §3.1 / §3.2 判定 协议是否入选;再在行内挂载 与本分区相关的样本概要(
sampleItems为过滤后的子集,见 §3.4)。
协议入选当且仅当:在其 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 升序。
关键词:协议号、母亲姓名/电话/身份证、在途样本编码、实验室入库编码。
协议入选当满足 公共协议条件 且符合 下列 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 降序。
关键词:协议号、母亲姓名/电话/身份证、未采集样本编码。
| 场景 | 上半区 · 在途 | 下半区 · 预产 |
|---|---|---|
| 协议无样本行 | — | 展示(no_sample) |
| 仅有未采集样本 | — | 展示(uncollected) |
| 仅有已采集未接收样本 | 展示 | — |
| 兼有未采集 + 已采集未接收 | 展示(在途概要) | 展示(未采集概要) |
| 全部样本已接收 | — | — |
后端复用 collection_protocol.list / research_donation.list 的组装方式,统一返回:
| 字段 | 说明 |
|---|---|
sampleItems[] |
{ sampleTypeName, sampleCode, sampleStatus, labStorageCode, transport? },已按分区过滤 |
sampleTypeNames |
逗号拼接 |
sampleCodes |
逗号拼接 |
labStorageCodes |
逗号拼接 |
sampleCollectSummary |
文字概要(分区语义不同) |
preDeliveryKind |
仅下半区:no_sample / uncollected(协议同时仅一种预产态;若仅 uncollected 则标 uncollected) |
上半区在途样本的 transport.etaTime 可汇总到列 预计到达(多样本取最早或展示「详见概要」,实施取最早一条)。
| 接口 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 在途样本列表 | 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),与采集协议单列表一致。
实现要点:
list_collection_protocols 同构的协议行。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在 采集协议单列表行 基础上扩展,细胞存储与捐赠 字段名统一(捐赠的 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.2 相同;额外必有 preDeliveryKind、preDeliveryKindLabel。
| 项 | 值 |
|---|---|
| 菜单名 | 预产及在途样本 |
| 父级 | 质检管理 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。
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 列定义并追加样本概要列,避免与录入页工具栏耦合。
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 摘要传参。
文件:web-admin/src/api/pre-transit-sample.ts
fetchPreTransitInTransitList(params)fetchPreTransitPreDeliveryList(params)文件:docs/sql/alter_sys_menu_add_pre_transit_sample.sql
biz:preTransitSample:listbiz:preTransitSample:list(查询,与菜单 perms 一致即可)order_num 调整为 2(若新菜单占 1)或新菜单 0、样本接收保持 1菜单 id 使用新 UUID(实施时生成,避免与现有冲突)。
sampleItems 仅含在途样本;已接收、纯未采集协议不出现。dsx/sxz 且非 ygq;no_sample / uncollected 协议各一行;同一协议可同时出现在上下区时样本概要不同。ProtocolViewDialog;捐赠行打开 DonationViewDialog。| # | 项 | 结论 |
|---|---|---|
| 1 | 上半区数据范围 | 仅 ycj + 未接收 |
| 2 | 操作列 | 仅查看 |
| 3 | 查看目标 | 采集 → 采集协议单;捐赠 → 捐赠协议单 |
| 4 | 布局 | 上下双分区、分开展示 |
| 5 | 来源 | 采集协议单 + 捐赠协议单均覆盖 |
| 6 | 下半区协议状态 | 仅 dsx + sxz,排除 ygq 已过期 |
| 7 | 在途过期样式 | 不标红、不特殊标记预计到达已过期行 |
| 8 | 下半区数据范围 | 样本未录入 + 样本未采集 |
| 9 | 列表粒度 | 上下半区均为协议单维度;样本为行内概要字段 |
| 10 | 列表样式 | 参照采集协议单列表(protocol/index.vue) |