# 畜牧医疗资源管理 — 技术方案

> 依据：`畜牧医疗资源管理功能需求.md`（同目录）

---

## 1. 技术架构

| 层级 | 说明 |
| --- | --- |
| **整体** | RuoYi **v3.9.2**（**springboot2** 分支）单体后端 + 若依 **Vue2** 前端（与分支配套） |
| **运行时** | JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，存储引擎 InnoDB，字符集 **utf8mb4** |
| **文件** | 复用 RuoYi 既有上传能力（本地/MinIO 等以项目现有配置为准）；业务表存访问 **URL**、**存储路径**（`photo_file_url` / `photo_file_path`） |
| **外部系统** | 平台 **用户/角色** 体系（分配账号时调用 `ISysUserService` 等）；**移动端** 通过查询 `publish_status=1` 资源展示（具体接口由移动端或网关模块实现） |

**后端分层（与若依一致）**

- `Controller`：参数接收、权限注解、返回 `AjaxResult` / `TableDataInfo`  
- `Service`：按资源类型分支校验、发布状态机、分配账号、替换照片删旧文件  
- `Mapper` + XML：持久化  
- `domain`：实体；校验与枚举建议 `MedicalResourceValidation`、`MedicalResourceRules`  

**代码包（建议）**：`com.ruoyi.web.modules.diseasetreatment`  
**初始化脚本**：`sql/biz_medical_resource.sql`

**一致性策略（与需求对齐）**

- 四类资源 **单表** 存储，以 `resource_type` 区分；新增后 **不可改类型**。  
- **修改 / 逻辑删除 / 发布**：仅 `publish_status=0` 且 `del_flag=0`（「已下架」亦为 `publish_status=0` 且 `offline_time` 非空，权限同未发布）。  
- **下架**：仅 `publish_status=1` → 置 `publish_status=0`、写 `offline_time`；**保留** `publish_time` 供审计。  
- **分配账号**：仅 `resource_type∈{004001,004003}`、`account_assigned=0`、`publish_status=0`；成功一次后不可重复；登录名冲突 **不** 置 `account_assigned=1`。  
- **移动端可见**：仅 `publish_status=1` 且 `del_flag=0`。

---

## 2. 数据库设计

### 2.1 表：`biz_medical_resource`（畜牧医疗资源主表）

单表承载四类资源共用字段 + 类型差异化可空列；逻辑删除用 `del_flag`。

| 字段名 | 类型 | 非空 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `id` | `bigint(20)` | Y | 自增 | 主键 |
| `resource_type` | `varchar(32)` | Y | — | 资讯类别编码（`parentCode=004`、`categoryType=6`），见 **2.2** |
| `resource_name` | `varchar(32)` | Y | — | 展示名称（姓名/团队名/机构名/设备名），需求 1～10 字 |
| `photo_file_url` | `varchar(512)` | Y | — | 照片访问 URL（与上传返回 `url` 对齐） |
| `photo_file_path` | `varchar(512)` | Y | — | 照片**存储路径**（与上传返回 `fileName` 等对齐，一般为 `/profile/...`） |
| `introduction` | `varchar(500)` | Y | — | 介绍，需求 1～500 字 |
| `contact_phone` | `varchar(20)` | N | NULL | 联系电话；类型 1/2/3 由应用层必填 |
| `affiliated_unit` | `varchar(64)` | N | NULL | 隶属单位 |
| `town_dept_id` | `bigint(20)` | N | NULL | 所属乡镇部门 ID（**仅兽医人员**，选填）；有值时分配账号写入 `sys_user.dept_id`，修改时同步 |
| `town_name` | `varchar(64)` | N | NULL | 所属乡镇名称冗余 |
| `detail_address` | `varchar(200)` | N | NULL | 详细地址（兽医、机构） |
| `consult_modes` | `varchar(32)` | N | NULL | 接诊方式，逗号分隔 **1**定点 **2**上门 **3**在线 |
| `service_area` | `varchar(200)` | N | NULL | 服务区域（兽医） |
| `fee_standard` | `decimal(10,2)` | N | NULL | 收费标准（元/小时，兽医） |
| `service_start_time` | `varchar(8)` | N | NULL | 服务开始 `HH:mm` |
| `service_end_time` | `varchar(8)` | N | NULL | 服务结束 `HH:mm` |
| `service_weekdays` | `varchar(32)` | N | NULL | 服务周日，逗号分隔 `1`～`7`（周一=1） |
| `max_daily_appointments` | `int(11)` | N | NULL | 单日最大接诊人数（仅机构 type=3） |
| `establish_date` | `date` | N | NULL | 成立时间（团队） |
| `team_size` | `int(11)` | N | NULL | 团队规模（人） |
| `team_members` | `varchar(500)` | N | NULL | 团队成员，选填 |
| `person_in_charge` | `varchar(32)` | N | NULL | 负责人（团队、机构） |
| `org_level` | `tinyint(4)` | N | NULL | 机构级别，见 **2.4** |
| `equipment_model` | `varchar(32)` | N | NULL | 设备型号 |
| `longitude` | `decimal(10,6)` | N | NULL | 经度（地图标点预留，本期不用） |
| `latitude` | `decimal(10,6)` | N | NULL | 纬度（预留） |
| `publish_status` | `tinyint(4)` | Y | `0` | 发布状态，见 **2.3** |
| `publish_time` | `datetime` | N | NULL | 最近发布时间 |
| `offline_time` | `datetime` | N | NULL | 最近下架时间；与 `publish_status=0` 组合表示「已下架」 |
| `account_assigned` | `tinyint(4)` | Y | `0` | 是否已分配账号，见 **2.5** |
| `sys_user_id` | `bigint(20)` | N | NULL | 关联 `sys_user.user_id` |
| `assigned_login_name` | `varchar(64)` | N | NULL | 已分配登录名（列表冗余展示） |
| `del_flag` | `char(1)` | Y | `'0'` | 删除标记，见 **2.5** |
| `create_by` | `varchar(64)` | N | — | 若依惯例 |
| `create_time` | `datetime` | N | — | 若依惯例 |
| `update_by` | `varchar(64)` | N | — | 若依惯例 |
| `update_time` | `datetime` | N | — | 若依惯例 |
| `remark` | `varchar(500)` | N | NULL | 备注 |

**索引**

- `PRIMARY KEY (id)`  
- `KEY idx_type (resource_type)` — Tab / 列表按类型筛选  
- `KEY idx_name (resource_name)` — 名称模糊  
- `KEY idx_publish (publish_status)` — 发布状态筛选  
- `KEY idx_del (del_flag)` — 逻辑删除  

**DDL 示例（MySQL 5.7）**

```sql
CREATE TABLE `biz_medical_resource` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `resource_type` varchar(32) NOT NULL COMMENT '资讯类别编码(parentCode=004,categoryType=6)',
  `resource_name` varchar(32) NOT NULL COMMENT '资源名称',
  `photo_file_url` varchar(512) DEFAULT NULL COMMENT '照片URL',
  `photo_file_path` varchar(512) DEFAULT NULL COMMENT '照片路径',
  `introduction` varchar(500) DEFAULT NULL COMMENT '介绍',
  `contact_phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
  `affiliated_unit` varchar(64) DEFAULT NULL COMMENT '隶属单位',
  `detail_address` varchar(200) DEFAULT NULL COMMENT '详细地址',
  `consult_modes` varchar(32) DEFAULT NULL COMMENT '接诊方式1,2,3',
  `service_area` varchar(200) DEFAULT NULL COMMENT '服务区域',
  `fee_standard` decimal(10,2) DEFAULT NULL COMMENT '收费标准元/小时',
  `service_start_time` varchar(8) DEFAULT NULL COMMENT '服务开始HH:mm',
  `service_end_time` varchar(8) DEFAULT NULL COMMENT '服务结束HH:mm',
  `service_weekdays` varchar(32) DEFAULT NULL COMMENT '服务周日1-7',
  `max_daily_appointments` int(11) DEFAULT NULL COMMENT '单日最大接诊人数(仅机构)',
  `establish_date` date DEFAULT NULL COMMENT '成立时间',
  `team_size` int(11) DEFAULT NULL COMMENT '团队规模',
  `team_members` varchar(500) DEFAULT NULL COMMENT '团队成员',
  `person_in_charge` varchar(32) DEFAULT NULL COMMENT '负责人',
  `org_level` tinyint(4) DEFAULT NULL COMMENT '1诊所2医院',
  `equipment_model` varchar(32) DEFAULT NULL COMMENT '设备型号',
  `longitude` decimal(10,6) DEFAULT NULL COMMENT '经度预留',
  `latitude` decimal(10,6) DEFAULT NULL COMMENT '纬度预留',
  `publish_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0非发布态1已发布',
  `publish_time` datetime DEFAULT NULL COMMENT '发布时间',
  `offline_time` datetime DEFAULT NULL COMMENT '下架时间',
  `account_assigned` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0未分配1已分配',
  `sys_user_id` bigint(20) DEFAULT NULL COMMENT '关联用户ID',
  `assigned_login_name` varchar(64) DEFAULT NULL COMMENT '分配登录名',
  `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0正常2删除',
  `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_type` (`resource_type`),
  KEY `idx_name` (`resource_name`),
  KEY `idx_publish` (`publish_status`),
  KEY `idx_del` (`del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='畜牧医疗资源';
```

**界面三态与落库条件（应用层映射，与需求 §2.4 一致）**

| 界面状态 | `publish_status` | `offline_time` |
| --- | --- | --- |
| 未发布 | `0` | `NULL` |
| 已发布 | `1` | 任意 |
| 已下架 | `0` | **非** `NULL` |

列表 Query `publishStatus`：`0` 未发布 / `1` 已发布 / `2` 已下架（分别映射上表三行）。

**类型与字段落库矩阵（应用层强校验，禁止非法落库）**

| 字段 | 兽医(1) | 团队(2) | 机构(3) | 设备(4) |
| --- | --- | --- | --- | --- |
| `resource_name` / `photo_*` / `introduction` | ○/○/○ | ○/○/○ | ○/○/○ | ○/○/○ |
| `contact_phone` | ○ | ○ | ○ | — |
| `affiliated_unit` | ○ | ○ | — | ○ |
| `detail_address` | ○ | — | ○ | — |
| `consult_modes` / `service_area` / `fee_standard` | ✓/○/○ | — | — | — |
| `service_start_time` / `service_end_time` / `service_weekdays` | ○ | — | ○ | — |
| `max_daily_appointments` | — | — | ○ | — |
| `establish_date` / `team_size` / `team_members` | — | ○/○/○ | — | — |
| `person_in_charge` | — | ○ | ○ | — |
| `org_level` | — | — | ✓ | — |
| `equipment_model` | — | — | — | ○ |

### 2.2 资源类型 `resource_type`

数据来自 `GET /category/informationCategory/children?parentCode=004&categoryType=6`（响应 `code`、`name`）。落库与接口传 **叶子 `code`**。

| 编码 | 含义 |
| --- | --- |
| `004001` | 兽医人员 |
| `004002` | 专家团队 |
| `004003` | 诊疗机构 |
| `004004` | 医疗设备 |

保存校验：`MedicalResourceTypeValidator` 以上述 children 返回的 `code` 集合为准。历史 `tinyint` 迁移见 `sql/biz_medical_resource_alter_resource_type.sql`（`1`→`004001` … `4`→`004004`）。

### 2.3 发布状态 `publish_status`

| 值 | 含义 |
| --- | --- |
| `0` | 非发布态（含未发布、已下架；由 `offline_time` 区分展示） |
| `1` | 已发布 |

**发布：** `publish_status=1`，`publish_time=now()`。  
**下架：** `publish_status=0`，`offline_time=now()`；**不修改** `publish_time`。

### 2.4 机构级别 `org_level`

| 值 | 含义 |
| --- | --- |
| `1` | 动物诊所 |
| `2` | 动物医院 |

### 2.5 其他枚举

**接诊方式 `consult_modes`（多选入库）**

| 值 | 含义 |
| --- | --- |
| `1` | 定点接诊 |
| `2` | 上门接诊 |
| `3` | 在线接诊 |

**服务周日 `service_weekdays`（多选入库）**：`1`～`7` 表示周一至周日。

**账号分配 `account_assigned`**

| 值 | 含义 |
| --- | --- |
| `0` | 未分配 |
| `1` | 已分配 |

**删除标记 `del_flag`**

| 值 | 含义 |
| --- | --- |
| `0` | 正常 |
| `2` | 已逻辑删除 |

**分配账号默认角色（配置项，非本表字段）**

| `resource_type` | 默认 `role_id` |
| --- | --- |
| `004001` 兽医 | **100** |
| `004003` 机构 | **102** |

登录名规则：`Pinyin4j` 全拼（小写、无空格）+ `id`。

---

## 3. 接口设计

统一响应：**RuoYi 惯例** `AjaxResult`（`code` / `msg` / `data`）或分页 `TableDataInfo`（`rows` / `total`）；错误文案区分参数校验、状态非法、文件非法、账号创建失败等。

**权限标识建议（示例）**：`diseaseTreatment:medicalResource:list|query|add|edit|remove|publish|offline|assignAccount`

**Base Path（示例）**：`/diseaseTreatment/medicalResource`（实际前缀与若依 `context-path`、模块路由对齐）

### 3.1 分页列表

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `GET /diseaseTreatment/medicalResource/list` |
| **权限** | `diseaseTreatment:medicalResource:list` |
| **Query** | `pageNum`（默认 1）、`pageSize`（默认 **20**）、`resourceType`（**精确**，与 Tab 一致，**必填**）、`resourceName`（名称模糊，可空）、`publishStatus`（`0`/`1`/`2`，见 **§2.1** 三态映射，可空） |
| **排序** | 默认 `create_time DESC`, `id DESC` |
| **条件** | `del_flag='0'` |
| **响应** | `TableDataInfo` 行内字段：id、resourceType、resourceName、introduction（可截断）、publishStatus、publishTime、accountAssigned、assignedLoginName、createTime 及类型相关列等 |

### 3.2 详情

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `GET /diseaseTreatment/medicalResource/{id}` |
| **权限** | `diseaseTreatment:medicalResource:query` |
| **响应** | 全业务字段（驼峰）；`consultModes`、`serviceWeekdays` 以数组返回；含双维发布展示字段、`accountAssigned`、`assignedLoginName`、审计字段；仅 `del_flag=0` |

### 3.3 新增

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `POST /diseaseTreatment/medicalResource` |
| **权限** | `diseaseTreatment:medicalResource:add` |
| **Body** | JSON：`resourceType`、`resourceName`、`photoFileUrl`、`photoFilePath`、`introduction` 及按类型必填字段；`consultModes`、`serviceWeekdays` 为数组；`remark` 可空；照片须先上传 |
| **校验** | `MedicalResourceValidation` 按 **§2.1** 矩阵校验；手机号、服务时段、正数/正整数、照片后缀 jpg/jpeg/png |
| **落库** | `publish_status=0`，`offline_time=NULL`，`account_assigned=0`，`del_flag=0`；`resource_type` 保存后不可变 |

### 3.4 修改

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `PUT /diseaseTreatment/medicalResource` |
| **权限** | `diseaseTreatment:medicalResource:edit` |
| **前置** | `publish_status=0` 且 `del_flag=0`；否则返回「已发布资源请先下架后再编辑」 |
| **Body** | 含 `id`；可替换各业务字段及 `photoFileUrl` / `photoFilePath`；**不可修改** `resourceType` |
| **逻辑** | 更新库表；替换照片时按旧 `photo_file_path` 删除磁盘文件；**不自动发布** |

### 3.5 删除

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `DELETE /diseaseTreatment/medicalResource/{ids}` |
| **权限** | `diseaseTreatment:medicalResource:remove` |
| **规则** | **`publish_status=1` 禁止**；仅 `publish_status=0` 且 `del_flag=0` 允许逻辑删除 |
| **副作用** | `del_flag='2'`；删除照片物理文件；**若 `account_assigned=1` 且 `sys_user_id` 非空**，调用 `ISysUserService.deleteUserById` 删除平台账号；存在下游引用时由 `MedicalResourceReferenceChecker` 拒绝 |

### 3.6 发布

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `POST /diseaseTreatment/medicalResource/publish/{id}` |
| **权限** | `diseaseTreatment:medicalResource:publish` |
| **前置** | `publish_status=0` 且 `del_flag=0`；全量字段校验通过 |
| **结果** | `publish_status=1`，`publish_time=now()`；移动端可查询展示 |

### 3.7 下架

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `POST /diseaseTreatment/medicalResource/offline/{id}` |
| **权限** | `diseaseTreatment:medicalResource:offline` |
| **前置** | `publish_status=1` |
| **结果** | `publish_status=0`，`offline_time=now()`；**保留** `publish_time`；移动端不可见 |

### 3.8 分配账号

| 项 | 说明 |
| --- | --- |
| **Method / URI** | `POST /diseaseTreatment/medicalResource/assignAccount/{id}` |
| **权限** | `diseaseTreatment:medicalResource:assignAccount` |
| **前置** | `resource_type∈{004001,004003}`；`account_assigned=0`；`publish_status=0`；`del_flag=0` |
| **结果** | 创建 `sys_user`，绑定 **§2.5** 默认角色；写 `sys_user_id`、`assigned_login_name`、`account_assigned=1` |
| **失败** | 登录名冲突等：返回明确 `msg`，**不**置 `account_assigned=1` |

> **地图标点**：本期不提供接口。

---

## 4. 与移动端、账号体系衔接（流程）

### 4.1 角色说明

| 角色 | 说明 |
| --- | --- |
| **畜牧医疗资源业务服务** | 本模块 CRUD、发布/下架、分配账号 |
| **移动端 / 其他业务模块** | 查询 `publish_status=1` 且 `del_flag=0` 的资源用于列表、详情、预约引用 |
| **平台用户服务** | 分配账号时创建用户并绑定角色 |

### 4.2 发布与移动端可见性

```text
后台「发布」→ 本地 publish_status=1
  → 移动端查询条件：publish_status=1 AND del_flag=0
后台「下架」→ 本地 publish_status=0，offline_time 有值
  → 移动端不再返回该条
```

### 4.3 分配账号流程

```text
用户点击「分配账号」→ Service 校验 type∈{1,3}、未分配、未发布
  → 生成登录名（拼音+id）→ 调用户服务创建账号并绑定 role_id（100 或 102）
  ← 成功 → account_assigned=1，写入 sys_user_id、assigned_login_name
  ← 失败 → 提示原因，允许重试（仍须满足仅一次成功分配）
```

### 4.4 删除与账号联动（草稿 §10）

```text
用户删除资源 → 校验未发布/已下架、无下游引用
  → 若 account_assigned=1：MedicalResourceAccountAssigner.deleteLinkedAccount → deleteUserById
  → 删除照片文件 → logicDelete del_flag=2
```

---

## 5. 照片与上传（实现提示）

- 前端：先调若依 **`/common/upload`**，得到 **`url`**（→ `photoFileUrl`）、**存储路径**（→ `photoFilePath`，一般为 `fileName`）；**10MB** 在提交前校验，可不单独落库。  
- 服务端：后缀白名单 **jpg/jpeg/png**；`photo_file_path` 须以 `/profile` 前缀；替换照片时删除旧物理文件。

---

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

| 类型 | 名称 | 权限标识 |
| --- | --- | --- |
| 菜单 | 畜牧医疗资源管理 | `diseaseTreatment:medicalResource:list` |
| 按钮 | 查询 | `diseaseTreatment:medicalResource:query` |
| 按钮 | 新增 | `diseaseTreatment:medicalResource:add` |
| 按钮 | 修改 | `diseaseTreatment:medicalResource:edit` |
| 按钮 | 删除 | `diseaseTreatment:medicalResource:remove` |
| 按钮 | 发布 | `diseaseTreatment:medicalResource:publish` |
| 按钮 | 下架 | `diseaseTreatment:medicalResource:offline` |
| 按钮 | 分配账号 | `diseaseTreatment:medicalResource:assignAccount` |

组件路径：`diseaseTreatment/medicalResource/index`（挂载「牧业疫病诊疗服务」目录下）。

---

## 7. 交付清单（研发勾选）

- [ ] 表 `biz_medical_resource` DDL 与初始化脚本（`sql/biz_medical_resource.sql`）  
- [ ] Domain / Mapper / Service / Controller（`diseasetreatment` 包）  
- [ ] `MedicalResourceValidation`、`MedicalResourceRules`、分配账号组件  
- [ ] 菜单与按钮权限 SQL  
- [ ] 单元测试 / MockMvc：类型校验、发布态三态、分配账号、已发布不可改删  

---

## 8. 修订记录

| 日期 | 说明 |
| --- | --- |
| — | 初稿，对齐 `畜牧医疗资源管理功能需求.md` |
| — | 按 `养殖标准管理技术方案.md` 版式重整：技术架构分层表、库表五列、接口逐条表格、照片上传与交付清单章节 |
| — | 明确 `publish_status`+`offline_time` 三态；分配角色 100/102；地图标点本期无接口 |
| — | 删除接口：已分配账号时联动 `deleteUserById`（对齐草稿 §10） |
| — | `max_daily_appointments` 仅机构 type=3 校验与落库；兽医保存时清空该字段（对齐草稿 §2） |
