Files
fdesk/app/common/logic/PermLogic.php
T

286 lines
10 KiB
PHP
Raw Normal View History

2025-07-11 18:01:23 +08:00
<?php
namespace app\common\logic;
use app\common\model\User;
use app\common\model\Resource;
2025-07-25 18:10:11 +08:00
use app\common\model\Systems;
2025-07-11 18:01:23 +08:00
class PermLogic
{
/**
2025-07-14 18:55:59 +08:00
* 获取用户所有资源(合并角色+直接分配),并加入公共菜单,排序按sort字段
*/
2025-07-25 18:10:11 +08:00
public function getUserResources(int $userId, string $systemCode)
2025-07-11 18:01:23 +08:00
{
2025-07-25 18:10:11 +08:00
$system = Systems::where('code', $systemCode)->first();
// 获取用户及其关联角色资源和直接分配的资源
2025-07-11 18:01:23 +08:00
$user = User::with(['roles.resources', 'resources'])->find($userId);
2025-07-11 18:01:23 +08:00
if (!$user) {
return collect();
}
$all = collect();
// 合并角色资源,排除不需要权限认证的资源
2025-07-11 18:01:23 +08:00
foreach ($user->roles as $role) {
$all = $all->merge(
2025-07-25 18:10:11 +08:00
$role->resources->filter(function ($resource) use($system) {
// var_dump($resource->toArray());
// 只保留需要权限认证的资源(或公共资源)
2025-07-25 18:10:11 +08:00
return !$resource->no_auth && $system->id == $resource->system_id;
})
);
2025-07-11 18:01:23 +08:00
}
// 合并用户直接分配的资源,排除不需要权限认证的资源
$all = $all->merge(
$user->resources->filter(function ($resource) {
// 只保留需要权限认证的资源(或公共资源)
return !$resource->no_auth;
})
);
// 加入公共菜单,公共菜单不管是否授权,所有人都能访问
2025-07-14 18:55:59 +08:00
$publicResources = Resource::where('no_auth', 1)
->orderBy('sort', 'asc') // 按 sort 字段升序排序
->get();
2025-07-14 19:01:42 +08:00
// 合并所有公共资源
$all = $all->merge($publicResources);
// 返回唯一的资源列表,并按 id 排序
2025-07-14 19:01:42 +08:00
// 使用 sortBy('sort') 来确保最终结果根据 'sort' 字段排序
return $all->unique('id')->values()->sortBy('sort');
2025-07-11 18:01:23 +08:00
}
/**
2025-07-22 15:29:54 +08:00
* 构建目录/菜单树
2025-07-22 10:21:41 +08:00
*
* @param \Illuminate\Support\Collection $resources 全部资源集合
* @param int $parentId 当前父级资源 ID
* @param string $parentPath 父级完整路径(用于递归)
2025-07-11 18:01:23 +08:00
* @return array
*/
2025-07-22 15:29:54 +08:00
public function buildTree_bak($resources, int $parentId = 0, string $parentPath = ''): array
2025-07-11 18:01:23 +08:00
{
$tree = [];
2025-07-22 10:21:41 +08:00
foreach ($resources as $node) {
2025-07-22 10:41:38 +08:00
// 只处理目录和菜单,不把 permission 当作菜单节点
if ($node->parent_id !== $parentId || $node->type === 'permission') {
2025-07-22 10:21:41 +08:00
continue;
2025-07-11 18:01:23 +08:00
}
2025-07-22 10:21:41 +08:00
// —— 拼接当前节点的完整路径 ——
$currentPath = rtrim($parentPath, '/');
2025-07-11 18:01:23 +08:00
if (!empty($node->url)) {
2025-07-22 10:21:41 +08:00
$urlSegment = ltrim($node->url, '/');
$currentPath = $currentPath === ''
? $urlSegment
: "{$currentPath}/{$urlSegment}";
2025-07-11 18:01:23 +08:00
}
2025-07-22 10:21:41 +08:00
// —— 递归构建子节点 ——
2025-07-22 10:41:38 +08:00
// 这里只会继续收目录和菜单,permission 永远不会进入此方法
$children = $this->buildTree($resources, $node->id, $currentPath);
2025-07-11 18:01:23 +08:00
2025-07-22 10:21:41 +08:00
// —— 本级权限列表 ——
2025-07-11 18:01:23 +08:00
$authList = $resources
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
->map(fn($r) => [
'id' => $r->id,
'title' => $r->name,
'auth_mark' => $r->code,
2025-07-22 10:21:41 +08:00
])
->values()
->all();
// —— 判断是否有子目录或子菜单 ——
2025-07-22 10:41:38 +08:00
$hasChildrenMenu = ! empty($children);
2025-07-22 10:21:41 +08:00
// —— 计算 component 字段 ——
if ($hasChildrenMenu) {
if ($node->type === 'menu' && !empty($node->url)) {
// menu 类型且自身有 url,用自身 url(加前导 slash)
$componentValue = '/' . ltrim($node->url, '/');
} else {
// 其它含子项的节点,固定 Layout 组件
$componentValue = '/index/index';
}
} else {
// 叶子节点:拼接路径,确保以 slash 开头
$componentValue = $currentPath !== ''
? '/' . ltrim($currentPath, '/')
: '';
}
2025-07-11 18:01:23 +08:00
$tree[] = [
'id' => $node->id,
'name' => $node->name,
'path' => $node->url,
'component' => $componentValue,
'meta' => [
'title' => $node->name,
'icon' => $node->icon,
'keepAlive' => true,
'authList' => $authList,
'openType' => $node->open_type,
2025-07-22 11:00:32 +08:00
'isHide' => $node->is_hide == 0 ? false : true,
'isHideTab' => $node->is_hide_tab == 0 ? false : true
2025-07-11 18:01:23 +08:00
],
2025-07-22 10:57:37 +08:00
'children' => $children
2025-07-11 18:01:23 +08:00
];
}
2025-07-22 10:21:41 +08:00
2025-07-11 18:01:23 +08:00
return $tree;
}
2025-07-22 15:29:54 +08:00
public function buildTree_bak2($resources, int $parentId = 0, string $parentPath = ''): array
2025-07-21 16:43:43 +08:00
{
$tree = [];
foreach ($resources as $node) {
if ($node->parent_id !== $parentId) {
continue;
}
// —— 拼接当前节点的完整路径 ——
$currentPath = $parentPath;
// 去掉末尾多余 slash
$currentPath = rtrim($currentPath, '/');
if (!empty($node->url)) {
// 如果当前节点有 url,则拼接
$urlSegment = ltrim($node->url, '/');
$currentPath = $currentPath === ''
? $urlSegment
: "{$currentPath}/{$urlSegment}";
}
// —— 递归构建子节点 ——
$children = [];
2025-07-22 15:29:54 +08:00
if ($node->type === 'directory') {
2025-07-21 16:43:43 +08:00
$children = $this->buildTree($resources, $node->id, $currentPath);
}
// —— 收集本级的 permission 权限列表 ——
$authList = $resources
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
->map(fn($r) => [
'id' => $r->id,
'title' => $r->name,
'auth_mark' => $r->code,
])
->values()
->all();
// —— 判断是否有子菜单/目录 ——
$hasChildrenMenu = $resources
->where('parent_id', $node->id)
->whereIn('type', ['directory', 'menu'])
->isNotEmpty();
// —— 计算 component 字段 ——
if ($hasChildrenMenu) {
// 只要有子项,就一律显示顶层 Layout 组件
$componentValue = '/index/index';
} else {
// 叶子节点:如果定义了 url,就使用拼接后的路径;否则用占位符(这里用空串,你可替换)
$componentValue = $currentPath !== '' ? $currentPath : '';
}
$tree[] = [
'id' => $node->id,
'name' => $node->name,
'path' => $node->url,
'component' => $componentValue,
'meta' => [
'title' => $node->name,
'icon' => $node->icon,
'keepAlive' => true,
'authList' => $authList,
'openType' => $node->open_type,
],
'children' => $children,
];
}
return $tree;
}
2025-07-22 15:29:54 +08:00
public function buildTree($resources, int $parentId = 0, string $parentPath = ''): array
{
$tree = [];
foreach ($resources as $node) {
if ($node->parent_id !== $parentId) continue;
// 拼接完整路径
$currentPath = $parentPath;
if ($currentPath && substr($currentPath, -1) === '/') {
$currentPath = rtrim($currentPath, '/');
}
if (!empty($node->url)) {
if (!$currentPath) {
$currentPath = $node->url;
} else {
$url = ltrim($node->url, '/');
$currentPath = $currentPath . '/' . $url;
}
}
// 子节点递归
$children = [];
if ($node->type === 'directory') {
$children = $this->buildTree($resources, $node->id, $currentPath);
}
2025-07-21 16:43:43 +08:00
2025-07-22 15:29:54 +08:00
// 权限
$authList = $resources
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
->map(fn($r) => [
'id' => $r->id,
'title' => $r->name,
'auth_mark' => $r->code,
])->values()->all();
// 判断是否有子级菜单(非权限)
$hasChildrenMenu = collect($resources)->where('parent_id', $node->id)
->whereIn('type', ['directory', 'menu'])->isNotEmpty();
$componentValue = $hasChildrenMenu ? '/index/index' : $currentPath;
$tree[] = [
'id' => $node->id,
'name' => $node->name,
'path' => $node->url,
'component' => $componentValue,
'meta' => [
'title' => $node->name,
'icon' => $node->icon,
'keepAlive' => true,
'authList' => $authList,
'openType' => $node->open_type,
'isHide' => $node->is_hide == 0 ? false : true,
'isHideTab' => $node->is_hide_tab == 0 ? false : true
2025-07-22 15:29:54 +08:00
],
'children' => $children,
];
}
return $tree;
}
2025-07-11 18:01:23 +08:00
/**
* 获取用户所有权限code
*/
2025-07-25 18:10:11 +08:00
public function getPermissionCodes(int $userId, string $systemCode): array
2025-07-11 18:01:23 +08:00
{
2025-07-25 18:10:11 +08:00
$resources = $this->getUserResources($userId, $systemCode);
2025-07-11 18:01:23 +08:00
return $resources
->filter(fn($res) => $res->type === 'permission')
->pluck('code')
->unique()
->values()
->all();
}
}