|
@@ -38,7 +38,7 @@
|
|
|
show-checkbox
|
|
show-checkbox
|
|
|
node-key="id"
|
|
node-key="id"
|
|
|
:default-expand-all="false"
|
|
:default-expand-all="false"
|
|
|
- :check-strictly="true"
|
|
|
|
|
|
|
+ :check-strictly="checkStrictly"
|
|
|
:default-checked-keys="defaultCheckedKeys"
|
|
:default-checked-keys="defaultCheckedKeys"
|
|
|
:expand-on-click-node="false"
|
|
:expand-on-click-node="false"
|
|
|
@check="handlePermissionCheck"
|
|
@check="handlePermissionCheck"
|
|
@@ -145,6 +145,14 @@ const defaultCheckedKeys = ref<number[]>([]);
|
|
|
// 保存加载状态
|
|
// 保存加载状态
|
|
|
const saveLoading = ref(false);
|
|
const saveLoading = ref(false);
|
|
|
|
|
|
|
|
|
|
+// 标志位:防止自动勾选"查看"权限时触发递归
|
|
|
|
|
+const isAutoCheckingView = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+// 控制父子节点是否严格独立(false表示父子关联,true表示严格独立)
|
|
|
|
|
+// 在设置初始选中状态时使用true,避免因为父子关联导致所有子节点被选中
|
|
|
|
|
+// 设置完成后改为false,允许用户操作时的父子关联
|
|
|
|
|
+const checkStrictly = ref(false);
|
|
|
|
|
+
|
|
|
// 加载菜单树数据
|
|
// 加载菜单树数据
|
|
|
const loadMenuTree = async () => {
|
|
const loadMenuTree = async () => {
|
|
|
try {
|
|
try {
|
|
@@ -195,12 +203,13 @@ const findMenuIdByName = (menuList: any[], permissionName: string): number | nul
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 从权限详情数据中提取所有菜单ID
|
|
// 从权限详情数据中提取所有菜单ID
|
|
|
|
|
+// 规则:一级权限只要有数据就勾选,二级和三级权限按需添加
|
|
|
const extractMenuIdsFromPermissions = (permissionList: RolePermissionItem[], menuTree: MenuItem[]): number[] => {
|
|
const extractMenuIdsFromPermissions = (permissionList: RolePermissionItem[], menuTree: MenuItem[]): number[] => {
|
|
|
const menuIds: number[] = [];
|
|
const menuIds: number[] = [];
|
|
|
const addedIds = new Set<number>();
|
|
const addedIds = new Set<number>();
|
|
|
|
|
|
|
|
permissionList.forEach(permission => {
|
|
permissionList.forEach(permission => {
|
|
|
- // 处理一级权限
|
|
|
|
|
|
|
+ // 处理一级权限:只要有数据就添加
|
|
|
if (permission.level1Permission) {
|
|
if (permission.level1Permission) {
|
|
|
const menuId = findMenuIdByName(menuTree, permission.level1Permission);
|
|
const menuId = findMenuIdByName(menuTree, permission.level1Permission);
|
|
|
if (menuId !== null && !addedIds.has(menuId)) {
|
|
if (menuId !== null && !addedIds.has(menuId)) {
|
|
@@ -269,9 +278,29 @@ const loadRoleData = async () => {
|
|
|
defaultCheckedKeys.value = menuIds;
|
|
defaultCheckedKeys.value = menuIds;
|
|
|
|
|
|
|
|
// 设置树形组件的选中状态
|
|
// 设置树形组件的选中状态
|
|
|
|
|
+ // 临时使用精确模式(check-strictly="true"),避免因为父子关联导致所有子节点被选中
|
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
|
if (permissionTreeRef.value) {
|
|
if (permissionTreeRef.value) {
|
|
|
- permissionTreeRef.value.setCheckedKeys(defaultCheckedKeys.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;
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
} else {
|
|
} else {
|
|
@@ -295,10 +324,104 @@ const checkRoleNameDuplicate = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 检查同级是否有其他非"查看"权限被勾选
|
|
|
|
|
+const hasOtherCheckedSiblings = (currentNode: any, checkedKeys: number[]): boolean => {
|
|
|
|
|
+ if (!currentNode || !currentNode.parent) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const parentData = currentNode.parent.data;
|
|
|
|
|
+ if (!parentData.children || parentData.children.length === 0) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查同级中是否有非"查看"权限被勾选
|
|
|
|
|
+ return parentData.children.some((child: any) => {
|
|
|
|
|
+ // 排除当前节点和"查看"权限
|
|
|
|
|
+ return child.id !== currentNode.data.id && child.label !== "查看" && checkedKeys.includes(child.id);
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 权限选择变化
|
|
// 权限选择变化
|
|
|
const handlePermissionCheck = (data: any, checked: any) => {
|
|
const handlePermissionCheck = (data: any, checked: any) => {
|
|
|
|
|
+ // 如果正在自动勾选"查看"权限,直接返回,避免递归
|
|
|
|
|
+ if (isAutoCheckingView.value) {
|
|
|
|
|
+ const checkedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
+ roleForm.permissions = checkedKeys;
|
|
|
|
|
+ roleFormRef.value?.validateField("permissions");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取当前选中的 keys
|
|
|
const checkedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
const checkedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
+
|
|
|
|
|
+ // 判断是否是三级节点(叶子节点,没有子节点)
|
|
|
|
|
+ const isLeafNode = !data.children || data.children.length === 0;
|
|
|
|
|
+
|
|
|
|
|
+ // 判断当前节点是否被勾选
|
|
|
|
|
+ const isChecked = checkedKeys.includes(data.id);
|
|
|
|
|
+
|
|
|
|
|
+ // 通过 el-tree 的 getNode 方法获取节点对象
|
|
|
|
|
+ const currentNode = permissionTreeRef.value?.getNode(data.id);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果尝试取消勾选"查看"权限
|
|
|
|
|
+ if (isLeafNode && data.label === "查看" && !isChecked && currentNode) {
|
|
|
|
|
+ // 检查同级是否有其他非"查看"权限被勾选
|
|
|
|
|
+ if (hasOtherCheckedSiblings(currentNode, checkedKeys)) {
|
|
|
|
|
+ // 如果有其他权限被勾选,阻止取消"查看"权限,重新勾选
|
|
|
|
|
+ isAutoCheckingView.value = true;
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ permissionTreeRef.value?.setChecked(data.id, true, false);
|
|
|
|
|
+ const updatedCheckedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
+ roleForm.permissions = updatedCheckedKeys;
|
|
|
|
|
+ ElMessage.warning("当同级有其他权限被勾选时,查看权限不能取消");
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ isAutoCheckingView.value = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新权限列表
|
|
|
roleForm.permissions = checkedKeys;
|
|
roleForm.permissions = checkedKeys;
|
|
|
|
|
+
|
|
|
|
|
+ // 如果勾选的是三级权限(叶子节点),自动勾选同级的"查看"权限
|
|
|
|
|
+ if (isChecked && isLeafNode && data.label !== "查看" && currentNode) {
|
|
|
|
|
+ if (currentNode.parent) {
|
|
|
|
|
+ // 获取父节点的数据
|
|
|
|
|
+ const parentNode = currentNode.parent;
|
|
|
|
|
+ const parentData = parentNode.data;
|
|
|
|
|
+
|
|
|
|
|
+ // 在父节点的子节点中查找"查看"权限
|
|
|
|
|
+ if (parentData.children && parentData.children.length > 0) {
|
|
|
|
|
+ const viewPermission = parentData.children.find((child: any) => child.label === "查看");
|
|
|
|
|
+
|
|
|
|
|
+ if (viewPermission) {
|
|
|
|
|
+ // 检查"查看"权限是否已经被勾选
|
|
|
|
|
+ const viewNode = permissionTreeRef.value?.getNode(viewPermission.id);
|
|
|
|
|
+ if (viewNode && !viewNode.checked) {
|
|
|
|
|
+ // 设置标志位,防止递归
|
|
|
|
|
+ isAutoCheckingView.value = true;
|
|
|
|
|
+
|
|
|
|
|
+ // 自动勾选"查看"权限(第三个参数 false 表示不深度勾选子节点)
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ permissionTreeRef.value?.setChecked(viewPermission.id, true, false);
|
|
|
|
|
+ // 更新权限列表
|
|
|
|
|
+ const updatedCheckedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
+ roleForm.permissions = updatedCheckedKeys;
|
|
|
|
|
+
|
|
|
|
|
+ // 重置标志位
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ isAutoCheckingView.value = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 触发表单验证
|
|
// 触发表单验证
|
|
|
roleFormRef.value?.validateField("permissions");
|
|
roleFormRef.value?.validateField("permissions");
|
|
|
};
|
|
};
|
|
@@ -312,6 +435,43 @@ const handleBack = () => {
|
|
|
const handleCancel = () => {
|
|
const handleCancel = () => {
|
|
|
router.back();
|
|
router.back();
|
|
|
};
|
|
};
|
|
|
|
|
+
|
|
|
|
|
+// 获取所有需要传递的菜单ID(包括父节点)
|
|
|
|
|
+const getAllCheckedMenuIds = (): number[] => {
|
|
|
|
|
+ if (!permissionTreeRef.value) return [];
|
|
|
|
|
+
|
|
|
|
|
+ const checkedKeys = permissionTreeRef.value.getCheckedKeys() || [];
|
|
|
|
|
+ const allMenuIds = new Set<number>();
|
|
|
|
|
+
|
|
|
|
|
+ // 先添加所有被勾选的节点ID(过滤掉null和undefined)
|
|
|
|
|
+ checkedKeys.forEach((key: any) => {
|
|
|
|
|
+ if (key !== null && key !== undefined && typeof key === "number") {
|
|
|
|
|
+ allMenuIds.add(key);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 遍历所有被勾选的节点,找到它们的父节点并添加到列表中
|
|
|
|
|
+ checkedKeys.forEach((key: any) => {
|
|
|
|
|
+ if (key === null || key === undefined) return;
|
|
|
|
|
+
|
|
|
|
|
+ const node = permissionTreeRef.value?.getNode(key);
|
|
|
|
|
+ if (node && node.parent) {
|
|
|
|
|
+ // 递归向上查找所有父节点
|
|
|
|
|
+ let parent = node.parent;
|
|
|
|
|
+ while (parent && parent.data) {
|
|
|
|
|
+ const parentId = parent.data.id;
|
|
|
|
|
+ // 只添加有效的数字ID
|
|
|
|
|
+ if (parentId !== null && parentId !== undefined && typeof parentId === "number") {
|
|
|
|
|
+ allMenuIds.add(parentId);
|
|
|
|
|
+ }
|
|
|
|
|
+ parent = parent.parent;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return Array.from(allMenuIds);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 保存
|
|
// 保存
|
|
|
const handleSave = async () => {
|
|
const handleSave = async () => {
|
|
|
if (!roleFormRef.value) return;
|
|
if (!roleFormRef.value) return;
|
|
@@ -321,7 +481,9 @@ const handleSave = async () => {
|
|
|
|
|
|
|
|
saveLoading.value = true;
|
|
saveLoading.value = true;
|
|
|
try {
|
|
try {
|
|
|
- const checkedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
|
|
|
|
|
|
|
+ // 获取所有被勾选的菜单ID(包括父节点)
|
|
|
|
|
+ const checkedKeys = getAllCheckedMenuIds();
|
|
|
|
|
+
|
|
|
// 从缓存中获取 createdId,如果没有则从用户信息中获取 storeId
|
|
// 从缓存中获取 createdId,如果没有则从用户信息中获取 storeId
|
|
|
const createdId = localGet("createdId") || localGet("geeker-user")?.userInfo?.storeId || "";
|
|
const createdId = localGet("createdId") || localGet("geeker-user")?.userInfo?.storeId || "";
|
|
|
|
|
|