浏览代码

角色管理

zouzs 4 周之前
父节点
当前提交
b3f76f1b12

+ 1 - 1
public/platform-config.json

@@ -1,6 +1,6 @@
 {
   "Version": "6.1.0",
-  "Title": "PureAdmin",
+  "Title": "统一权限管理系统",
   "FixedHeader": true,
   "HiddenSideBar": false,
   "MultiTagsCache": false,

+ 15 - 0
src/api/system/menu.ts

@@ -29,4 +29,19 @@ export const deleteMenu = (id: number) => {
 
 export const getSystemList = () => {
     return http.request<BasicResponseModel>("get", baseUrlApi(`system/businessSystem/list`));
+}
+
+export interface DeptTreeModel<T = any> {
+    code: number;
+    msg: string;
+    depts: T,
+    checkedKeys: number[]
+}
+
+export const getMenuListTree = () => {
+    return http.request<BasicResponseModel>("get", baseUrlApi(`system/menu/treeselect`));
+}
+
+export const getMenuListTreeSelect = (id?: number) => {
+    return http.request<DeptTreeModel>("get", baseUrlApi(`system/menu/roleMenuTreeselect/${id}`));
 }

+ 31 - 3
src/api/system/role.ts

@@ -14,8 +14,15 @@ export interface BasicPageResponseModel<T = any> {
     total: number;
 }
 
+export interface DeptTreeModel<T = any> {
+    code: number;
+    msg: string;
+    depts: T,
+    checkedKeys: number[]
+}
+
 export const getSystemRoleList = (query?: object) => {
-    return http.request<BasicPageResponseModel>("post", baseUrlApi("/system/role/list"), {params: query});
+    return http.request<BasicPageResponseModel>("post", baseUrlApi("system/role/list"), {params: query});
 };
 
 export const changeRoleStatus = (roleId: number, status: string) => {
@@ -23,5 +30,26 @@ export const changeRoleStatus = (roleId: number, status: string) => {
         roleId,
         status
     };
-    return http.request<BasicResponseModel>("put", baseUrlApi("/system/role/changeStatus"), {data});
-}
+    return http.request<BasicResponseModel>("put", baseUrlApi("system/role/changeStatus"), {data});
+}
+
+export const getSystemRoleDeptTree = (id?: string) => {
+    return http.request<DeptTreeModel>("get", baseUrlApi(`system/role/deptTree/${id}`));
+}
+
+export const addSystemRole = (data: object) => {
+    return http.request<BasicResponseModel>("post", baseUrlApi("system/role"), {data});
+}
+
+export const updateSystemRole = (data: object) => {
+    return http.request<BasicResponseModel>("put", baseUrlApi("system/role"), {data});
+}
+
+export const deleteSystemRole = (id: string) => {
+    return http.request<BasicResponseModel>("delete", baseUrlApi(`system/role/${id}`));
+}
+
+export const getSystemRoleById = (id?: string) => {
+    return http.request<BasicResponseModel>("get", baseUrlApi(`system/role/${id}`));
+}
+

+ 0 - 3
src/utils/http/index.ts

@@ -80,7 +80,6 @@ class PureHttp {
                     : new Promise(resolve => {
                         const data = getToken();
                         if (data) {
-                            console.log("请求拦截器拿到的token", data)
                             const now = new Date().getTime();
                             const expired = parseInt(data.expires_in) - now <= 0;
                             if (expired) {
@@ -137,7 +136,6 @@ class PureHttp {
                     PureHttp.initConfig.beforeResponseCallback(response);
                     return response.data;
                 }
-                console.log('111111', response);
                 if (response.data.code === 401) {
                     console.log('用户未登录')
                     // 用户未登录
@@ -149,7 +147,6 @@ class PureHttp {
             (error: PureHttpError) => {
                 const $error = error;
                 $error.isCancelRequest = Axios.isCancel($error);
-                console.log('111111', $error);
                 if ($error.status === 401) {
                     console.log('登录状态已过期')
                     // 用户未登录

+ 3 - 3
src/views/system/menu/index.vue

@@ -60,7 +60,7 @@ import {
 } from "@/api/system/menu";
 
 defineOptions({
-  name: "PageTable"
+  name: "Menu"
 });
 
 interface TableRow {
@@ -568,12 +568,12 @@ const handleSubmit = async (values: FieldValues) => {
 }
 
 const handleClose = () => {
-  // 重置表单
+  /*// 重置表单
   nextTick(() => {
     if (dialogForm.value) {
       dialogForm.value.formInstance.resetFields()
     }
-  })
+  })*/
   console.log(dialogForm.value.formInstance)
 }
 

+ 111 - 0
src/views/system/role/components/menuTree.vue

@@ -0,0 +1,111 @@
+<script setup lang="ts">
+import {onMounted, ref, defineEmits, watch, nextTick} from "vue";
+import {getMenuListTree} from "@/api/system/menu";
+import {type CheckboxValueType} from 'element-plus'
+
+
+onMounted(() => {
+  getMenuList();
+})
+
+const emit = defineEmits(['update:modelValue'])
+
+const menuList = ref([]);
+const getMenuList = async () => {
+  let res = await getMenuListTree();
+  menuList.value = res.data;
+}
+
+const model = defineModel()
+
+watch(model, (value: number[]) => {
+  console.log(value)
+  nextTick(() => {
+    setCheckedKeys(value)
+    const allKeys = getAllKeys(menuList.value);
+    console.log(allKeys.length);
+    isIndeterminate.value = value.length > 0 && value.length < allKeys.length;
+  })
+}, {immediate: true})
+
+const menuRef = ref(null)
+
+const menuCheckStrictly = ref(true)
+const menuNodeAll = ref(false)
+const menuExpand = ref(false)
+const isIndeterminate = ref(false)
+const handleCheckedTreeExpand = (value: CheckboxValueType) => {
+  // 递归展开
+  for (let i = 0; i < menuList.value.length; i++) {
+    menuRef.value.store.nodesMap[menuList.value[i].id].expanded = value;
+  }
+}
+
+const handleCheckedTreeNodeAll = (value: CheckboxValueType) => {
+  menuRef.value.setCheckedNodes(value ? menuList.value : []);
+  isIndeterminate.value = false;
+  const allKeys = getAllKeys(menuList.value);
+  model.value = value ? allKeys : [];
+  console.log(model.value)
+  console.log(menuNodeAll.value)
+}
+
+const handleTreeCheck = (_: any, checkedState: any) => {
+  const allKeys = getAllKeys(menuList.value);
+  const checkedCount = checkedState.checkedKeys.length;
+  menuNodeAll.value = checkedCount === allKeys.length;
+  isIndeterminate.value = checkedCount > 0 && checkedCount < allKeys.length;
+  model.value = checkedState.checkedKeys
+  emit("update:modelValue", checkedState.checkedKeys)
+}
+
+// 递归获取所有节点key
+const getAllKeys = (data: any) => {
+  return data.reduce((keys: any, node: any) => {
+    keys.push(node.id);
+    if (node.children && menuCheckStrictly) {
+      keys.push(...getAllKeys(node.children));
+    }
+    return keys;
+  }, []);
+}
+
+const setCheckedKeys = (keys: number[], leafOnly = false) => {
+  return menuRef.value.setCheckedKeys(keys, leafOnly)
+}
+</script>
+
+<template>
+  <div style="width: 100%">
+    <el-row type="flex" justify="space-between" align="middle">
+      <el-col :span="4">
+        <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event)">全部展开/折叠
+        </el-checkbox>
+      </el-col>
+      <el-col :span="4">
+        <el-checkbox :indeterminate="isIndeterminate" v-model="menuNodeAll"
+                     @change="handleCheckedTreeNodeAll($event)">全选/全不选
+        </el-checkbox>
+      </el-col>
+      <el-col :span="4">
+        <el-checkbox v-model="menuCheckStrictly">级联下级
+        </el-checkbox>
+      </el-col>
+    </el-row>
+    <el-tree class="tree-border" :data="menuList" show-checkbox ref="menuRef" node-key="id"
+             empty-text="加载中,请稍后"
+             :check-strictly="!menuCheckStrictly" @check="handleTreeCheck">
+    </el-tree>
+  </div>
+</template>
+
+<style scoped lang="scss">
+/* tree border */
+.tree-border {
+  width: 100%;
+  margin-top: 5px;
+  border: 1px solid #e5e6e7;
+  background: #FFFFFF none;
+  border-radius: 4px;
+}
+</style>

+ 195 - 252
src/views/system/role/index.vue

@@ -14,7 +14,8 @@
           actionBar: { buttons, type: 'link', width: 180, showNumber: 2 },
           adaptive: { offsetBottom: 50 },
           onSelectionChange: handleSelect,
-          onFormChange: handleTableChange
+          onFormChange: handleTableChange,
+          onClickAction: handleTableOption,
         }"
     >
       <template #table-title>
@@ -29,33 +30,51 @@
         v-model="form"
         v-model:visible="dialogVisible"
         @confirm="handleSubmit"
+        @change="handleFormChange"
         @submit-error="handleSubmitError"
         @close="handleClose"
         :form="{ columns, labelPosition: 'right',labelWidth: 100, rules, rowProps: {gutter: 20}, colProps: {span: 12} }"
-        :dialog="{ title: dialogTitle + '菜单', width: 800, confirmLoading }"
-    />
+        :dialog="{ title: dialogTitle + '角色', width: 600, confirmLoading }"
+    >
+      <template #plus-field-menuIds>
+        <menu-tree v-model="form.menuIds"></menu-tree>
+      </template>
+    </PlusDialogForm>
   </div>
 </template>
 
 <script lang="ts" setup>
-import {computed, defineOptions, nextTick, reactive, ref, toRefs} from "vue";
+import {computed, defineOptions, nextTick, onMounted, reactive, ref, toRefs} from "vue";
 import type {FormRules} from 'element-plus'
 import {ElMessage, ElMessageBox} from "element-plus";
 import {
   type FieldValues,
   type PlusColumn,
+  type ButtonsCallBackParams,
   PlusDialogForm,
   PlusPage,
   PlusPageInstance,
   useTable
 } from "plus-pro-components";
 import {cloneDeep} from "lodash-es";
-import {changeRoleStatus, getSystemRoleList} from "@/api/system/role";
+import {
+  addSystemRole,
+  changeRoleStatus, deleteSystemRole,
+  getSystemRoleById,
+  getSystemRoleDeptTree,
+  getSystemRoleList, updateSystemRole
+} from "@/api/system/role";
+import MenuTree from "@/views/system/role/components/menuTree.vue";
+import {getMenuListTreeSelect} from "@/api/system/menu";
 
 defineOptions({
-  name: "PageTable"
+  name: "Role"
 });
 
+onMounted(async () => {
+  await getDeptList()
+})
+
 interface TableRow {
   id: number;
   name: string;
@@ -65,7 +84,7 @@ interface TableRow {
 }
 
 // 菜单列表
-const menuList = ref([]);
+
 const plusPageInstance = ref<PlusPageInstance | null>(null)
 
 const getList = async (query: Record<string, any>) => {
@@ -118,7 +137,18 @@ const tableConfig: PlusColumn[] = [
     hideInTable: true,
     valueType: "tree-select",
     fieldProps: {
-
+      checkStrictly: true,
+      defaultExpandAll: false,
+      style: {width: '100%'},
+      data: computed(() => {
+        return deptList.value
+      }),
+      // el-tree-select 组件属性
+      props: {
+        label: 'label',
+        value: 'id',
+        children: 'children'
+      }
     }
   },
   {
@@ -169,56 +199,38 @@ const dialogForm = ref(null);
 
 interface State {
   dialogVisible: boolean;
-  detailsVisible: boolean;
   confirmLoading: boolean;
   selectedIds: number[];
   isCreate: boolean;
   form: {
-    component: string, // 组件路径
-    icon: string, // 菜单图标
-    isCache: string, // 是否缓存 (0缓存 1不缓存)
-    isFrame: string, // 是否外链 (0是 1否)
-    menuName: string,// 菜单名称
-    menuType: string, // 菜单类型(M目录 C菜单 F按钮)
-    orderNum: string,// 显示排序
-    parentId: number,// 上级菜单
-    path: string, // 路由地址
-    perms: string, // 权限标识
-    query: string, // 路由参数
-    routeName: string, // 路由名称
-    status: string, // 菜单状态(0正常 1停用)
-    systemCode: string, // 系统编码
-    url: string, // 网关URL
-    urlmatch: string, // 网关权限
-    visible: string, // 显示状态(0显示 1隐藏)
+    businessType: string
+    deptId: number
+    menuIds: number[]
+    remark: string
+    roleKey: string
+    roleName: string
+    roleSort: number
+    status: string,
+    isMenuCheckStrictly: string
   };
   rules: FormRules;
 }
 
 const state = reactive<State>({
   dialogVisible: false,
-  detailsVisible: false,
   confirmLoading: false,
   selectedIds: [],
   isCreate: false,
   form: {
-    component: null, // 组件路径
-    icon: null, // 菜单图标
-    isCache: '0', // 是否缓存 (0缓存 1不缓存)
-    isFrame: '1', // 是否外链 (0是 1否)
-    menuName: null,// 菜单名称
-    menuType: 'M', // 菜单类型(M目录 C菜单 F按钮)
-    orderNum: null,// 显示排序
-    parentId: 0,// 上级菜单
-    path: null, // 路由地址
-    perms: null, // 权限标识
-    query: null, // 路由参数
-    routeName: null, // 路由名称
-    status: '0', // 菜单状态(0正常 1停用)
-    systemCode: null, // 系统编码
-    url: null, // 网关URL
-    urlmatch: null, // 网关权限
-    visible: '0', // 显示状态(0显示 1隐藏)
+    businessType: '',
+    deptId: null,
+    menuIds: [],
+    remark: "",
+    roleKey: "",
+    roleName: "",
+    roleSort: null,
+    status: "",
+    isMenuCheckStrictly: '0'
   },
   rules: {
     parentId: [{required: true, message: '请选择上级菜单', trigger: 'blur'}],
@@ -228,236 +240,123 @@ const state = reactive<State>({
   }
 })
 
+const deptList = ref([])
+
+const getDeptList = async () => {
+  let res = await getSystemRoleDeptTree('2');
+  if (res.code === 200) {
+    deptList.value = res.depts
+  }
+}
+
+// 表单字段
 const columns: PlusColumn[] = [
   {
-    label: '上级菜单',
-    prop: 'parentId',
+    label: "角色名称",
+    prop: "roleName",
+    valueType: "input",
     colProps: {span: 24},
-    valueType: 'tree-select',
     fieldProps: {
-      placeholder: '请选择上级菜单',
-      clearable: true,
-      showSearch: true,
-      checkStrictly: true,
-      defaultExpandAll: false,
-      style: {width: '100%'},
-      data: computed(() => {
-        return [{menuId: 0, menuName: '主类目', children: [...menuList.value]},]
-      }),
-      // el-tree-select 组件属性
-      props: {
-        label: 'menuName',
-        value: 'menuId',
-        children: 'children'
-      }
+      clearable: true
     }
   },
   {
-    label: "系统编码",
-    prop: "systemCode",
-    valueType: 'input',
+    label: "权限字符",
+    prop: "roleKey",
+    valueType: "input",
     colProps: {span: 24},
+    tooltip: "控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)",
     fieldProps: {
-      placeholder: '请输入系统编码',
       clearable: true
     }
   },
   {
-    label: "菜单类型",
-    prop: "menuType",
-    valueType: 'radio',
+    label: "业务类型",
+    prop: "businessType",
+    valueType: "input",
     colProps: {span: 24},
     fieldProps: {
-      placeholder: '请选择菜单类型',
-      clearable: true,
-      options: [
-        {label: '目录', value: 'M'},
-        {label: '菜单', value: 'C'},
-        {label: '按钮', value: 'F'}
-      ],
-    },
-  },
-  {
-    label: "菜单图标",
-    prop: "icon",
-    valueType: 'input',
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入菜单图标',
-      clearable: true,
-    },
-    hideInForm: computed(() => form.value.menuType === 'F')
+      clearable: true
+    }
   },
   {
-    label: "显示排序",
-    prop: "orderNum",
-    valueType: 'input-number',
-    colProps: {span: 12},
+    label: "组织ID",
+    prop: "deptId",
+    valueType: "tree-select",
+    colProps: {span: 24},
     fieldProps: {
-      placeholder: '请输入显示排序',
+      checkStrictly: true,
+      defaultExpandAll: false,
       style: {width: '100%'},
-      min: 0
+      data: computed(() => {
+        return deptList.value
+      }),
+      // el-tree-select 组件属性
+      props: {
+        label: 'label',
+        value: 'id',
+        children: 'children'
+      }
     }
   },
   {
-    label: "菜单名称",
-    prop: "menuName",
-    colProps: {span: 12},
+    label: "角色顺序",
+    prop: "roleSort",
+    valueType: "input-number",
+    colProps: {span: 24},
     fieldProps: {
-      placeholder: '请输入菜单名称',
-      clearable: true
+      clearable: true,
+      min: 0
     }
   },
   {
-    label: "路由名称",
-    prop: "routeName",
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入路由名称',
-      clearable: true
-    },
-    hideInForm: computed(() => form.value.menuType !== 'C')
-  },
-  {
-    label: "是否外链",
-    prop: "isFrame",
-    valueType: 'radio',
-    colProps: {span: 12},
-    fieldProps: {
-      options: [
-        {label: '是', value: '0'},
-        {label: '否', value: '1'}
-      ]
-    },
-    tooltip: '选择是外链则路由地址需要以`http(s)://`开头',
-    hideInForm: computed(() => form.value.menuType === 'F')
-  },
-  {
-    label: "路由地址",
-    prop: "path",
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入路由地址',
-      clearable: true
-    },
-    tooltip: "访问的路由地址,如:`role`,如外网地址需内链访问则以`http(s)://`开头",
-    hideInForm: computed(() => form.value.menuType === 'F')
-  },
-  {
-    label: "组件路径",
-    prop: "component",
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入组件路径',
-      clearable: true
-    },
-    tooltip: "访问的组件路径,如:`system/role/index`,默认在`views`目录下",
-    hideInForm: computed(() => form.value.menuType !== 'C')
-  },
-  {
-    label: "权限字符",
-    prop: "perms",
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入权限标识',
-      clearable: true
-    },
-    tooltip: "控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:role:list')`)",
-    hideInForm: computed(() => form.value.menuType === 'M')
-  },
-  {
-    label: "网关URL",
-    prop: "url",
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入URL',
-      clearable: true
-    },
-  },
-  {
-    label: "网关权限",
-    prop: "urlmatch",
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入网关权限标识',
-      clearable: true
-    },
-    tooltip: "控制器中定义的权限字符",
-  },
-  {
-    label: "路由参数",
-    prop: "query",
-    colProps: {span: 12},
-    fieldProps: {
-      placeholder: '请输入路由参数',
-      clearable: true
-    },
-    tooltip: "访问路由的默认传递参数,如:`{\"id\": 1, \"name\": \"ry\"}`",
-    hideInForm: computed(() => form.value.menuType !== 'C')
-  },
-  {
-    label: "是否缓存",
-    prop: "isCache",
-    valueType: 'radio',
-    colProps: {span: 12},
+    label: "状态",
+    prop: "status",
+    valueType: "radio",
+    colProps: {span: 24},
     fieldProps: {
+      clearable: true,
       options: [
-        {label: '是', value: '0'},
-        {label: '否', value: '1'}
+        {
+          label: '正常',
+          value: '0'
+        },
+        {
+          label: '停用',
+          value: '1'
+        }
       ]
-    },
-    tooltip: "选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致",
-    hideInForm: computed(() => form.value.menuType !== 'C')
+    }
   },
   {
-    label: "显示状态",
-    prop: "visible",
-    valueType: 'radio',
-    colProps: {span: 12},
-    fieldProps: {
-      options: [
-        {label: '显示', value: '0'},
-        {label: '隐藏', value: '1'}
-      ]
-    },
-    tooltip: "选择隐藏则路由将不会出现在侧边栏,但仍然可以访问",
-    hideInForm: computed(() => form.value.menuType === 'F')
+    label: "菜单权限",
+    prop: "menuIds",
+    colProps: {span: 24},
   },
   {
-    label: "菜单状态",
-    prop: "status",
-    valueType: 'radio',
-    colProps: {span: 12},
+    label: "备注",
+    prop: "remark",
+    valueType: "textarea",
+    colProps: {span: 24},
     fieldProps: {
-      options: [
-        {label: '正常', value: '0'},
-        {label: '停用', value: '1'}
-      ]
-    },
-    tooltip: "选择停用则路由将不会出现在侧边栏,也不能被访问"
-  },
+      clearable: true,
+      minRow: 2
+    }
+  }
 ]
 
 // 创建
 const handleCreate = (): void => {
   form.value = {
-    component: null, // 组件路径
-    icon: null, // 菜单图标
-    isCache: '0', // 是否缓存 (0缓存 1不缓存)
-    isFrame: '1', // 是否外链 (0是 1否)
-    menuName: null,// 菜单名称
-    menuType: 'M', // 菜单类型(M目录 C菜单 F按钮)
-    orderNum: null,// 显示排序
-    parentId: 0,// 上级菜单
-    path: null, // 路由地址
-    perms: null, // 权限标识
-    query: null, // 路由参数
-    routeName: null, // 路由名称
-    status: '0', // 菜单状态(0正常 1停用)
-    systemCode: null, // 系统编码
-    url: null, // 网关URL
-    urlmatch: null, // 网关权限
-    visible: '0', // 显示状态(0显示 1隐藏)
+    businessType: '',
+    deptId: null,
+    menuIds: [],
+    remark: "",
+    roleKey: "",
+    roleName: "",
+    roleSort: null,
+    status: '0',
+    isMenuCheckStrictly: '0'
   }
   state.isCreate = true
   state.dialogVisible = true
@@ -468,6 +367,10 @@ const handleSelect = (data: any) => {
   state.selectedIds = [...data].map(item => item.id)
 }
 
+const handleFormChange = (values: FieldValues) => {
+  console.log(values)
+}
+
 const handleTableChange = (values: FieldValues) => {
   console.log(values)
   ElMessageBox.confirm("确定修改此数据吗?", "提示", {
@@ -475,22 +378,22 @@ const handleTableChange = (values: FieldValues) => {
     cancelButtonText: "取消",
     type: "warning",
   })
-    .then(async () => {
-      try {
-        let res = await changeRoleStatus(values.row.roleId, values.row.status)
-        if (res.code === 200) {
-          ElMessage.success('修改成功')
-          refresh()
-        } else {
-          ElMessage.error(res.msg)
+      .then(async () => {
+        try {
+          let res = await changeRoleStatus(values.row.roleId, values.row.status)
+          if (res.code === 200) {
+            ElMessage.success('修改成功')
+            refresh()
+          } else {
+            ElMessage.error(res.msg)
+          }
+        } catch (e) {
+          ElMessage.error('修改失败')
         }
-      } catch (e) {
-        ElMessage.error('修改失败')
-      }
-    })
-    .finally(() => {
-      refresh()
-    });
+      })
+      .finally(() => {
+        refresh()
+      });
 }
 
 const handleSubmit = async (values: FieldValues) => {
@@ -499,7 +402,8 @@ const handleSubmit = async (values: FieldValues) => {
   if (state.isCreate) {
     try {
       let params = form.value
-      let res = await addMenu(params)
+      params.isMenuCheckStrictly = '0'
+      let res = await addSystemRole(params)
       if (res.code === 200) {
         ElMessage.success('新增成功')
         confirmLoading.value = false
@@ -515,7 +419,8 @@ const handleSubmit = async (values: FieldValues) => {
     // 编辑
     try {
       let params = form.value
-      let res = await updateMenu(params)
+      params.isMenuCheckStrictly = '0'
+      let res = await updateSystemRole(params)
       if (res.code === 200) {
         ElMessage.success('修改成功')
         confirmLoading.value = false
@@ -568,5 +473,43 @@ buttons.value = [
   }
 ];
 
+const handleTableOption = ({row, buttonRow}: ButtonsCallBackParams): void => {
+  console.log(row)
+  switch (buttonRow.code) {
+    case 'edit':
+      handleEdit(row.roleId)
+      break
+    case 'delete':
+      handleDelete(row.roleId)
+      break
+  }
+}
+
+const handleEdit = async (id: string) => {
+  let res = await getSystemRoleById(id);
+  let res1 = await getMenuListTreeSelect(id);
+  console.log(res, res1)
+  form.value = res.data
+  form.value.menuIds = res1.checkedKeys
+  state.isCreate = false
+  state.dialogVisible = true
+}
+
+const handleDelete = (id: string) => {
+  ElMessageBox.confirm('确定删除吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(async () => {
+    let res = await deleteSystemRole(id)
+    if (res.code === 200) {
+      ElMessage.success(res.msg)
+      refresh()
+    } else {
+      ElMessage.error(res.msg)
+    }
+  })
+}
+
 const {form, confirmLoading, rules, dialogVisible} = toRefs(state)
 </script>