fix:sample/plate 之前的开发

This commit is contained in:
彭帅
2026-05-28 11:56:17 +08:00
parent fc36bc83e3
commit 8b65de36b8
367 changed files with 57752 additions and 947 deletions

View File

@@ -0,0 +1,89 @@
# 数据录入需求总览
本文档基于 `docs/architecture` 下 5 份架构文档拆解,目标是把 BrAPI Test Server 的数据录入需求按上游到下游梳理清楚:
```text
Core 基础数据 -> Germplasm/Seed 种质种子 -> Phenotyping 表型 -> Genotyping 基因型
```
## 文档索引
| 顺序 | 文档 | 说明 |
| --- | --- | --- |
| 1 | `01-core-data-entry-requirements.md` | crop、person、program、location、trial、season、study、list |
| 2 | `02-germplasm-seed-entry-requirements.md` | breeding_method、germplasm、attribute、cross、seed_lot、pedigree |
| 3 | `03-phenotyping-entry-requirements.md` | ontology、trait、method、scale、observation_variable、observation_unit、event、image、observation |
| 4 | `04-genotyping-entry-requirements.md` | plate、sample、reference、variantset、variant、callset、allele_call、genome_map |
## 总体录入链路
```mermaid
flowchart TD
CROP["crop 作物"] --> PROGRAM["program 项目"]
PERSON["person 人员"] --> PROGRAM
PROGRAM --> TRIAL["trial 试验批次"]
PROGRAM --> LOCATION["location 地点"]
TRIAL --> STUDY["study 研究/试验单元"]
LOCATION --> STUDY
CROP --> BM["breeding_method 育种方法"]
BM --> G["germplasm 种质"]
G --> GAV["germplasm_attribute_value 种质属性值"]
PROGRAM --> CP["crossing_project 杂交项目"]
CP --> CROSS["cross_entity Cross/PlannedCross"]
G --> CROSSP["cross_parent 亲本"]
CROSS --> CROSSP
G --> MIX["seed_lot_content_mixture 批次组成"]
CROSS --> MIX
MIX --> SL["seed_lot 种子批次"]
STUDY --> OU["observation_unit 观测单元"]
G --> OU
SL --> OU
CROSS --> OU
OU --> OBS["observation 观测值"]
OU --> SAMPLE["sample 样本"]
STUDY --> SAMPLE
SAMPLE --> CALLSET["callset 调用集合"]
VARIANT["variant 变异位点"] --> CALL["allele_call 基因型结果"]
CALLSET --> CALL
```
## 全局界面原则
| 页面类型 | 用途 | 建议界面 |
| --- | --- | --- |
| 列表页 | 查询、筛选、分页、批量操作 | 顶部筛选区 + 表格 + 新增按钮 + 行内查看/编辑 |
| 新增/编辑页 | 单表主数据录入 | 分组表单,必填字段靠前,外键使用搜索选择器 |
| 详情页 | 查看主表及下游数据 | 顶部摘要 + Tab基本信息、关联数据、扩展信息、外部引用 |
| 关系选择器 | 选择上游依赖 | 支持按 ID、名称、作物、项目、study 搜索 |
| 批量导入 | 初始化和大批量数据 | 上传 CSV/Excel + 字段映射 + 预校验 + 导入结果 |
## 全局字段规则
| 字段类型 | 录入规则 |
| --- | --- |
| `id` / `DbId` | 系统生成或用户提供;必须唯一;编辑时不可随意修改 |
| 名称字段 | 必填或强建议必填;用于下拉选择展示 |
| 外键字段 | 页面展示名称,提交保存实际 ID |
| 枚举字段 | 使用下拉框或单选控件 |
| 日期时间 | 使用日期/时间选择器,保存前统一格式 |
| `additional_info` | 作为高级配置,用键值编辑器录入 |
| `external_references` | 作为外部系统引用,用可增删表格录入 |
## 总体录入顺序
1. 录入 Core`crop``person``program``location``trial``season``study``list`
2. 录入 Germplasm/Seed`breeding_method``germplasm_attribute_definition``germplasm``germplasm_attribute_value``crossing_project``cross_entity``cross_parent``pedigree_node``pedigree_edge``seed_lot``seed_lot_content_mixture``seed_lot_transaction`
3. 录入 Phenotyping`ontology``trait``method``scale``observation_variable``observation_unit``event``image``observation`
4. 录入 Genotyping`plate``sample``reference_set``reference``reference_bases``variantset``variant``callset``allele_call``genome_map``linkageGroup``marker_position`
## 通用验收标准
1. 每张表都有列表、新增、编辑、详情能力。
2. 每个外键字段都能通过名称搜索选择,而不是要求用户手填数据库 ID。
3. 下游表新增时必须校验上游数据是否存在。
4. 删除或禁用上游数据时,需要提示被哪些下游表引用。
5. 支持按模块导入 CSV/Excel并在导入前给出错误行和错误原因。
6. 详情页能看到关键下游关联,例如 `study` 下的 observation unit、sample、variantset。

View File

@@ -0,0 +1,755 @@
# Core 模块业务需求文档
## 1. 模块定位
Core 是项目、试验、地点、人员、季节的基础上下文模块,是所有业务数据的总上游。它不是普通字典维护,而是为后续 Germplasm/Seed、Phenotyping、Genotyping 提供“这批数据属于哪个项目、哪次试验、哪个地点、哪个年度、谁负责”的业务台账。
推荐先完成 Core 录入,再录入 Germplasm、Phenotyping、Genotyping。
## 2. 真实业务理解
Core 不只是“基础字典”,它在真实育种业务里是项目台账:回答“谁在什么项目、什么地点、什么年度、做哪一次试验”。后续所有材料、田间布置、表型采集、样本检测、基因型结果,都需要回到 Core 上下文里解释。
最常见的业务链路是:
```text
crop 作物
-> program 长期育种项目
-> trial 某一批试验/区域试验
-> study 一次真正落地执行的试验
```
例如:
```text
crop: 水稻
program: 水稻抗倒伏育种项目
trial: 2026 湖北区域试验
location: 荆门试验站
season: 2026 春季
study: 2026 荆门水稻抗倒伏田间试验
```
这里最关键的是 `study``program` 更像长期项目,`trial` 是试验批次,`study` 才是具体执行单元。后续 `observation_unit``event``observation``plate``sample``variantset` 都会直接或间接挂到 `study` 上。
## 3. 用户角色和使用场景
| 角色 | 主要职责 | 典型入口 | 权限重点 |
| --- | --- | --- | --- |
| 项目管理员 | 维护作物、项目、人员、地点等基础台账 | crop、person、program、location 列表页 | 可新增/编辑基础数据,可停用未被引用的数据 |
| 试验负责人 | 创建 trial 和 study维护联系人、季节、试验设计 | trial 列表、study 列表、Study 工作台 | 可创建试验上下文,可配置 study 联系人、season、变量清单 |
| 数据录入员 | 进入 Study 工作台继续录观测单元、表型、样本 | Study 工作台 | 主要使用下游入口,一般不能删除 Core 主数据 |
| 数据管理员 | 处理导入、导出、停用、删除校验、数据修复 | 导入导出页、数据质量页 | 可批量导入、导出、停用,有删除前引用检查权限 |
### 3.1 项目管理员场景
项目管理员先建立 `crop``person``program``location`。例如创建“水稻抗倒伏育种项目”,选择 crop=水稻,负责人=张三。录完后,试验负责人才能在该项目下创建 trial 和 study。
### 3.2 试验负责人场景
试验负责人创建“2026 湖北区域试验”和“2026 荆门水稻抗倒伏田间试验”。创建 study 时选择 program、trial、location、season保存后进入 Study 工作台。
### 3.3 数据录入员场景
数据录入员通常不从 crop/program 开始,而是从 Study 工作台进入,继续录 observation unit、observation、sample 等下游数据。
### 3.4 数据管理员场景
数据管理员负责批量导入 Core 数据、处理重复数据、做删除/停用前检查。例如某 trial 已有关联 study 时,不允许物理删除,只能停用。
## 用户为什么要录 Core
| 用户问题 | 由哪些表回答 | 录完能做什么 |
| --- | --- | --- |
| 我们做什么作物? | `crop` | 限定项目、材料、变量、图谱的作物范围 |
| 谁负责项目和试验? | `person``program.lead_person_id``trial_contact``study_contact` | 项目责任追踪、联系人展示、权限和通知 |
| 这是哪个长期育种项目? | `program` | 聚合多个 trial/study、材料、样本、结果 |
| 这是哪一批试验? | `trial` | 管理区域试验、年度试验、批次试验 |
| 试验在哪里、哪一季做? | `location``season``study_season` | 支持多地点、多季节筛选和统计 |
| 哪一次试验真正落地执行? | `study` | 进入 Study 工作台,继续录观测单元、表型、样本、基因型 |
## 6. 页面需求
Core 的核心页面不应该只是表单 CRUD而应该围绕 `study` 做“Study 工作台”。
### 6.1 Study 工作台
```text
Study 工作台
├─ 基本信息:名称、编号、类型、起止日期、负责人
├─ 上下文crop、program、trial、location、season
├─ 试验设计experimental design、observation level、growth facility
├─ 联系人/附件study_contact、data_link、external_references
├─ 观测单元:跳转 observation_unit
├─ 表型数据:跳转 observation / matrix
├─ 样本与样本板:跳转 sample / plate
├─ 基因型数据:跳转 variantset / callset / allele_call
└─ 导入导出:按 study 导入观测单元、表型、样本、基因型
```
### 6.2 Crop 列表页
| 项目 | 需求 |
| --- | --- |
| 功能 | 查询 crop新增、编辑、查看详情、停用 |
| 筛选 | 关键词搜索,按 crop_name 模糊匹配 |
| 表格字段 | `crop_name`、下游 program 数、下游 study 数、状态 |
| 操作 | 查看、编辑、停用 |
| 验收标准 | crop 已被 program/germplasm/study 引用时,不允许物理删除 |
### 6.3 Person 列表页
| 项目 | 需求 |
| --- | --- |
| 功能 | 查询人员;新增、编辑、查看详情、停用 |
| 筛选 | 姓名、邮箱、机构 |
| 表格字段 | 姓名、邮箱、电话、机构、负责项目数、参与 study 数 |
| 操作 | 查看、编辑、停用 |
| 验收标准 | 邮箱格式正确;作为负责人或联系人被引用时,不允许物理删除 |
### 6.4 Program 列表页
| 项目 | 需求 |
| --- | --- |
| 功能 | 查询 program新增、编辑、查看详情、停用 |
| 筛选 | crop、负责人、program_type、关键词 |
| 表格字段 | `name``abbreviation`、crop、负责人、trial 数、study 数 |
| 操作 | 查看、编辑、停用、查看 trial、查看 study |
| 验收标准 | 创建 program 时必须选择 crop负责人来自 person 选择器 |
### 6.5 Trial 列表页
| 项目 | 需求 |
| --- | --- |
| 功能 | 查询 trial新增、编辑、查看详情、停用 |
| 筛选 | crop、program、active、起止日期、关键词 |
| 表格字段 | `trial_name`、program、crop、`start_date``end_date`、active |
| 操作 | 查看、编辑、停用、查看 study |
| 验收标准 | 选择 program 后自动带出 crop已被 study 引用时不允许物理删除 |
### 6.6 Location 列表页
| 项目 | 需求 |
| --- | --- |
| 功能 | 查询 location新增、编辑、查看详情、停用 |
| 筛选 | crop、program、location_type、country、关键词 |
| 表格字段 | `location_name`、location_type、country、program、crop、父级地点 |
| 操作 | 查看、编辑、停用、地图查看 |
| 验收标准 | 父级地点不能选择自己;坐标字段格式合法 |
### 6.7 Season 列表页
| 项目 | 需求 |
| --- | --- |
| 功能 | 查询 season新增、编辑、查看详情、停用 |
| 筛选 | year、season |
| 表格字段 | `year``season`、关联 study 数 |
| 操作 | 查看、编辑、停用 |
| 验收标准 | 同一年份内 season 名称不建议重复 |
### 6.8 Study 列表页
| 项目 | 需求 |
| --- | --- |
| 功能 | 查询 study新增、编辑、查看详情、停用点击 study 名称进入 Study 工作台 |
| 筛选 | crop、program、trial、location、season、active、study_type、关键词 |
| 表格字段 | `study_name``study_code`、program、trial、location、`start_date``end_date`、active |
| 操作 | 查看、编辑、停用、进入工作台 |
| 验收标准 | 选择 program 后只展示该 program 下的 trial选择 trial 后自动带出 crop已有 observation_unit/sample/observation 时不能物理删除 |
### 6.9 Study 新增/编辑页
| 区域 | 字段/功能 | 要求 |
| --- | --- | --- |
| 基本信息 | study_name、study_code、study_type、active、start_date、end_date | study_name 必填;结束日期不早于开始日期 |
| 上下文 | crop、program、trial、location、season | program、trial、crop、location 必选program -> trial 联动 |
| 说明信息 | study_description、cultural_practices、observation_units_description、license、documentationurl | URL 格式校验 |
| 联系人 | study_contact | 多选 person可增删 |
| 季节 | study_season | 可多选 season |
| 提交后 | 保存成功进入 Study 工作台 | 新建成功后自动跳转 |
### 6.10 List 详情页
| 项目 | 需求 |
| --- | --- |
| 功能 | 维护 list 和 list_item |
| 页面形态 | 顶部 list 基本信息,下方 list_item 表格 |
| 操作 | 新增 item、批量导入 item、删除 item、排序 |
| 验收标准 | 同一 list 内 item 不重复 |
## 哪些表是业务动作痕迹
| 动作 | 痕迹表 | 说明 |
| --- | --- | --- |
| 给 trial 添加联系人 | `trial_contact` | trial 与 person 的关系,不是独立主数据 |
| 给 study 添加联系人 | `study_contact` | study 与 person 的关系 |
| 给 study 绑定季节 | `study_season` | 一个 study 可关联多个 season |
| 给 study 绑定观测变量 | `study_variable` | 表示该 study 要采集哪些指标 |
| 给 trial 记录出版物 | `trial_publication` | trial 的文献/报告引用 |
| 给 list 添加成员 | `list_item` | list 的明细项,是分组动作留下的记录 |
## 4. 核心业务流程
### 4.1 新建 Core 试验上下文流程
1. 用户创建 `crop`
2. 用户创建 `person`
3. 用户创建 `program`,并选择 `crop` 和负责人 `lead_person_id`
4. 用户创建 `location`,可选绑定 `program``crop`
5. 用户创建 `trial`,选择 `program` 后自动带出 `crop`
6. 用户创建 `season`
7. 用户创建 `study`,按 `program -> trial -> location -> season` 的顺序选择上下文。
8. `study` 创建成功后,系统自动进入 Study 工作台。
### 4.2 业务流程图
```mermaid
flowchart TD
A["创建 crop"] --> B["创建 person"]
B --> C["创建 program<br/>选择 crop / lead person"]
C --> D["创建 location<br/>可选 program / crop"]
C --> E["创建 trial<br/>选择 program 自动带出 crop"]
E --> F["创建 season"]
D --> G["创建 study<br/>选择 program -> trial -> location -> season"]
F --> G
G --> H["进入 Study 工作台"]
```
## 5. 核心对象说明
### 5.1 crop 作物
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `crop` |
| 前置依赖 | 无 |
| 主要字段 | 作物 ID、作物名称、公共作物名、描述 |
| 下游引用 | `program``location``trial``study``germplasm``observation_variable``genome_map` |
#### 界面形态
列表页展示作物名称、描述、更新时间、下游引用数量。新增页是轻量表单,重点是作物名称唯一校验。详情页展示该作物下的项目、试验、研究、种质、图谱入口。
#### 校验规则
1. 作物名称必填且唯一。
2. 已被下游引用的作物不能直接删除,只允许停用或提示引用关系。
### 5.2 person 人员
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `person` |
| 前置依赖 | 无 |
| 主要字段 | 姓名、邮箱、机构、联系方式、角色 |
| 下游引用 | `program.lead_person_id``trial_contact``study_contact``list.list_owner_person_id` |
#### 界面形态
列表页支持姓名、邮箱、机构筛选。新增/编辑页用联系人表单。详情页展示负责的 program、参与的 trial/study、拥有的 list。
#### 校验规则
1. 姓名必填。
2. 邮箱格式正确。
3. 同一邮箱不建议重复录入。
### 5.3 program 项目
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `program` |
| 前置依赖 | `crop`,可选 `person` |
| 主要字段 | 项目名称、作物、负责人、缩写、目标、描述 |
| 下游引用 | `trial``study``location``crossing_project``seed_lot``plate``sample` |
#### 界面形态
新增页分为“基本信息”和“负责人/作物”两组。作物和负责人使用搜索选择器。详情页 Tab 展示 trial、study、location、seed lot、sample。
#### 校验规则
1. 项目名称必填。
2. 作物必选。
3. 选择负责人时必须存在于 `person`
### 5.4 location 地点
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `location` |
| 前置依赖 | 可选 `crop``program`、父级 `location`、坐标 |
| 主要字段 | 地点名称、地点类型、国家/地区、经纬度、父级地点、所属项目 |
| 下游引用 | `study``seed_lot` |
#### 界面形态
列表页支持地图/表格两种视图。新增页包含基本信息、行政区、坐标、父级地点。详情页展示该地点下的 study 和 seed lot。
#### 校验规则
1. 地点名称必填。
2. 经纬度格式合法。
3. 父级地点不能选择自己。
### 5.5 trial 试验批次
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `trial` |
| 前置依赖 | `program``crop` |
| 主要字段 | 试验名称、项目、作物、开始/结束日期、联系人、出版物 |
| 下游引用 | `study``observation_unit``observation``plate``sample` |
#### 界面形态
新增页包含基本信息、项目作物、联系人、出版物四个区域。联系人用可增删表格选择 `person`。详情页展示 study 列表和 phenotyping/genotyping 入口。
#### 校验规则
1. 试验名称必填。
2. program 与 crop 必须匹配。
3. 结束日期不能早于开始日期。
### 5.6 season 季节
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `season` |
| 前置依赖 | 无 |
| 主要字段 | 季节名称、年份、开始日期、结束日期 |
| 下游引用 | `study_season`、部分 `observation` |
#### 界面形态
列表页按年份和季节筛选。新增页是简单表单。详情页展示关联 study。
#### 校验规则
1. 名称和年份必填。
2. 同一年份内季节名称不建议重复。
### 5.7 study 研究/试验实施单元
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `study` |
| 前置依赖 | `crop``program``trial``location`,可选 `season` |
| 主要字段 | study 名称、study 类型、项目、试验、地点、季节、开始/结束日期、实验设计 |
| 下游引用 | `observation_unit``event``observation``plate``sample``variantset` |
#### 界面形态
新增页是分组表单:基本信息、上下文、地点季节、实验设计、联系人。上下文字段按顺序联动:选择 program 后过滤 trial 和 crop选择 trial 后带出 crop。详情页作为工作台展示 observation unit、observation、sample、variantset。
#### 校验规则
1. study 名称必填。
2. program、trial、crop、location 必选。
3. trial 必须属于所选 program。
4. study 是下游核心引用,删除必须强提示。
### 5.8 list / list_item 通用列表
#### 数据库录入
| 项目 | 要求 |
| --- | --- |
| 表 | `list``list_item` |
| 前置依赖 | 可选 `person` |
| 主要字段 | 列表名称、列表类型、owner、项目项 ID、项目项名称 |
| 下游引用 | 业务查询和分组 |
#### 界面形态
列表页展示 list。详情页内嵌 list item 表格,支持手动添加、批量导入、排序。新增 item 时可选择目标类型,例如 germplasm、study、sample。
#### 校验规则
1. list 名称必填。
2. list item 在同一 list 内不应重复。
3. 如果绑定 ownerowner 必须存在于 `person`
## 7. 字段需求
### crop
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 作物主键,新增时系统生成,也可导入时指定 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `crop_name` | varchar(255) | 文本框 | 作物名称,用于所有下拉选择展示 | 必填、建议唯一 |
### person
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 人员主键 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `description` | varchar(255) | 多行文本 | 人员说明、职责补充 | 可选 |
| `email_address` | varchar(255) | 邮箱输入框 | 邮箱地址 | 邮箱格式校验,建议唯一 |
| `first_name` | varchar(255) | 文本框 | 名 | 与 `last_name` 至少填写一个 |
| `institute_name` | varchar(255) | 文本框/选择器 | 所属机构 | 可选 |
| `last_name` | varchar(255) | 文本框 | 姓 | 与 `first_name` 至少填写一个 |
| `mailing_address` | varchar(255) | 多行文本 | 通讯地址 | 可选 |
| `middle_name` | varchar(255) | 文本框 | 中间名 | 可选 |
| `phone_number` | varchar(255) | 电话输入框 | 联系电话 | 可选,格式提示 |
| `userid` | varchar(255) | 文本框 | 外部用户 ID 或登录名 | 可选,建议唯一 |
### program
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 项目主键 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `abbreviation` | varchar(255) | 文本框 | 项目缩写 | 可选 |
| `documentationurl` | varchar(255) | URL 输入框 | 项目文档链接 | URL 格式校验 |
| `funding_information` | varchar(255) | 多行文本 | 经费来源说明 | 可选 |
| `name` | varchar(255) | 文本框 | 项目名称 | 必填 |
| `objective` | varchar(255) | 多行文本 | 项目目标 | 可选 |
| `program_type` | integer | 下拉框 | 项目类型枚举 | 可选,按 BrAPI 枚举 |
| `crop_id` | varchar(255) | 作物选择器 | 所属作物 | 必选,来源 `crop.id` |
| `lead_person_id` | varchar(255) | 人员选择器 | 项目负责人 | 可选,来源 `person.id` |
### location
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 地点主键 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `abbreviation` | varchar(255) | 文本框 | 地点缩写 | 可选 |
| `coordinate_description` | varchar(255) | 多行文本 | 坐标描述 | 可选 |
| `coordinate_uncertainty` | varchar(255) | 文本框 | 坐标不确定性 | 可选 |
| `country_code` | varchar(255) | 国家代码选择器 | 国家代码 | 可选,建议 ISO 代码 |
| `country_name` | varchar(255) | 文本框 | 国家名称 | 可选,可由国家代码带出 |
| `documentationurl` | varchar(255) | URL 输入框 | 地点文档链接 | URL 格式校验 |
| `environment_type` | varchar(255) | 下拉框/文本框 | 环境类型 | 可选 |
| `exposure` | varchar(255) | 文本框 | 暴露条件 | 可选 |
| `institute_address` | varchar(255) | 多行文本 | 机构地址 | 可选 |
| `institute_name` | varchar(255) | 文本框 | 机构名称 | 可选 |
| `location_name` | varchar(255) | 文本框 | 地点名称 | 必填 |
| `location_type` | varchar(255) | 下拉框 | 地点类型,如 field、greenhouse、storage | 可选 |
| `site_status` | varchar(255) | 下拉框 | 地点状态 | 可选 |
| `slope` | varchar(255) | 文本框 | 坡度 | 可选 |
| `topography` | varchar(255) | 文本框 | 地形 | 可选 |
| `coordinates_id` | varchar(255) | 坐标选择器/地图取点 | 坐标对象 | 可选,来源 `geojson/coordinate` |
| `crop_id` | varchar(255) | 作物选择器 | 关联作物 | 可选,来源 `crop.id` |
| `parent_location_id` | varchar(255) | 地点选择器 | 父级地点 | 可选,不能选择自己 |
| `program_id` | varchar(255) | 项目选择器 | 所属项目 | 可选,来源 `program.id` |
### trial
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 试验主键 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `active` | boolean | 开关 | 是否启用 | 默认启用 |
| `documentationurl` | varchar(255) | URL 输入框 | 试验文档链接 | URL 格式校验 |
| `end_date` | timestamp | 日期选择器 | 结束日期 | 不早于 `start_date` |
| `start_date` | timestamp | 日期选择器 | 开始日期 | 可选 |
| `trial_description` | varchar(255) | 多行文本 | 试验描述 | 可选 |
| `trial_name` | varchar(255) | 文本框 | 试验名称 | 必填 |
| `trialpui` | varchar(255) | 文本框 | 试验永久标识 | 可选,建议唯一 |
| `crop_id` | varchar(255) | 作物选择器 | 所属作物 | 必选,来源 `crop.id` |
| `program_id` | varchar(255) | 项目选择器 | 所属项目 | 必选,来源 `program.id` |
### season
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 季节主键 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `season` | varchar(255) | 文本框/下拉框 | 季节名称,如 Spring、Summer | 必填 |
| `year` | integer | 年份选择器 | 年份 | 必填,四位年份 |
### study
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | study 主键 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `active` | boolean | 开关 | 是否启用 | 默认启用 |
| `cultural_practices` | varchar(255) | 多行文本 | 栽培管理说明 | 可选 |
| `documentationurl` | varchar(255) | URL 输入框 | study 文档链接 | URL 格式校验 |
| `end_date` | timestamp | 日期选择器 | 结束日期 | 不早于 `start_date` |
| `license` | varchar(255) | 文本框 | 数据许可证 | 可选 |
| `observation_units_description` | varchar(255) | 多行文本 | 观测单元说明 | 可选 |
| `start_date` | timestamp | 日期选择器 | 开始日期 | 可选 |
| `study_code` | varchar(255) | 文本框 | study 编码 | 可选,建议同项目内唯一 |
| `study_description` | varchar(255) | 多行文本 | study 描述 | 可选 |
| `study_name` | varchar(255) | 文本框 | study 名称 | 必填 |
| `studypui` | varchar(255) | 文本框 | study 永久标识 | 可选,建议唯一 |
| `study_type` | varchar(255) | 下拉框 | study 类型 | 可选 |
| `crop_id` | varchar(255) | 作物选择器 | 所属作物 | 必选,来源 `crop.id` |
| `location_id` | varchar(255) | 地点选择器 | 实施地点 | 必选,来源 `location.id` |
| `program_id` | varchar(255) | 项目选择器 | 所属项目 | 必选,来源 `program.id` |
| `trial_id` | varchar(255) | 试验选择器 | 所属 trial | 必选,来源 `trial.id` |
### list
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 列表主键 | 必填、唯一 |
| `auth_user_id` | varchar(255) | 隐藏 | 数据所属用户 | 登录上下文自动写入 |
| `date_created` | timestamp | 只读日期时间 | 创建时间 | 系统自动写入 |
| `date_modified` | timestamp | 只读日期时间 | 修改时间 | 系统自动更新 |
| `description` | varchar(255) | 多行文本 | 列表描述 | 可选 |
| `list_name` | varchar(255) | 文本框 | 列表名称 | 必填 |
| `list_owner_name` | varchar(255) | 文本框 | 列表 owner 名称 | 可选,可由 owner person 带出 |
| `list_source` | varchar(255) | 文本框 | 列表来源 | 可选 |
| `list_type` | integer | 下拉框 | 列表类型 | 必填,按 BrAPI 枚举 |
| `list_owner_person_id` | varchar(255) | 人员选择器 | 列表 owner | 可选,来源 `person.id` |
### list_item
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 列表项主键 | 必填、唯一 |
| `item` | varchar(255) | 文本框/对象选择器 | 列表项值,可存目标对象 ID 或文本 | 必填,同一 list 内不重复 |
| `list_id` | varchar(255) | List 选择器 | 所属列表 | 必选,来源 `list.id` |
### trial_contact
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `trial_db_id` | varchar(255) | Trial 选择器 | 所属 trial | 必选,来源 `trial.id` |
| `person_db_id` | varchar(255) | 人员选择器 | 联系人 | 必选,来源 `person.id` |
### trial_publication
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `id` | varchar(255) | 隐藏/只读 | 出版物记录主键 | 必填、唯一 |
| `publicationpui` | varchar(255) | 文本框 | 出版物 PUI | 可选 |
| `publication_reference` | varchar(255) | 文本框/URL | 出版物引用 | 可选 |
| `trial_id` | varchar(255) | Trial 选择器 | 所属 trial | 必选,来源 `trial.id` |
### study_contact
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `study_db_id` | varchar(255) | Study 选择器 | 所属 study | 必选,来源 `study.id` |
| `person_db_id` | varchar(255) | 人员选择器 | 联系人 | 必选,来源 `person.id` |
### study_season
| 字段 | 类型 | 控件 | 录入说明 | 校验/来源 |
| --- | --- | --- | --- | --- |
| `study_db_id` | varchar(255) | Study 选择器 | 所属 study | 必选,来源 `study.id` |
| `season_db_id` | varchar(255) | Season 选择器 | 关联季节 | 必选,来源 `season.id` |
## 8. 接口需求
接口命名可以按项目现有 BrAPI Controller 适配;本节描述前端页面需要的能力,不强制限定最终 URL 必须完全一致。
### 8.1 CRUD 接口
| 对象 | 接口 | 用途 |
| --- | --- | --- |
| crop | `GET /crops` | crop 分页查询 |
| crop | `POST /crops` | 新增 crop |
| crop | `GET /crops/{id}` | crop 详情 |
| crop | `PUT /crops/{id}` | 编辑 crop |
| crop | `DELETE /crops/{id}` | 删除或停用 crop需做引用检查 |
| person | `GET /persons` | person 分页查询 |
| person | `POST /persons` | 新增 person |
| person | `GET /persons/{id}` | person 详情 |
| person | `PUT /persons/{id}` | 编辑 person |
| person | `DELETE /persons/{id}` | 删除或停用 person需做引用检查 |
| program | `GET /programs` | program 分页查询 |
| program | `POST /programs` | 新增 program |
| program | `GET /programs/{id}` | program 详情 |
| program | `PUT /programs/{id}` | 编辑 program |
| program | `DELETE /programs/{id}` | 删除或停用 program需做引用检查 |
| location | `GET /locations` | location 分页查询 |
| location | `POST /locations` | 新增 location |
| location | `GET /locations/{id}` | location 详情 |
| location | `PUT /locations/{id}` | 编辑 location |
| trial | `GET /trials` | trial 分页查询 |
| trial | `POST /trials` | 新增 trial |
| trial | `GET /trials/{id}` | trial 详情 |
| trial | `PUT /trials/{id}` | 编辑 trial |
| trial | `DELETE /trials/{id}` | 删除或停用 trial需检查 study 引用 |
| season | `GET /seasons` | season 查询 |
| season | `POST /seasons` | 新增 season |
| season | `PUT /seasons/{id}` | 编辑 season |
| study | `GET /studies` | study 分页查询 |
| study | `POST /studies` | 新增 study |
| study | `GET /studies/{id}` | study 详情 |
| study | `PUT /studies/{id}` | 编辑 study |
| study | `DELETE /studies/{id}` | 删除或停用 study需检查下游引用 |
| list | `GET /lists` | list 查询 |
| list | `POST /lists` | 新增 list |
| list | `PUT /lists/{id}` | 编辑 list |
| list item | `POST /lists/{id}/items` | 给 list 添加 item |
| list item | `DELETE /lists/{id}/items/{itemId}` | 删除 list item |
### 8.2 详情聚合接口
| 接口 | 用途 | 返回重点 |
| --- | --- | --- |
| `GET /programs/{id}/trials` | 查询 program 下 trial | trial 基础信息、active |
| `GET /programs/{id}/studies` | 查询 program 下 study | study 基础信息、location、trial |
| `GET /trials/{id}/studies` | 查询 trial 下 study | study 列表 |
| `GET /studies/{id}/workbench` | Study 工作台聚合信息 | study 基本信息、联系人、season、observation_unit 数、observation 数、sample 数、variantset 数 |
| `GET /studies/{id}/contacts` | study 联系人 | person 列表 |
| `GET /studies/{id}/seasons` | study 季节 | season 列表 |
### 8.3 选择器接口
| 接口 | 用途 | 参数 |
| --- | --- | --- |
| `GET /selectors/crops` | crop 搜索下拉 | `keyword` |
| `GET /selectors/persons` | person 搜索下拉 | `keyword``instituteName` |
| `GET /selectors/programs` | program 搜索下拉 | `keyword``cropId` |
| `GET /selectors/trials` | trial 搜索下拉 | `keyword``programId``cropId``active` |
| `GET /selectors/locations` | location 搜索下拉 | `keyword``programId``cropId``locationType` |
| `GET /selectors/seasons` | season 搜索下拉 | `year``keyword` |
| `GET /selectors/studies` | study 搜索下拉 | `keyword``programId``trialId``locationId``active` |
### 8.4 导入导出接口
| 接口 | 用途 |
| --- | --- |
| `GET /imports/templates/core/{objectType}` | 下载 Core 对象导入模板 |
| `POST /imports/core/{objectType}/preview` | 上传文件并预校验,不落库 |
| `POST /imports/core/{objectType}/commit` | 确认导入 |
| `GET /exports/core/{objectType}` | 导出当前筛选结果 |
| `GET /imports/{jobId}/errors` | 获取导入错误报告 |
## 9. 联动规则
| 场景 | 联动规则 |
| --- | --- |
| 创建 program | 必须先选择 crop负责人从 person 选择器选择 |
| 创建 trial | 选择 program 后自动带出 croptrial 的 crop 必须与 program.crop_id 一致 |
| 创建 location | 选择 program 后可自动带出 crop但允许地点作为公共地点不绑定 program |
| 创建 study | 先选 program再按 program 过滤 trial选择 trial 后自动带出 crop |
| 创建 study | location 可按 program/crop 过滤season 支持多选 |
| 编辑 study | 如果已有 observation_unit/sample/observation变更 program/trial/crop/location 前必须二次确认并检查一致性 |
| Study 工作台 | 入口必须携带 study_id下游新增 observation_unit、sample、variantset 默认继承该 study 上下文 |
| 外键显示 | 前端展示名称,提交保存 ID表格列需要同时支持名称展示和 ID 调试查看 |
## 10. 删除/停用规则
| 对象 | 删除/停用规则 |
| --- | --- |
| crop | 已被 program、location、trial、study、germplasm、observation_variable、genome_map 引用时,不允许物理删除 |
| person | 已作为 program 负责人、trial 联系人、study 联系人、list owner 时,不允许物理删除 |
| program | 已有关联 trial、study、location、crossing_project、seed_lot、plate、sample 时,不允许物理删除 |
| location | 已被 study 或 seed_lot 引用时,不允许物理删除 |
| trial | 已被 study、observation_unit、observation、plate、sample 引用时,不允许物理删除 |
| season | 已被 study_season 或 observation 引用时,不允许物理删除 |
| study | 已被 observation_unit、event、observation、plate、sample、variantset 引用时,不允许物理删除 |
| list | 已有 list_item 时,删除前必须提示;可先清空明细再删除 |
删除失败时,后端应返回被引用对象类型和数量,前端弹窗展示,例如:
```text
该 study 已被以下数据引用,不能删除:
- observation_unit: 120
- observation: 560
- sample: 96
请先处理下游数据,或将 study 停用。
```
## 11. 导入导出需求
### 11.1 导入对象
Core 模块至少支持以下对象导入:
```text
crop
person
program
location
trial
season
study
list
list_item
trial_contact
study_contact
study_season
```
### 11.2 导入流程
1. 用户选择对象类型,例如 `study`
2. 下载 CSV/Excel 模板。
3. 用户填写模板并上传。
4. 系统做预校验:字段完整性、必填、格式、外键是否存在、联动关系是否一致。
5. 预览页展示可导入行、错误行、警告行。
6. 用户确认后提交导入。
7. 导入完成后生成导入报告。
### 11.3 导入模板要求
| 要求 | 说明 |
| --- | --- |
| 字段名 | 使用数据库字段名作为模板列名 |
| 外键列 | 支持填写 ID可额外支持名称匹配但名称重复时必须报错 |
| 错误报告 | 返回行号、字段名、错误原因、建议修正方式 |
| 幂等策略 | 可按 ID 更新;无 ID 时新增 |
| 权限 | 数据录入员可导入 study 下游数据Core 主数据导入建议仅项目管理员/数据管理员可操作 |
### 11.4 导出需求
1. 所有列表页支持导出当前筛选结果。
2. 导出文件应包含 ID 和展示名称。
3. study 导出应支持导出工作台摘要包括联系人、season、下游数据数量。
4. 导出大数据量时应走异步任务。
## 12. 验收标准
### 12.1 前端验收标准
1. 所有列表页支持分页、关键词搜索、基础筛选。
2. 所有外键字段前端展示名称,提交保存 ID。
3. 创建 program 时,必须选择 crop。
4. 创建 trial 时,选择 program 后自动带出 crop。
5. 创建 study 时,必须选择 program、trial、crop、location。
6. Study 列表页支持按 crop、program、trial、location、season、active 筛选。
7. 点击 study 名称或“进入工作台”按钮后进入 Study 工作台。
8. Study 工作台可以看到观测单元、表型、样本、基因型入口。
9. 删除被引用数据时,前端展示引用详情,不允许静默失败。
10. 导入预校验结果能展示错误行、错误字段、错误原因。
### 12.2 后端验收标准
1. 创建 program 时校验 `crop_id` 存在。
2. 创建 trial 时校验 `program_id` 存在,且 trial.crop_id 与 program.crop_id 一致。
3. 创建 study 时校验 `program_id``trial_id``crop_id``location_id` 存在。
4. 创建 study 时校验 trial 属于所选 program。
5. 删除 crop/program/trial/study 前必须检查下游引用。
6. `GET /studies/{id}/workbench` 能返回工作台所需聚合数量。
7. 选择器接口支持 keyword 模糊搜索和上游过滤参数。
8. 导入接口支持 preview 和 commit 两阶段。
### 12.3 测试点
1. 选择 program 后trial 下拉框只展示该 program 下的数据。
2. 选择 trial 后,系统自动带出 crop。
3. 已被 study 引用的 trial 不能直接删除。
4. 已被 observation_unit、sample、observation 引用的 study 不能直接删除。
5. study 创建成功后自动进入 Study 工作台。
6. 修改 study 的 program/trial/crop 时,如果已有下游数据,必须提示风险。
7. 导入 study 时,如果 trial 不属于 program应报错并指出行号。
8. 导入 location 时,如果 parent_location_id 指向自己,应报错。
9. 导出列表时,筛选条件必须生效。
10. 所有接口返回的分页字段一致,便于前端表格复用。

View File

@@ -0,0 +1,609 @@
# Germplasm / Seed 模块专业数据录入需求文档 V2
## 1. 文档目的
本文档用于指导 Germplasm / Seed 模块的前端页面、后端接口、字段校验、数据导入、测试验收设计。本文档不再只描述数据库表关系,而是从真实育种业务出发,解释每个字段的业务意义、录入方式、控件建议、校验规则和上下游影响。
## 2. 模块定位
Germplasm / Seed 模块描述育种材料的生命周期:
```text
材料身份 -> 材料属性 -> 杂交计划/实际杂交 -> 亲本 -> 系谱 -> 种子批次 -> 库存流转 -> 被 study / observation_unit 使用
```
核心概念如下:
| 概念 | 业务含义 | 主要表 |
| ---------------------------- | --------------------------------------------------------- | ------------------------------------------------------------ |
| Germplasm 材料身份 | 一个品种、品系、后代材料、种质资源的身份信息 | `germplasm` |
| Germplasm Attribute 材料属性 | 材料自身稳定特征,如抗性、熟期、籽粒硬度、基因/QTL 标记等 | `germplasm_attribute_definition``germplasm_attribute_value` |
| Cross 杂交动作 | 一次计划杂交或实际杂交,包含亲本、状态、项目归属 | `crossing_project``cross_entity``cross_parent` |
| Pedigree 系谱 | 材料之间的亲子、同胞、后代关系 | `pedigree_node``pedigree_edge` |
| SeedLot 种子批次 | 某个材料或杂交组合对应的一批实物种子,有数量、单位、库位 | `seed_lot``seed_lot_content_mixture` |
| Transaction 库存流转 | 入库、出库、转移、分装、合并、消耗等动作流水 | `seed_lot_transaction` |
## 3. 推荐业务流程
```text
1. 维护育种方法 breeding_method
2. 维护材料属性定义 germplasm_attribute_definition
3. 创建材料 germplasm
4. 给材料补充属性值 germplasm_attribute_value
5. 如涉及杂交,创建 crossing_project
6. 创建计划杂交 cross_entity(planned=true)
7. 给计划杂交录入亲本 cross_parent
8. 实际完成杂交后,创建实际杂交 cross_entity(planned=false, planned_cross_id=计划杂交)
9. 如产生后代材料,创建新的 germplasm并补充 pedigree_node / pedigree_edge
10. 如产生实物种子,创建 seed_lot
11. 在 seed_lot_content_mixture 中描述批次组成
12. 后续库存变化通过 seed_lot_transaction 记录
13. seed_lot / germplasm / cross_entity 后续可作为 observation_unit 的材料来源
```
## 4. 页面总体设计
### 4.1 Germplasm 材料详情页
```text
Germplasm 详情页
├─ 基本信息名称、默认显示名、PUI、accession、作物、育种方法
├─ 分类信息genus、species、subtaxa、country_of_origin_code
├─ 来源信息acquisition_date、seed_source、seed_source_description、collection
├─ 属性值germplasm_attribute_value
├─ 系谱pedigree_node / pedigree_edge 树图
├─ 作为亲本cross_parent
├─ 种子批次seed_lot_content_mixture -> seed_lot
└─ 下游使用observation_unit、reference_set、sample 追踪
```
### 4.2 SeedLot 库存详情页
```text
SeedLot 详情页
├─ 当前库存amount、units、location、storage_location
├─ 批次组成germplasm / cross / mixture_percentage
├─ 出入库操作:入库、出库、转移、分装、合并、消耗
├─ 流转流水seed_lot_transaction
└─ 下游使用:哪些 study / observation_unit 使用了该批种子
```
### 4.3 CrossingProject 杂交项目工作台
```text
CrossingProject 工作台
├─ 项目信息name、program、description
├─ 计划杂交cross_entity(planned=true)
├─ 实际杂交cross_entity(planned=false)
├─ 亲本cross_parent
├─ 后代材料germplasm / pedigree_node
└─ 产生种子批次seed_lot
```
---
# 5. 字段级专业录入需求
## 5.1 breeding_method 育种方法
### 业务说明
`breeding_method` 是育种方法字典,用来说明某个 germplasm 是通过什么方式形成的,例如杂交选育、回交、自交系选育、诱变、转基因、克隆选择等。它不是一次具体杂交动作,而是材料来源方法的分类。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------- | -------------------------------------------- | -------------------------------- | --------- | -------------------------------- |
| `id` | 育种方法主键,系统内部唯一标识 | 新增时系统生成;导入时可允许指定 | 隐藏/只读 | 必填、唯一;编辑时不允许修改 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许前端手填 |
| `abbreviation` | 方法缩写,如 MB、BC、DH | 用户录入 | 文本框 | 可选;建议同一用户下唯一 |
| `description` | 方法解释,如“回交用于恢复目标基因” | 用户录入 | 多行文本 | 可选,限制长度 |
| `name` | 方法名称,如 Male Backcross、Doubled Haploid | 用户录入 | 文本框 | 必填;建议唯一;作为下拉展示名称 |
### 页面与交互
- 列表页展示:方法名称、缩写、描述、使用材料数量。
- 新增页为简单字典表单。
- 删除前检查是否被 `germplasm.breeding_method_id` 引用;已引用时不允许物理删除,只允许停用。
---
## 5.2 germplasm 种质 / 材料身份
### 业务说明
`germplasm` 是材料身份证,描述一个品种、品系、亲本、后代材料、遗传资源或研究材料“是谁”。它不表示库存数量,库存数量由 `seed_lot` 表达。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------------------------- | ------------------------------------------------------------ | -------------------------------------- | ----------------- | --------------------------------------------------------- |
| `id` | 种质主键,系统内部唯一标识 | 系统生成;导入可指定 | 隐藏/只读 | 必填、唯一;编辑不可随意修改 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `accession_number` | 材料在种质库/机构内的 accession 编号,如 PI 113869 | 用户录入或导入 | 文本框 | 可选;建议同一 crop / institution 下唯一 |
| `acquisition_date` | 材料进入本系统或本机构的获取日期 | 用户录入 | 日期选择器 | 可选;不得晚于当前日期太多,导入时允许缺月/缺日需统一规则 |
| `acquisition_source_code` | 获取来源编码,如采集、引进、交换、繁殖等 | 用户选择 | 下拉框 | 可选;值来自 BrAPI/MCPD 枚举或系统字典 |
| `biological_status_of_accession_code` | 材料生物状态,如野生、地方品种、育种材料、改良品种、突变体等 | 用户选择 | 下拉框 | 可选;使用受控枚举,不建议自由输入 |
| `collection` | 材料所属集合、群体、panel 或 collection | 用户录入/选择 | 文本框/选择器 | 可选;可用于分组筛选 |
| `country_of_origin_code` | 原产国或育成/选育国家代码 | 用户选择 | 国家代码选择器 | 可选;建议使用 ISO 3166-1 三字母代码 |
| `default_display_name` | 系统默认展示名,给下拉框、表格、详情标题使用 | 用户录入,可由 germplasm_name 自动带出 | 文本框 | 与 `germplasm_name` 至少填一个;建议必填 |
| `documentationurl` | 材料说明文档、外部数据库页面或 DOI 链接 | 用户录入 | URL 输入框 | 可选;校验 URL 格式 |
| `genus` | 属名,如 Oryza、Triticum | 用户录入/字典选择 | 文本框/物种选择器 | 可选;建议首字母大写 |
| `germplasm_name` | 材料名称,可以是品种名、品系名、后代编号 | 用户录入 | 文本框 | 与 `default_display_name` 至少填一个;不强制全局唯一 |
| `germplasmpui` | 永久唯一标识,通常是 DOI、URI 或全局唯一编码 | 用户录入/外部导入 | 文本框/URL 输入框 | 可选;若填写必须唯一;建议用于跨系统交换 |
| `germplasm_preprocessing` | 材料用于试验前的统一处理说明,如消毒、催芽、低温处理 | 用户录入 | 文本框/多行文本 | 可选 |
| `mls_status` | 多边系统 MLS 状态,涉及植物遗传资源交换协议 | 用户选择 | 下拉框 | 可选;普通业务可隐藏到高级信息 |
| `seed_source` | 材料来源标识,如来源机构+accession或亲本组合描述 | 用户录入 | 文本框 | 可选;注意它不是库存批次,不等于 seed_lot |
| `seed_source_description` | 材料来源详细说明 | 用户录入 | 多行文本 | 可选 |
| `species` | 种名,如 sativa、aestivum | 用户录入/物种字典 | 文本框 | 可选;建议小写 |
| `species_authority` | 种名命名权威,如 L. | 用户录入 | 文本框 | 可选 |
| `subtaxa` | 亚种、变种、品种群、line 等更细分类 | 用户录入 | 文本框 | 可选 |
| `subtaxa_authority` | 亚种/变种命名权威 | 用户录入 | 文本框 | 可选 |
| `breeding_method_id` | 该材料形成所使用的育种方法 | 从 breeding_method 选择 | 搜索选择器 | 可选;必须引用存在的 breeding_method |
| `crop_id` | 所属作物 | 从 crop 选择 | 作物选择器 | 必填;后续 trial/study/attribute 应尽量同 crop |
### 录入建议
- 新建材料时,第一屏只放核心字段:`crop_id``germplasm_name``default_display_name``germplasmpui``accession_number``breeding_method_id`
- 分类与来源信息放在“高级信息”或“来源信息”分组。
- `germplasmpui``accession_number``germplasm_name` 三者不要混为一谈:
- `germplasm_name` 是人看的名字;
- `accession_number` 是机构内编号;
- `germplasmpui` 是跨系统长期唯一标识。
### 验收标准
1. 新增 germplasm 时,必须选择 crop。
2. `germplasm_name``default_display_name` 至少填写一个。
3. 下拉选择材料时展示 `default_display_name`,辅助展示 accession number / PUI。
4. 如果 germplasm 已被 seed lot、cross parent、observation unit 引用,不允许物理删除。
---
## 5.3 germplasm_attribute_definition 属性定义
### 业务说明
属性定义描述“材料可以有哪些稳定属性”。这些属性通常不是环境依赖的田间观测值,而是材料自身特征,例如籽粒颜色、抗病基因、硬度、熟期类型、特定 QTL、分子标记结果等。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ---------------------- | ------------------------------------------------------------ | ---------------------------- | ----------------- | ------------------------------------- |
| `id` | 属性定义主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `default_value` | 属性默认值 | 用户录入 | 动态输入框 | 可选;按 datatype / scale 校验 |
| `documentationurl` | 属性说明文档链接 | 用户录入 | URL 输入框 | 可选;校验 URL |
| `growth_stage` | 属性适用生长阶段,如 flowering | 用户录入/选择 | 下拉框/文本框 | 可选 |
| `institution` | 提交或维护该属性定义的机构 | 用户录入 | 文本框 | 可选 |
| `language` | 定义语言,如 zh、en | 用户选择 | 下拉框 | 可选;建议 ISO 639-1 |
| `scientist` | 提交该属性定义的科学家或负责人 | 用户录入/人员选择 | 文本框/人员选择器 | 可选 |
| `status` | 属性状态,如 recommended、obsolete、legacy | 用户选择 | 下拉框 | 可选;推荐使用枚举 |
| `submission_timestamp` | 属性定义提交时间 | 系统默认当前时间,可手动调整 | 日期时间选择器 | 可选;新增默认当前时间 |
| `crop_id` | 适用作物 | 从 crop 选择 | 作物选择器 | 可选;若填写,下游材料应同 crop |
| `method_id` | 属性测定方法 | 从 method 选择 | 方法选择器 | 可选;若填写,属性值录入按该方法解释 |
| `ontology_id` | 所属本体 | 从 ontology 选择 | 本体选择器 | 可选 |
| `scale_id` | 值标尺/单位/有效值范围 | 从 scale 选择 | 标尺选择器 | 可选;若填写,属性值必须按 scale 校验 |
| `trait_id` | 关联性状 | 从 trait 选择 | 性状选择器 | 可选 |
| `attribute_category` | 属性分类,如 Morphological、Genetic、Quality | 用户选择/录入 | 下拉框/文本框 | 可选;建议字典化 |
| `code` | 属性代码,便于导入导出 | 用户录入 | 文本框 | 可选;建议唯一 |
| `datatype` | 属性值数据类型,如 text、numeric、date、boolean、categorical | 用户选择 | 下拉框 | 必填 |
| `description` | 属性解释 | 用户录入 | 多行文本 | 可选 |
| `name` | 属性名称 | 用户录入 | 文本框 | 必填;作为属性选择器展示名称 |
| `pui` | 属性永久标识 | 用户录入 | 文本框/URL 输入框 | 可选;建议唯一 |
| `uri` | 属性 URI | 用户录入 | URL 输入框 | 可选;校验 URL |
### 录入建议
- 属性定义页面本质是“属性字典配置”。
- 前端应根据 `datatype` 动态决定属性值录入控件:
- numeric数字输入框
- categorical下拉框
- date日期选择器
- boolean开关
- text文本框。
- 若绑定了 `scale_id`,则优先按 scale 的单位、上下限、有效分类值校验。
---
## 5.4 germplasm_attribute_value 属性值
### 业务说明
属性值是“某个 germplasm 在某个属性上的实际取值”。它不是属性定义,也不是 observation。它适合记录材料相对稳定、不强依赖环境的特征。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ----------------- | ------------------------------ | -------------------------------------- | ---------- | ---------------------------------------- |
| `id` | 属性值主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `determined_date` | 属性值被测定或确认的日期 | 用户录入 | 日期选择器 | 可选;多次测定时必须填写以区分记录 |
| `value` | 某个材料在某个属性上的实际取值 | 用户录入 | 动态控件 | 必填;按 attribute datatype / scale 校验 |
| `attribute_id` | 属性定义 | 从 germplasm_attribute_definition 选择 | 属性选择器 | 必选;必须存在 |
| `germplasm_id` | 所属材料 | 从 germplasm 选择 | 材料选择器 | 必选;必须存在 |
### 录入建议
- 推荐嵌入 Germplasm 详情页的“属性值”Tab。
- 支持批量导入,模板列建议为:`germplasm_id/germplasm_name``attribute_code/attribute_name``value``determined_date`
- 同一个 germplasm + attribute 可以允许多次测定,但页面必须显示测定日期、来源和最新值标记。
---
## 5.5 crossing_project 杂交项目
### 业务说明
`crossing_project` 是某个育种项目下的一组杂交任务集合。它不是一次杂交而是一个杂交工作台例如“2026 抗倒伏杂交项目”。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------- | ------------------ | ------------------ | ---------- | ----------------------------- |
| `id` | 杂交项目主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `description` | 杂交项目说明 | 用户录入 | 多行文本 | 可选 |
| `name` | 杂交项目名称 | 用户录入 | 文本框 | 必填;同一 program 下建议唯一 |
| `program_id` | 所属育种项目 | 从 program 选择 | 项目选择器 | 必选;必须存在 |
### 页面与交互
- 详情页应展示计划杂交、实际杂交、潜在亲本、后代材料、产生的 seed lot。
- 创建 cross 时应自动带入 crossing_project_id。
---
## 5.6 cross_entity 计划杂交 / 实际杂交
### 业务说明
`cross_entity` 统一承载计划杂交和实际杂交。通过 `planned` 字段区分计划与实际,通过 `planned_cross_id` 指向来源计划。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------------- | ------------------------------------------- | ------------------------ | -------------- | --------------------------------------- |
| `id` | cross 主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `cross_type` | 杂交类型,如 biparental、self、backcross 等 | 用户选择 | 下拉框 | 可选;值来自枚举字典 |
| `name` | cross 名称,如 A × B、A/B、Cross-2026-001 | 用户录入或自动生成 | 文本框 | 必填;同一 crossing project 下建议唯一 |
| `planned` | 是否为计划杂交 | 页面根据入口自动设置 | 开关/分段控件 | 必填;计划杂交为 true实际杂交为 false |
| `status` | 状态,如 TODO、DONE、SKIPPED、FAILED | 用户选择/系统更新 | 下拉框 | 可选;计划杂交常用 TODO/DONE/SKIPPED |
| `crossing_project_id` | 所属杂交项目 | 从 crossing_project 选择 | 杂交项目选择器 | 必选 |
| `planned_cross_id` | 实际杂交来源的计划杂交 | 从 cross_entity 选择 | Cross 选择器 | 可选;不能选择自己;实际杂交建议填写 |
### 录入建议
- 页面上分成“计划杂交”和“实际杂交”两个入口,但后端都保存到 `cross_entity`
- 创建计划杂交时:`planned=true``planned_cross_id=null`
- 完成实际杂交时:`planned=false``planned_cross_id=原计划杂交 id`
- 亲本不要直接塞在 cross 主表字段中,应通过 `cross_parent` 维护,便于支持多亲本和 observation_unit 亲本来源。
---
## 5.7 cross_parent 杂交亲本
### 业务说明
`cross_parent` 表示某个 cross 的亲本。亲本可以来自 `germplasm`,也可以来自某个 `observation_unit`,例如田间某一株实际被选作父本/母本。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------------- | --------------------------------------------------- | ---------------------------------- | ----------------- | ------------------------------------- |
| `id` | 亲本记录主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `parent_type` | 亲本角色,如 MALE、FEMALE、SELF、POPULATION、CLONAL | 用户选择 | 下拉框 | 必填;使用枚举 |
| `cross_id` | 所属 cross | 从 cross_entity 选择或由详情页带入 | Cross 选择器/隐藏 | 必选 |
| `crossing_project_id` | 所属 crossing project | 由 cross 自动带出 | 只读/隐藏 | 可选;如填写必须与 cross 一致 |
| `germplasm_id` | 亲本材料 | 从 germplasm 选择 | 材料选择器 | 与 `observation_unit_id` 至少一个必填 |
| `observation_unit_id` | 亲本观测单元 | 从 observation_unit 选择 | 观测单元选择器 | 与 `germplasm_id` 至少一个必填 |
### 录入建议
- 在 Cross 详情页内嵌“亲本列表”。
- 常见快捷录入Parent1 / Parent2。
- 对于田间选株杂交,优先记录 observation_unit_id同时可带出 germplasm_id保证可追溯到具体植株。
---
## 5.8 pedigree_node 系谱节点
### 业务说明
`pedigree_node` 是系谱图中的节点,通常对应一个 germplasm。它用于描述材料在系谱树中的位置不等同于一次杂交记录。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------------- | --------------------- | ------------------------ | -------------- | ----------------------------------------- |
| `id` | 系谱节点主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `crossing_year` | 亲本最初杂交年份 | 用户录入 | 年份选择器 | 可选;四位年份 |
| `family_code` | 家系编号 | 用户录入 | 文本框 | 可选;同一 crossing_project 下建议唯一 |
| `pedigree_string` | 系谱字符串,如 A/B//C | 用户录入/系统生成 | 文本框 | 可选;建议支持 Purdy notation |
| `crossing_project_id` | 产生该节点的杂交项目 | 从 crossing_project 选择 | 杂交项目选择器 | 可选 |
| `germplasm_id` | 该系谱节点对应的材料 | 从 germplasm 选择 | 材料选择器 | 建议必填;同一 germplasm 不建议重复建节点 |
### 录入建议
- Germplasm 详情页提供“系谱”Tab。
- 支持两种维护方式:树图拖拽维护、表格维护节点和边。
- 如果 cross 完成后产生后代 germplasm应自动或半自动创建 pedigree_node。
---
## 5.9 pedigree_edge 系谱边
### 业务说明
`pedigree_edge` 是系谱图中的边,描述节点之间的父子、同胞等关系。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------- | ------------------------------------------ | --------------------- | ---------- | ------------------------------------ |
| `id` | 系谱边主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `edge_type` | 边类型,如 parent、child、sibling | 用户选择 | 下拉框 | 必填 |
| `parent_type` | 如果是亲本关系,标识 MALE、FEMALE、SELF 等 | 用户选择 | 下拉框 | 可选;当 edge_type=parent 时建议必填 |
| `connceted_node_id` | 被连接节点 | 从 pedigree_node 选择 | 节点选择器 | 必选 |
| `this_node_id` | 当前节点 | 从 pedigree_node 选择 | 节点选择器 | 必选;不能等于 connected node |
### 录入建议
- 前端展示时不要暴露“this_node_id / connected_node_id”这种技术词应该显示为“当前材料”和“关联材料”。
- 添加父本/母本时,系统自动创建 edge_type=parent。
- 需要避免明显循环,例如 A 是 B 的父本,同时 B 又是 A 的父本。
---
## 5.10 seed_lot 种子批次
### 业务说明
`seed_lot` 是实物库存批次,描述某一批种子当前有多少、放在哪里、属于哪个项目。它不是 germplasm 身份;同一个 germplasm 可以有多个 seed_lot。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------- | ---------------------------------------------------- | --------------------- | ------------------- | ----------------------------- |
| `id` | SeedLot 主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `amount` | 当前库存数量,可以是粒数、重量、株数等 | 用户录入/交易自动更新 | 数字输入框 | 必填;非负;交易后自动更新 |
| `created_date` | 批次创建时间 | 系统默认,可导入 | 日期时间选择器/只读 | 默认当前时间 |
| `description` | 批次说明 | 用户录入 | 多行文本 | 可选 |
| `last_updated` | 最后更新时间,包含交易变化 | 系统自动更新 | 只读 | 不允许手动改 |
| `name` | 批次名称,如 华占-2026-荆门-扩繁批 | 用户录入或自动生成 | 文本框 | 必填;同一 program 下建议唯一 |
| `source_collection` | 原始来源 collection如野外采集、nursery、种质库集合 | 用户录入 | 文本框 | 可选 |
| `storage_location` | 具体库位描述,如 冰箱A-2层-盒03 | 用户录入 | 文本框 | 可选 |
| `units` | 数量单位,如 seeds、g、kg、plants | 用户选择 | 下拉框/文本框 | 必填;交易单位需一致或可换算 |
| `location_id` | 库存所在地点 | 从 location 选择 | 地点选择器 | 可选 |
| `program_id` | 所属项目 | 从 program 选择 | 项目选择器 | 可选;用于项目库存筛选 |
### 录入建议
- 创建 seed_lot 后必须进入“批次组成”Tab至少录入一条 `seed_lot_content_mixture`
- 普通用户不要直接编辑 amountamount 应通过入库、出库、转移、分装等交易动作更新。
- 支持库存状态:充足、低库存、耗尽,可由 amount 和阈值计算。
---
## 5.11 seed_lot_content_mixture 批次组成
### 业务说明
`seed_lot_content_mixture` 描述一个 seed_lot 由哪些材料或 cross 组成。单一材料批次也需要有一条组成记录,比例为 100%。混合批次则多条记录占比合计为 100%。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------------- | ----------------------------- | -------------------- | ------------------- | ---------------------------------------- |
| `id` | 批次组成主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `mixture_percentage` | 该材料或 cross 在批次中的占比 | 用户录入 | 百分比输入框 | 0 到 100同一 seed lot 总和建议等于 100 |
| `cross_id` | 来源 cross | 从 cross_entity 选择 | Cross 选择器 | 与 `germplasm_id` 至少一个必填 |
| `germplasm_id` | 来源 germplasm | 从 germplasm 选择 | 材料选择器 | 与 `cross_id` 至少一个必填 |
| `seed_lot_id` | 所属 seed lot | 由详情页带入或选择 | SeedLot 选择器/隐藏 | 必选 |
### 录入建议
- 新建 seed_lot 时,如果用户选择了单个 germplasm系统自动生成一条 mixture`germplasm_id=所选材料``mixture_percentage=100`
- 如果来源是某次杂交产生的种子,优先填写 `cross_id`
- 如果既能追溯 cross 又能追溯 germplasm可按系统设计决定是否允许同时填写若允许同时展示“来源杂交”和“当前材料身份”。
---
## 5.12 seed_lot_transaction 批次流转
### 业务说明
`seed_lot_transaction` 记录库存变化。它不应该由用户像普通表单一样手动维护,而应该由“入库、出库、转移、分装、合并、消耗”等业务动作自动生成。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------ | -------------------------------------------- | ----------------------- | ------------------- | ------------------------------------------------- |
| `id` | 流转记录主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `amount` | 流转数量 | 用户在业务动作中录入 | 数字输入框 | 必填;大于 0 |
| `description` | 流转说明,如用于某 study、分装原因、报废原因 | 用户录入 | 多行文本 | 可选;出库/报废建议必填 |
| `timestamp` | 流转发生时间 | 默认当前时间,可调整 | 日期时间选择器 | 必填 |
| `units` | 流转单位 | 默认继承 seed_lot.units | 下拉框/只读 | 必填;需与 seed_lot 单位一致或有换算关系 |
| `from_seed_lot_id` | 来源批次 | 按动作自动设置 | SeedLot 选择器/隐藏 | 与 `to_seed_lot_id` 至少一个存在 |
| `to_seed_lot_id` | 目标批次 | 按动作自动设置 | SeedLot 选择器/隐藏 | 与 `from_seed_lot_id` 至少一个存在;不能等于 from |
### 业务动作映射
| 动作 | from_seed_lot_id | to_seed_lot_id | amount 对库存影响 |
| --------- | ---------------- | -------------- | -------------------------------------------- |
| 入库 | 空 | 目标批次 | 目标批次增加 |
| 出库 | 来源批次 | 空 | 来源批次减少 |
| 转移 | 来源批次 | 目标批次 | 来源减少,目标增加 |
| 分装 | 原批次 | 新批次 | 原批次减少,新批次增加 |
| 合并 | 多个来源批次 | 目标批次 | 来源减少,目标增加;可能生成多条 transaction |
| 消耗/报废 | 来源批次 | 空 | 来源减少,并记录原因 |
### 验收标准
1. amount 必须大于 0。
2. 出库/消耗时amount 不得超过来源批次当前库存。
3. from 和 to 不能相同。
4. transaction 创建后应自动更新 seed_lot.amount 和 last_updated。
5. 已生成的 transaction 原则上不允许随意修改;如需纠错,应通过反向交易或更正记录处理。
---
# 6. 跨表联动与关键校验
## 6.1 选择器联动
| 场景 | 联动规则 |
| ------------------------- | ------------------------------------------------------------ |
| 创建 germplasm | 必须先选择 cropbreeding_method 可选 |
| 创建 attribute definition | crop 可选;若选择 trait/method/scale/ontology则必须引用存在记录 |
| 创建 attribute value | 选择 germplasm 后attribute 选择器优先展示同 crop 或未限定 crop 的属性 |
| 创建 crossing project | 必须选择 program |
| 创建 cross | 必须先选择 crossing_project计划杂交和实际杂交使用不同入口 |
| 创建 cross parent | 从 cross 详情页进入时自动带出 cross 和 crossing_project |
| 创建 seed lot | 可选择 program、location保存后必须维护 content mixture |
| 创建 transaction | 从 seed lot 详情页进入时自动带出 from/to seed lot |
## 6.2 删除规则
| 对象 | 删除限制 |
| -------------------- | ------------------------------------------------------------ |
| breeding_method | 已被 germplasm 引用时不可删除 |
| germplasm | 已被 attribute value、cross parent、seed lot mixture、pedigree、observation unit 引用时不可删除 |
| attribute definition | 已有 attribute value 时不可删除 |
| crossing_project | 已有 cross / cross parent / pedigree node 时不可删除 |
| cross_entity | 已有 parent、seed lot mixture、observation unit 引用时不可删除 |
| seed_lot | 已有 mixture、transaction、observation unit 引用时不可删除 |
| transaction | 原则上不可物理删除;只能冲销或作废 |
## 6.3 批量导入要求
### Germplasm 导入
必需列建议:
```text
crop_id 或 crop_name
germplasm_name 或 default_display_name
```
强烈建议列:
```text
accession_number
germplasmpui
breeding_method_name
country_of_origin_code
genus
species
seed_source
```
### SeedLot 导入
必需列建议:
```text
seed_lot_name
amount
units
germplasm_id/germplasm_name 或 cross_id/cross_name
mixture_percentage
```
### Attribute Value 导入
必需列建议:
```text
germplasm_id 或 germplasm_name
attribute_id 或 attribute_name/code
value
```
可选列:
```text
determined_date
source
remark
```
导入必须先预校验,错误报告至少包含:行号、字段、错误原因、建议修复方式。
---
# 7. 后端接口建议
## 7.1 主数据接口
```text
GET /germplasm
POST /germplasm
GET /germplasm/{id}
PUT /germplasm/{id}
DELETE /germplasm/{id}
GET /breeding-methods
POST /breeding-methods
GET /germplasm-attributes
POST /germplasm-attributes
GET /germplasm/{id}/attribute-values
POST /germplasm/{id}/attribute-values
GET /crossing-projects
POST /crossing-projects
GET /crossing-projects/{id}/crosses
GET /crosses
POST /crosses
GET /crosses/{id}/parents
POST /crosses/{id}/parents
GET /seed-lots
POST /seed-lots
GET /seed-lots/{id}/mixtures
POST /seed-lots/{id}/mixtures
GET /seed-lots/{id}/transactions
POST /seed-lots/{id}/transactions
```
## 7.2 选择器接口
```text
GET /selectors/crops
GET /selectors/breeding-methods
GET /selectors/germplasm?cropId=&keyword=
GET /selectors/germplasm-attributes?cropId=&datatype=&keyword=
GET /selectors/crossing-projects?programId=&keyword=
GET /selectors/crosses?crossingProjectId=&planned=&keyword=
GET /selectors/seed-lots?programId=&locationId=&keyword=
GET /selectors/observation-units?studyId=&germplasmId=&keyword=
```
---
# 8. 测试验收清单
1. 创建 germplasm 时,未选择 crop 不允许保存。
2. `germplasm_name``default_display_name` 都为空时不允许保存。
3. `germplasmpui` 重复时提示唯一性冲突。
4. attribute value 的 value 必须按 attribute datatype / scale 校验。
5. 创建 cross 时必须选择 crossing project。
6. 实际杂交选择 planned_cross_id 时不能选择自身。
7. cross parent 必须选择 parent_type。
8. cross parent 的 germplasm_id 和 observation_unit_id 至少填写一个。
9. seed lot 的 amount 不允许小于 0。
10. seed lot 的 units 必填。
11. seed lot content mixture 的 percentage 必须在 0 到 100 之间。
12. 同一 seed lot 的 mixture_percentage 总和不为 100 时,保存前应提示或禁止保存,具体取决于业务配置。
13. 出库数量不能超过当前库存。
14. transaction 创建后自动更新 seed_lot.amount。
15. 已有关联下游数据的 germplasm、cross、seed_lot 不允许物理删除。

View File

@@ -0,0 +1,778 @@
# Phenotyping 模块专业数据录入需求文档 V2
## 1. 文档目的
本文档用于指导 Phenotyping 表型模块的前端页面、后端接口、字段校验、数据导入和测试验收设计。本文档不只描述表关系,而是从真实育种表型采集业务出发,解释每个对象和字段的业务意义、录入方式、控件建议、校验规则和上下游影响。
## 2. 模块定位
Phenotyping 模块用于管理田间、温室、实验室或高通量设备采集到的表型数据。它的核心不是“录一张 observation 表”,而是完整描述:
```text
在哪个 study 里
对哪个 observation_unit
按照哪个 observation_variable
在什么时间、由谁、用什么方法
采集到了什么 value
并能关联事件、图片、坐标和上下文
```
## 3. 核心业务概念
| 概念 | 业务含义 | 关键表 |
| ---------------------------- | ---------------------------------------------------------- | ------------------------------------------------- |
| Ontology 本体 | 性状、方法、标尺、变量的术语来源,可以是本地本体或公开本体 | `ontology` |
| Trait 性状 | 测什么。例如株高、穗长、病害等级、籽粒颜色 | `trait` |
| Method 方法 | 怎么测。例如尺测、人工评分、无人机图像分析、实验室检测 | `method` |
| Scale 标尺 | 用什么单位或尺度表达。例如 cm、kg、0-5 等级、文本、布尔值 | `scale``scale_valid_value_category` |
| ObservationVariable 观测变量 | Trait + Method + Scale 的组合,表示一个可采集指标 | `observation_variable` |
| StudyVariable 研究采集指标 | 某个 study 计划采集哪些 observation variable | `study_variable` |
| ObservationUnit 观测单元 | 被观测对象。通常是 plot、plant、block、field、sample | `observation_unit` |
| Event 事件 | 管理动作或环境事件,如施肥、灌溉、打药、移栽、极端天气 | `event``event_param``event_observation_units` |
| Image 图像 | 田间图片、无人机图片、病害图片、长势图像等 | `image``image_observations` |
| Observation 观测值 | 某个观测单元在某个变量上的一次实际测量结果 | `observation` |
## 4. 推荐业务流程
```text
1. 准备 Core 上下文crop、program、trial、study、location、season
2. 维护或导入本体 ontology
3. 定义 trait / method / scale
4. 组合 observation_variable
5. 把 observation_variable 绑定到 study_variable形成本 study 的采集指标清单
6. 根据田间设计生成 observation_unit例如 block / plot / plant
7. 给 observation_unit 绑定材料来源germplasm / seed_lot / cross
8. 记录 event例如播种、移栽、施肥、灌溉、打药、采样、极端天气
9. 通过矩阵方式批量录入 observation
10. 上传 image并关联 observation_unit 或 observation
11. 做数据质控:缺失值、异常值、重复采集、单位和分类值校验
```
## 5. 推荐页面形态
### 5.1 Study 表型工作台
```text
Study 表型工作台
├─ 试验上下文study / trial / program / crop / location / season
├─ 指标清单study_variable
├─ 田间设计observation_unit 层级、block、plot、plant、row、column
├─ 材料布置germplasm、seed_lot、cross
├─ 表型矩阵observation_unit × observation_variable
├─ 田间事件event + event_param + event_observation_units
├─ 图片证据image + image_observations
├─ 数据质控:缺失值、异常值、重复值、单位校验、分类值校验
└─ 导入导出:观测单元模板、表型采集模板、图片元数据模板
```
### 5.2 表型矩阵录入
真实采集时不应只提供单条 observation 表单,而应支持矩阵录入:
| observation_unit | germplasm | 株高 cm | 穗长 cm | 倒伏等级 | 备注 |
| ---------------- | --------- | ------: | ------: | -------: | ---------- |
| Plot-001 | 华占 | 112.5 | 24.1 | 1 | 正常 |
| Plot-002 | 抗倒伏A | 98.3 | 22.8 | 0 | 正常 |
| Plot-003 | F2-001 | 101.6 | 23.0 | 4 | 台风后倒伏 |
保存时,系统按每个非空单元格生成一条 `observation`,每一列对应一个 `observation_variable`
---
# 6. 字段级专业录入需求
## 6.1 ontology 本体
### 业务说明
`ontology` 表示术语体系来源,用来说明 trait、method、scale、observation_variable 的定义来自哪里。它可以是本地维护的术语库,也可以是公开 Crop Ontology、Trait Ontology 或机构内部标准。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------ | ----------------------------------------- | -------------------------------- | --------------- | -------------------------------- |
| `id` | 本体主键,系统内部唯一标识 | 新增时系统生成;导入时可允许指定 | 隐藏/只读 | 必填、唯一;编辑时不可修改 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许前端手填 |
| `authors` | 本体作者或维护者 | 用户录入 | 文本框 | 可选;多个作者可用分号或数组扩展 |
| `copyright` | 本体版权说明 | 用户录入 | 文本框/多行文本 | 可选 |
| `description` | 本体用途说明 | 用户录入 | 多行文本 | 可选,建议填写 |
| `documentationurl` | 本体文档链接 | 用户录入 | URL 输入框 | 可选;若填写必须是合法 URL |
| `licence` | 本体许可证,例如 CC-BY、MIT、机构内部许可 | 用户录入/选择 | 文本框/下拉框 | 可选 |
| `ontology_name` | 本体名称,例如 Rice Trait Ontology | 用户录入 | 文本框 | 必填;同一用户下建议唯一 |
| `version` | 本体版本,例如 2024.1、v2.0 | 用户录入 | 文本框 | 可选;建议与外部本体版本一致 |
### 录入建议
- 若系统只是内部使用,可先创建一个“默认本体”或“本地表型本体”。
- 若对接 Crop Ontology建议保存 ontology 名称、版本、文档 URL。
- 本体删除前必须检查是否被 trait、method、scale、observation_variable 引用。
---
## 6.2 trait 性状
### 业务说明
`trait` 描述“测什么”。例如株高、叶长、穗长、倒伏等级、病害严重度、籽粒颜色。专业上 trait 可以拆成 `entity``attribute`
```text
Trait = Entity + Attribute
例如grain colour
entity = grain
attribute = colour
```
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------- | ----------------------------------------------------- | -------------------- | ----------------- | ---------------------------------------- |
| `id` | 性状主键,系统内部唯一标识 | 系统生成;导入可指定 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `attribute` | 性状属性,即被观察的特征,如 height、colour、severity | 用户录入/本体选择 | 文本框/本体选择器 | 可选;若填写 PUI建议同步填写 attribute |
| `attributepui` | 属性永久唯一标识,通常是 URI | 用户录入/本体带出 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
| `entity` | 性状实体,即观察对象部位,如 plant、leaf、grain、root | 用户录入/本体选择 | 文本框/本体选择器 | 可选 |
| `entitypui` | 实体永久唯一标识,通常是 URI | 用户录入/本体带出 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
| `main_abbreviation` | 性状主缩写,如 PH、GY、DTH | 用户录入 | 文本框 | 可选;同一 ontology 下建议唯一 |
| `status` | 性状状态,如 recommended、obsolete、legacy | 用户选择 | 下拉框 | 可选;推荐使用枚举 |
| `trait_class` | 性状分类,如 phenology、morphology、disease、quality | 用户选择/录入 | 下拉框/文本框 | 可选;建议字典化 |
| `trait_description` | 性状定义和说明 | 用户录入 | 多行文本 | 可选,但专业使用强烈建议填写 |
| `trait_name` | 性状名称,给用户看的名称 | 用户录入 | 文本框 | 必填;作为下拉展示名称 |
| `traitpui` | 性状永久唯一标识 | 用户录入/本体带出 | 文本框/URL 输入框 | 可选;若填写必须唯一 |
| `ontology_id` | 所属本体 | 从 ontology 选择 | 本体选择器 | 可选;必须引用存在的 ontology |
### 录入建议
- 简单业务可只填:`trait_name``trait_description``trait_class`
- 专业数据交换场景建议填写:`entity``attribute``traitpui``ontology_id`
- 不要把单位写进 trait。比如“株高 cm”不应该作为 trait正确拆分是 trait=株高scale=cm。
---
## 6.3 method 方法
### 业务说明
`method` 描述“怎么测”。同一个 trait 用不同方法测,会形成不同 observation_variable。例如
```text
Trait: plant height
Method 1: tape measure
Method 2: drone image processing
Scale: cm
```
这两个变量不能混为一谈,因为它们的数据来源、误差和可比性不同。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------- | ------------------------------------------------------------ | ------------------ | ----------------- | -------------------------------- |
| `id` | 方法主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `description` | 方法说明,如测量位置、工具、采样规则 | 用户录入 | 多行文本 | 可选;建议必填 |
| `formula` | 如果该方法通过计算得到结果,填写公式 | 用户录入 | 文本框/公式编辑器 | 可选;需要格式提示 |
| `method_class` | 方法分类,如 measurement、estimation、computed、image_analysis | 用户选择/录入 | 下拉框/文本框 | 可选;建议字典化 |
| `methodpui` | 方法永久唯一标识 | 用户录入/本体带出 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
| `name` | 方法名称 | 用户录入 | 文本框 | 必填;同一 ontology 下不建议重复 |
| `reference` | 方法参考文献、SOP、标准链接 | 用户录入 | 文本框/URL 输入框 | 可选;若为 URL 需校验格式 |
| `ontology_id` | 所属本体 | 从 ontology 选择 | 本体选择器 | 可选;必须引用存在的 ontology |
### 录入建议
- 方法页面应重点让用户说明“测量步骤”,否则后续数据不可复现。
- 对于人工评分,必须在 description 中说明评分标准,并通过 scale 配置有效分类值。
- 对于高通量图像方法reference 建议填写算法版本、模型版本或 SOP 链接。
---
## 6.4 scale 标尺
### 业务说明
`scale` 描述“用什么尺度表达结果”。它决定 observation.value 的合法值、单位、数据类型、小数位和分类值。常见类型:
```text
Numerical: 株高 cm、产量 kg/ha
Ordinal: 倒伏等级 0-5、病害等级 1-9
Categorical: 籽粒颜色 red/yellow/white
Text: 描述性备注
Boolean: 是否开花、是否倒伏
Date: 开花日期
```
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ----------------- | ----------------------------------------------------- | ------------------ | ----------------- | --------------------------------- |
| `id` | 标尺主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `data_type` | 数据类型,决定 observation.value 的输入控件和校验方式 | 用户选择 | 下拉框 | 必填;使用系统枚举 |
| `decimal_places` | 小数位数 | 用户录入 | 数字输入框 | 数值型可填;必须为非负整数 |
| `scale_name` | 标尺名称,如 cm、0-5 lodging score、disease score 1-9 | 用户录入 | 文本框 | 必填;同一 ontology 下建议唯一 |
| `scalepui` | 标尺永久唯一标识 | 用户录入/本体带出 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
| `units` | 单位,如 cm、mm、kg/ha、days | 用户选择/录入 | 单位选择器/文本框 | 数值型建议必填;分类型可为空 |
| `valid_value_max` | 最大有效值 | 用户录入 | 数字输入框/文本框 | 数值/等级型校验;必须大于等于 min |
| `valid_value_min` | 最小有效值 | 用户录入 | 数字输入框/文本框 | 数值/等级型校验;必须小于等于 max |
| `ontology_id` | 所属本体 | 从 ontology 选择 | 本体选择器 | 可选;必须引用存在 ontology |
### 录入建议
- `data_type` 是动态表单核心字段。前端要根据它渲染 observation.value
- Numerical数字输入框按 min/max/decimal_places 校验;
- Ordinal数字或下拉通常有 min/max
- Categorical下拉框选项来自 `scale_valid_value_category`
- Text文本框
- Boolean开关/单选;
- Date日期选择器。
- 如果 data_type 是分类型,必须至少配置一个 `scale_valid_value_category`
- 如果 data_type 是数值型,建议填写单位和有效范围。
---
## 6.5 scale_valid_value_category 分类有效值
### 业务说明
`scale_valid_value_category` 是分类型或等级型 scale 的合法取值表。例如倒伏等级 0-5、病害等级 1-9、颜色 red/yellow/white。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ---------- | --------------------------------- | --------------------------- | ----------------- | ------------------------ |
| `id` | 分类值主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `label` | 用户界面展示文案,如 “0 - 不倒伏” | 用户录入 | 文本框 | 必填 |
| `value` | 实际保存值,如 0、1、red | 用户录入 | 文本框 | 必填;同一 scale 内唯一 |
| `scale_id` | 所属 scale | 从 scale 选择或由详情页带出 | Scale 选择器/隐藏 | 必选;必须引用存在 scale |
### 录入建议
- 在 scale 详情页中以内嵌表格维护。
- 保存 observation 时,如果 scale 是分类型value 必须在该表中存在。
- label 可以给用户看value 用于保存和导出,二者可以不同。
---
## 6.6 observation_variable 观测变量
### 业务说明
`observation_variable` 是真正进入采集模板的指标。它由 trait、method、scale 组合而成。
```text
observation_variable = trait + method + scale
例如:株高 + 尺子测量 + cm = 株高-尺测法-cm
```
它不是观测结果,而是“可以被测的一列数据”。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ---------------------- | ------------------------------------------ | ------------------------ | ----------------- | ---------------------------------------- |
| `id` | 观测变量主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `default_value` | 默认观测值,例如默认等级、默认文本 | 用户录入 | 动态控件 | 可选;按 scale 校验 |
| `documentationurl` | 变量说明文档链接 | 用户录入 | URL 输入框 | 可选;若填写必须合法 URL |
| `growth_stage` | 建议采集生育期,如 flowering、maturity | 用户录入/选择 | 下拉框/文本框 | 可选;建议字典化 |
| `institution` | 定义该变量的机构 | 用户录入 | 文本框 | 可选 |
| `language` | 变量语言,如 zh、en | 用户选择 | 下拉框 | 可选;建议 ISO 639-1 |
| `scientist` | 提交或维护该变量的科学家/负责人 | 用户录入/人员选择 | 文本框/选择器 | 可选 |
| `status` | 变量状态,如 recommended、obsolete、legacy | 用户选择 | 下拉框 | 可选obsolete 不建议用于新 study |
| `submission_timestamp` | 变量提交时间 | 系统默认当前时间,可调整 | 日期时间选择器 | 可选;新增默认当前时间 |
| `crop_id` | 适用作物 | 从 crop 选择 | 作物选择器 | 可选;如果填写,下游 study 应尽量同 crop |
| `method_id` | 测定方法 | 从 method 选择 | 方法选择器 | 必选 |
| `ontology_id` | 所属本体 | 从 ontology 选择 | 本体选择器 | 可选 |
| `scale_id` | 标尺 | 从 scale 选择 | 标尺选择器 | 必选 |
| `trait_id` | 被测性状 | 从 trait 选择 | 性状选择器 | 必选 |
| `name` | 变量名称,采集矩阵列名 | 自动生成后允许修改 | 文本框 | 必填;同一 crop/ontology 下建议唯一 |
| `pui` | 变量永久唯一标识 | 用户录入/本体带出 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
### 录入建议
- 新建变量采用“三段式选择”:先选 trait再选 method再选 scale。
- 系统自动生成 name例如`trait_name + method_name + scale_name`,用户可修改。
- 变量详情页应展示:被哪些 study 使用、已有多少 observation、是否仍推荐使用。
- 如果变量已经产生 observation不建议修改 trait/method/scale只能停用旧变量并创建新变量。
---
## 6.7 study_variable 研究采集指标
### 业务说明
`study_variable` 是 study 和 observation_variable 的多对多关系,表示某个 study 计划采集哪些指标。它是“配置采集模板”的动作痕迹。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ---------------- | --------------------- | ---------------------------- | ----------------- | --------------------------- |
| `study_db_id` | 所属 study | 从 study 选择或由工作台带出 | Study 选择器/隐藏 | 必选;必须引用存在 study |
| `variable_db_id` | 该 study 要采集的变量 | 从 observation_variable 选择 | 变量多选器 | 必选;必须引用存在 variable |
### 录入建议
- 在 Study 表型工作台的“指标清单”Tab 中维护。
- 支持批量选择变量和从历史 study 复制变量清单。
- 若某变量已有 observation不允许从 study_variable 中直接移除,除非先处理已有观测数据。
---
## 6.8 observation_unit 观测单元
### 业务说明
`observation_unit` 是“被观测对象”。通常是 plot 或 plant也可以是 field、block、sub-plot、sample 等。它连接了 Core 上下文和材料来源,是表型数据的入口,也可以成为后续 genotyping sample 的来源。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ----------------------- | ------------------------------------ | ------------------------- | ----------------- | -------------------------------------------------- |
| `id` | 观测单元主键 | 系统生成;导入可指定 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `observation_unit_name` | 观测单元名称,如 Plot-001、Plant-003 | 用户录入/批量生成 | 文本框 | 必填;同一 study 内建议唯一 |
| `observation_unitpui` | 观测单元永久唯一标识 | 用户录入/系统生成 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
| `crop_id` | 作物 | 由 study 自动带出,可只读 | 作物选择器/只读 | 可选但建议有;需与 study.crop 一致 |
| `cross_id` | 材料来源 cross | 从 cross_entity 选择 | Cross 选择器 | 可选;与 germplasm/seed_lot 至少建议选一个材料来源 |
| `germplasm_id` | 材料来源 germplasm | 从 germplasm 选择 | 材料选择器 | 可选;常用字段 |
| `program_id` | 项目 | 由 study 自动带出 | 项目选择器/只读 | 可选但建议有;需与 study.program 一致 |
| `seed_lot_id` | 种子批次来源 | 从 seed_lot 选择 | SeedLot 选择器 | 可选;田间播种建议填写 |
| `study_id` | 所属 study | 从 study 选择或工作台带出 | Study 选择器/隐藏 | 必选 |
| `trial_id` | 所属 trial | 由 study 自动带出 | Trial 选择器/只读 | 可选但建议有;需与 study.trial 一致 |
### 录入建议
- 推荐从 Study 表型工作台批量生成,不建议逐条手工建。
- 必须支持田间布局字段field、block、rep、plot、row、column、plant。若当前表没有这些字段应通过 position/level 附属表或 additional_info 保存。
- `germplasm_id` 代表材料身份;`seed_lot_id` 代表实际播种批次;二者建议都保留。
- 选择 seed_lot 时可自动带出 germplasm但不应强行覆盖用户选择。
### 观测层级建议
| 层级 | 含义 | 例子 |
| ------ | -------------- | ---------- |
| field | 田块或试验场 | Field-01 |
| block | 区组 | Block-01 |
| rep | 重复 | Rep-01 |
| plot | 小区 | Plot-001 |
| plant | 单株 | Plant-001 |
| sample | 样本级观测对象 | Sample-001 |
---
## 6.9 event 事件
### 业务说明
`event` 记录发生在 study 或 observation_unit 上的离散事件。它既可以是处理的一部分,也可以是影响结果的外部背景。例如播种、移栽、施肥、灌溉、打药、收获、采样、暴雨、台风、病害暴发等。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------- | ---------------------------------------------------------- | ------------------------- | ----------------- | -------------------------- |
| `id` | 事件主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `event_description` | 事件说明,如“台风后倒伏严重” | 用户录入 | 多行文本 | 可选;异常事件建议必填 |
| `event_type` | 事件类型名称,如 fertilizer、irrigation、planting、harvest | 用户选择/录入 | 下拉框/文本框 | 必填;建议使用事件类型字典 |
| `event_type_db_id` | 事件类型 ID可引用标准事件类型字典 | 用户选择/系统带出 | 选择器/隐藏 | 可选 |
| `study_id` | 事件所属 study | 从 study 选择或工作台带出 | Study 选择器/隐藏 | 必选 |
### 录入建议
- 在 Study 表型工作台的“事件”Tab 中维护。
- 新增事件时先选择作用范围:整个 study 或部分 observation_unit。
- 如果只作用于部分 plot/plant必须通过 `event_observation_units` 记录范围。
- 事件发生时间字段在你当前表结构中未显式列出,但业务上非常重要;如果数据库已有 event_date/time 字段,应强制录入;如果没有,建议补字段或放入 additional_info。
---
## 6.10 event_param 事件参数
### 业务说明
`event_param` 是事件的参数明细。例如施肥事件可以有肥料类型、剂量、单位;灌溉事件可以有水量、持续时间;打药事件可以有药剂名称、浓度、剂量。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------- | ------------------------------------- | ----------------- | ----------------- | ------------------------- |
| `id` | 事件参数主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `code` | 参数代码,如 N_RATE、IRR_VOL | 用户录入/字典带出 | 文本框 | 可选;同一事件内建议唯一 |
| `description` | 参数解释 | 用户录入 | 多行文本 | 可选 |
| `key` | 参数键,如 fertilizerType、dose、unit | 用户录入/字典选择 | 文本框 | 必填;同一事件内不应重复 |
| `name` | 参数名称,如 氮肥施用量 | 用户录入 | 文本框 | 可选 |
| `rdf_value` | RDF 或本体语义值 | 用户录入/系统带出 | 文本框 | 可选;普通业务可隐藏 |
| `units` | 参数单位,如 kg/ha、mm、L | 用户选择/录入 | 单位选择器 | 可选;数值参数建议必填 |
| `value` | 参数值 | 用户录入 | 动态控件 | 可选;若 key 需要值则必填 |
| `value_description` | 参数值说明 | 用户录入 | 多行文本 | 可选 |
| `event_id` | 所属事件 | 由事件详情页带出 | Event 选择器/隐藏 | 必选 |
### 录入建议
- 前端以键值表格方式维护。
- 可以为常用事件类型配置参数模板,例如 fertilizer 事件默认出现 fertilizerType、amount、units。
- 参数值是否必填取决于事件类型配置。
---
## 6.11 event_observation_units 事件作用范围
### 业务说明
`event_observation_units` 记录事件作用到哪些 observation_unit。比如一次施肥作用于整个 study则可以不逐个绑定如果某个处理只作用于部分 plot则必须明确绑定。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ---------------------- | ------------ | --------------------------------------- | ----------------- | ------------------------ |
| `event_entity_id` | 事件 | 由事件详情页带出 | Event 选择器/隐藏 | 必选 |
| `observation_units_id` | 事件作用对象 | 从当前 study 的 observation_unit 中选择 | 多选器/表格 | 必选;必须属于同一 study |
### 录入建议
- 支持按 block、rep、plot 范围批量选择。
- 如果事件作用于整个 study可以在 event 上记录 scope=study不必生成大量关系记录。
- 如果 event_observation_units 有记录,所有 observation_units 必须属于 event.study_id。
---
## 6.12 image 图像
### 业务说明
`image` 用于保存图片或图片元数据。图片可以是人工拍摄、无人机、固定相机、显微图、病害图片等。图片可以直接关联 observation_unit也可以通过 `image_observations` 关联具体 observation。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------------- | ------------------------------------- | ------------------------ | ------------------- | -------------------------------------- |
| `id` | 图片主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `copyright` | 图片版权或授权说明 | 用户录入 | 文本框 | 可选 |
| `description` | 图片说明如“Plot-003 台风后倒伏照片” | 用户录入 | 多行文本 | 可选,建议填写 |
| `image_data` | 图片二进制内容 | 用户上传 | 文件上传 | 与 `imageurl` 至少一个;限制大小和格式 |
| `image_file_name` | 图片文件名 | 上传时自动填充 | 只读/文本框 | 可选;上传时自动生成 |
| `image_file_size` | 文件大小 | 上传时自动识别 | 只读 | 可选;应限制最大大小 |
| `image_height` | 图片高度 | 上传后自动识别 | 只读/数字框 | 可选;必须为非负整数 |
| `imagemimetype` | MIME 类型,如 image/jpeg、image/png | 上传后自动识别 | 只读/下拉框 | 可选;只允许图片 MIME 类型 |
| `imageurl` | 外部图片 URL 或对象存储 URL | 用户填写/上传后生成 | URL 输入框 | 与 `image_data` 至少一个URL 格式校验 |
| `image_width` | 图片宽度 | 上传后自动识别 | 只读/数字框 | 可选;必须为非负整数 |
| `name` | 图片名称 | 用户录入/文件名带出 | 文本框 | 必填 |
| `time_stamp` | 拍摄或上传时间 | 用户录入/系统默认 | 日期时间选择器 | 可选;建议填写拍摄时间 |
| `coordinates_id` | 图片坐标 | 地图取点/坐标对象选择 | 地图控件/坐标选择器 | 可选;建议支持 Point/Polygon |
| `observation_unit_id` | 所属观测单元 | 从 observation_unit 选择 | 观测单元选择器 | 可选;若填写应属于同一 study 上下文 |
### 录入建议
- 推荐图片文件存对象存储,数据库只存 URL 和元数据,避免 bytea 过大。
- 手机拍照或无人机导入时应自动提取文件名、大小、宽高、MIME、拍摄时间和 GPS 信息。
- 对无人机俯拍图,可保存图像中心点,也可保存图像覆盖范围 Polygon。
---
## 6.13 image_observations 图片与观测值关系
### 业务说明
`image_observations` 表示某张图片支持或关联哪些 observation。比如一张倒伏照片可以关联一个 plot 的倒伏等级 observation。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ----------------- | ---------- | ------------------- | ------------------ | ---------------------------------------- |
| `image_entity_id` | 图片 | 由图片详情页带出 | Image 选择器/隐藏 | 必选 |
| `observations_id` | 关联观测值 | 从 observation 选择 | Observation 选择器 | 必选;建议与图片的 observation_unit 一致 |
### 录入建议
- 图片详情页支持关联多个 observation。
- observation 详情页也支持反向查看相关图片。
- 如果图片已绑定 observation_unit则关联 observation 时应过滤为同一 observation_unit 下的 observation。
---
## 6.14 observation 观测值
### 业务说明
`observation` 是 Phenotyping 模块最核心的事实表。它表示“某个 observation_unit 在某个 observation_variable 上的一次实际采集结果”。
```text
observation_unit = Plot-003
observation_variable = 株高-尺测法-cm
value = 112.5
observation_time_stamp = 2026-07-12 09:30
```
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------------- | ------------------ | ---------------------------------------- | ------------------- | ------------------------------------------ |
| `id` | 观测值主键 | 系统生成;导入可指定 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `collector` | 采集人 | 用户选择/登录用户带出 | 人员选择器/文本框 | 可选;人工采集建议填写 |
| `observation_time_stamp` | 观测时间 | 用户录入/采集设备带出 | 日期时间选择器 | 建议必填;按 ISO 8601 保存 |
| `uploaded_by` | 上传人 | 登录用户自动写入 | 只读 | 可选;批量导入时自动填 |
| `value` | 实际观测值 | 用户录入/导入/设备上传 | 动态控件 | 必填;按 variable.scale 校验 |
| `crop_id` | 作物上下文 | 由 observation_unit 或 study 自动带出 | 只读/隐藏 | 可选但建议保存;需与 observation_unit 一致 |
| `geo_coordinates_id` | 观测发生坐标 | 地图取点/设备 GPS | 地图控件/坐标选择器 | 可选;坐标需合法 |
| `observation_unit_id` | 被观测对象 | 从 observation_unit 选择或矩阵行带出 | 观测单元选择器/隐藏 | 必选 |
| `observation_variable_id` | 观测变量 | 从 observation_variable 选择或矩阵列带出 | 变量选择器/隐藏 | 必选 |
| `program_id` | 项目上下文 | 由 observation_unit/study 自动带出 | 只读/隐藏 | 可选但建议保存 |
| `season_id` | 季节 | 从 study season 或用户选择 | Season 选择器 | 可选;多季节 study 建议填写 |
| `study_id` | 所属 study | 由 observation_unit 自动带出 | 只读/隐藏 | 必选;需与 observation_unit.study 一致 |
| `trial_id` | 所属 trial | 由 observation_unit/study 自动带出 | 只读/隐藏 | 可选但建议保存 |
### 录入建议
- 普通录入优先走矩阵:行是 observation_unit列是 observation_variable。
- 单条表单只用于补录、纠错、详情编辑。
- value 必须使用 observation_variable.scale 决定控件和校验:
- 数值型:数字、小数位、范围;
- 分类型:只能从 valid category 中选;
- 日期型:日期格式;
- 布尔型true/false
- 文本型:长度限制。
- 同一 `observation_unit_id + observation_variable_id + observation_time_stamp` 可允许重复,但必须在页面展示重复标记、采集人和上传来源。
---
# 7. 跨表联动规则
| 场景 | 联动规则 |
| ------------------------- | ------------------------------------------------------------ |
| 创建 observation_variable | 必须先选择 trait、method、scale系统自动生成变量名称 |
| 配置 study_variable | 变量选择器优先展示同 crop 或未限定 crop 的变量 |
| 创建 observation_unit | 选择 study 后自动带出 crop、program、trial |
| 选择 seed_lot | 可自动带出 germplasm但允许用户确认 |
| 录入 observation | 选择 observation_unit 后自动带出 study、trial、program、crop |
| 录入 observation.value | 根据 observation_variable.scale 动态渲染控件和校验 |
| 新增 event | 从 study 工作台进入时自动带出 study_id |
| 选择事件作用范围 | 只能选择同一 study 下的 observation_unit |
| 上传 image | 如果从 observation_unit 详情页上传,自动绑定 observation_unit_id |
| 关联 image_observations | 如果图片已绑定 observation_unit只能关联同 observation_unit 的 observation |
---
# 8. 删除和停用规则
| 对象 | 删除限制 |
| -------------------- | ------------------------------------------------------------ |
| ontology | 已被 trait/method/scale/variable 引用时不可物理删除 |
| trait | 已被 observation_variable 或 germplasm_attribute_definition 引用时不可物理删除 |
| method | 已被 observation_variable 引用时不可物理删除 |
| scale | 已被 observation_variable 或 attribute definition 引用时不可物理删除 |
| observation_variable | 已产生 observation 时不可删除,只能停用或设为 obsolete |
| study_variable | 若已有该变量的 observation不允许直接移除 |
| observation_unit | 已有 observation、image、event、sample 时不可删除 |
| event | 已有关联 event_param 或 event_observation_units 时删除需级联确认或禁止 |
| image | 已关联 observation 时不可直接删除,应先解除关系或作废 |
| observation | 原始数据原则上不建议物理删除;建议保留修改历史或作废状态 |
---
# 9. 批量导入要求
## 9.1 ObservationUnit 导入模板
必需列建议:
```text
study_id 或 study_name
observation_unit_name
observation_level_name
observation_level_code
```
强烈建议列:
```text
germplasm_id 或 germplasm_name
seed_lot_id 或 seed_lot_name
block
rep
plot
row
column
```
## 9.2 ObservationVariable 导入模板
必需列建议:
```text
trait_name
method_name
scale_name
variable_name
```
可选列:
```text
trait_pui
method_pui
scale_pui
variable_pui
crop_name
growth_stage
status
```
## 9.3 Observation 矩阵导入模板
推荐格式:
```text
observation_unit_name,germplasm_name,collection_time,collector,PlantHeight_cm,LodgingScore_0_5,DiseaseScore_1_9
Plot-001,华占,2026-07-12T09:30:00+08:00,张三,112.5,1,2
Plot-002,抗倒伏A,2026-07-12T09:35:00+08:00,张三,98.3,0,1
```
导入规则:
1. 每个变量列必须能映射到一个 observation_variable。
2. 每一行必须能匹配一个 observation_unit。
3. 每个非空单元格生成一条 observation。
4. 空值不生成 observation除非用户选择“导入为空观测”。
5. 导入前必须预校验,错误报告包含行号、列名、错误原因、建议修复方式。
## 9.4 Image 导入模板
必需列建议:
```text
image_name
image_url 或 image_file
```
可选列:
```text
observation_unit_name
observation_id
capture_time
longitude
latitude
polygon
copyright
description
```
---
# 10. 后端接口建议
## 10.1 主数据接口
```text
GET /ontologies
POST /ontologies
GET /ontologies/{id}
PUT /ontologies/{id}
DELETE /ontologies/{id}
GET /traits
POST /traits
GET /traits/{id}
PUT /traits/{id}
GET /methods
POST /methods
GET /methods/{id}
PUT /methods/{id}
GET /scales
POST /scales
GET /scales/{id}
PUT /scales/{id}
GET /scales/{id}/valid-values
POST /scales/{id}/valid-values
GET /observation-variables
POST /observation-variables
GET /observation-variables/{id}
PUT /observation-variables/{id}
GET /studies/{studyId}/variables
POST /studies/{studyId}/variables
DELETE /studies/{studyId}/variables/{variableId}
GET /studies/{studyId}/observation-units
POST /studies/{studyId}/observation-units/batch-generate
POST /observation-units
PUT /observation-units/{id}
GET /studies/{studyId}/events
POST /studies/{studyId}/events
GET /events/{id}/params
POST /events/{id}/params
POST /events/{id}/observation-units
GET /images
POST /images
POST /images/upload
POST /images/{id}/observations
GET /observations
POST /observations
POST /observations/matrix
POST /observations/import
```
## 10.2 选择器接口
```text
GET /selectors/ontologies
GET /selectors/traits?ontologyId=&keyword=
GET /selectors/methods?ontologyId=&keyword=
GET /selectors/scales?ontologyId=&dataType=&keyword=
GET /selectors/observation-variables?cropId=&studyId=&keyword=
GET /selectors/studies?programId=&trialId=&keyword=
GET /selectors/observation-units?studyId=&level=&germplasmId=&keyword=
GET /selectors/events?studyId=&eventType=&keyword=
GET /selectors/images?observationUnitId=&keyword=
```
---
# 11. 测试验收清单
1. 创建 trait 时,`trait_name` 必填。
2. 创建 method 时,`name` 必填。
3. 创建 scale 时,`scale_name``data_type` 必填。
4. 分类型 scale 没有 valid value 时,应提示或禁止用于 observation_variable。
5. 创建 observation_variable 时trait、method、scale 必选。
6. observation_variable 名称可自动生成,也允许用户手动修改。
7. 配置 study_variable 时,不能重复绑定同一个 variable。
8. 创建 observation_unit 时study 必选。
9. 选择 study 后crop、program、trial 自动带出。
10. 同一 study 内 observation_unit_name 重复时提示。
11. observation_unit 至少建议绑定 germplasm、seed_lot、cross 中一个材料来源。
12. 创建 event 时study 和 event_type 必填。
13. event 绑定 observation_unit 时,所有 observation_unit 必须属于该 event 的 study。
14. 图片上传时image_data 和 imageurl 至少一个存在。
15. 图片 MIME 类型必须是允许的图片类型。
16. observation 创建时observation_unit、observation_variable、value 必填。
17. observation.value 必须按 scale.data_type 校验。
18. 数值型 value 必须在 valid_value_min 和 valid_value_max 范围内。
19. 分类型 value 必须属于 scale_valid_value_category。
20. observation 的 study/trial/program/crop 必须与 observation_unit 上下文一致。
21. 矩阵录入保存时,每个有效单元格生成一条 observation。
22. 导入失败时必须返回行号、字段、错误原因和修复建议。
23. 已产生 observation 的 observation_variable 不允许直接删除。
24. 已被 observation、image、event、sample 引用的 observation_unit 不允许物理删除。
25. 所有日期时间字段按 ISO 8601 保存,并保留时区或统一转换为 UTC。
---
# 12. 开发实现重点
1. `observation_variable` 是表型指标定义,不是观测值。
2. `observation_unit` 是被观测对象,不是实际测量值。
3. `observation` 才是真正的表型事实数据。
4. `value` 字段虽然数据库是字符串,但前端和后端必须按 scale 做类型校验。
5. `study` 是 Phenotyping 的核心上下文入口,几乎所有表型数据都应能追溯到 study。
6. 表型采集页面应优先做矩阵录入,不要只做单条 CRUD。
7. 图片不要直接塞数据库大字段为主,建议走对象存储 URL + 元数据。
8. Event 不只是备注,它是解释表型差异的重要上下文,应支持作用范围和参数化。

View File

@@ -0,0 +1,890 @@
# Genotyping 模块专业数据录入需求文档 V2
## 1. 文档目的
本文档用于指导 Genotyping 基因型模块的前端页面、后端接口、字段校验、文件导入、矩阵展示和测试验收设计。本文档不只描述数据库表关系,而是从真实基因型检测业务出发,解释每个对象和字段的业务意义、录入方式、控件建议、校验规则和上下游影响。
## 2. 模块定位
Genotyping 模块描述从田间或实验对象取样,到实验室检测,再到导入基因型结果矩阵的完整流程。
它的核心业务不是“录 allele_call 表”,而是:
```text
从哪个 study / observation_unit 取样
样本放在哪块 plate 的哪个 well
检测结果基于哪个 reference_set
结果文件包含哪些 variantset / variant
每个 sample 在每个 variant 上的 genotype 是什么
这些位点是否还映射到 genome_map / linkage_group
```
## 3. 核心业务主线
Genotyping 有三条主线:
```text
样本线study / observation_unit -> plate -> sample -> callset
位点线reference_set -> reference -> reference_bases -> variantset -> variant
结果线callset + variant -> allele_call
图谱线crop -> genome_map -> linkage_group -> marker_position -> variant
```
### 3.1 样本线
样本线回答:
```text
从哪个材料、哪个 plot、哪株植物或哪个样本来源取样
样本叫什么?
谁采的?什么时候采的?
放在哪块样本板哪个孔?
```
对应核心表:
```text
plate
sample
callset
```
### 3.2 位点线
位点线回答:
```text
检测结果基于哪个参考基因组?
参考序列有哪些 chromosome / scaffold / contig
检测了哪些 SNP / Indel / SV 位点?
这些位点属于哪个 variantset
```
对应核心表:
```text
reference_set
reference
reference_bases
variantset
variant
```
### 3.3 结果线
结果线回答:
```text
某个 sample 在某个 variant 上的 genotype 是什么?
测序深度是多少?
是否 phased
是否有 likelihood
```
对应核心表:
```text
callset
allele_call
```
### 3.4 图谱线
图谱线回答:
```text
某个位点在遗传图谱或物理图谱上的位置是什么?
它属于哪个 linkage group / chromosome / scaffold
单位是 cM 还是 Mb
```
对应核心表:
```text
genome_map
linkage_group
marker_position
```
---
# 4. 推荐业务流程
```text
1. 准备 Core / Phenotyping 上游数据crop、program、trial、study、observation_unit
2. 从 observation_unit 或 study 批量生成 sample
3. 创建 plate并把 sample 分配到 well / row / column
4. 送检或接收实验室结果文件
5. 创建 reference_set维护 reference / reference_bases
6. 创建 variantset导入 variant
7. 为 sample 生成 callset
8. 绑定 callset 与 variantset
9. 导入 allele_call形成 sample × variant 基因型矩阵
10. 如有遗传图谱,创建 genome_map / linkage_group / marker_position
11. 做结果质控缺失率、重复位点、重复样本、read depth、genotype 格式、reference 一致性
```
---
# 5. 推荐页面形态
## 5.1 Genotyping 工作台
建议以 study 或 genotyping project 为入口组织页面:
```text
Genotyping 工作台
├─ 样本管理sample 列表、从 observation_unit 生成 sample
├─ 样本板plate 列表、96/384 孔位布局
├─ 参考基因组reference_set、reference、reference_bases
├─ 变异集合variantset、variant、analysis、format
├─ 检测结果callset、allele_call、genotype matrix
├─ 遗传图谱genome_map、linkage_group、marker_position
├─ 导入导出sample 模板、VCF/Hapmap/CSV、allele matrix
└─ 质控:缺失率、重复率、深度、位点过滤、样本过滤
```
## 5.2 Plate 孔位布局页
样本板不建议只做普通 CRUD应提供 96 孔 / 384 孔布局视图:
```text
Plate-96-001
01 02 03 04
A SAMPLE-001 SAMPLE-002 SAMPLE-003 SAMPLE-004
B SAMPLE-013 SAMPLE-014 SAMPLE-015 SAMPLE-016
C SAMPLE-025 SAMPLE-026 EMPTY EMPTY
...
```
用户在孔位上放置 sample系统保存
```text
sample.plate_id
sample.well
sample.plate_row
sample.plate_column
```
## 5.3 Genotype Matrix 结果页
`allele_call` 是基因型矩阵中的一个格子:
| sample / callset | SNP001 | SNP002 | SNP003 |
| ---------------- | ------ | ------ | ------ |
| SAMPLE-001 | A/G | C/C | T/G |
| SAMPLE-002 | A/A | C/T | T/T |
| SAMPLE-003 | ./ . | C/C | T/G |
导入时:
```text
样本列 / 样本行 -> sample / callset
位点列 / 位点行 -> variant
单元格 genotype -> allele_call.genotype
```
---
# 6. 字段级专业录入需求
## 6.1 plate 样本板
### 业务说明
`plate` 用于管理承载样本的样本板或样本容器组。真实业务里,它通常是一块 96 孔板、384 孔板也可能是一组试管或实验室提交批次。plate 的核心价值是支持实验室送样、扫码、孔位追踪和结果回填。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------------------- | ----------------------------------------------- | ------------------------------ | ----------------- | -------------------------------------------- |
| `id` | 样本板主键,系统内部唯一标识 | 系统生成;导入可指定 | 隐藏/只读 | 必填、唯一;编辑不可修改 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许前端手填 |
| `client_plate_barcode` | 客户侧或外部实验室给出的板条码 | 用户录入/扫码/导入 | 文本框/扫码框 | 可选;建议唯一 |
| `client_plate_db_id` | 客户侧系统中的 plate ID | 用户录入/导入 | 文本框 | 可选;用于外部系统对接 |
| `plate_barcode` | 本系统样本板条码 | 系统生成/扫码录入 | 文本框/扫码框 | 可选;建议唯一 |
| `plate_format` | 样本板规格,如 96、384 | 用户选择 | 下拉框 | 可选;若填写,应限制为系统支持规格 |
| `plate_name` | 样本板名称,如 Plate-2026-001 | 用户录入/系统生成 | 文本框 | 与 barcode 至少一个必填 |
| `sample_submission_format` | 样本提交格式,如 DNA、tissue、seed、tube、plate | 用户选择 | 下拉框 | 可选;建议枚举化 |
| `sample_type` | 该板默认样本类型 | 用户选择 | 下拉框 | 可选;可作为 sample 默认值 |
| `status_time_stamp` | 样本板状态更新时间 | 系统自动写入 | 只读日期时间 | 可选;状态变化时自动更新 |
| `program_id` | 所属项目 | 从 program 选择或由 study 带出 | 项目选择器/只读 | 可选;若 study 已选,应与 study.program 一致 |
| `study_id` | 所属 study | 从 study 选择 | Study 选择器 | 可选;若选择则带出 trial/program |
| `submission_id` | 外部 vendor submission 或送检单 ID | 用户录入/选择 | 选择器/文本框 | 可选;用于实验室送检对接 |
| `trial_id` | 所属 trial | 从 trial 选择或由 study 带出 | Trial 选择器/只读 | 可选;若 study 已选,应与 study.trial 一致 |
### 录入建议
- 创建 plate 时,用户先选择 `plate_format`,系统生成孔位矩阵。
- 如果从 study 工作台创建,`program_id``trial_id``study_id` 自动带出。
- 如果通过实验室返回文件创建,应优先用 `plate_barcode``client_plate_barcode` 匹配。
### 验收标准
1. `plate_name``plate_barcode` 至少填写一个。
2. 同一系统中 `plate_barcode` 不应重复。
3. 选择 study 后trial/program 自动带出且保持一致。
4. plate_format 为 96 时,只允许 A01-H12384 时只允许 A01-P24。
---
## 6.2 sample 样本
### 业务说明
`sample` 是 genotyping 流程的样本入口表示从田间、温室、实验室或库存材料中取出的一个物理生物样本例如叶片、种子、DNA、组织、提取液等。sample 应尽可能关联 observation_unit这样才能把表型和基因型打通。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------------- | ------------------------------------ | -------------------------------------- | ---------------------- | --------------------------------------------------------- |
| `id` | 样本主键,系统内部唯一标识 | 系统生成;导入可指定 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `concentration` | 样本浓度,如 DNA 浓度 50 ng/µL | 用户录入/仪器导入 | 数字+单位输入 | 可选;建议拆分数值和单位,当前字段可暂存文本 |
| `plate_column` | 样本在 plate 中的列号 | 孔位选择自动生成 | 数字输入/孔位控件 | 绑定 plate 时必填或由 well 解析;范围受 plate_format 限制 |
| `plate_row` | 样本在 plate 中的行号 | 孔位选择自动生成 | 下拉/孔位控件 | 绑定 plate 时必填或由 well 解析;范围受 plate_format 限制 |
| `sample_barcode` | 样本条码 | 扫码/系统生成/导入 | 文本框/扫码框 | 可选;建议唯一 |
| `sample_description` | 样本说明 | 用户录入 | 多行文本 | 可选 |
| `sample_group_db_id` | 样本组 ID用于批次、送检组或处理组 | 用户选择/导入 | 选择器/文本框 | 可选 |
| `sample_name` | 样本名称,如 SAMPLE-001 | 用户录入/系统生成 | 文本框 | 必填;同一 study 下建议唯一 |
| `samplepui` | 样本永久唯一标识 | 用户录入/系统生成 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
| `sample_timestamp` | 采样时间 | 用户录入/设备带出 | 日期时间选择器 | 可选;建议必填 |
| `sample_type` | 样本类型,如 tissue、DNA、seed、leaf | 用户选择 | 下拉框 | 可选;建议枚举化 |
| `taken_by` | 采样人 | 用户选择/登录用户带出 | 人员选择器/文本框 | 可选 |
| `tissue_type` | 组织类型,如 leaf、root、grain、stem | 用户选择/录入 | 下拉框/文本框 | 可选;样本为组织时建议填写 |
| `volume` | 样本体积,如 50 µL | 用户录入/仪器导入 | 数字+单位输入 | 可选;当前字段可暂存文本 |
| `well` | 孔位,如 A01、H12 | 孔位布局选择 | 孔位选择器 | 绑定 plate 时建议必填;同一 plate 内唯一 |
| `observation_unit_id` | 来源观测单元 | 从 observation_unit 选择或批量生成带出 | ObservationUnit 选择器 | 可选但强烈建议填写;必须存在 |
| `plate_id` | 所属样本板 | 从 plate 选择 | Plate 选择器 | 可选;若填写需校验孔位唯一 |
| `program_id` | 项目上下文 | 由 observation_unit/study 带出 | 只读/隐藏 | 可选但建议保存;需与 study 一致 |
| `study_id` | 所属 study | 由 observation_unit 带出 | Study 选择器/只读 | 可选但建议保存;若有 observation_unit 必须一致 |
| `taxon_id_id` | 分类单元 ID | 从 taxon 选择 | Taxon 选择器 | 可选 |
| `trial_id` | 所属 trial | 由 observation_unit/study 带出 | Trial 选择器/只读 | 可选但建议保存 |
### 录入建议
- 推荐从 observation_unit 批量生成 sample一行 observation_unit 生成一个或多个 sample。
- 如果样本放入 plate应通过孔位布局页设置 well不建议手填 A01。
- `well``plate_row``plate_column` 应保持一致well=A01则 row=Acolumn=1。
- sample 是物理样本,不是 genotype 结果;结果必须进入 callset / allele_call。
### 验收标准
1. `sample_name` 必填。
2. 同一 plate 中 `well` 不允许重复。
3. 绑定 observation_unit 时study/trial/program 自动带出。
4. 绑定 plate 时well 必须符合 plate_format。
5. 样本已有 callset 时,不允许物理删除。
---
## 6.3 reference_set 参考集
### 业务说明
`reference_set` 表示一个参考基因组集合,也就是一套 reference genome assembly。它定义 variant 坐标体系。不同参考基因组版本之间的位点坐标不可随意混用。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------------------- | ---------------------------------------------- | ------------------ | ----------------- | ---------------------------- |
| `id` | 参考集主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `assemblypui` | 参考组装永久标识,如 DOI、INSDC accession、URI | 用户录入/导入 | 文本框/URL 输入框 | 可选;建议唯一 |
| `description` | 参考集说明 | 用户录入 | 多行文本 | 可选 |
| `is_derived` | 是否由其他参考集派生 | 用户选择 | 开关 | 可选 |
| `md5checksum` | 参考集校验值 | 用户录入/文件计算 | 文本框 | 可选;若填写应符合 MD5 格式 |
| `reference_set_name` | 参考集名称,如 IRGSP-1.0、B73 RefGen_v5 | 用户录入 | 文本框 | 必填;建议唯一 |
| `sourceuri` | 参考集来源 URI 或下载地址 | 用户录入 | URL 输入框 | 可选;校验 URL |
| `species_ontology_term` | 物种本体术语名称 | 用户录入/选择 | 文本框/本体选择器 | 可选 |
| `species_ontology_termuri` | 物种本体 URI | 用户录入/本体带出 | URL 输入框 | 可选;校验 URL |
| `source_germplasm_id` | 参考基因组来源材料 | 从 germplasm 选择 | Germplasm 选择器 | 可选;必须引用存在 germplasm |
### 录入建议
- reference_set 是 variantset 和 variant 的上游,不能随意改。
- 如果导入 VCF必须先明确该 VCF 的 reference_set。
- 同一 crop 可能存在多个 reference_set应在页面上清楚显示版本和来源。
---
## 6.4 reference 参考序列
### 业务说明
`reference` 是 reference_set 中的一条参考序列,例如 chromosome、contig、scaffold。variant 的坐标通常是基于某条 reference 的位置。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------- | --------------------------------------------- | --------------------- | ------------------- | ------------------------------- |
| `id` | 参考序列主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `length` | 序列长度 | 用户录入/FASTA 导入 | 数字输入框 | 必填或建议必填;非负整数 |
| `md5checksum` | 单条 reference 的 MD5 校验值 | 用户录入/文件计算 | 文本框 | 可选;若填写应符合 MD5 格式 |
| `reference_name` | 参考序列名称,如 chr1、1、Chr01、scaffold_001 | 用户录入/FASTA 导入 | 文本框 | 必填;同一 reference_set 内唯一 |
| `source_divergence` | 与来源序列的差异程度 | 用户录入/导入 | 数字输入框 | 可选;范围建议 0-1 或按业务定义 |
| `reference_set_id` | 所属 reference_set | 从 reference_set 选择 | ReferenceSet 选择器 | 必选 |
### 录入建议
- 建议通过 FASTA 索引文件批量导入 chromosome / contig。
- 同一 reference_set 下 reference_name 必须唯一。
- variant 导入时,文件中的 CHROM 必须能匹配 reference.reference_name。
---
## 6.5 reference_bases 参考片段
### 业务说明
`reference_bases` 保存 reference 的序列片段或分页。通常不建议人工录入,而是由 FASTA 导入或接口生成。对于大型基因组,不建议把完整序列全部塞入普通业务表,除非系统确实需要序列查询。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------- | ------------------ | ------------------- | --------------------- | --------------------------------------- |
| `id` | 参考片段主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `bases` | 碱基序列片段 | FASTA 导入/接口生成 | 多行文本/只读 | 必填;只能包含合法碱基字符 A/C/G/T/N 等 |
| `page_number` | 分页编号 | 系统生成 | 数字输入/只读 | 必填;非负整数;同一 reference 下唯一 |
| `reference_id` | 所属 reference | 由导入带出 | Reference 选择器/隐藏 | 必选 |
### 录入建议
- 不建议前端做手工新增入口,只提供查看和导入。
- 每页 bases 长度应固定或可配置,例如 2KB、10KB、100KB。
- 导入时校验页码连续性和字符合法性。
---
## 6.6 variantset 变异集合
### 业务说明
`variantset` 是一批 variant 和相关 call 的集合,通常对应一个 VCF 文件、一个 SNP 芯片结果、一个测序分析批次或一个 study 的基因型数据集。它必须明确 reference_set否则 variant 坐标无意义。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------ | ---------------------------------------------- | --------------------- | ------------------- | ----------------------------------------- |
| `id` | 变异集合主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `variant_set_name` | 变异集合名称,如 Rice-2026-SNPSet、VCF-Run-001 | 用户录入/文件名带出 | 文本框 | 必填;建议唯一 |
| `reference_set_id` | 使用的参考集 | 从 reference_set 选择 | ReferenceSet 选择器 | 必选 |
| `study_id` | 关联 study | 从 study 选择 | Study 选择器 | 可选;若填写,应与样本来源 study 保持一致 |
### 录入建议
- 导入 VCF/CSV 前必须先选择 reference_set。
- 如果 variantset 来源于某次 study 的样本检测,应填写 study_id。
- variantset 详情页应展示variant 数量、callset 数量、分析信息、文件格式、导入状态。
---
## 6.7 variant 变异位点
### 业务说明
`variant` 表示一个遗传序列上的位点或区间,可以是 SNP、INDEL、SV也可以是传统 marker。它通常由 reference_set、reference_name、start/end、reference_bases、alternate_bases 共同定义。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------ | ------------------------------------ | ------------------------------------- | ------------------------ | ------------------------------------------------ |
| `id` | 变异主键 | 系统生成/导入 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `created` | 创建时间 | 系统默认/文件导入 | 日期时间只读 | 可选;默认当前时间 |
| `variant_end` | 变异结束位置 | 文件导入/用户录入 | 数字输入框 | 可选;非负整数;不小于 start |
| `filters_applied` | 是否执行过过滤 | 文件导入/系统写入 | 开关/只读 | 可选 |
| `filters_passed` | 是否通过过滤 | 文件导入/系统写入 | 开关/只读 | 可选 |
| `reference_bases` | 参考等位基因或参考碱基 | 文件导入/用户录入 | 文本框 | 可选;合法碱基字符 |
| `variant_start` | 变异起始位置 | 文件导入/用户录入 | 数字输入框 | 必填;非负整数 |
| `svlen` | 结构变异长度 | 文件导入/用户录入 | 数字输入框 | 可选SV 类型时建议填写 |
| `updated` | 更新时间 | 系统自动写入 | 只读日期时间 | 自动更新 |
| `variant_name` | 变异名称,如 SNP001、chr1_123456_A_G | 用户录入/自动生成 | 文本框 | 必填或由位置自动生成;同一 variantset 下建议唯一 |
| `variant_type` | 变异类型,如 SNP、INDEL、SV、marker | 用户选择/文件导入 | 下拉框 | 可选;建议枚举化 |
| `reference_set_id` | 所属参考集 | 从 reference_set 选择/variantset 带出 | ReferenceSet 选择器/隐藏 | 必选;需与 variantset.reference_set 一致 |
| `variant_set_id` | 所属变异集合 | 从 variantset 选择 | VariantSet 选择器/隐藏 | 必选 |
### 录入建议
- 大量 variant 应通过 VCF、HapMap、CSV 批量导入,不建议手工录入。
- 如果当前表缺少 alternate_bases、reference_name 字段,应在导入逻辑或扩展表中补齐,否则变异定义不完整。
- variant 的唯一性建议使用:`reference_set_id + reference_name + start + reference_bases + alternate_bases`
---
## 6.8 callset 调用集合
### 业务说明
`callset` 表示某个 sample 参与一次测序、芯片或分析事件后形成的一组 genotype calls。多数情况下一个 sample 对应一个 callset但如果同一个 sample 多次送检或使用不同分析流程,则可以有多个 callset。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------- | -------------------------------- | ----------------------- | ------------- | ---------------------------- |
| `id` | CallSet 主键 | 系统生成/导入 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `call_set_name` | 调用集合名称,如 SAMPLE-001_Run1 | 用户录入/系统生成 | 文本框 | 必填;同一 sample 下建议唯一 |
| `created` | 创建时间 | 系统默认/导入 | 日期时间 | 默认当前时间 |
| `updated` | 更新时间 | 系统自动写入 | 只读日期时间 | 自动更新 |
| `sample_id` | 所属样本 | 从 sample 选择/导入匹配 | Sample 选择器 | 必选 |
### 录入建议
- 从 genotype 文件导入时,可以按样本列自动创建 callset。
- callset 需要通过 `callset_variant_sets` 绑定它覆盖的 variantset。
- sample 详情页应展示 callset 列表和每个 callset 的 variantset、call 数量、导入时间。
---
## 6.9 callset_variant_sets 调用集合与变异集合关系
### 业务说明
`callset_variant_sets` 表示某个 callset 覆盖哪些 variantset。它是一次检测结果和一批位点集合之间的关系。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ----------------- | -------- | ------------------------------- | ---------------------- | -------- |
| `call_sets_id` | 调用集合 | 从 callset 选择/导入自动创建 | CallSet 选择器/隐藏 | 必选 |
| `variant_sets_id` | 变异集合 | 从 variantset 选择/导入自动绑定 | VariantSet 选择器/隐藏 | 必选 |
### 录入建议
- 从 variantset 导入 genotype matrix 时,系统应自动绑定所有新建 callset 到该 variantset。
- 同一 callset + variantset 不允许重复。
---
## 6.10 allele_call 基因型结果
### 业务说明
`allele_call` 是最终基因型事实数据,表示某个 callset 在某个 variant 上的 genotype 结果。它是 genotype matrix 的一个格子。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------------- | --------------------------------------------------------- | ------------------------ | --------------------- | ------------------------------ |
| `id` | 基因型结果主键 | 系统生成/导入 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `genotype` | genotype 结果,如 A/G、0/1、0 | 1、AA、./. | 文件导入/少量手工修正 | 文本框/基因型控件 |
| `genotype_likelihood` | genotype likelihood表示不同 genotype 的可能性或置信信息 | 文件导入 | 数字输入框 | 可选;范围和含义按导入格式定义 |
| `phase_set` | phase set用于 phased genotype 分组 | 文件导入 | 文本框 | 可选phased 数据时使用 |
| `read_depth` | 测序深度 | 文件导入/用户录入 | 数字输入框 | 可选;非负整数 |
| `call_set_id` | 所属 callset | 从 callset 选择/导入匹配 | CallSet 选择器/隐藏 | 必选 |
| `variant_id` | 对应 variant | 从 variant 选择/导入匹配 | Variant 选择器/隐藏 | 必选 |
### 录入建议
- allele_call 不建议大量手工新增,主入口应该是 VCF/HapMap/CSV 文件导入。
- 同一 `call_set_id + variant_id` 不应重复。
- `genotype` 需要兼容常见格式:
- Allele 格式A/G、C/C、T/G
- VCF 编码0/0、0/1、1/1、0|1
- 缺失:./.、NA、N、--,具体缺失字符串由 variantset_format 配置。
- 导入后应支持按 sample/callset 或 variant 两种视角查询。
---
## 6.11 variantset_analysis 变异集合分析信息
### 业务说明
`variantset_analysis` 记录 variantset 的分析流程、软件、版本、参数、时间等信息。它是数据可追溯的重要来源。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ---------------- | ------------------------------------------------------------ | ------------------ | ---------------------- | -------------- |
| `id` | 分析记录主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `analysis_name` | 分析名称,如 GATK SNP Calling Run 2026-01 | 用户录入/导入带出 | 文本框 | 必填 |
| `created` | 创建时间 | 系统默认 | 日期时间 | 默认当前时间 |
| `description` | 分析说明,如软件版本、过滤参数 | 用户录入 | 多行文本 | 可选,建议填写 |
| `type` | 分析类型,如 SNP calling、imputation、filtering、chip genotyping | 用户选择/录入 | 下拉框/文本框 | 可选 |
| `updated` | 更新时间 | 系统自动写入 | 只读日期时间 | 自动更新 |
| `variant_set_id` | 所属 variantset | 从 variantset 选择 | VariantSet 选择器/隐藏 | 必选 |
### 录入建议
- 导入结果文件时,应生成或要求填写 analysis 信息。
- 推荐记录:软件名称、版本、参数、过滤阈值、执行人、执行日期。
---
## 6.12 variantset_format 变异集合文件格式
### 业务说明
`variantset_format` 描述 variantset 数据文件格式,例如 VCF、HapMap、CSV、TSV、DArTSeq 等。它影响 genotype 的解析方式、缺失值、phased/unphased 分隔符等。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| -------------------- | --------------------------------------------- | ------------------- | ---------------------- | ------------------------ |
| `id` | 格式记录主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `data_format` | 数据内部结构,如 VCF、HapMap、DArTSeq、matrix | 用户选择/文件识别 | 下拉框 | 可选;建议枚举化 |
| `expand_homozygotes` | 是否展开纯合 genotype例如 A -> A/A | 用户选择 | 开关 | 可选 |
| `file_format` | 文件 MIME 或外层格式,如 csv、tsv、zip、excel | 用户选择/文件识别 | 下拉框 | 可选 |
| `fileurl` | 原始结果文件链接 | 上传后生成/用户填写 | URL 输入框 | 可选URL 格式校验 |
| `sep_phased` | phased genotype 分隔符,如 `|` | 用户录入/默认 | 文本框 | 可选;通常为 `|` |
| `sep_unphased` | unphased genotype 分隔符,如 `/` | 用户录入/默认 | 文本框 | 可选;通常为 `/` |
| `unknown_string` | 缺失值字符串,如 `./.`、NA、-- | 用户录入/默认 | 文本框 | 可选;导入时用于缺失识别 |
| `variant_set_id` | 所属 variantset | 从 variantset 选择 | VariantSet 选择器/隐藏 | 必选 |
### 录入建议
- 文件上传时应自动识别 file_format 和 data_format。
- 缺失值字符串必须参与 allele_call 导入解析。
- 如果格式是 VCF应支持 phased/unphased 分隔符。
---
## 6.13 genome_map 遗传图谱
### 业务说明
`genome_map` 描述遗传图谱或物理图谱。遗传图谱通常单位为 cM物理图谱通常单位为 Mb 或 bp。它用于把 variant / marker 映射到 linkage group 上。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------ | ------------------------------ | ------------------ | ----------------- | ------------------------------------------ |
| `id` | 图谱主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `comments` | 图谱备注 | 用户录入 | 多行文本 | 可选 |
| `documentationurl` | 图谱说明文档或论文链接 | 用户录入 | URL 输入框 | 可选URL 格式校验 |
| `map_name` | 图谱名称 | 用户录入 | 文本框 | 必填;建议唯一 |
| `mappui` | 图谱永久唯一标识 | 用户录入 | 文本框/URL 输入框 | 可选;若填写建议唯一 |
| `published_date` | 发布时间 | 用户录入 | 日期选择器 | 可选 |
| `scientific_name` | 物种学名 | 用户录入 | 文本框 | 可选 |
| `type` | 图谱类型,如 Genetic、Physical | 用户选择 | 下拉框 | 可选;建议枚举 |
| `unit` | 图谱单位,如 cM、Mb、bp | 用户选择 | 单位选择器 | 可选Genetic 常用 cMPhysical 常用 Mb/bp |
| `crop_id` | 所属作物 | 从 crop 选择 | Crop 选择器 | 必选 |
### 录入建议
- 图谱命名应能体现是 consensus map、mapping population map、reference genome map 还是 pan-genome map。
- 图谱类型和单位必须匹配Genetic + cMPhysical + Mb/bp。
---
## 6.14 linkage_group 连锁群
### 业务说明
`linkage_group` 是 genome_map 中的分组。它可能对应 chromosome、scaffold、contig 或传统遗传连锁群。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| --------------------- | -------------------------------------- | ------------------ | --------------------- | ---------------------------- |
| `id` | 连锁群主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `linkage_group_name` | 连锁群名称,如 Chr1、LG1、scaffold_001 | 用户录入/导入 | 文本框 | 必填;同一 genome_map 下唯一 |
| `max_marker_position` | 该连锁群最大 marker 位置 | 用户录入/导入计算 | 数字输入框 | 可选;非负数 |
| `genome_map_id` | 所属 genome_map | 从 genome_map 选择 | GenomeMap 选择器/隐藏 | 必选 |
### 录入建议
- 在 genome_map 详情页维护。
- 支持从 marker_position 文件批量导入时自动创建 linkage_group。
- 若填写 max_marker_positionmarker_position.position 不得超过该值。
---
## 6.15 marker_position 图谱位置
### 业务说明
`marker_position` 把 variant 映射到某个 linkage_group 上的位置。它用于遗传图谱定位、QTL、marker 辅助选择和图谱展示。
### 字段说明
| 字段 | 业务意义 | 录入方式 | 控件建议 | 校验规则 |
| ------------------ | --------------------------------- | --------------------- | ------------------- | ---------------------------------------- |
| `id` | 图谱位置主键 | 系统生成 | 隐藏/只读 | 必填、唯一 |
| `auth_user_id` | 数据所属用户或租户 | 登录上下文自动写入 | 隐藏 | 不允许手填 |
| `position` | variant 在 linkage_group 上的位置 | 用户录入/文件导入 | 数字输入框 | 必填;非负;不得超过 max_marker_position |
| `linkage_group_id` | 所属 linkage_group | 从 linkage_group 选择 | LinkageGroup 选择器 | 必选 |
| `variant_id` | 对应 variant | 从 variant 选择 | Variant 选择器 | 必选 |
### 录入建议
- 不建议逐条手工录入,优先通过 map 文件批量导入。
- 同一 genome_map 下,同一 variant 不应重复映射,除非业务允许多图谱位置。
---
# 7. 跨表联动规则
| 场景 | 联动规则 |
| ------------------------------- | ------------------------------------------------------------ |
| 从 observation_unit 生成 sample | 自动带出 study、trial、program可带出 germplasm 信息用于展示 |
| 给 sample 分配 plate | 选择 well 后自动生成 plate_row、plate_column |
| 创建 plate | 选择 study 后自动带出 trial/program |
| 创建 variantset | 必须先选择 reference_set |
| 导入 variant | variant.reference_set 必须与 variantset.reference_set 一致 |
| 创建 callset | 必须选择 sample可按 sample_name 自动生成 call_set_name |
| 导入 allele_call | 先匹配 callset再匹配 variant匹配不到时进入错误报告 |
| 绑定 callset_variant_sets | 导入 genotype matrix 时自动绑定 callset 与 variantset |
| 创建 genome_map | 必须选择 crop |
| 创建 marker_position | variant 与 linkage_group 最好来自同一 crop/reference 背景 |
---
# 8. 删除和停用规则
| 对象 | 删除限制 |
| --------------- | ------------------------------------------------------- |
| plate | 已有 sample 时不可删除 |
| sample | 已有 callset 时不可删除 |
| reference_set | 已有 reference、variantset、variant 时不可删除 |
| reference | 已有 reference_bases 或 variant 引用时不可删除 |
| variantset | 已有 variant、callset 绑定或 allele_call 结果时不可删除 |
| variant | 已有 allele_call 或 marker_position 时不可删除 |
| callset | 已有 allele_call 时不可删除 |
| allele_call | 原始检测结果原则上不建议物理删除,应支持作废或版本化 |
| genome_map | 已有 linkage_group 时不可删除 |
| linkage_group | 已有 marker_position 时不可删除 |
| marker_position | 可删除,但需记录操作日志 |
---
# 9. 批量导入要求
## 9.1 Sample 导入模板
必需列建议:
```text
sample_name
study_id 或 study_name
```
强烈建议列:
```text
observation_unit_id 或 observation_unit_name
sample_barcode
sample_type
tissue_type
sample_timestamp
taken_by
plate_name
well
```
导入规则:
1. 如果提供 observation_unit系统自动带出 study/trial/program。
2. 如果提供 plate + well需校验同板孔位唯一。
3. 如果 plate 不存在,可根据配置自动创建或报错。
## 9.2 Plate 导入模板
```text
plate_name
plate_barcode
plate_format
study_name
sample_name
well
```
导入规则:
1. plate_format 决定合法 well 范围。
2. 同一 plate + well 不允许重复。
3. sample_name 不存在时,可配置是否自动创建 sample。
## 9.3 Variant 导入模板
建议支持 VCF / HapMap / CSV。
CSV 必需列建议:
```text
variant_name
reference_name
variant_start
reference_bases
alternate_bases
variant_type
variant_set_name
reference_set_name
```
导入规则:
1. 必须先选择或创建 reference_set。
2. CHROM / reference_name 必须能匹配 reference。
3. variant_start 必须非负。
4. alternate_bases 不能为空,除非只是导入传统 marker。
## 9.4 Genotype Matrix / Allele Call 导入模板
推荐矩阵格式:
```text
variant_name,SAMPLE-001,SAMPLE-002,SAMPLE-003
SNP001,A/G,A/A,./.
SNP002,C/C,C/T,C/C
SNP003,T/G,T/T,T/G
```
导入规则:
1. 每个样本列必须能匹配 sample 或 callset。
2. 每个 variant 行必须能匹配 variant。
3. 每个非空 genotype 单元格生成一条 allele_call。
4. 缺失值按 variantset_format.unknown_string 处理。
5. 同一 callset + variant 已存在时,根据导入策略选择覆盖、跳过或报错。
## 9.5 Genome Map 导入模板
```text
map_name
linkage_group_name
variant_name
position
unit
```
导入规则:
1. map_name 不存在时可配置自动创建 genome_map。
2. linkage_group 不存在时可配置自动创建。
3. variant 必须存在。
4. position 必须非负且不超过 max_marker_position。
---
# 10. 后端接口建议
## 10.1 主数据接口
```text
GET /plates
POST /plates
GET /plates/{id}
PUT /plates/{id}
GET /plates/{id}/layout
POST /plates/{id}/assign-samples
GET /samples
POST /samples
POST /samples/batch-from-observation-units
GET /samples/{id}
PUT /samples/{id}
GET /samples/{id}/callsets
GET /reference-sets
POST /reference-sets
GET /reference-sets/{id}
GET /reference-sets/{id}/references
POST /reference-sets/{id}/references
GET /references
POST /references
GET /references/{id}/bases
POST /references/{id}/bases/import
GET /variantsets
POST /variantsets
GET /variantsets/{id}
GET /variantsets/{id}/variants
POST /variantsets/{id}/variants/import
GET /variantsets/{id}/formats
POST /variantsets/{id}/formats
GET /variantsets/{id}/analyses
POST /variantsets/{id}/analyses
GET /variants
POST /variants
GET /variants/{id}
GET /callsets
POST /callsets
GET /callsets/{id}
POST /callsets/{id}/variantsets
GET /allele-calls
POST /allele-calls/import
GET /allele-matrix
GET /genome-maps
POST /genome-maps
GET /genome-maps/{id}/linkage-groups
POST /genome-maps/{id}/linkage-groups
POST /marker-positions/import
```
## 10.2 选择器接口
```text
GET /selectors/plates?studyId=&keyword=
GET /selectors/samples?studyId=&plateId=&keyword=
GET /selectors/reference-sets?cropId=&keyword=
GET /selectors/references?referenceSetId=&keyword=
GET /selectors/variantsets?referenceSetId=&studyId=&keyword=
GET /selectors/variants?variantSetId=&referenceName=&start=&end=&keyword=
GET /selectors/callsets?sampleId=&variantSetId=&keyword=
GET /selectors/genome-maps?cropId=&keyword=
GET /selectors/linkage-groups?genomeMapId=&keyword=
```
---
# 11. 测试验收清单
1. 创建 plate 时plate_name 和 plate_barcode 至少填写一个。
2. plate_barcode 重复时提示唯一性冲突。
3. plate_format=96 时,只允许 A01-H12plate_format=384 时,只允许 A01-P24。
4. sample_name 必填。
5. sample 绑定 plate 时,同一 plate + well 不允许重复。
6. sample 绑定 observation_unit 后study/trial/program 自动带出。
7. reference_set_name 必填。
8. reference_name 在同一 reference_set 内不允许重复。
9. reference.length 必须为非负整数。
10. reference_bases.bases 只能包含合法碱基字符。
11. variantset 必须选择 reference_set。
12. variant.reference_set_id 必须与 variantset.reference_set_id 一致。
13. variant_start 必须非负。
14. variant_end 不得小于 variant_start。
15. variant_name 为空时系统能按 reference + position + allele 自动生成。
16. callset 必须绑定 sample。
17. 同一 sample 下 call_set_name 不建议重复。
18. callset + variantset 关系不允许重复。
19. allele_call 必须绑定 callset 和 variant。
20. 同一 callset + variant 不允许重复,除非系统支持版本化。
21. read_depth 必须为非负整数。
22. genotype 必须符合导入格式规则。
23. 缺失 genotype 必须按 unknown_string 统一处理。
24. 导入 genotype matrix 时,无法匹配的 sample、variant 必须返回错误报告。
25. 导入失败报告必须包含行号、列名、错误原因、建议修复方式。
26. genome_map 必须选择 crop。
27. linkage_group_name 在同一 genome_map 内不允许重复。
28. marker_position.position 必须非负,且不超过 max_marker_position。
29. 已有关联下游数据的 sample、variant、callset、variantset 不允许物理删除。
30. 所有导入操作必须记录导入批次、上传人、上传时间和原始文件链接。
---
# 12. 开发实现重点
1. `sample` 是物理样本,不是基因型结果。
2. `callset` 是 sample 参与一次检测/分析形成的结果集合。
3. `allele_call` 才是某个 sample/callset 在某个 variant 上的 genotype 结果。
4. `variantset` 必须绑定 reference_set否则位点坐标没有意义。
5. 大量 variant 和 allele_call 不应手工录入,主入口必须是文件导入。
6. plate 必须做孔位布局,不要只做普通表单。
7. genotype matrix 页面必须支持按 sample 和按 variant 两种方向查看。
8. VCF/HapMap/CSV 的解析规则要独立成导入服务,不要散落在页面逻辑里。
9. reference_set、variantset、callset、analysis、format 都是结果可追溯的关键上下文。
10. 已导入的基因型结果建议支持版本化或作废,不建议直接物理删除。