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
@@ -35,6 +35,12 @@ class DataScopeService
/** @var string[] 明确允许在多角色组合中放开全部数据的内置角色名。 */
private const ALL_SCOPE_ROLE_NAMES = ['管理员', '系统管理员'];
/** @var int[] 默认一线角色:医生(1)、医助(2),业务上自带“只看本人”的收窄。 */
private const DEFAULT_FRONTLINE_ROLE_IDS = [1, 2];
/** @var int[] 默认团队/管理角色(经理、组长、管理员等):按数据范围查看团队数据。 */
private const DEFAULT_TEAM_ROLE_IDS = [3, 7, 8];
/**
* 计算当前 admin 的有效数据范围。
*/
@@ -263,4 +269,93 @@ class DataScopeService
self::SCOPE_SELF => '仅本人',
][$scope] ?? '全部';
}
/**
* 当前 admin 持有的全部角色 id:优先取登录令牌缓存中的 role_id,缺失时查 admin_role。
*
* @return int[]
*/
public static function roleIdsOf(int $adminId, array $adminInfo = []): array
{
$roleIds = self::normalizeRoleIds($adminInfo['role_id'] ?? null);
if ($roleIds === [] && $adminId > 0) {
$roleIds = self::normalizeRoleIds(AdminRole::where('admin_id', $adminId)->column('role_id'));
}
return array_values(array_unique($roleIds));
}
/**
* 一线角色 id(默认医生 1、医助 2),可由 project.data_scope.frontline_roles 覆盖。
*
* @return int[]
*/
public static function frontlineRoleIds(): array
{
$ids = Config::get('project.data_scope.frontline_roles', self::DEFAULT_FRONTLINE_ROLE_IDS);
return self::normalizeRoleIds(\is_array($ids) && $ids !== [] ? $ids : self::DEFAULT_FRONTLINE_ROLE_IDS);
}
/**
* 是否持有团队/管理角色。
*
* 多角色按并集取最宽:只要有一个角色能看团队数据,就不再因为同时挂了医生/医助而收窄到本人。
* 判定口径:root;角色在 project.data_scope.team_roles 或 exempt_roles 中;
* 角色 data_scope 为「本部门及下级」/「仅本部门」;或 data_scope=1 且为内置管理员角色名。
* 新建角色默认 data_scope=1(全部)且不参与放大,主管类角色须把数据范围设为 2/3 才会被识别为团队角色。
*/
public static function hasTeamRole(int $adminId, array $adminInfo = []): bool
{
if ((int) ($adminInfo['root'] ?? 0) === 1) {
return true;
}
$roleIds = self::roleIdsOf($adminId, $adminInfo);
if ($roleIds === []) {
return false;
}
$configured = self::normalizeRoleIds(array_merge(
(array) (Config::get('project.data_scope.team_roles', self::DEFAULT_TEAM_ROLE_IDS) ?: []),
(array) (Config::get('project.data_scope.exempt_roles', []) ?: [])
));
if (array_intersect($roleIds, $configured) !== []) {
return true;
}
$roleRows = SystemRole::whereIn('id', $roleIds)
->whereNull('delete_time')
->field('id,name,data_scope')
->select()
->toArray();
foreach ($roleRows as $row) {
$scope = (int) ($row['data_scope'] ?? 0);
if ($scope === self::SCOPE_DEPT_AND_CHILD || $scope === self::SCOPE_DEPT) {
return true;
}
if ($scope === self::SCOPE_ALL
&& in_array(trim((string) ($row['name'] ?? '')), self::ALL_SCOPE_ROLE_NAMES, true)) {
return true;
}
}
return false;
}
/**
* 当前 admin 生效的“仅本人”一线角色(医生/医助)子集。
*
* root 或持有团队角色时返回 [](范围交给 DataScope 按部门决定);否则返回其持有的一线角色。
* 业务代码用 in_array(1|2, 本方法结果) 代替直接 in_array(1|2, 全部角色),多角色即取最宽范围。
*
* @return int[]
*/
public static function selfOnlyRoleIds(int $adminId, array $adminInfo = []): array
{
if (self::hasTeamRole($adminId, $adminInfo)) {
return [];
}
return array_values(array_intersect(self::roleIdsOf($adminId, $adminInfo), self::frontlineRoleIds()));
}
}