# 风险因子设置 — 技术方案

> 依据：同目录 `风险因子设置功能需求.md`。本模块为**全局单套**风险因子权重配置：**查询 + 保存**（非分页台账 CRUD）；五项权重须为正数且合计为 **1**。

---

## 1. 技术架构

| 项 | 说明 |
| --- | --- |
| **后端** | RuoYi **v3.9.2**（**springboot2** 分支）：JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，InnoDB，`utf8mb4` |
| **前端** | 若依 Vue2；权重小数录入；页面实时展示五项合计 |
| **代码包** | `com.ruoyi.web.modules.diseasedetection`（建议，与疫情上报、实验室检测同域） |

**分层**：`Controller`（`@PreAuthorize`、`AjaxResult`）→ `Service`（权重正数、合计为 1 校验）→ `Mapper`/XML → `domain`。

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

| 场景 | 行为 |
| --- | --- |
| 查询 | 返回当前生效的一套五项权重；无记录时可返回默认值或空对象（与产品约定） |
| 保存 | Body 一次性提交五项；服务端校验后 **UPDATE** 唯一配置行（无记录则 **INSERT**） |
| 因子项 | **固定五项**，不落因子字典表；字段名与 **§2.4** 一一对应 |

---

## 2. 数据库设计

### 2.1 表 `biz_risk_factor_weight`（风险因子权重配置）

全局**单行**配置表（`id = 1`）；不按区划、不按版本分多套。

| 字段 | 类型 | 非空 | 说明 |
| --- | --- | --- | --- |
| `id` | `bigint(20)` | Y | 主键；固定 **`1`**（单例） |
| `weight_breeding_density` | `decimal(8,4)` | Y | 养殖密度权重，> 0 |
| `weight_traffic_mobility` | `decimal(8,4)` | Y | 交通流动性权重，> 0 |
| `weight_quarantine_intensity` | `decimal(8,4)` | Y | 检疫强度权重，> 0 |
| `weight_meteorological_suitability` | `decimal(8,4)` | Y | 气象适宜度权重，> 0 |
| `weight_past_disease_level` | `decimal(8,4)` | Y | 既往发病水平权重，> 0 |
| `create_by` / `create_time` / `update_by` / `update_time` | 若依惯例 | — | 审计 |

**约束（业务层实现）**

- 五项之和 = **1**（建议容差 `|Σ − 1| ≤ 0.0001`，与 `decimal(8,4)` 一致）。  
- 各项 **> 0**（正数）。  
- 不提供 `del_flag`；配置始终有效。

### 2.2 DDL（MySQL 5.7）

```sql
CREATE TABLE `biz_risk_factor_weight` (
  `id` bigint(20) NOT NULL COMMENT '主键固定1',
  `weight_breeding_density` decimal(8,4) NOT NULL COMMENT '养殖密度权重',
  `weight_traffic_mobility` decimal(8,4) NOT NULL COMMENT '交通流动性权重',
  `weight_quarantine_intensity` decimal(8,4) NOT NULL COMMENT '检疫强度权重',
  `weight_meteorological_suitability` decimal(8,4) NOT NULL COMMENT '气象适宜度权重',
  `weight_past_disease_level` decimal(8,4) NOT NULL 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 '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='风险因子权重配置';

-- 初始化（可选）：五项各 0.2
INSERT INTO `biz_risk_factor_weight` (
  `id`, `weight_breeding_density`, `weight_traffic_mobility`, `weight_quarantine_intensity`,
  `weight_meteorological_suitability`, `weight_past_disease_level`,
  `create_by`, `create_time`
) VALUES (
  1, 0.2000, 0.2000, 0.2000, 0.2000, 0.2000, 'admin', NOW()
) ON DUPLICATE KEY UPDATE `id` = `id`;
```

### 2.3 因子编码（固定，与功能需求 §2.1 对应）

| 编码 | 因子名称 | 库字段 | API 驼峰 |
| --- | --- | --- | --- |
| `breeding_density` | 养殖密度 | `weight_breeding_density` | `breedingDensityWeight` |
| `traffic_mobility` | 交通流动性 | `weight_traffic_mobility` | `trafficMobilityWeight` |
| `quarantine_intensity` | 检疫强度 | `weight_quarantine_intensity` | `quarantineIntensityWeight` |
| `meteorological_suitability` | 气象适宜度 | `weight_meteorological_suitability` | `meteorologicalSuitabilityWeight` |
| `past_disease_level` | 既往发病水平 | `weight_past_disease_level` | `pastDiseaseLevelWeight` |

**响应可冗余**：`weightSum`（五项之和，便于前端核对）、`updateTime` 等。

---

## 3. 接口设计

**统一响应**：`AjaxResult`（`code` / `msg` / `data`）。

**权限标识**：`diseaseDetection:riskFactorWeight:query|edit`

**Base Path**：`/diseaseDetection/riskFactorWeight`

| # | 说明 | Method | URI | 权限 | 要点 |
| --- | --- | --- | --- | --- | --- |
| 3.1 | 获取当前权重 | GET | `/diseaseDetection/riskFactorWeight` | `...:query` | 返回 **§3.1.1**；无记录时 `data` 为 `null` 或默认五项 |
| 3.2 | 保存权重 | PUT | `/diseaseDetection/riskFactorWeight` | `...:edit` | Body **§3.2.1**；校验通过后 upsert `id=1` |

> 不提供分页 `list`、按 `id` 删除；菜单权限可用 `query` 进入页面，`edit` 控制保存。

#### 3.1.1 查询响应 `data`（示例）

```json
{
  "breedingDensityWeight": 0.2,
  "trafficMobilityWeight": 0.2,
  "quarantineIntensityWeight": 0.2,
  "meteorologicalSuitabilityWeight": 0.2,
  "pastDiseaseLevelWeight": 0.2,
  "weightSum": 1.0,
  "updateBy": "admin",
  "updateTime": "2026-05-19 10:00:00"
}
```

#### 3.2.1 保存 Body（JSON，驼峰）

| 字段 | 必填 | 说明 |
| --- | --- | --- |
| `breedingDensityWeight` | Y | > 0 |
| `trafficMobilityWeight` | Y | > 0 |
| `quarantineIntensityWeight` | Y | > 0 |
| `meteorologicalSuitabilityWeight` | Y | > 0 |
| `pastDiseaseLevelWeight` | Y | > 0 |

五项之和须 **= 1**（容差见 **§2.1**）；非法则返回业务错误，**不**部分更新。

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

| 项 | 规则 |
| --- | --- |
| 正数 | 每项 `> 0`，且为合法 `decimal` |
| 合计 | `sum(五项) = 1`（`|Σ − 1| ≤ 0.0001`） |
| 原子性 | 一次请求更新全部五个字段 |
| 单例 | 仅维护 `id = 1` 一行 |

校验类建议：`RiskFactorWeightValidation`（`validateForSave`）。

---

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

| 类型 | 名称 | 权限标识 |
| --- | --- | --- |
| 菜单 | 风险因子权重 | `diseaseDetection:riskFactorWeight:query` |
| 按钮 | 保存 | `diseaseDetection:riskFactorWeight:edit` |

组件路径建议：`diseaseDetection/riskFactorWeight/index`（单页表单 + 保存按钮）。

**菜单 SQL 示例**（挂「疾病检测与上报」目录 `2110` 下，ID 按需调整）：

```sql
INSERT INTO sys_menu VALUES
('2113', '风险因子权重', '2110', '3', 'riskFactorWeight', 'diseaseDetection/riskFactorWeight/index', '', '', 1, 0, 'C', '0', '0', 'diseaseDetection:riskFactorWeight:query', 'slider', 'admin', sysdate(), '', NULL, '风险因子权重');
INSERT INTO sys_menu VALUES
('21131', '风险因子保存', '2113', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'diseaseDetection:riskFactorWeight:edit', '#', 'admin', sysdate(), '', NULL, '');
```

---

## 5. 交付清单

- [ ] `sql/biz_risk_factor_weight.sql`、初始化数据、菜单权限 SQL  
- [ ] `BizRiskFactorWeight` Domain / Mapper / Service / Controller  
- [ ] `RiskFactorWeightValidation`（正数、合计为 1）  
- [ ] 前端：单页五项录入、实时合计、保存  
- [ ] 单元/接口测试：和不为 1、某项 ≤ 0、首次保存 insert、再次保存 update  

---

## 6. 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初稿：单表单行配置；GET + PUT；五项固定字段 |
