From c86c6c1bafbb14678f70bbbacd3bfb4e13339fad Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Mon, 28 Oct 2024 11:55:57 +0800 Subject: [PATCH] feat : menu list --- app/Cache/Redis/Admin/MenuCache.php | 30 +++- app/Controller/Admin/AuthController.php | 62 +++++++- app/Model/AdminMenu.php | 28 +++- app/Request/Admin/AuthRequest.php | 19 ++- app/Service/Admin/User/RoleMenuService.php | 173 ++++++++++++++++++++- sync/http/admin/auth.http | 26 ++++ 6 files changed, 322 insertions(+), 16 deletions(-) diff --git a/app/Cache/Redis/Admin/MenuCache.php b/app/Cache/Redis/Admin/MenuCache.php index 69e5652..3704e82 100644 --- a/app/Cache/Redis/Admin/MenuCache.php +++ b/app/Cache/Redis/Admin/MenuCache.php @@ -24,6 +24,17 @@ class MenuCache #[Inject] protected AdminMenu $adminMenuModel; + /** + * 菜单 + * @var string + */ + protected string $menuKey; + + public function __construct() + { + $this->menuKey = AdminRedisKey::adminMenuList(); + } + /** * @return array * @throws ContainerExceptionInterface @@ -32,21 +43,30 @@ class MenuCache */ public function getMenu(): array { - $key = AdminRedisKey::adminMenuList(); - - if ($this->redis->exists($key,'system')) { - return json_decode($this->redis->get($key,'system'),true); + if ($this->redis->exists($this->menuKey,'system')) { + return json_decode($this->redis->get($this->menuKey,'system'),true); } $allMenuList = $this->adminMenuModel->getAllMenu(); $data = $this->getDbMenu($allMenuList); - $this->redis->set($key,json_encode($data)); + $this->redis->set($this->menuKey,json_encode($data)); return $data; } + /** + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws RedisException + */ + public function delMenu(): void + { + $this->redis->delete($this->menuKey); + } + /** * 递归生成合适的数据 * @param array $allMenuList diff --git a/app/Controller/Admin/AuthController.php b/app/Controller/Admin/AuthController.php index ec0d4a8..895823f 100644 --- a/app/Controller/Admin/AuthController.php +++ b/app/Controller/Admin/AuthController.php @@ -13,6 +13,8 @@ use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\Middlewares; use Hyperf\HttpServer\Annotation\RequestMapping; use Hyperf\Validation\Annotation\Scene; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; #[Controller(prefix: "admin/auth")] #[Middlewares([ @@ -20,27 +22,66 @@ use Hyperf\Validation\Annotation\Scene; ])] class AuthController extends AbstractController { - public function menu_add(AuthRequest $request) + /** + * 添加菜单 + * @param AuthRequest $request + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + #[RequestMapping(path: "menu_add", methods: "POST")] + #[Scene(scene: "menu_add")] + public function menuAdd(AuthRequest $request) { return (new RoleMenuService)->add(); } - public function menu_edit() + /** + * 修改菜单 + * @param AuthRequest $request + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + #[RequestMapping(path: "menu_edit", methods: "POST")] + #[Scene(scene: "menu_edit")] + public function menuEdit(AuthRequest $request) { return (new RoleMenuService)->edit(); } - public function menu_del() + /** + * @param AuthRequest $request + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws \RedisException + */ + #[RequestMapping(path: "menu_del", methods: "GET")] + #[Scene(scene: "menu_del")] + public function menuDel(AuthRequest $request) { return (new RoleMenuService)->del(); } + /** + * 菜单列表 + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws \RedisException + */ #[RequestMapping(path: "menu_list", methods: "GET")] - public function menu_list() + public function menuList() { return (new RoleMenuService)->handle(); } + /** + * 菜单详情 + * @param AuthRequest $request + * @return array + */ #[RequestMapping(path: "menu", methods: "GET")] #[Scene(scene: "menu_info")] public function menu(AuthRequest $request) @@ -48,6 +89,19 @@ class AuthController extends AbstractController return (new RoleMenuService)->details(); } + /** + * 构建菜单缓存 + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws \RedisException + */ + #[RequestMapping(path: "menu_build_cache", methods: "GET")] + public function buildMenuCache() + { + return (new RoleMenuService)->buildCache(); + } + public function role_add(AuthRequest $request) { return (new RoleService)->add(); diff --git a/app/Model/AdminMenu.php b/app/Model/AdminMenu.php index 6c9229c..13ee0c2 100644 --- a/app/Model/AdminMenu.php +++ b/app/Model/AdminMenu.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace App\Model; use App\Constants\Admin\AuthCode; +use Hyperf\Database\Model\Builder; use Hyperf\DbConnection\Model\Model; +use Hyperf\Tappable\HigherOrderTapProxy; /** * @property int $id @@ -49,6 +51,30 @@ class AdminMenu extends Model */ public function getAllMenu(): array { - return $this->where('status', AuthCode::MENU_STATUS_ENABLE)->orderBy('sort', 'desc')->get()->toArray(); + return $this + ->where('status', AuthCode::MENU_STATUS_ENABLE) + ->orderBy('sort', 'desc') + ->get() + ->toArray(); + } + + /** + * @param int $url + * @return Builder|\Hyperf\Database\Model\Model|null + */ + public function getMenuByUrl(int $url): \Hyperf\Database\Model\Model|Builder|null + { + return $this + ->where('url', $url) + ->first(); + } + + /** + * @param int $id + * @return HigherOrderTapProxy|mixed|null + */ + public function getChildMenuType(int $id) + { + return $this->where('parent_id', $id)->value('type'); } } diff --git a/app/Request/Admin/AuthRequest.php b/app/Request/Admin/AuthRequest.php index f638cd7..25e5b87 100644 --- a/app/Request/Admin/AuthRequest.php +++ b/app/Request/Admin/AuthRequest.php @@ -24,6 +24,12 @@ class AuthRequest extends FormRequest return [ 'role_id' => 'required|integer', 'menu_id' => 'required|integer', + 'menu_name' => 'required|string', + 'menu_url' =>'required|string', + 'menu_status' => 'required|string', + 'menu_parent_id' => 'integer|exists:admin_menu,id', + 'page' =>'required|integer', + 'limit' => 'required|integer', ]; } @@ -32,11 +38,20 @@ class AuthRequest extends FormRequest return [ 'role_id.required' => 'id必填', 'menu_id.required' => 'id必填', + 'menu_name.required' => '名称必填', + 'menu_url.required' => 'url必填', + 'menu_status.required' => '状态必填', + 'menu_parent_id.exists' => 'parent_id不存在', + 'page.required' => 'page必填', + 'limit.required' => 'limit必填' ]; } protected array $scenes = [ - 'role_info' => 'role_id', - 'menu_info' => 'menu_id', + 'role_info' => ['role_id'], + 'menu_info' => ['menu_id'], + 'menu_add' => ['menu_name','menu_url','menu_status','parent_id'], + 'menu_edit' => ['menu_id','menu_name','menu_url','menu_status','parent_id'], + 'menu_del' => ['menu_id'] ]; } diff --git a/app/Service/Admin/User/RoleMenuService.php b/app/Service/Admin/User/RoleMenuService.php index 0b1bb00..27c7a56 100644 --- a/app/Service/Admin/User/RoleMenuService.php +++ b/app/Service/Admin/User/RoleMenuService.php @@ -15,6 +15,8 @@ use App\Constants\Admin\AuthCode; use App\Exception\AdminException; use App\Model\AdminMenu; use App\Service\Admin\BaseService; +use Exception; +use Hyperf\DbConnection\Db; use Hyperf\Di\Annotation\Inject; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -49,18 +51,154 @@ class RoleMenuService extends BaseService return $this->return->success('success', ['list' => $data]); } - public function add() + /** + * 添加逻辑 + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function add(): array { + $url = $this->request->input('menu_url'); + if (!empty($this->adminMenuModel->getMenuByUrl($url))) throw new AdminException('已存在相同路由的权限菜单'); + + $insertButtonArr = []; + if (!empty($permissionList = $this->request->input('permission_list'))) { + $permissionList = json_decode($permissionList, true); + foreach ($permissionList as $one) { + if (empty($one['value'])) throw new AdminException('按钮权限值错误'); + if (empty($one['menu_url'])) throw new AdminException('按钮路由值错误'); + $insertButtonArr[] = [ + 'url' => $one['menu_url'], + 'value' => $one['value'], + 'title' => $one['label'], + 'type' => AuthCode::MENU_TYPE_BUTTON, + 'status' => AuthCode::MENU_STATUS_ENABLE, + 'sort' => 0, + ]; + } + } + + Db::beginTransaction(); + try { + $batchModel = $model = new AdminMenu(); + + $model->parent_id = $this->request->input('parent_id',0); + $model->url = $url; + $model->title = $this->request->input('menu_name'); + $model->value = $this->request->input('menu_value','views'); + $model->type = $this->request->input('menu_type',AuthCode::MENU_TYPE_LIST); + $model->icon = $this->request->input('menu_icon',''); + $model->status = $this->request->input('menu_status',AuthCode::MENU_STATUS_ENABLE); + $model->sort = $this->request->input('menu_sort',0); + if (!$model->save()) throw new Exception('添加失败'); + + foreach ($insertButtonArr as &$one) { + $one['parent_id'] = $model->id; + } + + if (!$batchModel->insert($insertButtonArr)) throw new Exception('添加失败'); + + Db::commit(); + + $this->reconfigurationCache(); + } catch (Exception $exception) { + Db::rollBack(); + throw new AdminException($exception->getMessage()); + } + return $this->return->success(); } - public function edit() + /** + * 修改权限 + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function edit(): array { + $menuId = $this->request->input('menu_id'); + $url = $this->request->input('menu_url'); + $oldUrlInfo = $this->adminMenuModel->getMenuByUrl($url); + $menuInfo = $this->adminMenuModel->where('id',$menuId)->first(); + if (!empty($oldUrlInfo) && $oldUrlInfo->id != $menuId) throw new AdminException('已存在相同路由的权限菜单'); + if (empty($menuInfo)) throw new AdminException('路由不存在'); + + $childrenType = $this->adminMenuModel->getChildMenuType($menuId); + $permissionList = $this->request->input('permission_list'); + $insertButtonArr = []; + if (!empty($permissionList) && $childrenType != AuthCode::MENU_TYPE_LIST) { + $permissionList = json_decode($permissionList, true); + foreach ($permissionList as $one) { + if (empty($one['value'])) throw new AdminException('按钮权限值错误'); + if (empty($one['menu_url'])) throw new AdminException('按钮路由值错误'); + $insertButtonArr[] = [ + 'parent_id' => $menuId, + 'url' => $one['menu_url'], + 'value' => $one['value'], + 'title' => $one['label'], + 'type' => AuthCode::MENU_TYPE_BUTTON, + 'status' => AuthCode::MENU_STATUS_ENABLE, + 'sort' => 0, + ]; + } + } + + Db::beginTransaction(); + try { + if (!empty($permissionList)) { + $model = new AdminMenu(); + if (!$model->insert($insertButtonArr)) throw new Exception('添加失败'); + } + + $menuInfo->parent_id = $this->request->input('parent_id',0); + $menuInfo->url = $url; + $menuInfo->title = $this->request->input('menu_name'); + $menuInfo->value = $this->request->input('menu_value','views'); + $menuInfo->type = $this->request->input('menu_type',AuthCode::MENU_TYPE_LIST); + $menuInfo->icon = $this->request->input('menu_icon',''); + $menuInfo->status = $this->request->input('menu_status',AuthCode::MENU_STATUS_ENABLE); + $menuInfo->sort = $this->request->input('menu_sort',0); + + if (!$menuInfo->save()) throw new Exception('添加失败'); + + Db::commit(); + + $this->reconfigurationCache(); + } catch (Exception $exception) { + Db::rollBack(); + throw new AdminException($exception->getMessage()); + } + return $this->return->success(); } - public function del() + /** + * 删除逻辑 + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws RedisException + */ + public function del(): array { + $menuId = $this->request->input('menu_id'); + $res = $this->adminMenuModel->where('id',$menuId)->first(); + if (!$res) throw new AdminException('路由不存在'); + + $ids = [$res->id]; + $topIds = [$res->id]; + while(true) { + $topIds = $this->adminMenuModel->whereIn('parent_id',$topIds)->pluck('id')->toArray(); + $ids = array_merge($ids,$topIds); + if (empty($oneLevelIds)) break; + } + + $this->adminMenuModel->whereIn('id',$ids)->delete(); + + $this->reconfigurationCache(); + return $this->return->success(); } @@ -72,7 +210,7 @@ class RoleMenuService extends BaseService { $menuId = $this->request->input('menu_id'); $res = $this->adminMenuModel->where('id',$menuId)->first(); - if (!$res) throw new AdminException('角色不存在'); + if (!$res) throw new AdminException('路由不存在'); $res = $res->toArray(); //闭包函数获取子集 @@ -100,4 +238,31 @@ class RoleMenuService extends BaseService return $this->return->success('success',['info' => $res]); } + + /** + * 构建缓存 + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws RedisException + */ + public function buildCache() + { + $this->reconfigurationCache(); + + return $this->return->success('success'); + } + + /** + * 重构缓存 + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws RedisException + */ + private function reconfigurationCache(): void + { + $this->menuCache->delMenu(); + $this->menuCache->getMenu(); + } } \ No newline at end of file diff --git a/sync/http/admin/auth.http b/sync/http/admin/auth.http index 39ac6bd..576da56 100644 --- a/sync/http/admin/auth.http +++ b/sync/http/admin/auth.http @@ -13,6 +13,32 @@ GET {{host}}/admin/auth/menu_list Content-Type: application/json Authorization: Bearer {{admin_token}} +### 权限单添加 +POST {{host}}/admin/auth/menu_add +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{admin_token}} + +### 权限修改 +POST {{host}}/admin/auth/menu_edit +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{admin_token}} + +### 权限删除 +GET {{host}}/admin/auth/menu_del?menu_id=1 +Content-Type: application/json +Authorization: Bearer {{admin_token}} + +### 权限详情 +GET {{host}}/admin/auth/menu?menu_id=1 +Content-Type: application/json +Authorization: Bearer {{admin_token}} + +### 权限构建缓存 +GET {{host}}/admin/auth/menu_build_cache +Content-Type: application/json +Authorization: Bearer {{admin_token}} + + ### 角色详情 GET {{host}}/admin/auth/role?role_id=1