whereRaw('0 = 1'); return; } if ((int) ($adminInfo['root'] ?? 0) === 1) { return; } $roleIds = $currentRoleIds === null ? self::roleIds($adminId) : self::normalizeIds($currentRoleIds); // 团队判断和具体数据范围必须使用同一组角色,不能混入登录缓存中的旧授权。 $adminInfo['role_id'] = $roleIds; $appointmentTable = (new Appointment())->getTable(); $statusList = implode(',', self::EFFECTIVE_APPOINTMENT_STATUSES); // 新授权入口已显式要求当前读时,预约子查询也必须使用当前读。 // 仅外层 FOR UPDATE 不会把 EXISTS 内部从 MySQL RR 旧快照切换出来。 $appointmentLock = $currentRoleIds !== null && $query->getConfig('type') === 'mysql' ? ' FOR UPDATE' : ''; // 管理角色按系统的数据范围查看“范围内医助归属或医生接诊”的患者。 if (DataScopeService::hasTeamRole($adminId, $adminInfo, $currentRoleIds === null ? null : $roleIds)) { $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}){$appointmentLock}))" ); 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}{$appointmentLock})"; } // 未知/异常角色按本人医助或本人医生关系收窄,拒绝意外放大全库。 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}{$appointmentLock})"; } $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); $adminInfo['role_id'] = $roleIds; if (DataScopeService::hasTeamRole($adminId, $adminInfo)) { $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 $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; }))); } }