1.修复角色组不能选择权限的报错

2.修复角色创建子角色报权限不够的问题
This commit is contained in:
2026-05-29 10:06:10 +08:00
parent 2140b37dfd
commit eba80b1bf4
7 changed files with 194 additions and 51 deletions

View File

@@ -19,6 +19,11 @@ class Group extends Backend
{
protected string $authMethod = 'allAuthAndOthers';
/**
* 角色组表单分配权限树(仅需登录 + 具备角色组管理相关权限,不依赖菜单规则管理权限)
*/
protected array $noNeedPermission = ['rules'];
protected ?object $model = null;
protected string|array $preExcludeFields = ['create_time', 'update_time'];
@@ -90,7 +95,7 @@ class Group extends Backend
if ($inheritRes !== null) {
return $inheritRes;
}
$rulesRes = $this->handleRules($data);
$rulesRes = $this->handleRules($data, $pidInt);
if ($rulesRes instanceof Response) return $rulesRes;
$result = false;
@@ -161,7 +166,7 @@ class Group extends Backend
if ($inheritRes !== null) {
return $inheritRes;
}
$rulesRes = $this->handleRules($data);
$rulesRes = $this->handleRules($data, $pidInt);
if ($rulesRes instanceof Response) return $rulesRes;
$result = false;
@@ -296,9 +301,29 @@ class Group extends Backend
}
/**
* 当前登录管理员可分配给下级角色组的菜单权限树(与 Rule::getMenus 一致,走角色组管理权限)
*/
public function rules(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if (!$this->auth->isSuperAdmin() && !$this->canManageRoleGroups()) {
return $this->error(__('You have no permission'), [], 401);
}
return $this->success('', [
'list' => $this->getAssignableMenuRules($request),
]);
}
/**
* @param int $pidInt 上级角色组 ID大于 0 表示创建/编辑的是下级组,可与当前管理员拥有相同菜单权限
* @return array|Response
*/
private function handleRules(array &$data)
private function handleRules(array &$data, int $pidInt = 0)
{
if (!empty($data['rules']) && is_array($data['rules'])) {
$superAdmin = true;
@@ -310,7 +335,6 @@ class Group extends Backend
$checkedRules[] = $postRuleId;
}
}
foreach ($allRuleIds as $ruleId) {
if (!in_array($ruleId, $checkedRules)) {
$superAdmin = false;
@@ -320,9 +344,15 @@ class Group extends Backend
if ($superAdmin && $this->auth->isSuperAdmin()) {
$data['rules'] = '*';
} else {
$ownedRuleIds = $this->auth->getRuleIds();
$ownedRuleIds = $this->normalizeRuleIds($this->auth->getRuleIds());
$checkedRules = $this->normalizeRuleIds($checkedRules);
if (!array_diff($ownedRuleIds, $checkedRules)) {
// 仅限制「非下级」角色组防止子管理员新建与自己平级的全权限组下级组pid>0允许授予相同菜单权限
if (
$pidInt <= 0
&& $ownedRuleIds !== []
&& !array_diff($ownedRuleIds, $checkedRules)
) {
return $this->error(__('Role group has all your rights, please contact the upper administrator to add or do not need to add!'));
}
@@ -338,6 +368,23 @@ class Group extends Backend
return $data;
}
/**
* @param array<int|string> $ids
* @return array<int>
*/
private function normalizeRuleIds(array $ids): array
{
$result = [];
foreach ($ids as $id) {
if ($id === '*' || $id === '' || $id === null) {
continue;
}
$result[] = (int) $id;
}
return array_values(array_unique($result));
}
private function getGroups(Request $request, array $where = []): array
{
$pk = $this->model->getPk();
@@ -500,4 +547,82 @@ class Group extends Backend
return null;
}
private function canManageRoleGroups(): bool
{
foreach (['auth/group/index', 'auth/group/add', 'auth/group/edit', 'auth/Group/index', 'auth/Group/add', 'auth/Group/edit'] as $routePath) {
if ($this->auth->check($routePath)) {
return true;
}
}
return false;
}
/**
* @return array<int, array<string, mixed>>
*/
private function getAssignableMenuRules(Request $request): array
{
$ids = $this->auth->getRuleIds();
$where = [];
if (!in_array('*', $ids, true)) {
$where[] = ['id', 'in', $ids ?: [0]];
}
$rules = (new AdminRule())
->where($where)
->order(['weigh' => 'desc'])
->select()
->toArray();
$toEnglish = !$this->shouldForceMenuTitleZh($request) && $this->shouldTranslateMenuToEnglish();
foreach ($rules as $idx => $rule) {
$title = $rule['title'] ?? '';
if (is_string($title) && $title !== '') {
$rules[$idx]['title'] = $toEnglish ? $this->menuTitleToEn($title) : $this->menuTitleToZh($title);
}
}
return $this->tree->assembleChild($rules);
}
private function shouldTranslateMenuToEnglish(): bool
{
$lang = function_exists('locale') ? locale() : '';
$normalized = is_string($lang) ? strtolower(str_replace('_', '-', trim($lang))) : '';
return str_starts_with($normalized, 'en');
}
private function shouldForceMenuTitleZh(Request $request): bool
{
$flag = $request->get('force_menu_zh') ?? $request->post('force_menu_zh');
return in_array($flag, [1, '1', true, 'true', 'yes', 'on'], true);
}
private function menuTitleToZh(string $title): string
{
static $zhMap = null;
if (!is_array($zhMap)) {
$mapFile = app_path() . '/common/lang/zh-cn/admin_rule_title.php';
$loaded = is_file($mapFile) ? include $mapFile : [];
$zhMap = is_array($loaded) ? $loaded : [];
}
return isset($zhMap[$title]) && is_string($zhMap[$title]) ? $zhMap[$title] : $title;
}
private function menuTitleToEn(string $title): string
{
static $enMap = null;
if (!is_array($enMap)) {
$mapFile = app_path() . '/common/lang/en/admin_rule_title.php';
$loaded = is_file($mapFile) ? include $mapFile : [];
$enMap = is_array($loaded) ? $loaded : [];
}
return isset($enMap[$title]) && is_string($enMap[$title]) ? $enMap[$title] : $title;
}
}