# 实验室检测 — 技术方案

> 依据：同目录 `实验室检测功能需求.md`。本模块为检测台账 **CRUD**；检出率由服务端按「阳性检出数 ÷ 检测量」计算后落库，前端只读展示。

---

## 1. 技术架构

| 项 | 说明 |
| --- | --- |
| **后端** | RuoYi **v3.9.2**（**springboot2** 分支）：JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，InnoDB，`utf8mb4` |
| **前端** | 若依 Vue2；日期 `YYYY-MM-DD`；检出率百分比展示（建议保留 2 位小数） |
| **代码包** | `com.ruoyi.web.modules.diseasedetection`（建议，与疫情上报同域） |

**分层**：`Controller`（权限、`AjaxResult` / `TableDataInfo`）→ `Service`（枚举/数量/检出率校验与重算）→ `Mapper`/XML → `domain`。

**业务特征（摘要）**

- 无业务状态机；任意记录可改、可删。  
- 新增/修改 Body **不接受**客户端传入的 `detectionRate`，由 Service 写入。  
- 列表默认 `test_date DESC, create_time DESC, id DESC`。  
- 筛选：`sample_source`、`quarantine_station_id` 精确匹配（可空）。  
- **检疫点**：关联 `biz_quarantine_station`；新增/修改须校验运营状态为**正常**（`operate_status=1`）；下拉数据见 **§3.6**。

---

## 2. 数据库设计

### 2.1 表 `biz_lab_detection`（实验室检测）

| 字段 | 类型 | 非空 | 说明 |
| --- | --- | --- | --- |
| `id` | `bigint(20)` | Y | 主键 |
| `test_date` | `date` | Y | 检测日期 |
| `quarantine_station_id` | `bigint(20)` | Y | 检疫点（检疫站 ID），见 **§2.5** |
| `sample_source` | `tinyint(2)` | Y | 样本来源，见 **§2.3** |
| `test_quantity` | `int(11)` | Y | 检测量（份），≥ 0 |
| `positive_count` | `int(11)` | Y | 阳性检出数（份），≥ 0，且 ≤ `test_quantity` |
| `detection_rate` | `decimal(8,4)` | Y | 检出率（比值 0～1），= `positive_count / test_quantity`（`test_quantity=0` 时为 `0`） |
| `create_by` / `create_time` / `update_by` / `update_time` | 若依惯例 | — | 审计 |
| `remark` | `varchar(500)` | N | 备注（扩展） |

**索引**：`PRIMARY KEY (id)`；`KEY idx_test_date (test_date)`；`KEY idx_sample_source (sample_source)`。

**检出率**：保存/修改时 Service 重算并写入；`test_quantity = 0` 时强制 `positive_count = 0`、`detection_rate = 0`。

### 2.2 DDL（MySQL 5.7）

```sql
CREATE TABLE `biz_lab_detection` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `test_date` date NOT NULL COMMENT '检测日期',
  `quarantine_station_id` bigint(20) NOT NULL COMMENT '检疫点ID(检疫站)',
  `sample_source` tinyint(2) NOT NULL COMMENT '样本来源1场地2疫情送检3调运4日常',
  `test_quantity` int(11) NOT NULL DEFAULT '0' COMMENT '检测量份',
  `positive_count` int(11) NOT NULL DEFAULT '0' COMMENT '阳性检出数份',
  `detection_rate` decimal(8,4) NOT NULL DEFAULT '0.0000' COMMENT '检出率比值',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`),
  KEY `idx_test_date` (`test_date`),
  KEY `idx_sample_source` (`sample_source`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='实验室检测';
```

**存量库升级**：执行 `sql/biz_lab_detection_add_quarantine_station.sql`（须先为历史数据补全合法 `quarantine_station_id` 再设 NOT NULL，或空库直接建表）。

### 2.5 检疫点（检疫站）

| 项 | 说明 |
| --- | --- |
| 数据来源 | `biz_quarantine_station`（检疫站管理） |
| 可选范围 | `del_flag='0'` 且 `operate_status=1`（正常） |
| 列表展示 | LEFT JOIN 回显 `quarantineStationName`（`station_name`） |
| 逻辑外键 | 不建 DB 外键；Service 保存前校验检疫站存在且为正常运营 |

### 2.3 枚举编码（与功能需求 §2.1 对应）

**样本来源 `sample_source`**

| 值 | 标签 |
| --- | --- |
| 1 | 场地抽检 |
| 2 | 疫情上报送检 |
| 3 | 调运检疫 |
| 4 | 日常检测 |

> 展示可走 `sys_dict` 或前端 i18n；**入库必须为 1～4**，非法值拒绝。

### 2.4 字段与 API 驼峰对照

| 需求名称 | 库字段 | API 驼峰 |
| --- | --- | --- |
| 检测日期 | `test_date` | `testDate` |
| 检疫点 | `quarantine_station_id` | `quarantineStationId` |
| 检疫点名称 | —（JOIN） | `quarantineStationName`（只读） |
| 样本来源 | `sample_source` | `sampleSource` |
| 检测量 | `test_quantity` | `testQuantity` |
| 阳性检出数 | `positive_count` | `positiveCount` |
| 检出率 | `detection_rate` | `detectionRate`（比值；前端 ×100 展示为 %） |

---

## 3. 接口设计

**统一响应**：`AjaxResult` 或分页 `TableDataInfo`（`rows`、`total`）。

**权限标识**：`diseaseDetection:labDetection:list|query|add|edit|remove`

**Base Path**：`/diseaseDetection/labDetection`

| # | 说明 | Method | URI | 权限 | 要点 |
| --- | --- | --- | --- | --- | --- |
| 3.1 | 分页列表 | GET | `/diseaseDetection/labDetection/list` | `...:list` | Query **§3.1.1** |
| 3.2 | 详情 | GET | `/diseaseDetection/labDetection/{id}` | `...:query` | 含 `detectionRate` |
| 3.3 | 新增 | POST | `/diseaseDetection/labDetection` | `...:add` | Body **§3.3.1**；忽略客户端 `detectionRate` |
| 3.4 | 修改 | PUT | `/diseaseDetection/labDetection` | `...:edit` | Body 含 `id`；重算检出率 |
| 3.5 | 删除 | DELETE | `/diseaseDetection/labDetection/{ids}` | `...:remove` | 逗号分隔 |
| 3.6 | 检疫点下拉 | GET | `/diseaseDetection/labDetection/quarantineStationOptions` | `...:query` | 仅正常运营检疫站；`id`+`stationName` |

#### 3.1.1 列表 Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `pageNum` / `pageSize` | int | N | 默认 `1` / `20` |
| `sampleSource` | int | N | 样本来源 1～4，精确匹配 |
| `quarantineStationId` | long | N | 检疫点（检疫站 ID），**精确**匹配 |

**列表行（示例）**：`id`、`testDate`、`quarantineStationId`、`quarantineStationName`、`sampleSource`、`testQuantity`、`positiveCount`、`detectionRate`、`createTime`。

#### 3.3.1 新增 / 修改 Body（JSON，驼峰）

| 字段 | 新增 | 修改 | 说明 |
| --- | --- | --- | --- |
| `id` | — | Y | 主键 |
| `testDate` | Y | Y | `YYYY-MM-DD` |
| `quarantineStationId` | Y | Y | 须为正常运营检疫站 ID |
| `sampleSource` | Y | Y | 1～4 |
| `testQuantity` | Y | Y | 非负整数 |
| `positiveCount` | Y | Y | 非负整数；≤ `testQuantity` |
| `detectionRate` | — | — | **不得**由客户端传入 |

**响应详情/列表**：返回服务端计算的 `detectionRate`（如 `0.1250` 表示 12.50%）。

### 3.2 服务端校验（摘要）

| 项 | 规则 |
| --- | --- |
| 枚举 | `sampleSource` ∈ 1～4 |
| 数量 | `testQuantity`、`positiveCount` 为非负整数；`positiveCount ≤ testQuantity` |
| 零检测量 | `testQuantity = 0` 时 `positiveCount` 必须为 0 |
| 检出率 | `detectionRate = testQuantity > 0 ? positiveCount / testQuantity : 0`，四舍五入与 `decimal(8,4)` 一致 |
| 检疫点 | `quarantineStationId` 非空；对应检疫站存在、`operate_status=1` |
| 修改/删除 | 无状态限制 |

#### 3.6 检疫点下拉响应 `data[]`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | long | 检疫站主键 |
| `stationName` | string | 检疫站名称 |

---

## 4. 菜单与权限 SQL（示例）

| 类型 | 名称 | 权限标识 |
| --- | --- | --- |
| 目录/菜单 | 实验室检测 | `diseaseDetection:labDetection:list` |
| 按钮 | 查询 | `diseaseDetection:labDetection:query` |
| 按钮 | 新增 | `diseaseDetection:labDetection:add` |
| 按钮 | 修改 | `diseaseDetection:labDetection:edit` |
| 按钮 | 删除 | `diseaseDetection:labDetection:remove` |

组件路径建议：`diseaseDetection/labDetection/index`；API 文件 `ruoyi-ui/src/api/diseaseDetection/labDetection.js`。

---

## 5. 交付清单

- [ ] `sql/biz_lab_detection.sql`、样本来源字典（可选）、菜单权限 SQL  
- [ ] `BizLabDetection` Domain / Mapper / Service / Controller  
- [ ] 前端：列表筛选、表单实时算出检出率（只读）、CRUD  
- [ ] 用例：阳性大于检测量、零检测量、检出率与库一致、筛选与批量删除  

---

## 6. 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初稿：单表 CRUD；检出率服务端落库 |
| 1.1 | 增加检疫点 `quarantine_station_id`；列表精确筛选；检疫点下拉接口；关联检疫站管理（正常运营） |
