229 lines
6.9 KiB
Markdown
229 lines
6.9 KiB
Markdown
# 预约处方查询权限控制
|
|
|
|
## 修改说明
|
|
|
|
为 `getByAppointment` 接口添加了权限检查,确保用户只能查询自己有权限查看的处方。
|
|
|
|
## 修改内容
|
|
|
|
### 1. Controller 层修改
|
|
|
|
**文件**: `server/app/adminapi/controller/tcm/PrescriptionController.php`
|
|
|
|
**修改前**:
|
|
```php
|
|
public function getByAppointment()
|
|
{
|
|
$appointmentId = (int)($this->request->get('appointment_id') ?? 0);
|
|
if (!$appointmentId) {
|
|
return $this->fail('预约ID不能为空');
|
|
}
|
|
$prescription = PrescriptionLogic::getByAppointment($appointmentId);
|
|
return $this->data($prescription ?? []);
|
|
}
|
|
```
|
|
|
|
**修改后**:
|
|
```php
|
|
public function getByAppointment()
|
|
{
|
|
$appointmentId = (int)($this->request->get('appointment_id') ?? 0);
|
|
if (!$appointmentId) {
|
|
return $this->fail('预约ID不能为空');
|
|
}
|
|
$prescription = PrescriptionLogic::getByAppointment($appointmentId, (int)$this->adminId, $this->adminInfo);
|
|
if ($prescription === null) {
|
|
$msg = PrescriptionLogic::getError();
|
|
return $this->fail($msg !== '' ? $msg : '未找到处方或无权限查看');
|
|
}
|
|
return $this->data($prescription);
|
|
}
|
|
```
|
|
|
|
**改进点**:
|
|
- 传入当前登录用户的 `adminId` 和 `adminInfo`
|
|
- 处理权限检查失败的情况,返回明确的错误信息
|
|
- 区分"未找到处方"和"无权限查看"两种情况
|
|
|
|
### 2. Logic 层修改
|
|
|
|
**文件**: `server/app/adminapi/logic/tcm/PrescriptionLogic.php`
|
|
|
|
**修改前**:
|
|
```php
|
|
/**
|
|
* 根据预约ID获取处方
|
|
*/
|
|
public static function getByAppointment(int $appointmentId): ?array
|
|
{
|
|
$row = Prescription::where('appointment_id', $appointmentId)
|
|
->whereNull('delete_time')
|
|
->order('id', 'desc')
|
|
->find();
|
|
return $row ? $row->toArray() : null;
|
|
}
|
|
```
|
|
|
|
**修改后**:
|
|
```php
|
|
/**
|
|
* 根据预约ID获取处方(带权限检查)
|
|
*/
|
|
public static function getByAppointment(int $appointmentId, int $viewerAdminId, array $viewerAdminInfo): ?array
|
|
{
|
|
self::$error = '';
|
|
$row = Prescription::where('appointment_id', $appointmentId)
|
|
->whereNull('delete_time')
|
|
->order('id', 'desc')
|
|
->find();
|
|
|
|
if (!$row) {
|
|
return null;
|
|
}
|
|
|
|
// 权限检查:只返回当前用户有权限查看的处方
|
|
if (!self::canViewPrescription($row, $viewerAdminId, $viewerAdminInfo)) {
|
|
self::setError('无权限查看此处方');
|
|
return null;
|
|
}
|
|
|
|
return $row->toArray();
|
|
}
|
|
```
|
|
|
|
**改进点**:
|
|
- 添加 `viewerAdminId` 和 `viewerAdminInfo` 参数
|
|
- 使用 `canViewPrescription()` 方法进行权限检查
|
|
- 设置错误信息,便于前端显示
|
|
|
|
## 权限规则
|
|
|
|
根据 `canViewPrescription()` 方法,以下用户可以查看处方:
|
|
|
|
1. **超级管理员** - 可以查看所有处方
|
|
2. **处方创建人** - 可以查看自己创建的处方
|
|
3. **医助** - 可以查看自己协助的处方
|
|
4. **共享处方** - 所有人可以查看标记为共享的处方
|
|
5. **可见角色** - 处方指定的可见角色可以查看
|
|
6. **有开方权限的医生** - 拥有 `tcm.diagnosis/kaifang` 权限的医生可以查看所有处方(只读)
|
|
|
|
## 使用场景
|
|
|
|
这个接口主要用于以下场景:
|
|
|
|
1. **查看病历按钮** - 在预约列表中点击"查看病历"时调用
|
|
2. **处方历史查询** - 根据预约ID查询患者的历史处方
|
|
3. **医生协作** - 其他医生查看患者的处方记录(需要有开方权限)
|
|
|
|
## 前端调用示例
|
|
|
|
```typescript
|
|
// admin/src/views/tcm/appointment/list.vue
|
|
const handleViewCase = async (row: any) => {
|
|
if (!row.id) {
|
|
feedback.msgWarning('预约信息不完整')
|
|
return
|
|
}
|
|
try {
|
|
const prescription = await prescriptionGetByAppointment({ appointment_id: row.id })
|
|
if (prescription?.id) {
|
|
prescriptionRef.value?.openById(prescription.id)
|
|
} else {
|
|
feedback.msgWarning('该预约暂无病历记录,请先开方')
|
|
}
|
|
} catch (error: any) {
|
|
// 权限不足或其他错误
|
|
feedback.msgError(error?.msg || '获取病历失败')
|
|
}
|
|
}
|
|
```
|
|
|
|
## 错误处理
|
|
|
|
### 可能的错误信息
|
|
|
|
1. **"预约ID不能为空"** - 未传入 `appointment_id` 参数
|
|
2. **"未找到处方或无权限查看"** - 处方不存在或当前用户无权限查看
|
|
3. **"无权限查看此处方"** - 处方存在但当前用户无权限查看
|
|
|
|
### 前端处理建议
|
|
|
|
```typescript
|
|
try {
|
|
const prescription = await prescriptionGetByAppointment({ appointment_id: row.id })
|
|
// 成功获取处方
|
|
} catch (error: any) {
|
|
if (error?.msg?.includes('无权限')) {
|
|
feedback.msgWarning('您没有权限查看此处方')
|
|
} else if (error?.msg?.includes('未找到')) {
|
|
feedback.msgWarning('该预约暂无病历记录')
|
|
} else {
|
|
feedback.msgError(error?.msg || '获取病历失败')
|
|
}
|
|
}
|
|
```
|
|
|
|
## 测试建议
|
|
|
|
### 1. 权限测试
|
|
|
|
**测试用例 1: 创建人查看自己的处方**
|
|
- 医生A创建处方
|
|
- 医生A查看该处方
|
|
- 预期:成功返回处方数据
|
|
|
|
**测试用例 2: 其他医生查看处方(有开方权限)**
|
|
- 医生A创建处方
|
|
- 医生B(有 `tcm.diagnosis/kaifang` 权限)查看该处方
|
|
- 预期:成功返回处方数据(只读)
|
|
|
|
**测试用例 3: 其他医生查看处方(无开方权限)**
|
|
- 医生A创建处方
|
|
- 医生C(无 `tcm.diagnosis/kaifang` 权限)查看该处方
|
|
- 预期:返回"无权限查看此处方"错误
|
|
|
|
**测试用例 4: 医助查看协助的处方**
|
|
- 医生A创建处方,医助B协助
|
|
- 医助B查看该处方
|
|
- 预期:成功返回处方数据
|
|
|
|
**测试用例 5: 查看共享处方**
|
|
- 医生A创建处方并标记为共享
|
|
- 任何用户查看该处方
|
|
- 预期:成功返回处方数据
|
|
|
|
### 2. 边界测试
|
|
|
|
**测试用例 6: 预约不存在**
|
|
- 传入不存在的 `appointment_id`
|
|
- 预期:返回"未找到处方或无权限查看"
|
|
|
|
**测试用例 7: 预约存在但无处方**
|
|
- 传入存在的 `appointment_id`,但该预约没有创建处方
|
|
- 预期:返回"未找到处方或无权限查看"
|
|
|
|
**测试用例 8: 处方已删除**
|
|
- 传入已删除处方的 `appointment_id`
|
|
- 预期:返回"未找到处方或无权限查看"
|
|
|
|
## 安全性说明
|
|
|
|
1. **防止越权访问** - 用户只能查看自己有权限的处方,防止查看其他医生的私有处方
|
|
2. **数据隔离** - 通过权限检查实现数据隔离,保护患者隐私
|
|
3. **审计追踪** - 所有查询操作都会记录当前用户信息,便于审计
|
|
4. **错误信息脱敏** - 对于无权限的情况,不暴露处方是否存在的详细信息
|
|
|
|
## 相关文档
|
|
|
|
- `PRESCRIPTION_VIEW_PERMISSION_FIX.md` - 处方查看权限修复文档
|
|
- `BUG_FIXES_SUMMARY.md` - Bug修复总结文档
|
|
|
|
## 总结
|
|
|
|
通过添加权限检查,确保了:
|
|
- ✅ 用户只能查询自己有权限查看的处方
|
|
- ✅ 防止越权访问其他医生的私有处方
|
|
- ✅ 支持医生协作(有开方权限的医生可以查看所有处方)
|
|
- ✅ 保护患者隐私和数据安全
|
|
- ✅ 提供明确的错误信息,便于前端处理
|