Files
brapi-java/docs/requirements/03-phenotyping-entry-requirements.md
2026-05-28 11:56:17 +08:00

779 lines
49 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 不只是备注,它是解释表型差异的重要上下文,应支持作用范围和参数化。