This commit is contained in:
Your Name
2026-04-27 15:30:28 +08:00
parent 23bd86e056
commit fe14f67965
21 changed files with 2335 additions and 449 deletions
@@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
namespace app\common\service\DataScope;
use app\adminapi\logic\dept\DeptLogic;
use app\common\model\auth\AdminDept;
use app\common\model\auth\AdminRole;
use app\common\model\auth\SystemRole;
use think\facade\Config;
/**
* 数据范围(数据隔离)工具服务。
*
* 设计约定:
* - ALL (1) = 全部数据,不附加过滤
* - DEPT_AND_CHILD (2) = 本部门及所有子部门(取 admin 全部部门的并集)
* - DEPT (3) = 仅本部门(取 admin 全部部门的并集,不含子孙)
* - SELF (4) = 仅本人
*
* 多角色时取「范围最大」= data_scope 最小值。
* root 管理员固定为 ALL。未挂任何部门时,范围退化为 SELF(可由 config 关闭)。
*
* 关键返回:`getVisibleAdminIds` 返回 int[](可见 admin_id 集合)或 nullALL = 不过滤)。
*/
class DataScopeService
{
public const SCOPE_ALL = 1;
public const SCOPE_DEPT_AND_CHILD = 2;
public const SCOPE_DEPT = 3;
public const SCOPE_SELF = 4;
/**
* 计算当前 admin 的有效数据范围。
*/
public static function getEffectiveScope(array $adminInfo): int
{
if (!self::isEnabled()) {
return self::SCOPE_ALL;
}
if ((int) ($adminInfo['root'] ?? 0) === 1) {
return self::SCOPE_ALL;
}
$roleIds = array_values(array_filter(array_map(
'intval',
is_array($adminInfo['role_id'] ?? null) ? $adminInfo['role_id'] : []
)));
$exempt = array_map('intval', Config::get('project.data_scope.exempt_roles', []) ?: []);
if ($roleIds !== [] && array_intersect($roleIds, $exempt) !== []) {
return self::SCOPE_ALL;
}
if ($roleIds === []) {
return self::SCOPE_SELF;
}
$scopes = SystemRole::whereIn('id', $roleIds)
->whereNull('delete_time')
->column('data_scope');
$scopes = array_values(array_filter(array_map('intval', $scopes), static function (int $v): bool {
return $v >= self::SCOPE_ALL && $v <= self::SCOPE_SELF;
}));
if ($scopes === []) {
return self::SCOPE_ALL;
}
return (int) min($scopes);
}
/**
* 可见 admin id 集合;null = 不过滤(ALL
*
* @return array<int>|null
*/
public static function getVisibleAdminIds(int $adminId, array $adminInfo): ?array
{
$scope = self::getEffectiveScope($adminInfo);
if ($scope === self::SCOPE_ALL) {
return null;
}
if ($scope === self::SCOPE_SELF) {
return $adminId > 0 ? [$adminId] : [];
}
$myDeptIds = AdminDept::where('admin_id', $adminId)->column('dept_id');
$myDeptIds = array_values(array_filter(array_map('intval', $myDeptIds), static function (int $v): bool {
return $v > 0;
}));
if ($myDeptIds === []) {
$fallback = (bool) Config::get('project.data_scope.no_dept_fallback_self', true);
return $fallback ? [$adminId] : [];
}
$targetDeptIds = [];
if ($scope === self::SCOPE_DEPT) {
$targetDeptIds = $myDeptIds;
} else {
foreach ($myDeptIds as $did) {
foreach (DeptLogic::getSelfAndDescendantIds($did) as $id) {
$id = (int) $id;
if ($id > 0) {
$targetDeptIds[$id] = true;
}
}
}
$targetDeptIds = array_keys($targetDeptIds);
}
if ($targetDeptIds === []) {
return $adminId > 0 ? [$adminId] : [];
}
$ids = AdminDept::whereIn('dept_id', $targetDeptIds)->column('admin_id');
$ids = array_values(array_unique(array_filter(array_map('intval', $ids), static function (int $v): bool {
return $v > 0;
})));
if ($adminId > 0 && !in_array($adminId, $ids, true)) {
$ids[] = $adminId;
}
return $ids;
}
public static function isEnabled(): bool
{
return (bool) Config::get('project.data_scope.enabled', true);
}
public static function isAll(array $adminInfo): bool
{
return self::getEffectiveScope($adminInfo) === self::SCOPE_ALL;
}
/**
* 文字描述(日志 / 接口返回可选使用)
*/
public static function scopeLabel(int $scope): string
{
return [
self::SCOPE_ALL => '全部',
self::SCOPE_DEPT_AND_CHILD => '本部门及下级',
self::SCOPE_DEPT => '仅本部门',
self::SCOPE_SELF => '仅本人',
][$scope] ?? '全部';
}
}