feat : role

This commit is contained in:
2024-10-28 17:56:19 +08:00
parent c86c6c1baf
commit d6465b21d8
12 changed files with 485 additions and 90 deletions

View File

@@ -5,6 +5,7 @@ namespace App\Cache\Redis\Admin;
use App\Cache\Redis\RedisCache;
use App\Constants\Admin\AuthCode;
use App\Model\AdminMenu;
use App\Service\ServiceTrait\AdminRoleMenuTrait;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -12,6 +13,8 @@ use RedisException;
class MenuCache
{
use AdminRoleMenuTrait;
/**
* @var RedisCache $redis
*/
@@ -30,6 +33,9 @@ class MenuCache
*/
protected string $menuKey;
/**
* 构造函数注入 key
*/
public function __construct()
{
$this->menuKey = AdminRedisKey::adminMenuList();
@@ -51,7 +57,7 @@ class MenuCache
$data = $this->getDbMenu($allMenuList);
$this->redis->set($this->menuKey,json_encode($data));
$this->redis->set($this->menuKey,json_encode($data),'system');
return $data;
}
@@ -64,38 +70,6 @@ class MenuCache
*/
public function delMenu(): void
{
$this->redis->delete($this->menuKey);
}
/**
* 递归生成合适的数据
* @param array $allMenuList
* @param int $parentId
* @return array
*/
private function getDbMenu(array $allMenuList, int $parentId = 0): array
{
$menuList = [];
foreach ($allMenuList as $menu) {
if ($menu['parent_id'] == $parentId) {
$children = $this->getDbMenu($allMenuList, (int)$menu['id']);
if (!empty($children)) {
//获取第一个 type 如何是菜单
if ($children[0]['type'] == AuthCode::MENU_TYPE_LIST) {
$menu['children'] = $children;
} else {
foreach ($children as $child) {
$menu['permissionList'][] = [
'id' => $child['id'],
'label' => $child['title'],
'value' => $child['value'],
];
}
}
}
$menuList[] = $menu;
}
}
return $menuList;
$this->redis->delete($this->menuKey,'system');
}
}

View File

@@ -0,0 +1,129 @@
<?php
namespace App\Cache\Redis\Admin;
use App\Cache\Redis\RedisCache;
use App\Constants\Admin\AuthCode;
use App\Model\AdminMenu;
use App\Model\AdminRoleMenu;
use App\Service\ServiceTrait\AdminRoleMenuTrait;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class RoleCache
{
use AdminRoleMenuTrait;
/**
* 注入 redis 方法
* @var RedisCache $redis
*/
#[Inject]
protected RedisCache $redis;
/**
* 注入模型
* @var AdminRoleMenu $adminRoleMenuModel
*/
#[Inject]
protected AdminRoleMenu $adminRoleMenuModel;
/**
* 注入模型
* @var AdminMenu $adminMenuModel
*/
#[Inject]
protected AdminMenu $adminMenuModel;
/**
* @var string
*/
private string $roleMenuArrKey;
/**
* @var string
*/
private string $roleMenuListKey;
/**
* @var int
*/
private int $roleId = 0;
/**
* 获取 key
* @return void
*/
private function getKey(): void
{
$this->roleMenuArrKey = AdminRedisKey::adminMenuArrByRoleId($this->roleId);
$this->roleMenuListKey = AdminRedisKey::adminMenuListByRoleId($this->roleId);
}
/**
* @param int $roleId
* @return array|array[]
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \RedisException
*/
public function getRoleCache(int $roleId): array
{
$this->roleId = $roleId;
$this->getKey();
if ($this->redis->exists($this->roleMenuArrKey,'system') && $this->redis->exists($this->roleMenuListKey,'system')) {
return [
'role_arr' => $this->redis->sMembers($this->roleMenuArrKey,'system'),
'role_list' => json_decode($this->redis->get($this->roleMenuListKey,'system'),true),
];
}
if ($this->roleId == AuthCode::SUPERADMIN) {
$menuIds = $this->adminMenuModel->getAllIds();
$data = (new MenuCache)->getMenu();
// $menuList = $this->adminMenuModel->getAllMenu();
} else {
$menuIds = $this->adminRoleMenuModel->getMenuByRoleId($this->roleId);
$menuList = $this->adminMenuModel->getRoleMenu($menuIds);
$data = $this->getDbMenu($menuList);
}
if (empty($menuIds) || empty($menuList)) {
return [
'role_arr' => [],
'role_list' => []
];
}
$this->delRoleCache();
$this->redis->set($this->roleMenuListKey,json_encode($data),'system');
$this->redis->sAddBatch($this->roleMenuArrKey,$menuIds,'system');
return [
'role_arr' => $menuIds,
'role_list' => $data
];
}
/**
* @param int $roleId
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \RedisException
*/
public function delRoleCache(int $roleId = 0): void
{
if ($roleId > 0) {
$this->roleId = $roleId;
$this->getKey();
}
$this->redis->delete($this->roleMenuArrKey,'system');
$this->redis->delete($this->roleMenuListKey,'system');
}
}

View File

@@ -272,6 +272,21 @@ class RedisCache
return $this->getRedis($poolName)->sRem($key, $value);
}
/**
* 集合批量添加
* @param $key
* @param array $values
* @param string $poolName
* @return bool|int|Redis
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws RedisException
*/
public function sAddBatch($key, array $values, string $poolName = 'default')
{
return $this->getRedis($poolName)->sAddArray($key, $values);
}
// +--------------------------------------------------------------------------------------------------------------------------------------------
// | hash
// +--------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -23,4 +23,9 @@ class AuthCode
* 按钮
*/
const MENU_TYPE_BUTTON = 2;
/**
* 超级管理员
*/
const SUPERADMIN = 1;
}

View File

@@ -9,6 +9,7 @@ use App\Middleware\Admin\JwtAuthMiddleware;
use App\Request\Admin\AuthRequest;
use App\Service\Admin\User\RoleMenuService;
use App\Service\Admin\User\RoleService;
use Exception;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middlewares;
use Hyperf\HttpServer\Annotation\RequestMapping;
@@ -102,29 +103,63 @@ class AuthController extends AbstractController
return (new RoleMenuService)->buildCache();
}
/**
* @param AuthRequest $request
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
#[RequestMapping(path: "role_add", methods: "POST")]
#[Scene(scene: "role_add")]
public function role_add(AuthRequest $request)
{
return (new RoleService)->add();
}
public function role_edit()
/**
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
#[RequestMapping(path: "role_edit", methods: "POST")]
#[Scene(scene: "role_edit")]
public function roleEdit()
{
return (new RoleService)->edit();
}
public function role_status()
/**
* @param AuthRequest $request
* @return array
* @throws Exception
*/
#[RequestMapping(path: "role_change_status", methods: "POST")]
#[Scene(scene: "role_change_status")]
public function roleChangeStatus(AuthRequest $request)
{
return (new RoleService)->changeStatus();
}
public function role_list()
/**
* @return array
*/
#[RequestMapping(path: "role_list", methods: "GET")]
#[Scene(scene: "role_list")]
public function roleList(AuthRequest $request)
{
return (new RoleService)->handle();
}
/**
* @param AuthRequest $request
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \RedisException
*/
#[RequestMapping(path: "role", methods: "GET")]
#[Scene(scene: "role_info")]
public function role(AuthRequest $request)
public function role(AuthRequest $request): array
{
return (new RoleService)->details();
}

View File

@@ -59,10 +59,38 @@ class AdminMenu extends Model
}
/**
* @param int $url
* @return array
*/
public function getAllIds()
{
return $this
->where('status', AuthCode::MENU_STATUS_ENABLE)
->orderBy('sort', 'desc')
->pluck('id')
->toArray();
}
/**
* @param $ids
* @return array|false
*/
public function getRoleMenu($ids): array|false
{
$res = $this
->where('status', AuthCode::MENU_STATUS_ENABLE)
->whereIn('id',$ids)
->orderBy('sort', 'desc')
->get();
if (empty($res)) return false;
return $res->toArray();
}
/**
* @param string $url
* @return Builder|\Hyperf\Database\Model\Model|null
*/
public function getMenuByUrl(int $url): \Hyperf\Database\Model\Model|Builder|null
public function getMenuByUrl(string $url): \Hyperf\Database\Model\Model|Builder|null
{
return $this
->where('url', $url)
@@ -73,7 +101,7 @@ class AdminMenu extends Model
* @param int $id
* @return HigherOrderTapProxy|mixed|null
*/
public function getChildMenuType(int $id)
public function getChildMenuType(int $id): mixed
{
return $this->where('parent_id', $id)->value('type');
}

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
* @property int $role_id
* @property int $menu_id
*/
class AdminRoleMenu extends Model
{
/**
* The table associated with the model.
*/
protected ?string $table = 'admin_role_menu';
/**
* The attributes that are mass assignable.
*/
protected array $fillable = [];
/**
* The attributes that should be cast to native types.
*/
protected array $casts = ['role_id' => 'integer', 'menu_id' => 'integer'];
/**
* 获取角色菜单列表
* @param int $roleId
* @return array
*/
public function getMenuByRoleId(int $roleId): array
{
return $this->where('role_id', $roleId)->pluck('menu_id')->toArray();
}
}

View File

@@ -26,10 +26,11 @@ class AuthRequest extends FormRequest
'menu_id' => 'required|integer',
'menu_name' => 'required|string',
'menu_url' =>'required|string',
'menu_status' => 'required|string',
'menu_status' => 'required|in:1,2',
'menu_parent_id' => 'integer|exists:admin_menu,id',
'page' =>'required|integer',
'limit' => 'required|integer',
'role_status' => 'required|in:1,2',
'role_name' => 'required|string',
];
}
@@ -41,14 +42,21 @@ class AuthRequest extends FormRequest
'menu_name.required' => '名称必填',
'menu_url.required' => 'url必填',
'menu_status.required' => '状态必填',
'menu_status.in' => '状态值错误',
'menu_parent_id.exists' => 'parent_id不存在',
'page.required' => 'page必填',
'limit.required' => 'limit必填'
'limit.required' => 'limit必填',
'role_status.required' => '状态必填',
'role_status.in' => '状态值错误'
];
}
protected array $scenes = [
'role_info' => ['role_id'],
'role_add' => ['role_name','role_status'],
'role_edit' => ['role_id','role_name','role_status'],
'role_change_status' => ['role_id','role_status'],
'role_list' => ['limit'],
'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'],

View File

@@ -118,7 +118,7 @@ class RoleMenuService extends BaseService
*/
public function edit(): array
{
$menuId = $this->request->input('menu_id');
$menuId = (int)$this->request->input('menu_id');
$url = $this->request->input('menu_url');
$oldUrlInfo = $this->adminMenuModel->getMenuByUrl($url);
$menuInfo = $this->adminMenuModel->where('id',$menuId)->first();
@@ -213,32 +213,40 @@ class RoleMenuService extends BaseService
if (!$res) throw new AdminException('路由不存在');
$res = $res->toArray();
//闭包函数获取子集
$res = function() use($res,$menuId) {
$children = $this->adminMenuModel->where('parent_id',$menuId)->select(['type','value','title','id'])->get();
$res['permissionList'] = [];
if (!empty($children)) {
$children = $children->toArray();
if ($children[0]['type'] == AuthCode::MENU_TYPE_LIST) {
return $res;
}
foreach ($children as $one)
{
$res['permissionList'][] = [
'id' => $one['id'],
'label' => $one['title'],
'value' => $one['value'],
];
}
}
return $res;
};
//获取子集
$res = $this->getChildren($res,$menuId);
return $this->return->success('success',['info' => $res]);
}
/**
* @param $res
* @param $menuId
* @return array
*/
private function getChildren(&$res,$menuId): array
{
$children = $this->adminMenuModel->where('parent_id',$menuId)->get(['type','value','title','id']);
$res['permission_list'] = [];
if (!empty($children)) {
$children = $children->toArray();
if ($children[0]['type'] == AuthCode::MENU_TYPE_LIST) {
return $res;
}
foreach ($children as $one)
{
$res['permission_list'][] = [
'id' => $one['id'],
'label' => $one['title'],
'value' => $one['value'],
];
}
}
return $res;
}
/**
* 构建缓存
* @return array

View File

@@ -10,12 +10,18 @@ declare(strict_types=1);
namespace App\Service\Admin\User;
use App\Cache\Redis\Admin\MenuCache;
use App\Cache\Redis\Admin\RoleCache;
use App\Constants\Admin\AuthCode;
use App\Exception\AdminException;
use App\Model\AdminRole;
use App\Model\AdminRoleMenu;
use App\Service\Admin\BaseService;
use Exception;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class RoleService extends BaseService
{
@@ -25,6 +31,24 @@ class RoleService extends BaseService
#[Inject]
protected AdminRole $adminRoleModel;
/**
* @var AdminRoleMenu
*/
#[Inject]
protected AdminRoleMenu $adminRoleMenuModel;
/**
* @var RoleCache
*/
#[Inject]
protected RoleCache $roleCache;
/**
* @var MenuCache
*/
#[Inject]
protected MenuCache $menuCache;
/**
* 查询字段
* @var array|string[]
@@ -37,7 +61,7 @@ class RoleService extends BaseService
*/
public function handle(): array
{
$limit = $this->request->input('limit', 10);
$limit = (int)$this->request->input('limit', 10);
$list = $this->adminRoleModel->paginate($limit,$this->field)->toArray();
@@ -45,9 +69,15 @@ class RoleService extends BaseService
}
public function add()
/**
* 添加角色
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function add(): array
{
$name = $this->request->input('name');
$name = $this->request->input('role_name');
if ($this->adminRoleModel->getInfoByName($name)) throw new AdminException('角色已存在');
@@ -56,17 +86,29 @@ class RoleService extends BaseService
$model = new AdminRole();
$model->name = $name;
$model->status = $this->request->input('status', 1);
$model->remark = $this->request->input('remark', '');
$model->status = $this->request->input('role_status', 1);
$model->remark = $this->request->input('role_remark', '');
if (!$model->save()) throw new Exception('添加失败');
//todo 添加角色权限
$menuIdArr = explode(',', $this->request->input('menu_ids'));
if (!$model->save()) throw new Exception('添加失败-角色错误');
//添加角色权限
if (!empty($this->request->input('menu_ids')))
{
$menuIdArr = explode(',', $this->request->input('menu_ids'));
$insertArr = [];
foreach ($menuIdArr as $menuId) {
$insertArr[] = [
'role_id' => $model->id,
'menu_id' => $menuId,
];
}
if (!(new AdminRoleMenu)->insert($insertArr)) throw new Exception('添加失败-权限组错误');
}
Db::commit();
$this->roleCache->getRoleCache($model->id);
} catch (Exception $e) {
Db::rollBack();
throw new AdminException($e->getMessage());
@@ -76,26 +118,50 @@ class RoleService extends BaseService
}
/**
* 修改
* 修改角色
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function edit(): array
{
$id = $this->request->input('id');
$id = (int)$this->request->input('role_id');
if (!$info = $this->adminRoleModel->getInfoById($id)) throw new AdminException('角色不存在');
$name = $this->request->input('role_name');
$oldInfo = $this->adminRoleModel->getInfoByName($name);
if ($oldInfo->id != $id) throw new AdminException('角色已存在');
Db::beginTransaction();
try {
$info->name = $this->request->input('name');
$info->status = $this->request->input('status', 1);
$info->remark = $this->request->input('remark', '');
$info->name = $name;
$info->status = $this->request->input('role_status', 1);
$info->remark = $this->request->input('role_remark', '');
if (!$info->save()) throw new Exception('修改失败');
if (!$info->save()) throw new Exception('修改失败-角色错误');
//todo 删除权限 添加角色权限
//删除权限 添加角色权限
if (!empty($this->request->input('menu_ids'))) {
//todo 判断数据一致 是否修改
$this->adminRoleMenuModel->where('role_id', $info->id)->delete();
$menuIdArr = explode(',', $this->request->input('menu_ids'));
$insertArr = [];
foreach ($menuIdArr as $menuId) {
$insertArr[] = [
'role_id' => $info->id,
'menu_id' => $menuId,
];
}
if (!(new AdminRoleMenu)->insert($insertArr)) throw new Exception('修改失败-权限组错误');
}
Db::commit();
$this->roleCache->delRoleCache($info->id);
$this->roleCache->getRoleCache($info->id);
} catch (Exception $e) {
Db::rollBack();
throw new AdminException($e->getMessage());
@@ -111,20 +177,24 @@ class RoleService extends BaseService
*/
public function changeStatus(): array
{
$id = $this->request->input('id');
$id = (int)$this->request->input('role_id');
if ($id == AuthCode::SUPERADMIN) throw new AdminException('超级管理员不可关闭');
if (!$info = $this->adminRoleModel->getInfoById($id)) throw new AdminException('角色不存在');
$info->status = $this->request->input('status', 0);
$info->status = $this->request->input('role_status', 0);
if (!$info->save()) throw new Exception('修改失败');
if (!$info->save()) throw new AdminException('修改失败');
return $this->return->success();
}
/**
* 详情
* 详情角色
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \RedisException
*/
public function details(): array
{
@@ -132,6 +202,14 @@ class RoleService extends BaseService
$res = $this->adminRoleModel->where('id',$roleId)->first($this->field);
if (!$res) throw new AdminException('角色不存在');
return $this->return->success('success',['info' => $res->toArray()]);
$data = $this->roleCache->getRoleCache((int)$roleId);
$menuList = $this->menuCache->getMenu();
return $this->return->success('success',[
'info' => $res->toArray(),
'role_arr' => $data['role_arr'],
'role_list' => $data['role_list'],
]);
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\ServiceTrait;
use App\Constants\Admin\AuthCode;
trait AdminRoleMenuTrait
{
/**
* 递归生成合适的数据
* @param array $allMenuList
* @param int $parentId
* @return array
*/
protected function getDbMenu(array $allMenuList, int $parentId = 0): array
{
$menuList = [];
foreach ($allMenuList as $menu) {
if ($menu['parent_id'] == $parentId) {
$children = $this->getDbMenu($allMenuList, (int)$menu['id']);
if (!empty($children)) {
//获取第一个 type 如何是菜单
if ($children[0]['type'] == AuthCode::MENU_TYPE_LIST) {
$menu['children'] = $children;
} else {
foreach ($children as $child) {
$menu['permissionList'][] = [
'id' => $child['id'],
'label' => $child['title'],
'value' => $child['value'],
];
}
}
}
$menuList[] = $menu;
}
}
return $menuList;
}
}

View File

@@ -18,18 +18,22 @@ POST {{host}}/admin/auth/menu_add
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{admin_token}}
menu_name=第二页&menu_url=/admin/second&menu_icon=fa fa-user&menu_sort=2&menu_status=1&parent_id=0
### 权限修改
POST {{host}}/admin/auth/menu_edit
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{admin_token}}
menu_id=11&menu_name=第二页1&menu_url=/admin/second&menu_icon=fa fa-user&menu_sort=2&menu_status=1&parent_id=0
### 权限删除
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
GET {{host}}/admin/auth/menu?menu_id=2
Content-Type: application/json
Authorization: Bearer {{admin_token}}
@@ -45,5 +49,28 @@ GET {{host}}/admin/auth/role?role_id=1
Content-Type: application/json
Authorization: Bearer {{admin_token}}
### 角色列表
GET {{host}}/admin/auth/role_list?limit=10
Content-Type: application/json
Authorization: Bearer {{admin_token}}
###
### 角色更改状态
POST {{host}}/admin/auth/role_change_status
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{admin_token}}
role_id=1&role_status=2
### 角色添加
POST {{host}}/admin/auth/role_add
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{admin_token}}
role_name=测试&role_status=1&menu_ids=1,2,3,4,5,6,7,8,9&role_remark=测试
### 角色修改
POST {{host}}/admin/auth/role_edit
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{admin_token}}
role_id=3&role_name=测试&role_status=1&menu_ids=1,2,3,4,5,6,7&role_remark=测试