perf: tree table

This commit is contained in:
xingyu 2022-11-17 22:55:09 +08:00
parent 5d4673ac00
commit bc97bd30a0
4 changed files with 141 additions and 203 deletions

View File

@ -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) {

View File

@ -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)
}
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

View File

@ -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[]>([
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: null,
action: true,
columns: [
{
label: '上级部门',
title: '上级部门',
field: 'parentId',
component: 'Input'
isTable: false
},
{
label: '部门名称',
title: '部门名称',
field: 'name',
component: 'Input',
formItemProps: {
rules: [required]
isSearch: true,
table: {
treeNode: true,
align: 'left'
}
},
{
label: '负责人',
field: 'leaderUserId',
component: 'Input'
title: '负责人',
field: 'leaderUserId'
},
{
label: '联系电话',
field: 'phone',
component: 'Input'
title: '联系电话',
field: 'phone'
},
{
label: '邮箱',
field: 'email',
component: 'Input'
title: '邮箱',
field: 'email'
},
{
label: '显示排序',
field: 'sort',
component: 'Input'
title: '显示排序',
field: 'sort'
},
{
label: '状态',
title: t('common.status'),
field: 'status',
component: 'RadioButton',
componentProps: {
options: [
{
label: '开启',
value: 0
},
{
label: '关闭',
value: 1
dictType: DICT_TYPE.COMMON_STATUS,
dictData: 'number',
isSearch: true
}
]
}
}
])
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -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,35 +11,10 @@
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 }">
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
@ -81,14 +30,13 @@
@click="handleDelete(row.id)"
/>
</template>
</vxe-column>
</vxe-table>
</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>