Browse Source

子账号与角色管理

lxr 2 months ago
parent
commit
3bca311523

+ 13 - 0
src/api/modules/accountRoleManagement.ts

@@ -61,6 +61,15 @@ export interface UpdateRoleDto {
   remark?: string;
 }
 
+// 更新子账号请求参数
+export interface UpdateAccountDto {
+  accountName: string;
+  phone: string;
+  roleId: number;
+  storeId: number;
+  userId: number;
+}
+
 // 通用响应接口
 export interface ApiResponse {
   code: number;
@@ -227,3 +236,7 @@ export const operationLog = (params: {
 }): Promise<ResultData<OperationLogPageResponse>> => {
   return http.get<OperationLogPageResponse>(PORT_NONE + `/platform/operationLog/page`, params, { loading: false });
 };
+// 编辑子账号
+export const updateSubAccount = (updateAccountDto: UpdateAccountDto): Promise<ResultData<ApiResponse>> => {
+  return http.post<ApiResponse>(PORT_NONE + `/platform/user-role/updateSubAccount`, updateAccountDto, { loading: false });
+};

+ 166 - 4
src/views/accountRoleManagement/roleManagement/create.vue

@@ -38,7 +38,7 @@
               show-checkbox
               node-key="id"
               :default-expand-all="false"
-              :check-strictly="true"
+              :check-strictly="checkStrictly"
               :default-checked-keys="defaultCheckedKeys"
               :expand-on-click-node="false"
               @check="handlePermissionCheck"
@@ -145,6 +145,14 @@ const defaultCheckedKeys = ref<number[]>([]);
 // 保存加载状态
 const saveLoading = ref(false);
 
+// 标志位:防止自动勾选"查看"权限时触发递归
+const isAutoCheckingView = ref(false);
+
+// 控制父子节点是否严格独立(false表示父子关联,true表示严格独立)
+// 在设置初始选中状态时使用true,避免因为父子关联导致所有子节点被选中
+// 设置完成后改为false,允许用户操作时的父子关联
+const checkStrictly = ref(false);
+
 // 加载菜单树数据
 const loadMenuTree = async () => {
   try {
@@ -195,12 +203,13 @@ const findMenuIdByName = (menuList: any[], permissionName: string): number | nul
 };
 
 // 从权限详情数据中提取所有菜单ID
+// 规则:一级权限只要有数据就勾选,二级和三级权限按需添加
 const extractMenuIdsFromPermissions = (permissionList: RolePermissionItem[], menuTree: MenuItem[]): number[] => {
   const menuIds: number[] = [];
   const addedIds = new Set<number>();
 
   permissionList.forEach(permission => {
-    // 处理一级权限
+    // 处理一级权限:只要有数据就添加
     if (permission.level1Permission) {
       const menuId = findMenuIdByName(menuTree, permission.level1Permission);
       if (menuId !== null && !addedIds.has(menuId)) {
@@ -269,9 +278,29 @@ const loadRoleData = async () => {
       defaultCheckedKeys.value = menuIds;
 
       // 设置树形组件的选中状态
+      // 临时使用精确模式(check-strictly="true"),避免因为父子关联导致所有子节点被选中
       nextTick(() => {
         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 {
@@ -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) => {
+  // 如果正在自动勾选"查看"权限,直接返回,避免递归
+  if (isAutoCheckingView.value) {
+    const checkedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
+    roleForm.permissions = checkedKeys;
+    roleFormRef.value?.validateField("permissions");
+    return;
+  }
+
+  // 获取当前选中的 keys
   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;
+
+  // 如果勾选的是三级权限(叶子节点),自动勾选同级的"查看"权限
+  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");
 };
@@ -312,6 +435,43 @@ const handleBack = () => {
 const handleCancel = () => {
   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 () => {
   if (!roleFormRef.value) return;
@@ -321,7 +481,9 @@ const handleSave = async () => {
 
     saveLoading.value = true;
     try {
-      const checkedKeys = permissionTreeRef.value?.getCheckedKeys() || [];
+      // 获取所有被勾选的菜单ID(包括父节点)
+      const checkedKeys = getAllCheckedMenuIds();
+
       // 从缓存中获取 createdId,如果没有则从用户信息中获取 storeId
       const createdId = localGet("createdId") || localGet("geeker-user")?.userInfo?.storeId || "";
 

+ 49 - 16
src/views/accountRoleManagement/subAccountManagement/create.vue

@@ -76,7 +76,8 @@ import {
   type RolePermissionItem,
   type RoleItem,
   createAccountAndAssignRole,
-  getSubAccountDetail
+  getSubAccountDetail,
+  updateSubAccount
 } from "@/api/modules/accountRoleManagement";
 import { localGet } from "@/utils";
 import PermissionItem from "./PermissionItem.vue";
@@ -97,7 +98,8 @@ const subAccountForm = reactive({
   accountName: "",
   phone: "",
   roleId: undefined as number | undefined,
-  permissions: [] as number[]
+  permissions: [] as number[],
+  userId: undefined as number | undefined
 });
 
 // 表单验证规则
@@ -326,6 +328,7 @@ const loadSubAccountData = async () => {
       subAccountForm.accountName = accountData.accountName || "";
       subAccountForm.phone = accountData.phone || "";
       subAccountForm.roleId = accountData.roleId;
+      subAccountForm.userId = accountData.userId || Number(accountId.value);
 
       // 如果有权限数据,先加载角色权限列表,然后设置选中状态
       if (subAccountForm.roleId) {
@@ -379,25 +382,55 @@ const handleSave = async () => {
 
     saveLoading.value = true;
     try {
-      // TODO: 调用创建/编辑子账号接口
       const createdId = localGet("createdId") || localGet("geeker-user")?.userInfo?.storeId || "";
+      const storeId = Number(createdId) || 0;
 
-      const createAccountDto = {
-        accountName: subAccountForm.accountName,
-        phone: subAccountForm.phone,
-        roleId: subAccountForm.roleId,
-        storeId: createdId
-      };
-      const res = await createAccountAndAssignRole(createAccountDto);
-      if (res.code === 200) {
-        ElMessage.success(isEdit.value ? "编辑成功" : "创建成功");
-        setTimeout(() => {
-          router.push("/accountRoleManagement/subAccountManagement");
-        }, 1000);
+      if (isEdit.value) {
+        // 编辑模式:调用更新接口
+        if (!subAccountForm.userId) {
+          ElMessage.error("缺少用户ID,无法更新");
+          return;
+        }
+
+        const updateAccountDto = {
+          accountName: subAccountForm.accountName,
+          phone: subAccountForm.phone,
+          roleId: subAccountForm.roleId || 0,
+          storeId: storeId,
+          userId: subAccountForm.userId
+        };
+        const res = await updateSubAccount(updateAccountDto);
+        const code = typeof res.code === "string" ? parseInt(res.code) : res.code;
+        if (code === 200) {
+          ElMessage.success("编辑成功");
+          setTimeout(() => {
+            router.push("/accountRoleManagement/subAccountManagement");
+          }, 1000);
+        } else {
+          ElMessage.error(res.msg || "编辑失败");
+        }
       } else {
-        ElMessage.error(res.msg || "创建失败");
+        // 创建模式:调用创建接口
+        const createAccountDto = {
+          accountName: subAccountForm.accountName,
+          phone: subAccountForm.phone,
+          roleId: subAccountForm.roleId,
+          storeId: storeId
+        };
+        const res = await createAccountAndAssignRole(createAccountDto);
+        const code = typeof res.code === "string" ? parseInt(res.code) : res.code;
+        if (code === 200) {
+          ElMessage.success("创建成功");
+          setTimeout(() => {
+            router.push("/accountRoleManagement/subAccountManagement");
+          }, 1000);
+        } else {
+          ElMessage.error(res.msg || "创建失败");
+        }
       }
     } catch (error) {
+      console.error("保存失败:", error);
+      ElMessage.error("保存失败,请重试");
     } finally {
       saveLoading.value = false;
     }