study-api-v2/app/Services/System/SystemMenuService.php

343 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services\System;
use App\Models\System\SystemMenu;
use App\Services\BaseService;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* 系统菜单服务类
*/
class SystemMenuService extends BaseService
{
protected string $modelClass = SystemMenu::class;
/**
* 获取系统菜单列表
*/
public function getList(array $params): LengthAwarePaginator
{
$query = SystemMenu::query();
// 搜索条件
if (!empty($params['keyword'])) {
$query->where(function ($q) use ($params) {
$q->where('name', 'like', '%' . $params['keyword'] . '%')
->orWhere('path', 'like', '%' . $params['keyword'] . '%')
->orWhere('component', 'like', '%' . $params['keyword'] . '%');
});
}
// 状态筛选
if (isset($params['status'])) {
$query->where('status', $params['status']);
}
// 菜单类型筛选
if (isset($params['type'])) {
$query->where('type', $params['type']);
}
// 父级菜单筛选
if (isset($params['parent_id'])) {
$query->where('parent_id', $params['parent_id']);
}
// 显示状态筛选
if (isset($params['visible'])) {
$query->where('visible', $params['visible']);
}
// 排序
$query->orderBy('sort', 'asc')
->orderBy('id', 'desc');
return $query->paginate($params['page_size'] ?? 15);
}
/**
* 获取简单列表(用于下拉选择等)
*/
public function getSimpleList(): array
{
return SystemMenu::select('id', 'name', 'parent_id')
->where('status', 1)
->orderBy('sort', 'asc')
->get()
->toArray();
}
/**
* 获取树形菜单结构
*/
public function getMenuTree(): array
{
$menus = SystemMenu::where('status', 0)
->orderBy('sort', 'asc')
->get()
->toArray();
return $this->buildTree($menus);
}
/**
* 根据用户权限获取菜单树
*
* @param \App\Models\User $user 用户对象
* @param bool $convertToCamelCase 是否转换为驼峰命名默认true
* @return array
*/
public function getMenuTreeByPermission(\App\Models\User $user, bool $convertToCamelCase = true, $isTree = true): array
{
// 获取用户角色
$userRoles = $user->roles()->where('status', 0)->get();
$roleCodes = $userRoles->pluck('code')->toArray();
// 判断是否为超级管理员username为admin或角色编码包含admin相关
$isSuperAdmin = $user->username === 'admin' ||
in_array('admin', $roleCodes) ||
in_array('super_admin', $roleCodes);
// 获取菜单权限
if ($isSuperAdmin) {
// 超级管理员获取所有菜单
$menus = SystemMenu::where('status', 0)
->where('visible', 1)
->whereIn('type', [1, 2])
->orderBy('sort', 'asc')
->orderBy('id', 'asc')
->get();
} else {
// 普通用户根据角色权限获取菜单
$roleIds = $userRoles->pluck('id')->toArray();
if (empty($roleIds)) {
$menus = collect([]);
} else {
$menuIds = \App\Models\System\SystemRoleMenu::whereIn('role_id', $roleIds)
->pluck('menu_id')
->unique()
->toArray();
$menus = SystemMenu::whereIn('id', $menuIds)
->where('status', 0)
->where('visible', 1)
->whereIn('type', [1, 2])
->orderBy('sort', 'asc')
->orderBy('id', 'asc')
->get();
}
}
if($isTree){
// 构建菜单树形结构
return $this->buildPermissionMenuTree($menus->toArray(), 0, $convertToCamelCase);
}else{
$menuItem = [];
foreach($menus as $menu){
if ($convertToCamelCase) {
$menuItem[] = [
'id' => $menu['id'],
'parentId' => $menu['parent_id'],
'name' => $menu['name'],
'component' => $menu['component'],
'componentName' => $menu['component_name'],
'icon' => $menu['icon'],
'keepAlive' => $menu['keep_alive'],
'visible' => $menu['visible'],
'alwaysShow' => $menu['always_show'],
'path' => $menu['path'],
];
} else {
// 使用表字段命名
$menuItem[] = [
'id' => $menu['id'],
'parent_id' => $menu['parent_id'],
'name' => $menu['name'],
'component' => $menu['component'],
'component_name' => $menu['component_name'],
'icon' => $menu['icon'],
'keep_alive' => $menu['keep_alive'],
'visible' => $menu['visible'],
'always_show' => $menu['always_show'],
'path' => $menu['path'],
];
}
}
return $menuItem;
}
}
/**
* 构建权限菜单树形结构
*
* @param array $menus 菜单数组
* @param int $parentId 父级菜单ID
* @param bool $convertToCamelCase 是否转换为驼峰命名
* @return array
*/
private function buildPermissionMenuTree(array $menus, int $parentId = 0, bool $convertToCamelCase = true): array
{
$tree = [];
foreach ($menus as $menu) {
if ($menu['parent_id'] == $parentId) {
// 根据参数决定字段命名格式
if ($convertToCamelCase) {
$menuItem = [
'id' => $menu['id'],
'parentId' => $menu['parent_id'],
'name' => $menu['name'],
'component' => $menu['component'],
'componentName' => $menu['component_name'],
'icon' => $menu['icon'],
'keepAlive' => $menu['keep_alive'],
'visible' => $menu['visible'],
'alwaysShow' => $menu['always_show'],
'path' => $menu['path'],
];
} else {
// 使用表字段命名
$menuItem = [
'id' => $menu['id'],
'parent_id' => $menu['parent_id'],
'name' => $menu['name'],
'component' => $menu['component'],
'component_name' => $menu['component_name'],
'icon' => $menu['icon'],
'keep_alive' => $menu['keep_alive'],
'visible' => $menu['visible'],
'always_show' => $menu['always_show'],
'path' => $menu['path'],
];
}
// 递归获取子菜单
$children = $this->buildPermissionMenuTree($menus, $menu['id'], $convertToCamelCase);
$menuItem['children'] = $children;
$tree[] = $menuItem;
}
}
return $tree;
}
/**
* 检查用户是否为超级管理员
*
* @param \App\Models\User $user
* @return bool
*/
public function isSuperAdmin(\App\Models\User $user): bool
{
if ($user->username === 'admin') {
return true;
}
$roleCodes = $user->roles()->where('status', 0)->pluck('code')->toArray();
return in_array('admin', $roleCodes) || in_array('superadmin', $roleCodes);
}
/**
* 获取用户有权限的菜单ID列表
*
* @param \App\Models\User $user
* @return array
*/
public function getUserMenuIds(\App\Models\User $user): array
{
if ($this->isSuperAdmin($user)) {
// 超级管理员返回所有菜单ID
return SystemMenu::where('status', 0)
->where('visible', 1)
->whereIn('type', [1, 2])
->pluck('id')
->toArray();
}
// 普通用户根据角色权限获取菜单ID
$roleIds = $user->roles()->where('status', 0)->pluck('id')->toArray();
if (empty($roleIds)) {
return [];
}
return \App\Models\System\SystemRoleMenu::whereIn('role_id', $roleIds)
->pluck('menu_id')
->unique()
->toArray();
}
/**
* 获取父级菜单列表
*/
public function getParentMenus(): array
{
return SystemMenu::where('type', '!=', 3) // 排除按钮类型
->where('status', 0)
->select('id', 'name', 'parent_id')
->orderBy('sort', 'asc')
->get()
->toArray();
}
/**
* 构建树形结构
*/
private function buildTree(array $menus, int $parentId = 0): array
{
$tree = [];
foreach ($menus as $menu) {
if ($menu['parent_id'] == $parentId) {
$children = $this->buildTree($menus, $menu['id']);
if (!empty($children)) {
$menu['children'] = $children;
}
$tree[] = $menu;
}
}
return $tree;
}
/**
* 创建前的数据处理
*/
protected function beforeCreate(array &$data): void
{
// 如果没有设置排序,则设置为最大值+1
if (!isset($data['sort'])) {
$maxSort = SystemMenu::max('sort') ?? 0;
$data['sort'] = $maxSort + 1;
}
// 如果没有设置状态,默认为启用
if (!isset($data['status'])) {
$data['status'] = 1;
}
// 如果没有设置显示状态,默认为显示
if (!isset($data['visible'])) {
$data['visible'] = 0;
}
// 如果没有设置父级ID默认为0
if (!isset($data['parent_id'])) {
$data['parent_id'] = 0;
}
}
/**
* 更新前的数据处理
*/
protected function beforeUpdate(array &$data, $model): void
{
// 不能将自己设置为自己的父级
if (isset($data['parent_id']) && $data['parent_id'] == $model->id) {
throw new \App\Exceptions\BusinessException(
\App\Helpers\ResponseEnum::CLIENT_PARAMETER_ERROR,
'不能将自己设置为父级菜单'
);
}
}
}