sujunling il y a 2 ans
Parent
commit
e236c5f7f1

+ 14 - 0
src/api/sys/menu.ts

@@ -4,14 +4,28 @@ import { useUserStore } from '/@/store/modules/user';
 import { RoleEnum } from '/@/enums/roleEnum';
 import menu from '/@/mock/menu.json'
 import menu_get_ids from '/@/mock/menu_get_ids.json'
+import tool from '/@/utils/Tool';
 
 enum Api {
   BaseMenuUrl = '/menu',
   GetMenuList = '/menu/me/menus',
   SysAdminMenuList = '/admin/me/menus',
   GetMenuIdsByRoleId = '/menu/get_ids/',
+  GetChildDepartment = '/user-center/department/getChildDepartment'
 }
 
+/**
+ * @description: 获取结构列表
+ */
+
+export const structureList = () => {
+  return new Promise<void>((resolve, reject) => {
+    defHttp.post({ url: Api.GetChildDepartment }).then((res) => {
+      resolve(tool.structureTree([res.datas]))
+    })
+  })
+};
+
 /**
  * @description: Get user menu based on id
  */

+ 1 - 1
src/locales/lang/zh-CN/routes/common.ts

@@ -59,7 +59,7 @@ export default {
     organizationManagement: '组织管理',
     dictManagement: '字典管理',
     modifyPassword: '修改密码',
-    pageSystemTitleCreateMenu: '新增菜单',
+    pageSystemTitleCreateMenu: '新增机构',
     pageSystemTitleCreateTenant: '新增租户',
     pageSystemTitleEditMenu: '编辑菜单',
     pageSystemTitleEditTenant: '编辑租户',

+ 22 - 0
src/mock/menu.json

@@ -1060,6 +1060,28 @@
                             "status": "0"
                         },
                         "redirect": ""
+                    },
+                    {
+                        "id": "244dd88c-d414-4c38-85a0-86104d21b172",
+                        "createTime": "2021-11-16 19:17:48",
+                        "updateTime": "2021-12-20 11:46:16",
+                        "name": "机构管理",
+                        "parentId": "a8ffa8c5-637e-471b-a9e6-b60cebe95713",
+                        "children": [],
+                        "path": "/system/structure",
+                        "type": "SYSADMIN",
+                        "permission": "system:organization:view",
+                        "sort": 2,
+                        "component": "/systemAdmin/system/structure/index",
+                        "meta": {
+                            "icon": "ant-design:gold-outlined",
+                            "title": "机构管理",
+                            "isLink": false,
+                            "menuType": "1",
+                            "ignoreKeepAlive": false,
+                            "hideMenu": false,
+                            "status": "0"
+                        }
                     }
                 ],
                 "meta": {

+ 17 - 0
src/utils/Tool.js

@@ -14,6 +14,23 @@ var tool = {
             }
         }
         return result;
+    },
+
+    structureTree(data) {
+        return data.map(i => {
+            let newItem = {
+                id: i.depInfo.departid,
+                label: i.depInfo.departName,
+                name: i.depInfo.departName,
+                value: i.depInfo.departid,
+                children: i.childDep,
+                ...i.depInfo,
+            };
+            if (i.childDep && i.childDep.length > 0) {
+                newItem.children = this.structureTree(i.childDep);
+            }
+            return newItem;
+        });
     }
 }
 

+ 1 - 0
src/views/systemAdmin/system/organization/index.vue

@@ -1,5 +1,6 @@
 <template>
   <div class="p-4">
+    11111
     <BasicTable :clickToRowSelect="false" @register="registerTable" @fetch-success="onFetchSuccess">
       <template #toolbar>
         <Authority value="api:yt:organization:post">

+ 0 - 1
src/views/systemAdmin/system/role/RoleDrawer.vue

@@ -84,7 +84,6 @@ export default defineComponent({
           keys,
           keyType
         );
-
         // 更新
         if (unref(isUpdate)) {
           checked.value = [];

+ 141 - 0
src/views/systemAdmin/system/structure/StructureDrawer.vue

@@ -0,0 +1,141 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :title="getTitle"
+    width="50%"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" />
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form/index';
+  import { formSchema } from './structure.data';
+  import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
+
+  // 加载菜单
+  import { getMenuList } from '/@/api/sys/menu';
+
+  import { saveMenuApi } from '/@/api/system/menu';
+  import { listToTree } from '/@/utils/menuUtil';
+
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { metaModel } from '/@/api/system/model/menuModel';
+
+  export default defineComponent({
+    name: 'MenuDrawer',
+    components: { BasicDrawer, BasicForm },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      let menuId;
+
+      const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
+        labelWidth: 100,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+        // baseColProps: { lg: 12, md: 24 },
+      });
+      const { t } = useI18n(); //加载国际化
+
+      //默认传递页面数据
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        setDrawerProps({ confirmLoading: false });
+        isUpdate.value = !!data?.isUpdate;
+
+        //初始化,菜单名称为可用
+        updateSchema({ field: 'title', componentProps: { disabled: false } });
+        //如果是编辑操作,设置页面数据
+        if (unref(isUpdate)) {
+          // // 动态设置 表单值
+          //
+          let menuObj: metaModel = Reflect.get(data.record, 'meta');
+          Reflect.set(data.record, 'menuType', menuObj.menuType); //meta.menuType
+          Reflect.set(data.record, 'title', menuObj.title); //meta.title
+          Reflect.set(data.record, 'icon', menuObj.icon); //meta.icon
+          Reflect.set(data.record, 'hideMenu', menuObj.hideMenu); //meta.hideMenu
+          Reflect.set(data.record, 'ignoreKeepAlive', menuObj.ignoreKeepAlive); //meta.ignoreKeepAlive
+          Reflect.set(data.record, 'isLink', menuObj.isLink); //meta.isLink
+          Reflect.set(data.record, 'status', menuObj.status); //meta.status
+          //为表单赋值
+          setFieldsValue({
+            ...data.record,
+          });
+
+          //编辑模式,菜单名称为不可用
+          updateSchema({ field: 'title', componentProps: { disabled: false } });
+        }
+        if (isUpdate.value) {
+          menuId = Reflect.get(data.record, 'id');
+        }
+        //加载菜单
+        let treeData = await getMenuList(1);
+        treeData = listToTree(treeData);
+        updateSchema({
+          field: 'parentId',
+          componentProps: { treeData },
+        });
+      });
+
+      //得到页面标题
+      const getTitle = computed(() =>
+        !unref(isUpdate)
+          ? t('routes.common.system.pageSystemTitleCreateMenu')
+          : t('routes.common.system.pageSystemTitleEditMenu')
+      );
+
+      //提交按钮
+      async function handleSubmit() {
+        try {
+          const values = await validate();
+          setDrawerProps({ confirmLoading: true });
+          // TODO custom api
+
+          // 处理权限标识为null时,后台空指针
+          let permissionStr: string = Reflect.get(values, 'permission');
+          if (permissionStr === undefined || permissionStr === null) {
+            Reflect.set(values, 'permission', ' ');
+          }
+
+          // 添加属性;
+          //当前作为默认管理员操作;
+          Reflect.set(values, 'type', 'SYSADMIN');
+          Reflect.set(values, 'name', Reflect.get(values, 'title'));
+          //当前选择为菜单时操作
+          let menuType: string = Reflect.get(values, 'menuType');
+          if (menuType === '0') {
+            Reflect.set(values, 'component', 'LAYOUT');
+          }
+          if (isUpdate.value) {
+            Reflect.set(values, 'id', menuId);
+          }
+
+          //为meta设置值
+          const metaTemp: metaModel = {
+            icon: Reflect.get(values, 'icon'),
+            title: Reflect.get(values, 'title'),
+            isLink: Reflect.get(values, 'isLink'),
+            menuType: Reflect.get(values, 'menuType'),
+            ignoreKeepAlive: Reflect.get(values, 'ignoreKeepAlive'), //[创建菜单,才需要]
+            hideMenu: Reflect.get(values, 'hideMenu'),
+            status: Reflect.get(values, 'status'),
+          };
+          Reflect.set(values, 'meta', metaTemp);
+          // saveMenu
+          await saveMenuApi(values, isUpdate.value);
+
+          closeDrawer(); //关闭侧框
+          emit('success');
+        } finally {
+          setDrawerProps({ confirmLoading: false });
+        }
+      }
+
+      return { registerDrawer, registerForm, getTitle, handleSubmit };
+    },
+  });
+</script>

+ 188 - 0
src/views/systemAdmin/system/structure/index.vue

@@ -0,0 +1,188 @@
+<template>
+  <div class="p-4">
+    <BasicTable @register="registerTable" @fetch-success="onFetchSuccess">
+      <template #toolbar>
+        <Button type="primary" @click="handleCreate">
+          {{ getI18nCreateMenu }}
+        </Button>
+        <Button type="primary" danger :disabled="getCanBatchDelete" @click="handleBatchDelete">
+          批量删除
+        </Button>
+      </template>
+      <template #action="{ record }">
+        <TableAction :actions="[
+          {
+            label: '编辑',
+            tooltip: '编辑',
+            icon: 'clarity:note-edit-line',
+            onClick: handleEdit.bind(null, record),
+          },
+          {
+            label: '删除',
+            tooltip: '删除',
+            icon: 'ant-design:delete-outlined',
+            color: 'error',
+            popConfirm: {
+              title: getDeleteTitle(),
+              confirm: handleDelete.bind(null, record),
+            },
+          },
+        ]" />
+      </template>
+    </BasicTable>
+
+    <!-- 弹出框 -->
+    <MenuDrawer @register="registerDrawer" @success="handleSuccess" />
+  </div>
+</template>
+<script lang="ts">
+//导入所需插件
+import { computed, defineComponent, nextTick } from 'vue';
+
+// 导入表格组件,表格事件
+import { BasicTable, useTable, TableAction } from '/@/components/Table';
+
+// 加载表格数据
+import { structureList, delMenu } from '/@/api/sys/menu';
+// 加载自定义侧边弹出框 组件
+import { useDrawer } from '/@/components/Drawer';
+
+// 导入子页面【新增、修改】
+import MenuDrawer from './StructureDrawer.vue';
+
+// 导入列 属性,和搜索栏内容
+import { columns } from './structure.data';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { Button, notification } from 'ant-design-vue';
+import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm';
+import { isArray } from '/@/utils/is';
+// 自定义表格组件和属性
+export default defineComponent({
+  name: 'MenuManagement',
+  components: { BasicTable, MenuDrawer, TableAction, Button },
+  setup() {
+    const [registerDrawer, { openDrawer }] = useDrawer(); //使用右侧弹出框
+    const { t } = useI18n(); //加载国际化
+    // 新增菜单
+    const getI18nCreateMenu = computed(() => t('routes.common.system.pageSystemTitleCreateMenu'));
+
+    const [
+      registerTable,
+      { reload, collapseAll, getRowSelection, getSelectRowKeys, setSelectedRowKeys },
+    ] = useTable({
+      title: '机构列表', //'菜单列表'
+      api: structureList, //加载数据
+      columns, //加载列
+      isTreeTable: true,
+      pagination: false,
+      striped: false,
+      showTableSetting: true,
+      bordered: true,
+      showIndexColumn: false,
+      canResize: false,
+      rowKey: (record) => record.id,
+      actionColumn: {
+        width: 200,
+        title: t('routes.common.system.pageSystemTitleOperation'), //操作
+        dataIndex: 'action',
+        slots: { customRender: 'action' },
+        fixed: 'right',
+      },
+      rowSelection: {
+        type: 'checkbox',
+      },
+    });
+
+    const getCanBatchDelete = computed(() => {
+      const rowSelection = getRowSelection();
+      return !rowSelection.selectedRowKeys?.length;
+    });
+    const { createSyncConfirm } = useSyncConfirm();
+    const handleBatchDelete = async () => {
+      const rowKeys = getSelectRowKeys();
+      try {
+        await createSyncConfirm({
+          iconType: 'warning',
+          content: '确认后所有选中的菜单将被删除',
+        });
+        await handleDelete({ id: rowKeys });
+        setSelectedRowKeys([]);
+        reload();
+      } catch (error) { }
+    };
+
+    /**
+     * 获得删除提示框的文字
+     */
+    function getDeleteTitle(): string {
+      let labelText = t('routes.common.system.pageSystemTitleWhetherDelete');
+      return labelText;
+    }
+
+    /**
+     * 打开新增菜单
+     */
+    function handleCreate() {
+      openDrawer(true, {
+        isUpdate: false,
+      });
+    }
+
+    /**
+     * 打开 编辑菜单
+     * @param record
+     */
+    function handleEdit(record: Recordable) {
+      openDrawer(true, {
+        record,
+        isUpdate: true,
+      });
+    }
+
+    /**
+     * 执行 删除操作
+     * @param record
+     */
+    async function handleDelete(record: Recordable) {
+      try {
+        let ids = isArray(record.id) ? record.id : [record.id];
+        await delMenu(ids);
+        notification.success({
+          message: '成功',
+          description: '删除菜单成功',
+          duration: 3,
+        });
+        await reload();
+      } catch (e) {
+        return Promise.reject(e);
+      }
+    }
+
+    /**
+     * 操作成功,重新加载页面
+     */
+    function handleSuccess() {
+      reload();
+    }
+
+    function onFetchSuccess() {
+      // 演示默认展开所有表项
+      nextTick(collapseAll);
+    }
+
+    return {
+      getDeleteTitle,
+      getI18nCreateMenu,
+      registerTable,
+      registerDrawer,
+      handleCreate,
+      handleEdit,
+      handleDelete,
+      handleSuccess,
+      onFetchSuccess,
+      getCanBatchDelete,
+      handleBatchDelete,
+    };
+  },
+});
+</script>

+ 117 - 0
src/views/systemAdmin/system/structure/structure.data.ts

@@ -0,0 +1,117 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { h } from 'vue';
+import { Tag } from 'ant-design-vue';
+import { Icon } from '/@/components/Icon';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { structureList } from '/@/api/sys/menu';
+const { t } = useI18n();
+
+//菜单管理页,所需的列 配置
+export const columns: BasicColumn[] = [
+  {
+    title: '机构名称',
+    dataIndex: 'departName',
+    width: 180,
+    align: 'left',
+  },
+  {
+    title: '机构ID',
+    dataIndex: 'id',
+    width: 250,
+  },
+  {
+    title: '父级ID',
+    dataIndex: 'parentId',
+    width: 250,
+  },
+  {
+    title: '排序',
+    dataIndex: 'orderId',
+    width: 50,
+  }
+];
+
+const isDir = (type: string) => type === '0';
+const isMenu = (type: string) => type === '1';
+const isButton = (type: string) => type === '2';
+
+//菜单管理页,所需的搜索内容
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'menuName',
+    label: t('routes.common.system.tableTitleSystemMenuName'), //菜单名称
+    // label: '菜单名称',
+    component: 'Input',
+    colProps: { span: 8 },
+    componentProps: {
+      maxLength: 255,
+    },
+    dynamicRules: () => {
+      return [
+        {
+          required: false,
+          validator: (_, value) => {
+            if (String(value).length > 255) {
+              return Promise.reject('字数不超过255个字');
+            }
+            return Promise.resolve();
+          },
+        },
+      ];
+    },
+  },
+  {
+    field: 'status',
+    label: t('routes.common.system.tableTitleSystemStatus'), //状态
+    // label: '状态',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: t('routes.common.system.tableTitleSystemEnable'), value: '0' },
+        // { label: '启用', value: '0' },
+
+        { label: t('routes.common.system.tableTitleSystemStop'), value: '1' },
+        // { label: '停用', value: '1' },
+      ],
+    },
+    colProps: { span: 8 },
+  },
+];
+
+//----------------------------------新增、编辑----------------------------------------------------------
+export const formSchema: FormSchema[] = [
+  {
+    field: 'departName',
+    label: '机构名称',
+    component: 'Input',
+    componentProps: {
+      maxLength: 255,
+      placeholder: '请输入角色名称',
+    },
+  },
+  {
+    label: '机构排序',
+    field: 'orderId',
+    component: 'Input',
+    componentProps: {
+      maxLength: 255,
+      placeholder: '请输入排序',
+    },
+  },
+  {
+    field: 'parentId',
+    component: 'ApiTreeSelect',
+    label: '上级机构',
+    componentProps: {
+      placeholder: '请选择父级机构',
+      api: async () => {
+        var data = await structureList();
+        return data;
+      },
+      onChange(value) {
+        parentId.value = value;
+      },
+    },
+  },
+];