This commit is contained in:
gr
2026-11-11 14:22:02 +08:00
parent 245618dcdc
commit a62311a8da
64878 changed files with 3747172 additions and 66 deletions
@@ -15,6 +15,7 @@ use app\common\model\dict\DictData;
use app\common\lists\ListsExtendInterface;
use app\common\lists\ListsSearchInterface;
use app\common\lists\Traits\HasDataScopeFilter;
use app\common\service\DataScope\DataScopeService;
use think\facade\Db;
/**
@@ -36,6 +37,29 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
&& (int) ($this->params['patient_id'] ?? 0) > 0;
}
/**
* 一线角色只看本人:医生看挂自己号的预约,医助看自己归属患者的预约,两者兼有时取并集(OR)。
* 账号兼有主管/经理/组长等团队角色时 $selfRoles 为空,此处不收窄,交给 applyDataScopeForAppointment 按部门范围过滤。
*
* @param mixed $query
* @param int[] $selfRoles DataScopeService::selfOnlyRoleIds() 的结果
*/
private function applyFrontlineSelfScope($query, array $selfRoles): void
{
$isDoctor = in_array(1, $selfRoles, true);
$isAssistant = in_array(2, $selfRoles, true);
$adminId = (int) $this->adminId;
if ($isDoctor && $isAssistant) {
$query->where(function ($q) use ($adminId) {
$q->where('a.doctor_id', $adminId)->whereOr('u.assistant_id', $adminId);
});
} elseif ($isDoctor) {
$query->where('a.doctor_id', $adminId);
} elseif ($isAssistant) {
$query->where('u.assistant_id', $adminId);
}
}
/**
* 数据隔离:医生或医助(u.assistant_id = diag.assistant_id)命中可见集合;progress_board 场景放开(看板跨医生查看)
*/
@@ -189,9 +213,9 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
*/
public function lists(): array
{
// 获取当前管理员的角色ID
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
// 当前账号生效的“仅本人”一线角色(多角色取并集:兼有主管/经理等团队角色时为空,交给数据范围按部门过滤)
$selfRoles = DataScopeService::selfOnlyRoleIds($this->adminId, $this->adminInfo);
// 处理患者姓名搜索
if (!empty($this->params['patient_name'])) {
$this->searchWhere[] = ['u.patient_name', 'like', '%' . $this->params['patient_name'] . '%'];
@@ -272,15 +296,7 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
$progressBoard = (int) ($this->params['progress_board'] ?? 0) === 1;
$diagScopeRelax = $this->appointmentListsScopeRelaxedForDiagnosis();
if (!$progressBoard && !$diagScopeRelax) {
// 如果是医生角色(role_id=1),只显示挂自己号的预约
if (in_array(1, $roleIds)) {
$query->where('a.doctor_id', $this->adminId);
}
// 如果是医助角色(role_id=2),只显示自己添加的患者的预约
if (in_array(2, $roleIds)) {
$query->where('u.assistant_id', $this->adminId);
}
$this->applyFrontlineSelfScope($query, $selfRoles);
}
$this->applyDataScopeForAppointment($query, $progressBoard);
@@ -416,7 +432,7 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
*/
private function applyAppointmentCountFilters($query, bool $applyStatusFilter): void
{
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
$selfRoles = DataScopeService::selfOnlyRoleIds($this->adminId, $this->adminInfo);
if (!empty($this->params['patient_name'])) {
$query->where('u.patient_name', 'like', '%' . $this->params['patient_name'] . '%');
@@ -473,12 +489,7 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
$progressBoard = (int) ($this->params['progress_board'] ?? 0) === 1;
$diagScopeRelax = $this->appointmentListsScopeRelaxedForDiagnosis();
if (!$progressBoard && !$diagScopeRelax) {
if (in_array(1, $roleIds)) {
$query->where('a.doctor_id', $this->adminId);
}
if (in_array(2, $roleIds)) {
$query->where('u.assistant_id', $this->adminId);
}
$this->applyFrontlineSelfScope($query, $selfRoles);
}
$this->applyDataScopeForAppointment($query, $progressBoard);
@@ -15,6 +15,7 @@ use app\common\model\auth\AdminRole;
use app\common\model\doctor\Appointment;
use app\common\model\doctor\Roster;
use app\common\model\tcm\Prescription;
use app\common\service\DataScope\DataScopeService;
use app\common\service\doctor\RosterSegmentService;
use think\db\Query;
use think\facade\Db;
@@ -539,9 +540,9 @@ class MyPatientProgressLists extends BaseAdminDataLists implements ListsSearchIn
return false;
}
$roleIds = $this->currentRoleIds();
return in_array(2, $roleIds, true) && array_intersect($roleIds, [3, 7, 8]) === [];
// 纯医助按归属排班;兼有团队角色(多角色取并集)时不按本人归属
return in_array(2, $this->currentRoleIds(), true)
&& !DataScopeService::hasTeamRole($this->adminId, $this->adminInfo);
}
/** @return int[] */
@@ -557,7 +558,7 @@ class MyPatientProgressLists extends BaseAdminDataLists implements ListsSearchIn
}
$roleIds = $this->currentRoleIds();
$isTeamRole = array_intersect($roleIds, [3, 7, 8]) !== [];
$isTeamRole = DataScopeService::hasTeamRole($this->adminId, $this->adminInfo);
$isDoctor = in_array(1, $roleIds, true);
$isAssistant = in_array(2, $roleIds, true);
@@ -34,6 +34,7 @@ use app\common\model\dict\DictData;
use app\common\model\tcm\DiagnosisRevisitDue;
use app\common\lists\ListsSearchInterface;
use app\common\lists\Traits\HasDataScopeFilter;
use app\common\service\DataScope\DataScopeService;
use app\common\service\tcm\RevisitDueService;
use think\facade\Db;
@@ -71,8 +72,8 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface
*/
public function lists(): array
{
// 获取当前管理员的角色ID
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
// 当前账号生效的“仅本人”一线角色(兼有主管/经理等团队角色时为空,由数据范围按部门过滤)
$selfRoles = DataScopeService::selfOnlyRoleIds($this->adminId, $this->adminInfo);
// 待分配医助筛选:assistant_id 为空或 0(放在最前面判断,便于跳过医助角色的自我过滤)
$pendingAssign = isset($this->params['pending_assign']) && (string) $this->params['pending_assign'] === '1';
@@ -86,8 +87,8 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface
: $this->searchWhere;
$query = Diagnosis::where($baseWhere);
// 医助角色(role_id=2):仅在普通列表(非待分配、非待分配宽搜)下限制为本人诊单;待分配窄列表与宽搜均不设此限
if (in_array(2, $roleIds) && !$pendingAssign && !$pendingWideSearch) {
// 纯医助账号:仅在普通列表(非待分配、非待分配宽搜)下限制为本人诊单;待分配窄列表与宽搜均不设此限
if (in_array(2, $selfRoles, true) && !$pendingAssign && !$pendingWideSearch) {
$query->where('assistant_id', $this->adminId);
}
@@ -566,8 +567,7 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface
*/
public function count(): int
{
// 获取当前管理员的角色ID
$roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id');
$selfRoles = DataScopeService::selfOnlyRoleIds($this->adminId, $this->adminInfo);
$pendingAssign = isset($this->params['pending_assign']) && (string) $this->params['pending_assign'] === '1';
@@ -579,7 +579,7 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface
: $this->searchWhere;
$query = Diagnosis::where($baseWhere);
if (in_array(2, $roleIds) && !$pendingAssign && !$pendingWideSearch) {
if (in_array(2, $selfRoles, true) && !$pendingAssign && !$pendingWideSearch) {
$query->where('assistant_id', $this->adminId);
}
@@ -14,6 +14,7 @@ use app\common\lists\ListsExcelInterface;
use app\common\lists\ListsExtendInterface;
use app\common\lists\ListsSearchInterface;
use app\common\lists\Traits\HasDataScopeFilter;
use app\common\service\DataScope\DataScopeService;
use app\common\model\Order;
use app\common\model\auth\Admin;
use app\common\model\auth\AdminDept;
@@ -550,9 +551,10 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
} elseif (PrescriptionOrderLogic::canViewOrderListStatsAllScope($this->adminInfo)) {
$this->applyDataScopeForPrescriptionOrder($query);
} else {
// 纯医助只看本人创建的订单;兼有主管等团队角色时(多角色取并集)走下方按数据范围的可见规则
$assistantRid = (int) Config::get('project.prescription_order_stats_assistant_role_id', 2);
$myRoles = array_map('intval', $this->adminInfo['role_id'] ?? []);
if ($assistantRid > 0 && in_array($assistantRid, $myRoles, true)) {
$selfRoles = DataScopeService::selfOnlyRoleIds($this->adminId, $this->adminInfo);
if ($assistantRid > 0 && in_array($assistantRid, $selfRoles, true)) {
$this->applyCreatorOnlyFilter($query);
$this->applyDataScopeForPrescriptionOrder($query);
} else {
@@ -1279,7 +1281,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$scope = 'all';
} else {
$ar = (int) Config::get('project.prescription_order_stats_assistant_role_id', 2);
if ($ar > 0 && in_array($ar, array_map('intval', $this->adminInfo['role_id'] ?? []), true)) {
if ($ar > 0 && in_array($ar, DataScopeService::selfOnlyRoleIds($this->adminId, $this->adminInfo), true)) {
$scope = 'assistant';
} elseif (PrescriptionOrderLogic::canViewOrdersForOwnPrescription($this->adminInfo)) {
$scope = 'own_rx';
@@ -932,9 +932,10 @@ class AppointmentLogic extends BaseLogic
$docId = (int) $appointment->doctor_id;
$asstId = $diag ? (int) $diag->assistant_id : 0;
$isRoot = !empty($adminInfo['root']) && (int) $adminInfo['root'] === 1;
// 仅纯一线角色(医生/医助)按本人关系收窄;兼有团队角色时为空,交给数据范围
$roleIds = $isRoot
? []
: array_map('intval', AdminRole::where('admin_id', $adminId)->column('role_id'));
: DataScopeService::selfOnlyRoleIds($adminId, $adminInfo);
$visibleIds = null;
if (!$isRoot && DataScopeService::isEnabled()) {
$visibleIds = DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
@@ -951,7 +952,7 @@ class AppointmentLogic extends BaseLogic
}
/**
* @param array<int, int> $roleIds
* @param array<int, int> $roleIds 生效的“仅本人”一线角色(DataScopeService::selfOnlyRoleIds)
* @param array<int, int>|null $visibleIds null 表示未启用数据范围或全量可见
*/
private static function appointmentRowManageableForScope(
@@ -965,11 +966,15 @@ class AppointmentLogic extends BaseLogic
if ($isRoot) {
return true;
}
if (in_array(1, $roleIds, true) && $doctorId !== $adminId) {
return false;
}
if (in_array(2, $roleIds, true) && $assistantId !== $adminId) {
return false;
// 医生看本人接诊、医助看本人归属,两者兼有取并集;任一关系命中即可
$isDoctor = in_array(1, $roleIds, true);
$isAssistant = in_array(2, $roleIds, true);
if ($isDoctor || $isAssistant) {
$ownsRow = ($isDoctor && $doctorId === $adminId)
|| ($isAssistant && $assistantId === $adminId);
if (!$ownsRow) {
return false;
}
}
if ($visibleIds === []) {
return false;
@@ -16,12 +16,12 @@ use think\facade\Db;
*
* 角色语义:医生只看本人接诊患者,医助只看本人归属患者;经理、
* 诊室组长和管理员按系统 DataScope 查看团队患者;root 查看全部。
* 多角色取并集:兼有团队角色(DataScopeService::hasTeamRole)时按团队范围,不再收窄到本人。
*/
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];
/**
@@ -44,7 +44,7 @@ class MyPatientLogic
$statusList = implode(',', self::EFFECTIVE_APPOINTMENT_STATUSES);
// 管理角色按系统的数据范围查看“范围内医助归属或医生接诊”的患者。
if (array_intersect($roleIds, self::TEAM_ROLE_IDS) !== []) {
if (DataScopeService::hasTeamRole($adminId, $adminInfo)) {
$visibleAdminIds = DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
if ($visibleAdminIds === null) {
return;
@@ -116,7 +116,7 @@ class MyPatientLogic
}
$roleIds = self::roleIds($adminId);
if (array_intersect($roleIds, self::TEAM_ROLE_IDS) !== []) {
if (DataScopeService::hasTeamRole($adminId, $adminInfo)) {
$scope = DataScopeService::getEffectiveScope($adminInfo);
$labels = [
DataScopeService::SCOPE_ALL => '全部数据',
@@ -71,8 +71,10 @@ class PerformanceDashboardScope
if (self::roleNamesMatch($roleNames, ['诊室组长', '组长'])) {
return self::KIND_GROUP_LEADER;
}
// 医助角色固定仅本人,不因部门负责人或 data_scope 放大到小组。
if (self::roleNamesMatch($roleNames, ['医助'])) {
// 纯医助账号固定仅本人,不因部门负责人或 data_scope 放大到小组;
// 多角色取并集:兼有主管等团队角色(data_scope 为部门范围)时按下方数据范围分类。
if (self::roleNamesMatch($roleNames, ['医助'])
&& !DataScopeService::hasTeamRole((int) ($adminInfo['admin_id'] ?? 0), $adminInfo)) {
return self::KIND_ASSISTANT;
}
@@ -1534,11 +1534,9 @@ class DiagnosisLogic extends BaseLogic
}
$diagnosisQuery = Diagnosis::where('id', $diagnosisId)
->where('patient_id', $patientId);
$roleIds = array_map(
'intval',
AdminRole::where('admin_id', $adminId)->column('role_id')
);
if (in_array(2, $roleIds, true)) {
// 纯医助只看本人归属诊单;兼有主管/经理等团队角色时交给下方数据范围按部门过滤
$selfRoles = DataScopeService::selfOnlyRoleIds($adminId, $adminInfo);
if (in_array(2, $selfRoles, true)) {
$diagnosisQuery->where('assistant_id', $adminId);
}
if (DataScopeService::isEnabled()) {
@@ -4359,8 +4357,9 @@ class DiagnosisLogic extends BaseLogic
}
$query = Diagnosis::where('id', $diagnosisId)->whereNull('delete_time');
$roleIds = array_map('intval', AdminRole::where('admin_id', $adminId)->column('role_id'));
if (in_array(2, $roleIds, true)) {
// 纯医助只看本人归属诊单;兼有团队角色时交给下方数据范围按部门过滤
$selfRoles = DataScopeService::selfOnlyRoleIds($adminId, $adminInfo);
if (in_array(2, $selfRoles, true)) {
$query->where('assistant_id', $adminId);
}
@@ -487,8 +487,13 @@ class PrescriptionOrderLogic
return false;
}
$assistantRid = (int) Config::get('project.prescription_order_stats_assistant_role_id', 2);
if ($assistantRid <= 0) {
return false;
}
// 多角色取并集:兼有主管等团队角色时不按“统计医助”收口
$selfRoles = DataScopeService::selfOnlyRoleIds((int) ($adminInfo['admin_id'] ?? 0), $adminInfo);
return $assistantRid > 0 && self::roleIntersect($adminInfo, [$assistantRid]);
return in_array($assistantRid, $selfRoles, true);
}
/**