|
@@ -149,9 +149,8 @@ const saveLoading = ref(false);
|
|
|
const isAutoCheckingView = ref(false);
|
|
const isAutoCheckingView = ref(false);
|
|
|
|
|
|
|
|
// 控制父子节点是否严格独立(false表示父子关联,true表示严格独立)
|
|
// 控制父子节点是否严格独立(false表示父子关联,true表示严格独立)
|
|
|
-// 在设置初始选中状态时使用true,避免因为父子关联导致所有子节点被选中
|
|
|
|
|
-// 设置完成后改为false,允许用户操作时的父子关联
|
|
|
|
|
-const checkStrictly = ref(false);
|
|
|
|
|
|
|
+// 设置为true,使父子节点独立,选择某一级时不会自动勾选下级
|
|
|
|
|
+const checkStrictly = ref(true);
|
|
|
|
|
|
|
|
// 加载菜单树数据
|
|
// 加载菜单树数据
|
|
|
const loadMenuTree = async () => {
|
|
const loadMenuTree = async () => {
|
|
@@ -202,6 +201,42 @@ const findMenuIdByName = (menuList: any[], permissionName: string): number | nul
|
|
|
return null;
|
|
return null;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 在指定的父节点下查找子节点ID(用于查找三级权限)
|
|
|
|
|
+const findChildMenuIdByName = (parentMenuList: any[], parentName: string, childName: string): number | null => {
|
|
|
|
|
+ // 先找到父节点
|
|
|
|
|
+ const parentMenu = findMenuNodeByName(parentMenuList, parentName);
|
|
|
|
|
+ if (!parentMenu) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 在父节点的子节点中查找
|
|
|
|
|
+ if (parentMenu.children && parentMenu.children.length > 0) {
|
|
|
|
|
+ for (const child of parentMenu.children) {
|
|
|
|
|
+ if (child.menuName === childName || child.label === childName) {
|
|
|
|
|
+ return child.menuId || child.id;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 通过权限名称匹配菜单节点(返回节点对象,用于查找子节点)
|
|
|
|
|
+const findMenuNodeByName = (menuList: any[], permissionName: string): any | null => {
|
|
|
|
|
+ for (const menu of menuList) {
|
|
|
|
|
+ if (menu.menuName === permissionName || menu.label === permissionName) {
|
|
|
|
|
+ return menu;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (menu.children && menu.children.length > 0) {
|
|
|
|
|
+ const found = findMenuNodeByName(menu.children, permissionName);
|
|
|
|
|
+ if (found !== null) {
|
|
|
|
|
+ return found;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 从权限详情数据中提取所有菜单ID
|
|
// 从权限详情数据中提取所有菜单ID
|
|
|
// 规则:一级权限只要有数据就勾选,二级和三级权限按需添加
|
|
// 规则:一级权限只要有数据就勾选,二级和三级权限按需添加
|
|
|
const extractMenuIdsFromPermissions = (permissionList: RolePermissionItem[], menuTree: MenuItem[]): number[] => {
|
|
const extractMenuIdsFromPermissions = (permissionList: RolePermissionItem[], menuTree: MenuItem[]): number[] => {
|
|
@@ -219,8 +254,8 @@ const extractMenuIdsFromPermissions = (permissionList: RolePermissionItem[], men
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 处理二级权限
|
|
// 处理二级权限
|
|
|
- // 注意:如果存在三级权限,不要单独添加二级权限ID,避免因为父子关联导致所有子节点被选中
|
|
|
|
|
- if (permission.level2Permission && !permission.level3Permission) {
|
|
|
|
|
|
|
+ // 由于 checkStrictly 为 true,父子节点独立,所以无论是否有三级权限,都可以安全地添加二级权限ID
|
|
|
|
|
+ if (permission.level2Permission) {
|
|
|
const menuId = findMenuIdByName(menuTree, permission.level2Permission);
|
|
const menuId = findMenuIdByName(menuTree, permission.level2Permission);
|
|
|
if (menuId !== null && !addedIds.has(menuId)) {
|
|
if (menuId !== null && !addedIds.has(menuId)) {
|
|
|
menuIds.push(menuId);
|
|
menuIds.push(menuId);
|
|
@@ -230,16 +265,19 @@ const extractMenuIdsFromPermissions = (permissionList: RolePermissionItem[], men
|
|
|
|
|
|
|
|
// 处理三级权限
|
|
// 处理三级权限
|
|
|
// 注意:level3Permission 可能包含多个权限名称(用空格分隔),需要拆分处理
|
|
// 注意:level3Permission 可能包含多个权限名称(用空格分隔),需要拆分处理
|
|
|
- if (permission.level3Permission) {
|
|
|
|
|
|
|
+ // 只有当 level3Permission 不为 null 且不为空字符串时才处理
|
|
|
|
|
+ // 重要:必须在对应的二级权限下查找三级权限,避免跨范围匹配
|
|
|
|
|
+ if (permission.level3Permission && permission.level3Permission.trim() && permission.level2Permission) {
|
|
|
// 将 level3Permission 按空格拆分为多个权限名称
|
|
// 将 level3Permission 按空格拆分为多个权限名称
|
|
|
const level3PermissionNames = permission.level3Permission
|
|
const level3PermissionNames = permission.level3Permission
|
|
|
.split(/\s+/) // 按一个或多个空白字符拆分
|
|
.split(/\s+/) // 按一个或多个空白字符拆分
|
|
|
.map(name => name.trim()) // 去除首尾空格
|
|
.map(name => name.trim()) // 去除首尾空格
|
|
|
.filter(name => name.length > 0); // 过滤空字符串
|
|
.filter(name => name.length > 0); // 过滤空字符串
|
|
|
|
|
|
|
|
- // 对每个权限名称分别进行精确匹配
|
|
|
|
|
|
|
+ // 对每个权限名称分别在对应的二级权限下进行精确匹配
|
|
|
level3PermissionNames.forEach(permissionName => {
|
|
level3PermissionNames.forEach(permissionName => {
|
|
|
- const menuId = findMenuIdByName(menuTree, permissionName);
|
|
|
|
|
|
|
+ // 在对应的二级权限下查找三级权限,避免在其他二级权限下误匹配
|
|
|
|
|
+ const menuId = findChildMenuIdByName(menuTree, permission.level2Permission, permissionName);
|
|
|
// 只有精确匹配到菜单项时才添加,避免误匹配
|
|
// 只有精确匹配到菜单项时才添加,避免误匹配
|
|
|
if (menuId !== null && !addedIds.has(menuId)) {
|
|
if (menuId !== null && !addedIds.has(menuId)) {
|
|
|
menuIds.push(menuId);
|
|
menuIds.push(menuId);
|
|
@@ -278,29 +316,13 @@ const loadRoleData = async () => {
|
|
|
defaultCheckedKeys.value = menuIds;
|
|
defaultCheckedKeys.value = menuIds;
|
|
|
|
|
|
|
|
// 设置树形组件的选中状态
|
|
// 设置树形组件的选中状态
|
|
|
- // 临时使用精确模式(check-strictly="true"),避免因为父子关联导致所有子节点被选中
|
|
|
|
|
|
|
+ // 由于 checkStrictly 为 true,父子节点独立,直接设置选中状态即可
|
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
|
if (permissionTreeRef.value) {
|
|
if (permissionTreeRef.value) {
|
|
|
- // 临时切换到精确模式
|
|
|
|
|
- checkStrictly.value = true;
|
|
|
|
|
-
|
|
|
|
|
- // 等待DOM更新后设置选中状态
|
|
|
|
|
- nextTick(() => {
|
|
|
|
|
- if (permissionTreeRef.value) {
|
|
|
|
|
- permissionTreeRef.value.setCheckedKeys(menuIds);
|
|
|
|
|
-
|
|
|
|
|
- // 设置完成后,切换回父子关联模式
|
|
|
|
|
- nextTick(() => {
|
|
|
|
|
- checkStrictly.value = false;
|
|
|
|
|
-
|
|
|
|
|
- // 更新权限列表(在父子关联模式下,父节点会被自动勾选)
|
|
|
|
|
- nextTick(() => {
|
|
|
|
|
- const finalCheckedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
- roleForm.permissions = finalCheckedKeys;
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ permissionTreeRef.value.setCheckedKeys(menuIds);
|
|
|
|
|
+ // 更新权限列表
|
|
|
|
|
+ const finalCheckedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
+ roleForm.permissions = finalCheckedKeys;
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
} else {
|
|
} else {
|
|
@@ -386,6 +408,30 @@ const handlePermissionCheck = (data: any, checked: any) => {
|
|
|
// 更新权限列表
|
|
// 更新权限列表
|
|
|
roleForm.permissions = checkedKeys;
|
|
roleForm.permissions = checkedKeys;
|
|
|
|
|
|
|
|
|
|
+ // 如果勾选了子节点,自动勾选所有父节点
|
|
|
|
|
+ if (isChecked && currentNode && currentNode.parent) {
|
|
|
|
|
+ // 递归向上查找并勾选所有父节点
|
|
|
|
|
+ let parent = currentNode.parent;
|
|
|
|
|
+ while (parent && parent.data) {
|
|
|
|
|
+ const parentId = parent.data.id;
|
|
|
|
|
+ const parentNode = permissionTreeRef.value?.getNode(parentId);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果父节点存在且未被勾选,则勾选它
|
|
|
|
|
+ if (parentNode && !parentNode.checked) {
|
|
|
|
|
+ permissionTreeRef.value?.setChecked(parentId, true, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 继续向上查找
|
|
|
|
|
+ parent = parent.parent;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新权限列表(包含新勾选的父节点)
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ const updatedCheckedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
+ roleForm.permissions = updatedCheckedKeys;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 如果勾选的是三级权限(叶子节点),自动勾选同级的"查看"权限
|
|
// 如果勾选的是三级权限(叶子节点),自动勾选同级的"查看"权限
|
|
|
if (isChecked && isLeafNode && data.label !== "查看" && currentNode) {
|
|
if (isChecked && isLeafNode && data.label !== "查看" && currentNode) {
|
|
|
if (currentNode.parent) {
|
|
if (currentNode.parent) {
|