新增功能
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
# 患者挂号系统实现文档
|
||||
|
||||
## 功能概述
|
||||
|
||||
实现了基于医生排班的患者挂号系统,支持15分钟间隔的时间段预约,防止重复预约,并根据医生排班状态控制挂号可用性。
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. 时间段管理
|
||||
- 每个时间段间隔15分钟
|
||||
- 上午时段:08:00 - 12:00(16个时间段)
|
||||
- 下午时段:14:00 - 18:00(16个时间段)
|
||||
- 每个时间段只能被一个患者预约
|
||||
|
||||
### 2. 排班状态控制
|
||||
- 出诊(status=1):允许挂号
|
||||
- 停诊(status=2):不允许挂号
|
||||
- 休息(status=3):不允许挂号
|
||||
- 请假(status=4):不允许挂号
|
||||
|
||||
### 3. 号源管理
|
||||
- 医生排班时设置号源数(quota)
|
||||
- 已预约数量不能超过号源数
|
||||
- 实时显示可用/已占用状态
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
admin/
|
||||
├── src/
|
||||
│ ├── api/
|
||||
│ │ └── doctor.ts # 新增挂号相关API
|
||||
│ └── views/
|
||||
│ ├── doctor/
|
||||
│ │ └── roster.vue # 医生排班管理(已存在)
|
||||
│ └── tcm/
|
||||
│ └── diagnosis/
|
||||
│ ├── index.vue # 诊断列表(已更新)
|
||||
│ └── appointment.vue # 挂号弹窗组件(新增)
|
||||
```
|
||||
|
||||
## API接口
|
||||
|
||||
### 1. 获取可用时间段
|
||||
```typescript
|
||||
GET /doctor.appointment/availableSlots
|
||||
参数:
|
||||
{
|
||||
doctor_id: number, // 医生ID
|
||||
date: string, // 日期 YYYY-MM-DD
|
||||
period: 'morning' | 'afternoon' // 时段
|
||||
}
|
||||
|
||||
返回:
|
||||
{
|
||||
slots: [
|
||||
{
|
||||
time: '08:00', // 时间
|
||||
available: true // 是否可预约
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 创建挂号
|
||||
```typescript
|
||||
POST /doctor.appointment/create
|
||||
参数:
|
||||
{
|
||||
patient_id: number, // 患者ID
|
||||
doctor_id: number, // 医生ID
|
||||
appointment_date: string, // 预约日期 YYYY-MM-DD
|
||||
period: 'morning' | 'afternoon', // 时段
|
||||
appointment_time: string, // 预约时间 HH:mm
|
||||
remark: string // 备注(可选)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 取消挂号
|
||||
```typescript
|
||||
POST /doctor.appointment/cancel
|
||||
参数:
|
||||
{
|
||||
id: number // 挂号记录ID
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 挂号列表
|
||||
```typescript
|
||||
GET /doctor.appointment/lists
|
||||
参数:
|
||||
{
|
||||
page_no: number,
|
||||
page_size: number,
|
||||
patient_id?: number,
|
||||
doctor_id?: number,
|
||||
date?: string
|
||||
}
|
||||
```
|
||||
|
||||
## 后端实现要点
|
||||
|
||||
### 1. 数据库表设计
|
||||
|
||||
```sql
|
||||
CREATE TABLE `doctor_appointment` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`patient_id` int(11) NOT NULL COMMENT '患者ID',
|
||||
`doctor_id` int(11) NOT NULL COMMENT '医生ID',
|
||||
`roster_id` int(11) NOT NULL COMMENT '排班ID',
|
||||
`appointment_date` date NOT NULL COMMENT '预约日期',
|
||||
`period` enum('morning','afternoon') NOT NULL COMMENT '时段',
|
||||
`appointment_time` time NOT NULL COMMENT '预约时间',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态:1=已预约,2=已取消,3=已完成',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `unique_appointment` (`doctor_id`,`appointment_date`,`appointment_time`,`status`),
|
||||
KEY `idx_patient` (`patient_id`),
|
||||
KEY `idx_doctor_date` (`doctor_id`,`appointment_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='医生挂号表';
|
||||
```
|
||||
|
||||
### 2. 获取可用时间段逻辑
|
||||
|
||||
```php
|
||||
public function availableSlots()
|
||||
{
|
||||
$doctorId = $this->request->get('doctor_id');
|
||||
$date = $this->request->get('date');
|
||||
$period = $this->request->get('period');
|
||||
|
||||
// 1. 检查医生排班
|
||||
$roster = DoctorRoster::where([
|
||||
'doctor_id' => $doctorId,
|
||||
'date' => $date,
|
||||
'period' => $period
|
||||
])->find();
|
||||
|
||||
// 如果没有排班或状态不是出诊,返回空数组
|
||||
if (!$roster || $roster->status != 1) {
|
||||
return $this->success(['slots' => []]);
|
||||
}
|
||||
|
||||
// 2. 生成时间段
|
||||
$slots = [];
|
||||
if ($period == 'morning') {
|
||||
$startHour = 8;
|
||||
$endHour = 12;
|
||||
} else {
|
||||
$startHour = 14;
|
||||
$endHour = 18;
|
||||
}
|
||||
|
||||
for ($hour = $startHour; $hour < $endHour; $hour++) {
|
||||
for ($minute = 0; $minute < 60; $minute += 15) {
|
||||
$time = sprintf('%02d:%02d', $hour, $minute);
|
||||
$slots[] = [
|
||||
'time' => $time,
|
||||
'available' => true
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 查询已预约的时间段
|
||||
$appointments = DoctorAppointment::where([
|
||||
'doctor_id' => $doctorId,
|
||||
'appointment_date' => $date,
|
||||
'period' => $period,
|
||||
'status' => 1 // 只查询有效预约
|
||||
])->column('appointment_time');
|
||||
|
||||
// 4. 标记已占用的时间段
|
||||
foreach ($slots as &$slot) {
|
||||
if (in_array($slot['time'], $appointments)) {
|
||||
$slot['available'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 检查号源限制
|
||||
$appointmentCount = count($appointments);
|
||||
if ($appointmentCount >= $roster->quota) {
|
||||
// 如果已达到号源上限,所有未预约的时间段也标记为不可用
|
||||
foreach ($slots as &$slot) {
|
||||
if ($slot['available']) {
|
||||
$slot['available'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success(['slots' => $slots]);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 创建挂号逻辑
|
||||
|
||||
```php
|
||||
public function create()
|
||||
{
|
||||
$data = $this->request->post();
|
||||
|
||||
// 1. 验证参数
|
||||
$validate = Validate::rule([
|
||||
'patient_id|患者ID' => 'require|integer',
|
||||
'doctor_id|医生ID' => 'require|integer',
|
||||
'appointment_date|预约日期' => 'require|date',
|
||||
'period|时段' => 'require|in:morning,afternoon',
|
||||
'appointment_time|预约时间' => 'require'
|
||||
]);
|
||||
|
||||
if (!$validate->check($data)) {
|
||||
return $this->fail($validate->getError());
|
||||
}
|
||||
|
||||
// 2. 检查医生排班
|
||||
$roster = DoctorRoster::where([
|
||||
'doctor_id' => $data['doctor_id'],
|
||||
'date' => $data['appointment_date'],
|
||||
'period' => $data['period']
|
||||
])->find();
|
||||
|
||||
if (!$roster) {
|
||||
return $this->fail('该医生当天未排班');
|
||||
}
|
||||
|
||||
if ($roster->status != 1) {
|
||||
return $this->fail('该医生当天不出诊');
|
||||
}
|
||||
|
||||
// 3. 检查时间段是否已被预约
|
||||
$exists = DoctorAppointment::where([
|
||||
'doctor_id' => $data['doctor_id'],
|
||||
'appointment_date' => $data['appointment_date'],
|
||||
'appointment_time' => $data['appointment_time'],
|
||||
'status' => 1
|
||||
])->find();
|
||||
|
||||
if ($exists) {
|
||||
return $this->fail('该时间段已被预约');
|
||||
}
|
||||
|
||||
// 4. 检查号源是否已满
|
||||
$appointmentCount = DoctorAppointment::where([
|
||||
'doctor_id' => $data['doctor_id'],
|
||||
'appointment_date' => $data['appointment_date'],
|
||||
'period' => $data['period'],
|
||||
'status' => 1
|
||||
])->count();
|
||||
|
||||
if ($appointmentCount >= $roster->quota) {
|
||||
return $this->fail('该时段号源已满');
|
||||
}
|
||||
|
||||
// 5. 创建挂号记录
|
||||
$appointment = DoctorAppointment::create([
|
||||
'patient_id' => $data['patient_id'],
|
||||
'doctor_id' => $data['doctor_id'],
|
||||
'roster_id' => $roster->id,
|
||||
'appointment_date' => $data['appointment_date'],
|
||||
'period' => $data['period'],
|
||||
'appointment_time' => $data['appointment_time'],
|
||||
'remark' => $data['remark'] ?? '',
|
||||
'status' => 1
|
||||
]);
|
||||
|
||||
return $this->success('挂号成功', $appointment);
|
||||
}
|
||||
```
|
||||
|
||||
## 前端组件说明
|
||||
|
||||
### appointment.vue 组件
|
||||
|
||||
挂号弹窗组件,包含以下功能:
|
||||
|
||||
1. **医生选择**:从医生列表中选择
|
||||
2. **日期选择**:不能选择过去的日期
|
||||
3. **时段选择**:上午/下午
|
||||
4. **时间段选择**:
|
||||
- 网格布局显示所有时间段
|
||||
- 可用时间段:蓝色,可点击
|
||||
- 已占用时间段:灰色,不可点击
|
||||
- 已选择时间段:深蓝色高亮
|
||||
5. **备注输入**:可选的备注信息
|
||||
|
||||
### 使用方式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<appointment-popup ref="appointmentRef" @success="handleSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import AppointmentPopup from './appointment.vue'
|
||||
|
||||
const appointmentRef = ref()
|
||||
|
||||
const handleAppointment = (patient) => {
|
||||
appointmentRef.value?.open(patient)
|
||||
}
|
||||
|
||||
const handleSuccess = () => {
|
||||
// 挂号成功后的处理
|
||||
console.log('挂号成功')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 权限控制
|
||||
|
||||
在诊断列表中,挂号按钮使用权限指令:
|
||||
|
||||
```vue
|
||||
<el-button
|
||||
v-perms="['tcm.diagnosis/guahao']"
|
||||
type="success"
|
||||
link
|
||||
@click="handleAppointment(row)"
|
||||
>
|
||||
挂号
|
||||
</el-button>
|
||||
```
|
||||
|
||||
需要在后端权限系统中添加对应的权限节点。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **时区处理**:确保前后端时间格式一致
|
||||
2. **并发控制**:使用数据库唯一索引防止重复预约
|
||||
3. **事务处理**:创建挂号时使用事务确保数据一致性
|
||||
4. **缓存策略**:可以对排班数据进行缓存提高性能
|
||||
5. **通知机制**:挂号成功后可以发送短信/消息通知
|
||||
|
||||
## 扩展功能建议
|
||||
|
||||
1. **预约提醒**:在预约时间前发送提醒
|
||||
2. **候补机制**:号源满时支持候补排队
|
||||
3. **预约改期**:支持修改预约时间
|
||||
4. **统计报表**:医生预约统计、患者预约历史
|
||||
5. **评价系统**:就诊后患者评价医生
|
||||
Reference in New Issue
Block a user