Kaynağa Gözat

feat(@six/smart-pharmacy): 智慧药事系统第一版角色管理接口对接

cmj 1 ay önce
ebeveyn
işleme
dfe32f75dc

+ 3 - 3
apps/smart-pharmacy/public/database/menu.json

@@ -1,6 +1,6 @@
 [
   {
-    "id": "2410",
+    "id": "1",
     "meta": {
       "icon": "ion:settings-outline",
       "order": 9997,
@@ -40,7 +40,7 @@
         "component": "/system/tisane/list"
       },
       {
-        "id": "2415",
+        "id": "101",
         "path": "/system/role",
         "name": "SystemRole",
         "meta": {
@@ -50,7 +50,7 @@
         "component": "/system/role/list"
       },
       {
-        "id": "2416",
+        "id": "100",
         "path": "/system/user",
         "name": "SystemUser",
         "meta": {

+ 8 - 0
apps/smart-pharmacy/src/api/index.ts

@@ -36,6 +36,14 @@ export const http = createRequestClient({
           items: body.rows,
         };
       }
+      // 角色菜单树等接口:menus、checkedKeys 可能与 data 平级返回
+      if (Array.isArray(body.menus) || Array.isArray(body.checkedKeys)) {
+        data = {
+          ...(data && typeof data === 'object' ? data : {}),
+          menus: body.menus ?? data?.menus,
+          checkedKeys: body.checkedKeys ?? data?.checkedKeys,
+        };
+      }
       const { code: _c, msg: _m, message: _msg, data: _d, ...r } = body;
       rest = r;
     }

+ 94 - 23
apps/smart-pharmacy/src/api/method/system.ts

@@ -13,7 +13,16 @@ import {
   toRole,
   toUser,
 } from '#/api/model';
-import { fromMenus } from '#/api/model/menu';
+import {
+  fromMenus,
+  normalizeMenuTreeSelect,
+  type TreeSelectMenuNode,
+} from '#/api/model/menu';
+
+export interface RoleMenuTreeselect {
+  menus: TreeSelectMenuNode[];
+  checkedKeys: string[];
+}
 
 export namespace SystemModel {
   export interface Project extends TransformRecord {
@@ -34,6 +43,8 @@ export namespace SystemModel {
     name: string;
     code?: string;
     permissions: string[];
+    deptIds?: Array<number | string>;
+    roleSort?: number;
     remark?: string;
     status: 0 | 1;
   }
@@ -114,14 +125,33 @@ export function listProjectsMethod(page = 1, size = 20, query?: TransformData) {
   );
 }
 
-export function listRolesMethod(page = 1, size = 20, query?: TransformData) {
-  return http.post<TransformList<SystemModel.Role>, TransformList>(
-    `/admin/right_RoleMgr/listPain`,
-    query,
+export function listRolesMethod(
+  page = 1,
+  size = 20,
+  query?: Partial<SystemModel.Role>,
+) {
+  return http.get<TransformList<SystemModel.Role>, TransformList>(
+    `/manager/system/role/list`,
     {
-      params: { page, limit: size },
+      params: { pageNum: page, pageSize: size, ...toRole(query) },
+      cacheFor: 0,
       transform({ items, ...data }) {
-        return { ...data, items: items.map((item) => fromRole(item)) };
+        const rows = items ?? [];
+        return {
+          ...data,
+          items: rows.map((item) => fromRole(item)),
+        };
+      },
+    },
+  );
+}
+
+export function getRoleMethod(id: string) {
+  return http.get<SystemModel.Role, TransformData>(
+    `/manager/system/role/${id}`,
+    {
+      transform(data) {
+        return fromRole(data);
       },
     },
   );
@@ -191,28 +221,35 @@ export function editOrganizationMethod(
   );
 }
 export function editRoleMethod(data: Partial<SystemModel.Role>) {
-  return http.post(
-    data.id ? `/admin/right_RoleMgr/update` : `/admin/right_RoleMgr/Add`,
-    toRole(data),
-  );
+  const isCreate = !data?.id;
+  const body = toRole(data, isCreate ? { create: true } : { update: true });
+  return isCreate
+    ? http.post(`/manager/system/role`, body)
+    : http.put(`/manager/system/role`, body);
 }
 
 export function updateRoleStatusMethod(
-  id: string,
-  data: Partial<Omit<SystemModel.Role, 'id'>>,
+  roleId: string,
+  data: Pick<SystemModel.Role, 'name' | 'status'>,
 ) {
-  const { pid, stateSel } = toRole({ ...data, id });
-  return http.put(`/admin/right_RoleMgr/changeStatus`, { pid, stateSel });
+  const id = Number(roleId) || roleId;
+  return http.put(`/manager/system/role/changeStatus`, {
+    roleId: id,
+    roleName: data.name,
+    status: String(data.status),
+  });
 }
 
-export function deleteRoleMethod(data: Pick<SystemModel.User, 'id'>) {
+export function deleteRoleMethod(data: Pick<SystemModel.Role, 'id'>) {
   return deleteRolesMethod([data]);
 }
 
-export function deleteRolesMethod(params: Pick<SystemModel.User, 'id'>[]) {
-  return http.post(`/admin/right_RoleMgr/BatchDelete`, void 0, {
-    params: { ids: params.map((item) => item.id).join(',') },
-  });
+export function deleteRolesMethod(params: Pick<SystemModel.Role, 'id'>[]) {
+  const roleIds = params
+    .map((item) => item.id)
+    .filter(Boolean)
+    .join(',');
+  return http.delete(`/manager/system/role/${roleIds}`);
 }
 
 // 获取用户列表
@@ -272,9 +309,7 @@ export function getUserMethod(id: string) {
   );
 }
 
-export function deleteUserMethod(
-  data: Pick<SystemModel.User, 'id' | 'pid'>,
-) {
+export function deleteUserMethod(data: Pick<SystemModel.User, 'id' | 'pid'>) {
   return deleteUsersMethod([data]);
 }
 
@@ -312,3 +347,39 @@ export function getMenusMethod() {
     },
   );
 }
+
+/** 获取菜单下拉树列表 */
+export function getMenuTreeselectMethod() {
+  return http.get<TreeSelectMenuNode[], TreeSelectMenuNode[]>(
+    `/manager/system/menu/treeselect`,
+    {
+      transform(data) {
+        return normalizeMenuTreeSelect(Array.isArray(data) ? data : []);
+      },
+    },
+  );
+}
+
+/** 加载对应角色菜单列表树(含已勾选菜单) */
+export async function getRoleMenuTreeselectMethod(
+  roleId: string,
+): Promise<RoleMenuTreeselect> {
+  const data = await http.get<TransformData, TransformData>(
+    `/manager/system/menu/roleMenuTreeselect/${roleId}`,
+    { cacheFor: 0 },
+  );
+
+  const checkedKeys = (
+    Array.isArray(data?.checkedKeys) ? data.checkedKeys : []
+  ).map((key) => String(key));
+
+  let menus = normalizeMenuTreeSelect(
+    Array.isArray(data?.menus) ? data.menus : [],
+  );
+
+  if (menus.length === 0) {
+    menus = await getMenuTreeselectMethod();
+  }
+
+  return { menus, checkedKeys };
+}

+ 14 - 0
apps/smart-pharmacy/src/api/model/menu.ts

@@ -8,6 +8,20 @@ export interface TreeSelectMenuNode {
   children?: TreeSelectMenuNode[];
 }
 
+/** 标准化菜单下拉树节点,供权限树组件使用 */
+export function normalizeMenuTreeSelect(
+  nodes?: TreeSelectMenuNode[],
+): TreeSelectMenuNode[] {
+  if (!Array.isArray(nodes)) return [];
+  return nodes.map((node) => ({
+    id: String(node.id),
+    label: node.label ?? '',
+    children: node.children?.length
+      ? normalizeMenuTreeSelect(node.children)
+      : undefined,
+  }));
+}
+
 type AccessMenuRoute = TransformData & {
   id?: string;
   children?: AccessMenuRoute[];

+ 84 - 18
apps/smart-pharmacy/src/api/model/role.ts

@@ -2,35 +2,101 @@ import type { SystemModel, TransformData } from '#/api';
 
 import { fromRow } from '#/api/model/index';
 
+function normalizeMenuIds(
+  permissions?: Array<number | string>,
+): Array<number | string> {
+  if (!Array.isArray(permissions)) return [];
+  return permissions
+    .map((menuId) => {
+      const num = Number(menuId);
+      return Number.isFinite(num) ? num : menuId;
+    })
+    .filter((menuId) => menuId !== '' && menuId !== undefined);
+}
+
+function normalizeDeptIds(
+  deptIds?: Array<number | string>,
+): Array<number | string> {
+  if (!Array.isArray(deptIds)) return [];
+  return deptIds
+    .map((deptId) => {
+      const num = Number(deptId);
+      return Number.isFinite(num) ? num : deptId;
+    })
+    .filter((deptId) => deptId !== '' && deptId !== undefined);
+}
+
+function resolveStatus(data?: Partial<SystemModel.Role>): string {
+  if (data?.status === 0 || data?.status === 1) return String(data.status);
+  return '0';
+}
+
 export function fromRole(data?: TransformData): SystemModel.Role {
   const roleId = data?.roleId ?? data?.pid ?? data?.id;
   const id = roleId === undefined || roleId === null ? '' : String(roleId);
   const statusRaw = data?.status ?? data?.stateSel;
+  let status: 0 | 1 = 1;
+  if (statusRaw === 0 || statusRaw === '0') status = 0;
+  else if (statusRaw === 1 || statusRaw === '1') status = 1;
+
   return {
-    ...fromRow({ ...data, id }),
+    ...fromRow({
+      ...data,
+      id,
+      createUser: data?.createBy ?? data?.createUser,
+      createTime: data?.createTime,
+      updateUser: data?.updateBy ?? data?.updateUser,
+      updateTime: data?.updateTime ?? data?.lastTime,
+    }),
     id,
-    name: data?.roleName ?? data?.rolename,
-    code: data?.roleKey ?? data?.rolecode,
-    remark: data?.remark,
-    status:
-      statusRaw === 0 || statusRaw === '0'
-        ? 0
-        : statusRaw === 1 || statusRaw === '1'
-          ? 1
-          : (({ '0': 0, '1': 1 } as const)[<string>data?.stateSel ?? '1'] ?? 1),
-    permissions: Array.isArray(data?.menuIds) ? data?.menuIds : [],
+    pid: id,
+    name: data?.roleName ?? data?.rolename ?? data?.name,
+    code: data?.roleKey ?? data?.rolecode ?? data?.roleCode,
+    remark: data?.remark ?? '',
+    roleSort: Number(data?.roleSort ?? 0),
+    status,
+    permissions: Array.isArray(data?.menuIds)
+      ? data.menuIds.map((menuId: unknown) => String(menuId))
+      : [],
+    deptIds: normalizeDeptIds(data?.deptIds).map(String),
   };
 }
 
-export function toRole(data?: Partial<SystemModel.Role>): TransformData {
+/** 新增/修改角色时后端要求的完整请求体 */
+function toRolePayload(data?: Partial<SystemModel.Role>): TransformData {
+  const roleId = data?.id ?? data?.pid;
+
+  return {
+    ...(roleId ? { roleId: Number(roleId) || roleId } : {}),
+    roleName: data?.name ?? '',
+    roleSort: data?.roleSort ?? 0,
+    status: resolveStatus(data),
+    menuIds: normalizeMenuIds(data?.permissions),
+    deptIds: normalizeDeptIds(data?.deptIds),
+    remark: data?.remark ?? '',
+  };
+}
+
+export function toRole(
+  data?: Partial<SystemModel.Role>,
+  options?: { create?: boolean; update?: boolean },
+): TransformData {
+  if (options?.create || options?.update) {
+    return toRolePayload(data);
+  }
+
+  const roleId = data?.id ?? data?.pid;
+  const menuIds = normalizeMenuIds(data?.permissions);
+  const deptIds = normalizeDeptIds(data?.deptIds);
+
   return {
-    roleId: data?.id,
-    pid: data?.id,
+    ...(roleId ? { roleId: Number(roleId) || roleId } : {}),
     roleName: data?.name,
-    rolename: data?.name,
+    roleKey: data?.code,
     remark: data?.remark,
-    status: data?.status === 0 ? '0' : data?.status === 1 ? '1' : void 0,
-    stateSel: data?.status === 0 ? '1' : '0',
-    menuIds: data?.permissions ?? [],
+    roleSort: data?.roleSort,
+    status: resolveStatus(data),
+    menuIds: menuIds.length ? menuIds : undefined,
+    deptIds: deptIds.length ? deptIds : undefined,
   };
 }

+ 39 - 21
apps/smart-pharmacy/src/views/system/role/data.ts

@@ -13,8 +13,8 @@ export function useRoleSearchFormSchema(): VbenFormSchema[] {
       componentProps: {
         allowClear: true,
         options: [
-          { label: $t('common.enabled'), value: 1 },
-          { label: $t('common.disabled'), value: 0 },
+          { label: $t('common.enabled'), value: 0 },
+          { label: $t('common.disabled'), value: 1 },
         ],
       },
       fieldName: 'status',
@@ -35,7 +35,7 @@ export function useRoleTableColumns<T = SystemModel.Role>(
       width: 200,
     },
     {
-      field: 'roleCode',
+      field: 'code',
       title: $t('table.column.roleCode'),
     },
     {
@@ -54,7 +54,7 @@ export function useRoleTableColumns<T = SystemModel.Role>(
     {
       cellRender: {
         attrs: { beforeChange: onStatusChange },
-        // props: { accessRole: '超级管理员' },
+        props: { _props: { checkedValue: 0, unCheckedValue: 1 } },
         name: onStatusChange ? 'CellSwitch' : 'CellTag',
       },
       field: 'status',
@@ -80,10 +80,42 @@ export function useRoleTableColumns<T = SystemModel.Role>(
   ];
 }
 
+function useRoleBaseFormSchema(): VbenFormSchema[] {
+  return [
+    {
+      component: 'InputNumber',
+      componentProps: {
+        class: 'w-full',
+        min: 0,
+      },
+      defaultValue: 0,
+      fieldName: 'roleSort',
+      label: '显示顺序',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        options: [
+          { label: $t('common.enabled'), value: 0 },
+          { label: $t('common.disabled'), value: 1 },
+        ],
+      },
+      defaultValue: 0,
+      fieldName: 'status',
+      label: $t('system.role.status'),
+    },
+    {
+      component: 'Input',
+      defaultValue: '',
+      fieldName: 'remark',
+      label: '备注',
+    },
+  ];
+}
+
 export function useRoleFormSchema(
   mode: 'add' | 'edit' | 'setting',
 ): VbenFormSchema[] {
-  console.log('useRoleFormSchema', mode);
   const schema: VbenFormSchema[] = [
     {
       component: 'Input',
@@ -93,7 +125,6 @@ export function useRoleFormSchema(
     },
   ];
 
-  // 编辑模式
   if (mode === 'setting') {
     schema.push({
       component: 'Input',
@@ -107,21 +138,8 @@ export function useRoleFormSchema(
     });
   }
 
-  // 设置模式
-  if (mode === 'edit') {
-    schema.push({
-      component: 'Input',
-      fieldName: 'remark',
-      label: '备注',
-    });
-  }
-
-  if (mode === 'add') {
-    schema.push({
-      component: 'Input',
-      fieldName: 'remark',
-      label: '备注',
-    });
+  if (mode === 'add' || mode === 'edit') {
+    schema.push(...useRoleBaseFormSchema());
   }
 
   return schema;

+ 30 - 46
apps/smart-pharmacy/src/views/system/role/list.vue

@@ -10,15 +10,18 @@ import type { SystemModel } from '#/api';
 import { Page, useVbenDrawer } from '@vben/common-ui';
 import { Plus } from '@vben/icons';
 
-import { Button, message, Modal } from 'ant-design-vue';
+import { Button, message, Modal, notification } from 'ant-design-vue';
 
 import { useVbenVxeGrid } from '#/adapter/vxe-table';
-import { deleteRoleMethod } from '#/api';
+import {
+  deleteRoleMethod,
+  listRolesMethod,
+  updateRoleStatusMethod,
+} from '#/api';
 import { $t } from '#/locales';
 
 import { useRoleSearchFormSchema, useRoleTableColumns } from './data';
 import Form from './modules/form.vue';
-import { mockData } from './mock';
 
 const [FormDrawer, formDrawerApi] = useVbenDrawer({
   connectedComponent: Form,
@@ -27,7 +30,6 @@ const [FormDrawer, formDrawerApi] = useVbenDrawer({
 
 const [Grid, gridApi] = useVbenVxeGrid({
   formOptions: {
-    fieldMappingTime: [['createTime', ['startTime', 'endTime']]],
     schema: useRoleSearchFormSchema(),
     submitOnChange: true,
   },
@@ -35,35 +37,15 @@ const [Grid, gridApi] = useVbenVxeGrid({
     columns: useRoleTableColumns(onActionClick, onStatusChange),
     height: 'auto',
     keepSource: true,
-    // proxyConfig: {
-    //   ajax: {
-    //     query({ page }, formValues) {
-    //       return listRolesMethod(page.currentPage, page.pageSize, formValues);
-    //     },
-    //   },
-    // },
-    // rowConfig: {
-    //   keyField: 'id',
-    // },
     proxyConfig: {
-      response: {
-        result: 'Data.Items',
-        total: 'Data.TotalRecordCount',
-      },
-
       ajax: {
-        query() {
-          return Promise.resolve({
-            Data: mockData.value,
-            ResultInfo: '操作成功',
-            ResultCode: 0,
-          });
+        query({ page }, formValues) {
+          return listRolesMethod(page.currentPage, page.pageSize, formValues);
         },
       },
     },
-
     rowConfig: {
-      keyField: 'pid',
+      keyField: 'id',
     },
   } as VxeTableGridOptions<SystemModel.Role>,
 });
@@ -113,25 +95,30 @@ function confirm(content: string, title: string) {
  */
 async function onStatusChange(newStatus: 0 | 1, row: SystemModel.Role) {
   const status: Recordable<string> = {
-    0: '用',
-    1: '用',
+    0: '用',
+    1: '用',
   };
   try {
     await confirm(
       `你要将${row.name}的状态切换为 【${status[newStatus.toString()]}】 吗?`,
       `切换状态`,
     );
-    mockData.value.Items = mockData.value.Items.map((item) => {
-      if (item.pid === row.pid) {
-        return {
-          ...item,
-          status: newStatus,
-        };
-      }
-      return item;
-    });
-    // await updateRoleStatusMethod(row.id, { status: newStatus });
-    return true;
+
+    try {
+      await updateRoleStatusMethod(row.id, {
+        name: row.name,
+        status: newStatus,
+      });
+      notification.success({
+        message: '切换状态成功',
+      });
+      return true;
+    } catch (error: any) {
+      notification.error({
+        message: error.message || '切换状态失败',
+      });
+      return false;
+    }
   } catch {
     return false;
   }
@@ -141,8 +128,7 @@ function onRefresh() {
   gridApi.query();
 }
 
-function onSetHandle(row?: SystemModel.Role) {
-  // formDrawerApi.setData(row ?? {}).open();
+function onSetHandle(row: SystemModel.Role) {
   formDrawerApi
     .setData({
       row,
@@ -158,16 +144,14 @@ function onEditHandle(row?: SystemModel.Role) {
       type: 'edit',
     })
     .open();
-  // formDrawerApi.setData(row ?? {}).open();
 }
-function onAddHandle(row?: SystemModel.Role) {
+
+function onAddHandle() {
   formDrawerApi
     .setData({
-      row,
       type: 'add',
     })
     .open();
-  // formDrawerApi.setData(row ?? {}).open();
 }
 
 async function onDeleteHandle(row: SystemModel.Role) {

+ 0 - 35
apps/smart-pharmacy/src/views/system/role/mock.ts

@@ -1,35 +0,0 @@
-import { ref } from 'vue';
-
-export const mockData = ref({
-  TotalRecordCount: 11,
-  TotalPageCount: 1,
-  PageSize: 20,
-  ButtonRight: '',
-  CurrentPageSize: 11,
-  Items: [
-    {
-      pid: '760631a1-58ca-49e7-9ec9-82475dbbcb5c',
-      createUser: 'admin',
-      lastTime: '2025-10-26 11:25:12',
-      isDelete: '0',
-      params: {},
-      name: '科长',
-      stateSel: '0',
-      status: 1,
-      remark: '这是一个备注222',
-      roleCode: '65015601',
-    },
-    {
-      pid: 'c0c6cd02-2ea9-4ec8-86e4-71239fe9f156',
-      createUser: 'admin',
-      lastTime: '2025-10-22 09:22:05',
-      isDelete: '0',
-      params: {},
-      name: '管理员222',
-      stateSel: '0',
-      status: 0,
-      remark: '这是一个备注',
-      roleCode: '65015600',
-    },
-  ],
-});

+ 80 - 178
apps/smart-pharmacy/src/views/system/role/modules/form.vue

@@ -1,228 +1,146 @@
 <script lang="ts" setup>
-import type { Recordable } from '@vben/types';
+import type { TreeSelectMenuNode } from '#/api/model/menu';
 
 import type { SystemModel } from '#/api';
 
-import { computed, ref } from 'vue';
+import { computed, nextTick, ref } from 'vue';
 
 import { useVbenDrawer, VbenTree } from '@vben/common-ui';
-import { IconifyIcon } from '@vben/icons';
 
-import { useRequest } from '@six/request';
 import { Spin } from 'ant-design-vue';
 
 import { useVbenForm } from '#/adapter/form';
-import { editRoleMethod, getMenusMethod } from '#/api';
+import {
+  editRoleMethod,
+  getRoleMenuTreeselectMethod,
+  getRoleMethod,
+} from '#/api';
 import { $t } from '#/locales';
 
-import { useRoleFormSchema } from '../data';
+import { useRequest } from '@six/request';
 
-import { mockData } from '../mock';
+import { useRoleFormSchema } from '../data';
 
 const emits = defineEmits(['success']);
 
-// const {
-//   loading,
-//   data: menus,
-//   send: loadMenus,
-// } = useRequest(getMenusMethod, { immediate: false, initialData: [] });
-
-const loading = ref(false);
-const menus = [
-  {
-    meta: {
-      icon: 'ion:settings-outline',
-      order: 9997,
-      title: 'system.title',
-    },
-    name: 'System',
-    path: '/system',
-    children: [
-      {
-        path: '/system/organization',
-        name: 'MedicalOrganization',
-        meta: {
-          icon: 'mdi:account-group',
-          title: '医疗机构管理',
-        },
-        component: '/system/organization/list',
-      },
-      {
-        path: '/system/enterprise',
-        name: 'SystemEnterprise',
-        meta: {
-          icon: 'mdi:account-group',
-          title: '企业管理',
-        },
-        component: '/system/enterprise/list',
-      },
-      {
-        path: '/system/user',
-        name: 'SystemUser',
-        meta: {
-          icon: 'charm:organisation',
-          title: '煎药中心管理',
-        },
-        component: '/system/user/list',
-      },
-      {
-        path: '/system/role',
-        name: 'SystemRole',
-        meta: {
-          icon: 'charm:organisation',
-          title: '角色管理',
-        },
-        component: '/system/role/list',
-      },
-      {
-        path: '/system/project',
-        name: 'SystemProject',
-        meta: {
-          icon: 'charm:organisation',
-          title: '用户管理',
-        },
-        component: '/system/project/list',
-      },
-    ],
-  },
-  {
-    meta: {
-      icon: 'ion:settings-outline',
-      order: 9998,
-      title: '处方管理',
-    },
-    name: 'RegisterRegister',
-    path: '/register/register',
-    children: [
-      {
-        path: '/system/role',
-        name: 'SystemRole1',
-        meta: {
-          icon: 'mdi:account-group',
-          title: '处方列表',
-        },
-        component: '/system/role/list',
-      },
-    ],
-  },
-];
-
 const edit = useRequest(editRoleMethod, { immediate: false }).onSuccess(() => {
   emits('success');
 });
 
 const formData = ref<SystemModel.Role>();
-const getTitle = computed(() => {
-  return formData.value?.id
-    ? $t('ui.actionTitle.edit', [$t('system.role.name')])
-    : $t('ui.actionTitle.create', [$t('system.role.name')]);
-});
+const mode = ref<'add' | 'edit' | 'setting'>('add');
+const menuTree = ref<TreeSelectMenuNode[]>([]);
+const menuLoading = ref(false);
 
-const title = ref('新增');
 const setTitle = computed(() => {
-  if (title.value === 'setting') {
+  if (mode.value === 'setting') {
     return '角色权限设置';
   }
-  if (title.value === 'edit') {
+  if (mode.value === 'edit') {
     return $t('ui.actionTitle.edit', [$t('system.role.name')]);
   }
   return $t('ui.actionTitle.create', [$t('system.role.name')]);
 });
 
-const mode = ref<'add' | 'edit' | 'setting'>('add');
-
 const [Form, formApi] = useVbenForm({
   schema: [],
   showDefaultActions: false,
 });
 
+async function loadRoleMenuTree(roleId: string) {
+  menuLoading.value = true;
+  try {
+    const { menus, checkedKeys } = await getRoleMenuTreeselectMethod(roleId);
+    menuTree.value = menus;
+    if (formData.value) {
+      formData.value.permissions = checkedKeys;
+    }
+    await nextTick();
+    await formApi.setValues({
+      name: formData.value?.name,
+      permissions: checkedKeys,
+    });
+    await formApi.resetValidate();
+  } finally {
+    menuLoading.value = false;
+  }
+}
+
 const [Drawer, drawerApi] = useVbenDrawer({
   async onConfirm() {
-    mockData.value.Items.push({
-      id: String(Math.random()),
-      name: formData.value?.name || '',
-      code: 'new_role_code',
-      createUser: 'admin',
-      lastTime: new Date().toISOString(),
-    });
-    drawerApi.close();
-    // const { valid } = await formApi.validate();
-    // if (!valid) return;
-    // drawerApi.lock();
-    // const data = await formApi.getValues();
-    // try {
-    //   await edit.send({ ...formData.value, ...data });
-    //   await drawerApi.close();
-    // } finally {
-    //   drawerApi.unlock();
-    // }
+    const { valid } = await formApi.validate();
+    if (!valid) return;
+    drawerApi.lock();
+    const data = await formApi.getValues();
+    try {
+      await edit.send({ ...formData.value, ...data });
+      await drawerApi.close();
+    } finally {
+      drawerApi.unlock();
+    }
   },
 
   async onOpenChange(isOpen) {
     if (isOpen) {
-      // const data = drawerApi.getData<SystemModel.Role>();
       const data = drawerApi.getData<{
         row?: SystemModel.Role;
         type: 'add' | 'edit' | 'setting';
       }>();
       await formApi.resetForm();
-      if (data) {
-        // formData.value = data;
-        formData.value = data.row;
-        title.value = data.type;
-        mode.value = data.type;
-        await formApi.setState({
-          schema: useRoleFormSchema(mode.value),
-        });
+      mode.value = data?.type ?? 'add';
+      menuTree.value = [];
+      await formApi.setState({
+        schema: useRoleFormSchema(mode.value),
+      });
+
+      if (mode.value === 'setting' && data?.row?.id) {
+        formData.value = await getRoleMethod(data.row.id);
+        await formApi.setValues({ name: formData.value.name });
+        await loadRoleMenuTree(data.row.id);
+      } else if (data?.row?.id) {
+        formData.value = await getRoleMethod(data.row.id);
+        await formApi.setValues(formData.value ?? {});
+        await formApi.resetValidate();
+      } else if (mode.value === 'add') {
+        formData.value = {
+          id: '',
+          name: '',
+          permissions: [],
+          deptIds: [],
+          roleSort: 0,
+          status: 0,
+          remark: '',
+        };
         await formApi.setValues(formData.value);
-        // 清除验证状态,避免在数据设置后立即显示验证错误
         await formApi.resetValidate();
-      }
-      if (menus.value.length === 0) {
-        await loadMenus();
-        if (formData.value?.permissions?.length) {
-          await formApi.setValues(formData.value);
-          // 再次清除验证状态
-          await formApi.resetValidate();
-        }
+      } else {
+        formData.value = data?.row;
+        await formApi.setValues(formData.value ?? {});
+        await formApi.resetValidate();
       }
     }
   },
 });
-
-function getNodeClass(node: Recordable<any>) {
-  const classes: string[] = [];
-  if (node.value?.type === 'button') {
-    classes.push('inline-flex');
-    if (node.index % 3 >= 1) {
-      classes.push('!pl-0');
-    }
-  }
-
-  return classes.join(' ');
-}
 </script>
 <template>
   <Drawer :title="setTitle">
     <Form>
       <template #permissions="slotProps">
-        <Spin :spinning="loading" wrapper-class-name="w-full menus-loading">
+        <Spin :spinning="menuLoading" wrapper-class-name="w-full menus-loading">
           <VbenTree
-            :tree-data="menus"
+            v-if="menuTree.length > 0"
+            :tree-data="menuTree"
             multiple
             bordered
             :default-expanded-level="2"
-            :get-node-class="getNodeClass"
+            :show-icon="false"
             v-bind="slotProps"
             value-field="id"
-            label-field="meta.title"
-            icon-field="meta.icon"
-          >
-            <template #node="{ value }">
-              <IconifyIcon v-if="value.meta.icon" :icon="value.meta.icon" />
-              {{ $t(value.meta.title) }}
-            </template>
-          </VbenTree>
+            label-field="label"
+          />
+          <div v-else-if="!menuLoading" class="text-sm text-gray-400">
+            暂无菜单数据
+          </div>
         </Spin>
       </template>
     </Form>
@@ -232,20 +150,4 @@ function getNodeClass(node: Recordable<any>) {
 .menus-loading {
   min-height: 24px;
 }
-
-:deep(.ant-tree-title) {
-  .tree-actions {
-    display: none;
-    margin-left: 20px;
-  }
-}
-
-:deep(.ant-tree-title:hover) {
-  .tree-actions {
-    display: flex;
-    flex: auto;
-    justify-content: flex-end;
-    margin-left: 20px;
-  }
-}
 </style>