# 我的预约（兽医）— 技术方案

> 依据：`我的预约(兽医)功能需求.md`（同目录）；关联 `我的预约(机构)`、`我的预约(专家)` 草稿与功能需求

---

## 1. 技术架构

| 项 | 说明 |
| --- | --- |
| **整体** | RuoYi **v3.9.2**（**springboot2** 分支）单体后端 + 若依 **Vue2** 管理端 |
| **运行时** | JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，InnoDB，`utf8mb4` |
| **关联表** | `biz_medical_resource`（兽医 `resource_type=1`，`sys_user_id` 绑定登录用户） |
| **移动端** | 预约写入由「预约服务」App 接口完成（可另包实现）；本模块为**兽医后台**查询与接单 |

**后端分层（兽医模块）**

| 层 | 职责 |
| --- | --- |
| `Controller` | 列表/详情/确认/拒绝；`@PreAuthorize`；`AjaxResult` / `TableDataInfo` |
| `Service` | 解析当前兽医 `provider_id`、状态机、越权校验、拒绝理由校验 |
| `Mapper` + XML | 统一预约表按 `provider_type=1` + `provider_id` 查询 |
| `support` | `VetAppointmentRules`、`VetAppointmentValidation`；可复用公共 `AppointmentStatus` 枚举 |

**代码包（建议）**：`com.ruoyi.web.modules.diagnosis`（与畜牧医疗资源同域）  
**公共预约域（建议）**：`com.ruoyi.web.modules.appointment`（枚举、实体、Mapper，供兽医/机构/专家三端复用）  
**初始化脚本**：`sql/biz_service_appointment.sql`（统一表）；专家评价表见 **§2.2**

---

## 2. 关联方案设计（三端共用）

### 2.1 统一预约主表 `biz_service_appointment`

移动端「预约服务」提交时写入**同一张表**，用 `provider_type` + `provider_id` 区分服务对象；三端后台**仅查询各自范围**，互不交叉。

| `provider_type` | 服务对象 | `provider_id` 指向 | 后台模块 | 初始 `status` |
| --- | --- | --- | --- | --- |
| `1` | 兽医 | `biz_medical_resource.id`（`resource_type=1`） | 我的预约（兽医） | `0` 待确认 |
| `2` | 诊疗机构 | `biz_medical_resource.id`（`resource_type=3`） | 我的预约（机构） | `5` 已预约 |
| `3` | 科技专家 | `biz_tech_resource.id`（`resource_type=1`） | 我的预约（专家） | `0` 待确认 |

### 2.2 状态枚举（库表单字段 `status`）

| 值 | 编码常量 | 兽医/专家展示 | 机构展示 | 兽医/专家可用 | 机构可用 |
| --- | --- | --- | --- | --- | --- |
| `0` | `PENDING` | 待确认 | — | ✓ | — |
| `1` | `CONFIRMED` | 已确认 | — | ✓ | — |
| `2` | `REJECTED` | 已拒绝 | — | ✓ | — |
| `3` | `CANCELLED` | 已取消 | 已取消 | ✓ | ✓ |
| `4` | `COMPLETED` | 已完成 | 已完成 | ✓ | ✓ |
| `5` | `BOOKED` | — | 已预约 | — | ✓ |

应用层按 `provider_type` 校验状态合法性（机构不得出现 `0/1/2`；兽医不得出现 `5`）。

### 2.3 三端接口与权限前缀（摘要）

| 模块 | Base Path（示例） | 写操作 |
| --- | --- | --- |
| 兽医（本文档） | `/diseaseTreatment/myAppointment/vet` | 确认、拒绝 |
| 机构 | `/diseaseTreatment/myAppointment/org` | 无（仅 list/query） |
| 专家 | `/techService/myAppointment/expert` | 确认、拒绝；评价 list（已完成） |

### 2.4 当前登录人解析（兽医）

```text
loginUser.userId
  → biz_medical_resource WHERE sys_user_id = ? AND resource_type = 1
      AND account_assigned = 1 AND del_flag = '0'
  → provider_id = id
列表/操作 WHERE provider_type = 1 AND provider_id = ?
```

无绑定记录时：列表返回空；确认/拒绝返回「未绑定兽医资源，无法操作」。

### 2.5 专家评价表（仅专家模块，兽医不涉及）

表 `biz_service_appointment_review`（`appointment_id` FK，`reviewer_name`，`review_time`，`summary`，可选星级字段）；兽医本期**无**评价查询接口。详见专家技术方案（待编）。

---

## 3. 数据库设计

### 3.1 表 `biz_service_appointment`（服务预约主表）

| 字段 | 类型 | 非空 | 默认 | 说明 |
| --- | --- | --- | --- | --- |
| `id` | `bigint(20)` | Y | 自增 | 主键 |
| `provider_type` | `tinyint(4)` | Y | — | 1兽医 2机构 3专家 |
| `provider_id` | `bigint(20)` | Y | — | 医疗资源/科技资源主键 |
| `appointee_name` | `varchar(64)` | Y | — | 预约人姓名 |
| `appoint_date` | `date` | Y | — | 预约日期 |
| `time_start` | `varchar(8)` | Y | — | 时段开始 `HH:mm` |
| `time_end` | `varchar(8)` | Y | — | 时段结束 `HH:mm` |
| `contact_phone` | `varchar(20)` | Y | — | 联系电话 |
| `service_address` | `varchar(200)` | Y | — | 服务地址 |
| `service_requirement` | `varchar(500)` | N | NULL | 服务需求 |
| `status` | `tinyint(4)` | Y | — | 见 **§2.2** |
| `reject_reason` | `varchar(200)` | N | NULL | 拒绝理由（已拒绝时） |
| `confirm_time` | `datetime` | N | NULL | 确认接诊时间（审计） |
| `reject_time` | `datetime` | N | NULL | 拒绝时间（审计） |
| `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_provider (provider_type, provider_id)`；`KEY idx_appoint_date (appoint_date)`；`KEY idx_status (status)`；`KEY idx_create_time (create_time)`。

**DDL（MySQL 5.7）**

```sql
CREATE TABLE `biz_service_appointment` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `provider_type` tinyint(4) NOT NULL COMMENT '1兽医2机构3专家',
  `provider_id` bigint(20) NOT NULL COMMENT '服务方资源ID',
  `appointee_name` varchar(64) NOT NULL COMMENT '预约人',
  `appoint_date` date NOT NULL COMMENT '预约日期',
  `time_start` varchar(8) NOT NULL COMMENT '开始HH:mm',
  `time_end` varchar(8) NOT NULL COMMENT '结束HH:mm',
  `contact_phone` varchar(20) NOT NULL COMMENT '联系电话',
  `service_address` varchar(200) NOT NULL COMMENT '服务地址',
  `service_requirement` varchar(500) DEFAULT NULL COMMENT '服务需求',
  `status` tinyint(4) NOT NULL COMMENT '0待确认1已确认2已拒绝3已取消4已完成5已预约',
  `reject_reason` varchar(200) DEFAULT NULL COMMENT '拒绝理由',
  `confirm_time` datetime DEFAULT NULL COMMENT '确认时间',
  `reject_time` datetime DEFAULT 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 '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`),
  KEY `idx_provider` (`provider_type`,`provider_id`),
  KEY `idx_appoint_date` (`appoint_date`),
  KEY `idx_status` (`status`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务预约主表';
```

### 3.2 列表查询条件（兽医 XML 片段语义）

```sql
WHERE provider_type = 1 AND provider_id = #{providerId}
  <if test="appointeeName != null and appointeeName != ''">
    AND appointee_name LIKE concat('%', #{appointeeName}, '%')
  </if>
  <if test="startDate != null">AND appoint_date &gt;= #{startDate}</if>
  <if test="endDate != null">AND appoint_date &lt;= #{endDate}</if>
  <if test="status != null">AND status = #{status}</if>
ORDER BY appoint_date DESC, create_time DESC, id DESC
```

操作前须 `SELECT ... FOR UPDATE` 或乐观校验：`id` + `provider_type=1` + `provider_id=当前兽医` + `status=0`。

---

## 4. 接口设计（兽医）

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

**权限标识（示例）**：`diseaseTreatment:vetMyAppointment:list|query|confirm|reject|complete`

**Base Path（示例）**：`/diseaseTreatment/myAppointment/vet`

| # | 说明 | Method | URI | 权限 | 要点 |
| --- | --- | --- | --- | --- | --- |
| 4.1 | 分页列表 | GET | `/list` | `...:list` | Query：`pageNum`（默认 1）、`pageSize`（默认 **20**）、`appointeeName`（预约人模糊）、`startDate`、`endDate`（`yyyy-MM-dd`）、`status`（`0`～`4`，兽医合法值）；服务端注入 `providerId`，禁止前端传 |
| 4.2 | 详情 | GET | `/{id}` | `...:query` | 校验归属当前兽医；返回全字段含 `rejectReason`、`status` 展示名 |
| 4.3 | 确认接诊 | POST | `/confirm/{id}` | `...:confirm` | 前置 `status=0`；更新 `status=1`，`confirm_time=now()`，`update_by` |
| 4.4 | 拒绝接诊 | POST | `/reject/{id}` | `...:reject` | Body：`rejectReason`（必填 1～100 字）；前置 `status=0`；更新 `status=2`，写 `reject_reason`、`reject_time` |
| 4.5 | 完成接诊 | POST | `/complete/{id}` | `...:complete` | 前置 `status=1`（已确认）；更新 `status=4`（已完成）；写 `update_by`、`update_time` |

### 4.1 列表响应字段（示例）

`id`、`appointeeName`、`appointDate`、`timeStart`、`timeEnd`、`contactPhone`、`serviceAddress`、`serviceRequirement`、`status`、`statusLabel`、`canComplete`、`rejectReason`、`createTime`。

前端展示时段：`timeStart + '~' + timeEnd`。

### 4.2 业务错误（`msg` 示例）

| 场景 | 文案 |
| --- | --- |
| 无兽医绑定 | 未绑定兽医资源，无法查询预约 |
| 越权 | 无权操作该预约记录 |
| 非待确认确认/拒绝 | 当前状态不允许确认接诊 / 当前状态不允许拒绝接诊 |
| 拒绝理由 | 请填写拒绝理由 / 拒绝理由不能超过 100 字 |
| 日期筛选 | 结束日期不能早于开始日期 |

### 4.3 机构 / 专家接口差异（关联实现时对照）

| 能力 | 兽医 URI | 机构 URI | 专家 URI |
| --- | --- | --- | --- |
| 列表 | `.../vet/list` | `.../org/list` | `.../expert/list` |
| 详情 | `.../vet/{id}` | `.../org/{id}` | `.../expert/{id}` |
| 确认 | `POST .../vet/confirm/{id}` | — | `POST .../expert/confirm/{id}` |
| 拒绝 | `POST .../vet/reject/{id}` | — | `POST .../expert/reject/{id}` |
| 评价列表 | — | — | `GET .../expert/reviewList/{id}`（仅已完成） |

机构列表列较少（无 `serviceAddress` 等待选列可在 SQL 仍查出，前端按需展示）。

---

## 5. 实现要点

| 项 | 说明 |
| --- | --- |
| 越权 | 所有 `id` 操作必须校验 `provider_type=1` 且 `provider_id=当前兽医` |
| 事务 | 确认/拒绝单条 `@Transactional`；更新前再次读 `status` |
| 并发 | `status!=0` 时返回状态已变更；与移动端取消竞态同理 |
| 日志 | `@Log` 记录确认、拒绝 |
| 组件路径 | `diseaseTreatment/myAppointment/vet/index` |

**可复用类（建议）**

- `AppointmentProviderType`、`AppointmentStatus`（枚举）  
- `BizServiceAppointment`（实体）  
- `BizServiceAppointmentMapper`（按 provider 查询）  
- `VetMyAppointmentServiceImpl` 封装兽医 scope + 状态机  

---

## 6. 与上下游衔接

| 系统 | 说明 |
| --- | --- |
| 移动端预约服务 | `INSERT` 记录：`provider_type=1`，`status=0`，字段来自预约表单 |
| 移动端取消 | 更新 `status=3`（允许态由 App 规则控制） |
| 已完成 | 兽医后台 **完成接诊**（`status` 1→4）或整体业务闭环置 `status=4` |
| 畜牧医疗资源 | 兽医发布且分配账号后才有本菜单数据 |

---

## 7. 交付清单

- [ ] `sql/biz_service_appointment.sql`（三端共用）  
- [ ] 公共 `appointment` 域实体 / 枚举 / Mapper  
- [ ] `VetMyAppointmentController` + Service + 校验  
- [ ] 菜单权限 SQL（兽医）  
- [ ] 单元测试 + MockMvc（列表 scope、确认、拒绝、状态拦截）  
- [ ] 机构/专家 Controller（可同迭代，共用 Mapper）  

---

## 8. 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初稿：统一预约表 + 兽医接口；三端关联状态与路径；专家评价表仅关联说明 |
