Files
zyt/server/app/adminapi/logic/firstvisit/MyPatientLogic.php
T
2026-08-05 11:08:02 +08:00

160 lines
5.7 KiB
PHP

<?php
declare(strict_types=1);
namespace app\adminapi\logic\firstvisit;
use app\common\model\auth\AdminRole;
use app\common\model\doctor\Appointment;
use app\common\model\tcm\Diagnosis;
use app\common\service\DataScope\DataScopeService;
use think\db\Query;
use think\facade\Db;
/**
* “我的患者”统一数据范围。
*
* 角色语义:医生只看本人接诊患者,医助只看本人归属患者;经理、
* 诊室组长和管理员按系统 DataScope 查看团队患者;root 查看全部。
*/
class MyPatientLogic
{
private const DOCTOR_ROLE_ID = 1;
private const ASSISTANT_ROLE_ID = 2;
private const TEAM_ROLE_IDS = [3, 7, 8];
private const EFFECTIVE_APPOINTMENT_STATUSES = [1, 3, 4];
/**
* @param Query $query 以 d 作为 zyt_tcm_diagnosis 别名的查询
*/
public static function applyScope(Query $query, int $adminId, array $adminInfo): void
{
if ($adminId <= 0) {
$query->whereRaw('0 = 1');
return;
}
if ((int) ($adminInfo['root'] ?? 0) === 1) {
return;
}
$roleIds = self::roleIds($adminId);
$appointmentTable = (new Appointment())->getTable();
$statusList = implode(',', self::EFFECTIVE_APPOINTMENT_STATUSES);
// 管理角色按系统的数据范围查看“范围内医助归属或医生接诊”的患者。
if (array_intersect($roleIds, self::TEAM_ROLE_IDS) !== []) {
$visibleAdminIds = DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
if ($visibleAdminIds === null) {
return;
}
$visibleAdminIds = self::normalizeIds($visibleAdminIds);
if ($visibleAdminIds === []) {
$query->whereRaw('0 = 1');
return;
}
$ids = implode(',', $visibleAdminIds);
$query->whereRaw(
"(CAST(d.assistant_id AS UNSIGNED) IN ({$ids})"
. " OR EXISTS (SELECT 1 FROM {$appointmentTable} scope_apt"
. ' WHERE scope_apt.patient_id = d.id'
. " AND scope_apt.status IN ({$statusList})"
. " AND scope_apt.doctor_id IN ({$ids})))"
);
return;
}
// 一线角色始终只取“本人关系”,不受数据库中医生角色 ALL 配置影响。
$conditions = [];
if (in_array(self::ASSISTANT_ROLE_ID, $roleIds, true)) {
$conditions[] = 'CAST(d.assistant_id AS UNSIGNED) = ' . $adminId;
}
if (in_array(self::DOCTOR_ROLE_ID, $roleIds, true)) {
$conditions[] = "EXISTS (SELECT 1 FROM {$appointmentTable} scope_apt"
. ' WHERE scope_apt.patient_id = d.id'
. " AND scope_apt.status IN ({$statusList})"
. " AND scope_apt.doctor_id = {$adminId})";
}
// 未知/异常角色按本人医助或本人医生关系收窄,拒绝意外放大全库。
if ($conditions === []) {
$conditions[] = 'CAST(d.assistant_id AS UNSIGNED) = ' . $adminId;
$conditions[] = "EXISTS (SELECT 1 FROM {$appointmentTable} scope_apt"
. ' WHERE scope_apt.patient_id = d.id'
. " AND scope_apt.status IN ({$statusList})"
. " AND scope_apt.doctor_id = {$adminId})";
}
$query->whereRaw('(' . implode(' OR ', $conditions) . ')');
}
public static function canAccessDiagnosis(int $diagnosisId, int $adminId, array $adminInfo): bool
{
if ($diagnosisId <= 0 || $adminId <= 0) {
return false;
}
$diagnosisTable = (new Diagnosis())->getTable();
$query = Db::table($diagnosisTable)
->alias('d')
->where('d.id', $diagnosisId)
->whereNull('d.delete_time')
->where('d.status', 1);
self::applyScope($query, $adminId, $adminInfo);
return (int) $query->count() > 0;
}
/** @return array{mode:string,label:string} */
public static function scopeMeta(int $adminId, array $adminInfo): array
{
if ((int) ($adminInfo['root'] ?? 0) === 1) {
return ['mode' => 'all', 'label' => '全部数据'];
}
$roleIds = self::roleIds($adminId);
if (array_intersect($roleIds, self::TEAM_ROLE_IDS) !== []) {
$scope = DataScopeService::getEffectiveScope($adminInfo);
$labels = [
DataScopeService::SCOPE_ALL => '全部数据',
DataScopeService::SCOPE_DEPT_AND_CHILD => '本部门及下级',
DataScopeService::SCOPE_DEPT => '本部门',
DataScopeService::SCOPE_SELF => '仅本人',
];
return [
'mode' => $scope === DataScopeService::SCOPE_ALL ? 'all' : 'team',
'label' => $labels[$scope] ?? '仅本人',
];
}
$isDoctor = in_array(self::DOCTOR_ROLE_ID, $roleIds, true);
$isAssistant = in_array(self::ASSISTANT_ROLE_ID, $roleIds, true);
if ($isDoctor && $isAssistant) {
return ['mode' => 'self', 'label' => '本人归属及接诊'];
}
if ($isDoctor) {
return ['mode' => 'self', 'label' => '本人接诊'];
}
return ['mode' => 'self', 'label' => '本人归属'];
}
/** @return int[] */
private static function roleIds(int $adminId): array
{
return self::normalizeIds(AdminRole::where('admin_id', $adminId)->column('role_id'));
}
/** @param array<int|string, mixed> $ids @return int[] */
private static function normalizeIds(array $ids): array
{
return array_values(array_unique(array_filter(array_map('intval', $ids), static function (int $id): bool {
return $id > 0;
})));
}
}