Files
zyt/PRESCRIPTION_GET_BY_APPOINTMENT_PERMISSION.md
T
2026-04-10 14:43:58 +08:00

6.9 KiB

预约处方查询权限控制

修改说明

getByAppointment 接口添加了权限检查,确保用户只能查询自己有权限查看的处方。

修改内容

1. Controller 层修改

文件: server/app/adminapi/controller/tcm/PrescriptionController.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 ?? []);
}

修改后:

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);
}

改进点:

  • 传入当前登录用户的 adminIdadminInfo
  • 处理权限检查失败的情况,返回明确的错误信息
  • 区分"未找到处方"和"无权限查看"两种情况

2. Logic 层修改

文件: server/app/adminapi/logic/tcm/PrescriptionLogic.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;
}

修改后:

/**
 * 根据预约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();
}

改进点:

  • 添加 viewerAdminIdviewerAdminInfo 参数
  • 使用 canViewPrescription() 方法进行权限检查
  • 设置错误信息,便于前端显示

权限规则

根据 canViewPrescription() 方法,以下用户可以查看处方:

  1. 超级管理员 - 可以查看所有处方
  2. 处方创建人 - 可以查看自己创建的处方
  3. 医助 - 可以查看自己协助的处方
  4. 共享处方 - 所有人可以查看标记为共享的处方
  5. 可见角色 - 处方指定的可见角色可以查看
  6. 有开方权限的医生 - 拥有 tcm.diagnosis/kaifang 权限的医生可以查看所有处方(只读)

使用场景

这个接口主要用于以下场景:

  1. 查看病历按钮 - 在预约列表中点击"查看病历"时调用
  2. 处方历史查询 - 根据预约ID查询患者的历史处方
  3. 医生协作 - 其他医生查看患者的处方记录(需要有开方权限)

前端调用示例

// 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. "无权限查看此处方" - 处方存在但当前用户无权限查看

前端处理建议

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修复总结文档

总结

通过添加权限检查,确保了:

  • 用户只能查询自己有权限查看的处方
  • 防止越权访问其他医生的私有处方
  • 支持医生协作(有开方权限的医生可以查看所有处方)
  • 保护患者隐私和数据安全
  • 提供明确的错误信息,便于前端处理