# 样本特殊标记 Implementation Plan > **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:** 在采集/捐赠协议单样本上维护 `isSpecial` + `specialRemark`,并在 web-admin 全链路只读展示红色加粗警示。 **Architecture:** 字段仅存 `biz_protocol_sample` / `biz_research_donation_sample`;下游 API JOIN 源表补字段;前端 `SpecialSampleDisplay` 统一渲染。 **Tech Stack:** FastAPI + SQLAlchemy + Vue 3 + Element Plus **Spec:** `docs/superpowers/specs/2026-07-01-special-sample-mark-design.md` --- ## File Map | 文件 | 职责 | |------|------| | `docs/sql/migrate-special-sample-mark.sql` | DDL 增量脚本 | | `backend/app/utils/sample_special.py` | 校验 + dict 转换工具 | | `backend/app/models/models.py` | `BizProtocolSample` 新列 | | `backend/app/models/research_donation.py` | `BizResearchDonationSample` 新列 | | `backend/app/crud/collection_protocol.py` | `_sample_to_dict` / `save_samples` / list sampleItems | | `backend/app/crud/research_donation.py` | 同上 + 转存储复制 | | `backend/app/crud/qc_work_order.py` | `_enrich_work_order_list_items` 补字段 | | `backend/app/crud/sample_reception.py` | 待/已接收 list item | | `backend/app/crud/protocol_sample_collection.py` | 样本采集信息 list | | `backend/app/crud/research_donation_sample_collection.py` | 捐赠样本采集 list | | `backend/app/crud/pre_transit_sample.py` | 转运前样本卡片 items | | `backend/app/crud/storage_release_review.py` | 入库审核 detail | | `backend/app/crud/cell_product.py` | 溯源链样本信息 | | `web-admin/src/components/business/special-sample-display/index.vue` | 公共展示组件 | | `web-admin/src/components/business/sample-transport-form-section/index.vue` | 录入 | | `web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue` | 采集查看 | | `web-admin/src/views/research-donation/list/DonationViewDialog.vue` | 捐赠查看 | | 下游 15+ vue 页面 | 样本编码旁 inline 展示 | --- ## Task 1: 数据库与 Model **Files:** - Create: `docs/sql/migrate-special-sample-mark.sql` - Modify: `backend/app/models/models.py`, `backend/app/models/research_donation.py` - [ ] **Step 1:** 执行 DDL(两表对称) ```sql ALTER TABLE `biz_protocol_sample` ADD COLUMN `is_special` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否特殊样本:0否 1是' AFTER `storage_expire_date`, ADD COLUMN `special_remark` varchar(256) DEFAULT NULL COMMENT '特殊说明' AFTER `is_special`; ALTER TABLE `biz_research_donation_sample` ADD COLUMN `is_special` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否特殊样本:0否 1是' AFTER `storage_expire_date`, ADD COLUMN `special_remark` varchar(256) DEFAULT NULL COMMENT '特殊说明' AFTER `is_special`; ``` - [ ] **Step 2:** ORM 增加 `is_special = Column(SmallInteger...)` 与 `special_remark = Column(String(256)...)` --- ## Task 2: 后端工具与核心 CRUD **Files:** - Create: `backend/app/utils/sample_special.py` - Modify: `backend/app/crud/collection_protocol.py`, `backend/app/crud/research_donation.py` - [ ] **Step 1:** 创建工具函数 ```python def sample_special_to_dict(sample) -> Dict[str, Any]: ... def validate_sample_special_raw(raw: dict, *, index: Optional[int] = None) -> None: ... def apply_sample_special_fields(obj, raw: dict) -> None: ... ``` - [ ] **Step 2:** `_sample_to_dict` 增加 `isSpecial` / `specialRemark` - [ ] **Step 3:** `save_samples` / `_create_samples` 循环内调用 `validate_sample_special_raw` + `apply_sample_special_fields` - [ ] **Step 4:** `research_donation.py` 转存储复制 `is_special`、`special_remark` - [ ] **Step 5:** `collection_protocol.py` 列表 `sampleItems` 构建补字段 --- ## Task 3: 下游 CRUD API **Files:** `sample_reception.py`, `protocol_sample_collection.py`, `research_donation_sample_collection.py`, `pre_transit_sample.py`, `qc_work_order.py`, `storage_release_review.py`, `cell_product.py` - [ ] **Step 1:** 凡已有 `BizProtocolSample` / `BizResearchDonationSample` 对象处,`item.update(sample_special_to_dict(sample))` - [ ] **Step 2:** `qc_work_order._enrich_work_order_list_items` 在 `sampleTypeName` 赋值后补 special 字段(覆盖质检+生产工单) --- ## Task 4: 前端公共组件与录入 **Files:** - Create: `web-admin/src/components/business/special-sample-display/index.vue` - Modify: `web-admin/src/components/business/sample-transport-form-section/index.vue` - [ ] **Step 1:** 创建 `SpecialSampleDisplay`(`v-if="isSpecial"`,danger 色加粗) - [ ] **Step 2:** 样本子弹窗增加 checkbox + textarea;取消勾选清空说明 - [ ] **Step 3:** `confirmSampleDialog` 校验:`isSpecial && !specialRemark.trim()` → warning - [ ] **Step 4:** 列表增加「特殊样本」列;`openAddSampleDialog` 初始化 `isSpecial: false, specialRemark: ''` - [ ] **Step 5:** `normalizeSampleRow` 保留 `isSpecial` / `specialRemark` --- ## Task 5: 协议查看弹窗 **Files:** `ProtocolViewDialog.vue`, `DonationViewDialog.vue` - [ ] **Step 1:** 样本卡片 header inline 展示 `SpecialSampleDisplay` --- ## Task 6: 下游展示页面(P1 全量) 在样本编码列/标题行旁接入 `SpecialSampleDisplay`: - [ ] `ProtocolAuditTab.vue`, `PreTransitProtocolCardList.vue` - [ ] `research-donation/audit/index.vue` - [ ] `SampleCollectionInfoTab.vue`, `DonationSampleCollectionInfoTab.vue` - [ ] `sample-reception/index.vue`, `SampleReceptionCardList.vue` - [ ] `QcWorkOrderProtocolGroup.vue`, `QcWorkOrderSampleGroup.vue`, `QcWorkOrderTaskSubList.vue` - [ ] `storage-release-review/index.vue`, `StorageReleaseReviewDialog.vue`, `StorageReleaseViewDialog.vue` - [ ] `ProductionWorkOrderCardList.vue`, `SampleReceptionDialog.vue`, `DispatchTaskDialog.vue` - [ ] `SampleCustomerViewDialog.vue` --- ## Task 7: 验证 - [ ] 本地执行 `docs/sql/migrate-special-sample-mark.sql` - [ ] `python scripts/check_field_consistency.py` - [ ] `./scripts/update-graph.sh frontend` + `backend` - [ ] 手工:协议单录入特殊样本 → 查看弹窗 → 样本接收/质检卡片可见红色标记 --- ## 部署前 1. 执行 `docs/sql/migrate-special-sample-mark.sql` 2. 重启 backend 3. 刷新 web-admin