Kaynağa Gözat

perf: tree table

xingyu 2 yıl önce
ebeveyn
işleme
bc97bd30a0

+ 4 - 3
yudao-ui-admin-vue3/src/hooks/web/useVxeCrudSchemas.ts

@@ -17,10 +17,10 @@ import { ComponentOptions } from '@/types/components'
 export type VxeCrudSchema = {
   primaryKey?: string // 主键ID
   primaryTitle?: string // 主键标题 默认为序号
-  primaryType?: VxeColumnPropTypes.Type // 不填写为数据库编号 还支持 "seq" | "radio" | "checkbox" | "expand" | "html" | null
+  primaryType?: VxeColumnPropTypes.Type // 不填写为数据库编号 null为不显示 还支持 "seq" | "radio" | "checkbox" | "expand" | "html" | null
   action?: boolean // 是否开启操作栏插槽
   actionTitle?: string // 操作栏标题 默认为操作
-  actionWidth?: string // 操作栏插槽宽度一般2个字带图标 text 类型按钮 50-70
+  actionWidth?: string // 操作栏插槽宽度,一般2个字带图标 text 类型按钮 50-70
   columns: VxeCrudColumns[]
 }
 type VxeCrudColumns = Omit<VxeTableColumn, 'children'> & {
@@ -170,7 +170,7 @@ const filterTableSchema = (crudSchema: VxeCrudSchema): VxeGridPropTypes.Columns
   const { t } = useI18n()
   const tableSchema: VxeGridPropTypes.Columns = []
   // 主键ID
-  if (crudSchema.primaryKey) {
+  if (crudSchema.primaryKey && crudSchema.primaryType) {
     const tableSchemaItem = {
       title: crudSchema.primaryTitle ? crudSchema.primaryTitle : t('common.index'),
       field: crudSchema.primaryKey,
@@ -179,6 +179,7 @@ const filterTableSchema = (crudSchema: VxeCrudSchema): VxeGridPropTypes.Columns
     }
     tableSchema.push(tableSchemaItem)
   }
+
   eachTree(crudSchema.columns, (schemaItem: VxeCrudColumns) => {
     // 判断是否显示
     if (schemaItem?.isTable !== false && schemaItem?.table?.show !== false) {

+ 31 - 22
yudao-ui-admin-vue3/src/hooks/web/useVxeGrid.ts

@@ -1,5 +1,5 @@
 import { computed, nextTick, reactive } from 'vue'
-import { SizeType, VxeGridProps } from 'vxe-table'
+import { SizeType, VxeGridProps, VxeTablePropTypes } from 'vxe-table'
 import { useAppStore } from '@/store/modules/app'
 import { VxeAllSchemas } from './useVxeCrudSchemas'
 import { useI18n } from '@/hooks/web/useI18n'
@@ -11,6 +11,7 @@ const message = useMessage() // 消息弹窗
 
 interface UseVxeGridConfig<T = any> {
   allSchemas: VxeAllSchemas
+  treeConfig?: VxeTablePropTypes.TreeConfig
   getListApi: (option: any) => Promise<T>
   deleteApi?: (option: any) => Promise<T>
   exportListApi?: (option: any) => Promise<T>
@@ -41,6 +42,7 @@ export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
   /**
    * grid options 初始化
    */
+  console.info(config?.allSchemas.tableSchema)
   const gridOptions = reactive<VxeGridProps>({
     loading: true,
     size: currentSize as any,
@@ -62,25 +64,6 @@ export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
       items: config?.allSchemas.searchSchema
     },
     columns: config?.allSchemas.tableSchema,
-    pagerConfig: {
-      border: false, // 带边框
-      background: true, // 带背景颜色
-      perfect: false, // 配套的样式
-      pageSize: 10, // 每页大小
-      pagerCount: 7, // 显示页码按钮的数量
-      autoHidden: true, // 当只有一页时自动隐藏
-      pageSizes: [5, 10, 20, 30, 50, 100], // 每页大小选项列表
-      layouts: [
-        'PrevJump',
-        'PrevPage',
-        'JumpNumber',
-        'NextPage',
-        'NextJump',
-        'Sizes',
-        'FullJump',
-        'Total'
-      ]
-    },
     proxyConfig: {
       seq: true, // 启用动态序号代理(分页之后索引自动计算为当前页的起始序号)
       form: true, // 启用表单代理,当点击表单提交按钮时会自动触发 reload 行为
@@ -91,8 +74,10 @@ export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
           if (config?.queryParams) {
             queryParams = Object.assign(queryParams, config.queryParams)
           }
-          queryParams.pageSize = page.pageSize
-          queryParams.pageNo = page.currentPage
+          if (!config?.treeConfig) {
+            queryParams.pageSize = page.pageSize
+            queryParams.pageNo = page.currentPage
+          }
           gridOptions.loading = false
           return new Promise(async (resolve) => {
             resolve(await config?.getListApi(queryParams))
@@ -120,6 +105,30 @@ export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
     }
   })
 
+  if (config?.treeConfig) {
+    gridOptions.treeConfig = config.treeConfig
+  } else {
+    gridOptions.pagerConfig = {
+      border: false, // 带边框
+      background: true, // 带背景颜色
+      perfect: false, // 配套的样式
+      pageSize: 10, // 每页大小
+      pagerCount: 7, // 显示页码按钮的数量
+      autoHidden: false, // 当只有一页时自动隐藏
+      pageSizes: [5, 10, 20, 30, 50, 100], // 每页大小选项列表
+      layouts: [
+        'PrevJump',
+        'PrevPage',
+        'JumpNumber',
+        'NextPage',
+        'NextJump',
+        'Sizes',
+        'FullJump',
+        'Total'
+      ]
+    }
+  }
+
   /**
    * 刷新列表
    * @param ref

+ 50 - 53
yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts

@@ -1,6 +1,9 @@
-import { required } from '@/utils/formRules'
 import { reactive } from 'vue'
-import { FormSchema } from '@/types/form'
+import { useI18n } from '@/hooks/web/useI18n'
+import { required } from '@/utils/formRules'
+import { DICT_TYPE } from '@/utils/dict'
+import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
+const { t } = useI18n() // 国际化
 
 // 表单校验
 export const rules = reactive({
@@ -17,55 +20,49 @@ export const rules = reactive({
   ]
 })
 
-export const modelSchema = reactive<FormSchema[]>([
-  {
-    label: '上级部门',
-    field: 'parentId',
-    component: 'Input'
-  },
-  {
-    label: '部门名称',
-    field: 'name',
-    component: 'Input',
-    formItemProps: {
-      rules: [required]
-    }
-  },
-  {
-    label: '负责人',
-    field: 'leaderUserId',
-    component: 'Input'
-  },
-  {
-    label: '联系电话',
-    field: 'phone',
-    component: 'Input'
-  },
-  {
-    label: '邮箱',
-    field: 'email',
-    component: 'Input'
-  },
-  {
-    label: '显示排序',
-    field: 'sort',
-    component: 'Input'
-  },
-  {
-    label: '状态',
-    field: 'status',
-    component: 'RadioButton',
-    componentProps: {
-      options: [
-        {
-          label: '开启',
-          value: 0
-        },
-        {
-          label: '关闭',
-          value: 1
-        }
-      ]
+// CrudSchema
+const crudSchemas = reactive<VxeCrudSchema>({
+  primaryKey: 'id',
+  primaryType: null,
+  action: true,
+  columns: [
+    {
+      title: '上级部门',
+      field: 'parentId',
+      isTable: false
+    },
+    {
+      title: '部门名称',
+      field: 'name',
+      isSearch: true,
+      table: {
+        treeNode: true,
+        align: 'left'
+      }
+    },
+    {
+      title: '负责人',
+      field: 'leaderUserId'
+    },
+    {
+      title: '联系电话',
+      field: 'phone'
+    },
+    {
+      title: '邮箱',
+      field: 'email'
+    },
+    {
+      title: '显示排序',
+      field: 'sort'
+    },
+    {
+      title: t('common.status'),
+      field: 'status',
+      dictType: DICT_TYPE.COMMON_STATUS,
+      dictData: 'number',
+      isSearch: true
     }
-  }
-])
+  ]
+})
+export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

+ 56 - 125
yudao-ui-admin-vue3/src/views/system/dept/index.vue

@@ -1,34 +1,8 @@
 <template>
   <ContentWrap>
-    <!-- 搜索工作栏 -->
-    <el-form :model="queryParams" ref="queryForm" :inline="true">
-      <el-form-item label="部门名称" prop="name">
-        <el-input v-model="queryParams.name" placeholder="请输入部门名称" />
-      </el-form-item>
-      <el-form-item label="状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择部门状态">
-          <el-option
-            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <!-- 操作:搜索 -->
-        <XButton
-          type="primary"
-          preIcon="ep:search"
-          :title="t('common.query')"
-          @click="handleQuery()"
-        />
-        <!-- 操作:重置 -->
-        <XButton preIcon="ep:refresh-right" :title="t('common.reset')" @click="resetQuery()" />
-      </el-form-item>
-    </el-form>
-    <vxe-toolbar>
-      <template #buttons>
+    <!-- 列表 -->
+    <vxe-grid ref="xGrid" v-bind="gridOptions" show-overflow class="xtable-scrollbar">
+      <template #toolbar_buttons>
         <!-- 操作:新增 -->
         <XButton
           type="primary"
@@ -37,58 +11,32 @@
           v-hasPermi="['system:dept:create']"
           @click="handleCreate()"
         />
-        <XButton title="展开所有" @click="xTable?.setAllTreeExpand(true)" />
-        <XButton title="关闭所有" @click="xTable?.clearTreeExpand()" />
+        <XButton title="展开所有" @click="xGrid?.setAllTreeExpand(true)" />
+        <XButton title="关闭所有" @click="xGrid?.clearTreeExpand()" />
       </template>
-    </vxe-toolbar>
-    <!-- 列表 -->
-    <vxe-table
-      show-overflow
-      keep-source
-      ref="xTable"
-      :loading="tableLoading"
-      :row-config="{ keyField: 'id' }"
-      :column-config="{ resizable: true }"
-      :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
-      :print-config="{}"
-      :export-config="{}"
-      :data="tableData"
-      class="xtable"
-    >
-      <vxe-column title="部门名称" field="name" width="200" tree-node />
-      <vxe-column title="负责人" field="leaderUserId" :formatter="userNicknameFormat" />
-      <vxe-column title="排序" field="sort" />
-      <vxe-column title="状态" field="status">
-        <template #default="{ row }">
-          <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
-        </template>
-      </vxe-column>
-      <vxe-column title="创建时间" field="createTime" formatter="formatDate" />
-      <vxe-column title="操作" width="200">
-        <template #default="{ row }">
-          <!-- 操作:修改 -->
-          <XTextButton
-            preIcon="ep:edit"
-            :title="t('action.edit')"
-            v-hasPermi="['system:dept:update']"
-            @click="handleUpdate(row.id)"
-          />
-          <!-- 操作:删除 -->
-          <XTextButton
-            preIcon="ep:delete"
-            :title="t('action.del')"
-            v-hasPermi="['system:dept:delete']"
-            @click="handleDelete(row.id)"
-          />
-        </template>
-      </vxe-column>
-    </vxe-table>
+      <template #actionbtns_default="{ row }">
+        <!-- 操作:修改 -->
+        <XTextButton
+          preIcon="ep:edit"
+          :title="t('action.edit')"
+          v-hasPermi="['system:dept:update']"
+          @click="handleUpdate(row.id)"
+        />
+        <!-- 操作:删除 -->
+        <XTextButton
+          preIcon="ep:delete"
+          :title="t('action.del')"
+          v-hasPermi="['system:dept:delete']"
+          @click="handleDelete(row.id)"
+        />
+      </template>
+    </vxe-grid>
   </ContentWrap>
   <!-- 添加或修改菜单对话框 -->
   <XModal id="deptModel" v-model="dialogVisible" :title="dialogTitle">
     <!-- 对话框(添加 / 修改) -->
     <!-- 操作工具栏 -->
-    <Form ref="formRef" :schema="modelSchema" :rules="rules">
+    <Form ref="formRef" :schema="allSchemas.formSchema" :rules="rules">
       <template #parentId>
         <el-tree-select
           node-key="id"
@@ -128,22 +76,32 @@
 import { nextTick, onMounted, reactive, ref, unref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useMessage } from '@/hooks/web/useMessage'
-import { ElForm, ElFormItem, ElInput, ElSelect, ElTreeSelect, ElOption } from 'element-plus'
-import { VxeTableInstance } from 'vxe-table'
-import { modelSchema } from './dept.data'
+import { VxeGridInstance } from 'vxe-table'
+import { ElSelect, ElTreeSelect, ElOption } from 'element-plus'
+import { allSchemas } from './dept.data'
 import * as DeptApi from '@/api/system/dept'
 import { getListSimpleUsersApi } from '@/api/system/user'
 import { required } from '@/utils/formRules.js'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { handleTree } from '@/utils/tree'
 import { FormExpose } from '@/components/Form'
+import { useVxeGrid } from '@/hooks/web/useVxeGrid'
 
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 // 列表相关的变量
-const xTable = ref<VxeTableInstance>()
-const tableLoading = ref(false)
-const tableData = ref()
+const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
+const treeConfig = {
+  transform: true,
+  rowField: 'id',
+  parentField: 'parentId',
+  expandAll: true
+}
+const { gridOptions, getList, deleteData } = useVxeGrid<DeptApi.DeptVO>({
+  allSchemas: allSchemas,
+  treeConfig: treeConfig,
+  getListApi: DeptApi.getDeptPageApi,
+  deleteApi: DeptApi.deleteDeptApi
+})
 // 弹窗相关的变量
 const dialogVisible = ref(false) // 是否显示弹出层
 const dialogTitle = ref('edit') // 弹出层标题
@@ -181,30 +139,6 @@ const getUserList = async () => {
   const res = await getListSimpleUsersApi()
   userOption.value = res
 }
-// ========== 查询 ==========
-const queryParams = reactive<DeptApi.DeptPageReqVO>({
-  name: undefined,
-  status: undefined
-})
-// 执行查询
-const getList = async () => {
-  tableLoading.value = true
-  const res = await DeptApi.getDeptPageApi(queryParams)
-  tableData.value = res
-  tableLoading.value = false
-}
-
-// 查询操作
-const handleQuery = async () => {
-  await getList()
-}
-
-// 重置操作
-const resetQuery = async () => {
-  queryParams.name = undefined
-  queryParams.status = undefined
-  await getList()
-}
 
 // ========== 新增/修改 ==========
 
@@ -247,13 +181,15 @@ const submitForm = async () => {
         data.leaderUserId = leaderUserId.value
         if (dialogTitle.value.startsWith('新增')) {
           await DeptApi.createDeptApi(data)
+          message.success(t('common.createSuccess'))
         } else if (dialogTitle.value.startsWith('修改')) {
           await DeptApi.updateDeptApi(data)
+          message.success(t('common.updateSuccess'))
         }
-        // 操作成功,重新加载列表
         dialogVisible.value = false
       } finally {
         actionLoading.value = false
+        await getList(xGrid)
       }
     }
   })
@@ -261,29 +197,24 @@ const submitForm = async () => {
 
 // 删除操作
 const handleDelete = async (rowId: number) => {
-  message.delConfirm().then(async () => {
-    await DeptApi.deleteDeptApi(rowId)
-    message.success(t('common.delSuccess'))
-    await getList()
-  })
-}
-
-const userNicknameFormat = (row) => {
-  if (!row && !row.row && !row.row.leaderUserId) {
-    return '未设置'
-  }
-  for (const user of userOption.value) {
-    if (row.row.leaderUserId === user.id) {
-      return user.nickname
-    }
-  }
-  return '未知【' + row.row.leaderUserId + '】'
+  await deleteData(xGrid, rowId)
 }
 
+//const userNicknameFormat = (row) => {
+//  if (!row && !row.row && !row.row.leaderUserId) {
+//    return '未设置'
+//  }
+//  for (const user of userOption.value) {
+//    if (row.row.leaderUserId === user.id) {
+//      return user.nickname
+//    }
+//  }
+//  return '未知【' + row.row.leaderUserId + '】'
+//}
+//
 // ========== 初始化 ==========
 onMounted(async () => {
   await getTree()
   await getUserList()
-  await getList()
 })
 </script>