Commit dc84ebde9ddc476c405c4a14f410bcdaf40b5387

Authored by xingyu4j
1 parent 1a45526a

perf: vxe demo

yudao-ui-admin-vue3/src/api/system/post/types.ts
@@ -5,7 +5,7 @@ export type PostVO = { @@ -5,7 +5,7 @@ export type PostVO = {
5 sort: number 5 sort: number
6 status: number 6 status: number
7 remark: string 7 remark: string
8 - createTime: string 8 + createTime?: string
9 } 9 }
10 10
11 export type PostPageReqVO = { 11 export type PostPageReqVO = {
yudao-ui-admin-vue3/src/hooks/web/useVxeCrudSchemas.ts
@@ -3,6 +3,7 @@ import { getIntDictOptions } from '@/utils/dict' @@ -3,6 +3,7 @@ import { getIntDictOptions } from '@/utils/dict'
3 import { reactive } from 'vue' 3 import { reactive } from 'vue'
4 import { 4 import {
5 FormItemRenderOptions, 5 FormItemRenderOptions,
  6 + VxeColumnPropTypes,
6 VxeFormItemProps, 7 VxeFormItemProps,
7 VxeGridPropTypes, 8 VxeGridPropTypes,
8 VxeTableDefines 9 VxeTableDefines
@@ -10,10 +11,13 @@ import { @@ -10,10 +11,13 @@ import {
10 import { eachTree } from 'xe-utils' 11 import { eachTree } from 'xe-utils'
11 import { useI18n } from '@/hooks/web/useI18n' 12 import { useI18n } from '@/hooks/web/useI18n'
12 import { VxeTableColumn } from '@/types/table' 13 import { VxeTableColumn } from '@/types/table'
  14 +import { FormSchema } from '@/types/form'
  15 +import { ComponentOptions } from '@/types/components'
13 16
14 export type VxeCrudSchema = Omit<VxeTableColumn, 'children'> & { 17 export type VxeCrudSchema = Omit<VxeTableColumn, 'children'> & {
15 field: string 18 field: string
16 title?: string 19 title?: string
  20 + formatter?: VxeColumnPropTypes.Formatter
17 search?: CrudSearchParams 21 search?: CrudSearchParams
18 table?: CrudTableParams 22 table?: CrudTableParams
19 form?: CrudFormParams 23 form?: CrudFormParams
@@ -35,7 +39,7 @@ type CrudTableParams = { @@ -35,7 +39,7 @@ type CrudTableParams = {
35 type CrudFormParams = { 39 type CrudFormParams = {
36 // 是否显示表单项 40 // 是否显示表单项
37 show?: boolean 41 show?: boolean
38 -} & Omit<VxeFormItemProps, 'field'> 42 +} & Omit<FormSchema, 'field'>
39 43
40 type CrudDescriptionsParams = { 44 type CrudDescriptionsParams = {
41 // 是否显示表单项 45 // 是否显示表单项
@@ -47,10 +51,10 @@ type CrudPrintParams = { @@ -47,10 +51,10 @@ type CrudPrintParams = {
47 show?: boolean 51 show?: boolean
48 } & Omit<VxeTableDefines.ColumnInfo[], 'field'> 52 } & Omit<VxeTableDefines.ColumnInfo[], 'field'>
49 53
50 -interface VxeAllSchemas { 54 +export type VxeAllSchemas = {
51 searchSchema: VxeFormItemProps[] 55 searchSchema: VxeFormItemProps[]
52 tableSchema: VxeGridPropTypes.Columns 56 tableSchema: VxeGridPropTypes.Columns
53 - formSchema: VxeFormItemProps[] 57 + formSchema: FormSchema[]
54 detailSchema: DescriptionsSchema[] 58 detailSchema: DescriptionsSchema[]
55 printSchema: VxeTableDefines.ColumnInfo[] 59 printSchema: VxeTableDefines.ColumnInfo[]
56 } 60 }
@@ -160,6 +164,9 @@ const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Column @@ -160,6 +164,9 @@ const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Column
160 field: schemaItem.field, 164 field: schemaItem.field,
161 title: schemaItem.table?.title || schemaItem.title 165 title: schemaItem.table?.title || schemaItem.title
162 } 166 }
  167 + if (schemaItem?.formatter) {
  168 + tableSchemaItem.formatter = schemaItem.formatter
  169 + }
163 170
164 // 删除不必要的字段 171 // 删除不必要的字段
165 delete tableSchemaItem.show 172 delete tableSchemaItem.show
@@ -171,32 +178,31 @@ const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Column @@ -171,32 +178,31 @@ const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Column
171 } 178 }
172 179
173 // 过滤 form 结构 180 // 过滤 form 结构
174 -const filterFormSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] => {  
175 - const formSchema: VxeFormItemProps[] = []  
176 - const { t } = useI18n() 181 +const filterFormSchema = (crudSchema: VxeCrudSchema[]): FormSchema[] => {
  182 + const formSchema: FormSchema[] = []
  183 +
177 eachTree(crudSchema, (schemaItem: VxeCrudSchema) => { 184 eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
178 // 判断是否显示 185 // 判断是否显示
179 if (schemaItem?.form?.show !== false) { 186 if (schemaItem?.form?.show !== false) {
180 - let itemRenderName = schemaItem?.form?.itemRender?.name || '$input'  
181 - let itemRender: FormItemRenderOptions = {  
182 - name: itemRenderName,  
183 - props: { placeholder: t('common.inputText') }  
184 - } 187 + let component = schemaItem?.form?.component || 'Input'
  188 + const options: ComponentOptions[] = []
  189 + let comonentProps = {}
185 if (schemaItem.dictType) { 190 if (schemaItem.dictType) {
186 - if (!(schemaItem.form && schemaItem.form.itemRender?.name)) itemRenderName = '$select'  
187 - itemRender = {  
188 - name: itemRenderName,  
189 - options: getIntDictOptions(schemaItem.dictType),  
190 - props: { placeholder: t('common.selectText') } 191 + getIntDictOptions(schemaItem.dictType).forEach((dict) => {
  192 + options.push(dict)
  193 + })
  194 + comonentProps = {
  195 + options: options
191 } 196 }
  197 + if (!(schemaItem.form && schemaItem.form.component)) component = 'Select'
192 } 198 }
193 const formSchemaItem = { 199 const formSchemaItem = {
194 // 默认为 input 200 // 默认为 input
195 - itemRender: itemRender, 201 + component: component,
  202 + componentProps: comonentProps,
196 ...schemaItem.form, 203 ...schemaItem.form,
197 - span: schemaItem.form?.span || 12,  
198 field: schemaItem.field, 204 field: schemaItem.field,
199 - title: schemaItem.form?.title || schemaItem.title 205 + label: schemaItem.form?.label || schemaItem.title
200 } 206 }
201 207
202 // 删除不必要的字段 208 // 删除不必要的字段
yudao-ui-admin-vue3/src/hooks/web/useVxeGrid.ts
1 import { computed, reactive } from 'vue' 1 import { computed, reactive } from 'vue'
2 import { VxeGridProps } from 'vxe-table' 2 import { VxeGridProps } from 'vxe-table'
3 import { useAppStore } from '@/store/modules/app' 3 import { useAppStore } from '@/store/modules/app'
  4 +import { VxeAllSchemas } from './useVxeCrudSchemas'
  5 +import { useI18n } from '@/hooks/web/useI18n'
  6 +import { useMessage } from '@/hooks/web/useMessage'
  7 +
  8 +const { t } = useI18n()
  9 +const message = useMessage() // 消息弹窗
  10 +
  11 +interface UseVxeGridConfig<T = any> {
  12 + allSchemas: VxeAllSchemas
  13 + getListApi: (option: any) => Promise<T>
  14 + delListApi?: (option: any) => Promise<T>
  15 + exportListApi?: (option: any) => Promise<T>
  16 +}
4 17
5 const appStore = useAppStore() 18 const appStore = useAppStore()
6 19
@@ -14,36 +27,40 @@ const currentSize = computed(() =&gt; { @@ -14,36 +27,40 @@ const currentSize = computed(() =&gt; {
14 } 27 }
15 }) 28 })
16 29
17 -export const useVxeGrid = (allSchemas, getPageApi) => { 30 +export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
18 const gridOptions = reactive<VxeGridProps>({ 31 const gridOptions = reactive<VxeGridProps>({
19 - loading: false, 32 + loading: true,
20 size: currentSize.value, 33 size: currentSize.value,
21 height: 800, 34 height: 800,
22 rowConfig: { 35 rowConfig: {
23 - keyField: 'id',  
24 - isCurrent: true,  
25 - isHover: true 36 + isCurrent: true, // 当鼠标点击行时,是否要高亮当前行
  37 + isHover: true // 当鼠标移到行时,是否要高亮当前行
  38 + },
  39 + showOverflow: 'tooltip', // 当内容溢出时显示为省略号
  40 + tooltipConfig: {
  41 + showAll: true // 开启全表工具提示
26 }, 42 },
27 toolbarConfig: { 43 toolbarConfig: {
28 custom: true, 44 custom: true,
29 slots: { buttons: 'toolbar_buttons' } 45 slots: { buttons: 'toolbar_buttons' }
30 }, 46 },
31 printConfig: { 47 printConfig: {
32 - columns: allSchemas.printSchema 48 + columns: config?.allSchemas.printSchema
33 }, 49 },
34 formConfig: { 50 formConfig: {
35 titleWidth: 100, 51 titleWidth: 100,
36 titleAlign: 'right', 52 titleAlign: 'right',
37 - items: allSchemas.searchSchema 53 + items: config?.allSchemas.searchSchema
38 }, 54 },
39 - columns: allSchemas.tableSchema, 55 + columns: config?.allSchemas.tableSchema,
40 pagerConfig: { 56 pagerConfig: {
41 - border: false,  
42 - background: false,  
43 - perfect: true,  
44 - pageSize: 10,  
45 - pagerCount: 7,  
46 - pageSizes: [5, 10, 15, 20, 50, 100, 200, 500], 57 + border: false, // 带边框
  58 + background: true, // 带背景颜色
  59 + perfect: true, // 配套的样式
  60 + pageSize: 10, // 每页大小
  61 + pagerCount: 7, // 显示页码按钮的数量
  62 + autoHidden: true, // 当只有一页时自动隐藏
  63 + pageSizes: [5, 10, 15, 20, 50, 100, 200, 500], // 每页大小选项列表
47 layouts: [ 64 layouts: [
48 'PrevJump', 65 'PrevJump',
49 'PrevPage', 66 'PrevPage',
@@ -61,17 +78,25 @@ export const useVxeGrid = (allSchemas, getPageApi) =&gt; { @@ -61,17 +78,25 @@ export const useVxeGrid = (allSchemas, getPageApi) =&gt; {
61 props: { result: 'list', total: 'total' }, 78 props: { result: 'list', total: 'total' },
62 ajax: { 79 ajax: {
63 query: ({ page, form }) => { 80 query: ({ page, form }) => {
64 - gridOptions.loading = true  
65 const queryParams = Object.assign({}, form) 81 const queryParams = Object.assign({}, form)
66 queryParams.pageSize = page.pageSize 82 queryParams.pageSize = page.pageSize
67 queryParams.pageNo = page.currentPage 83 queryParams.pageNo = page.currentPage
68 gridOptions.loading = false 84 gridOptions.loading = false
69 return new Promise(async (resolve) => { 85 return new Promise(async (resolve) => {
70 - resolve(await getPageApi(queryParams)) 86 + resolve(await config?.getListApi(queryParams))
71 }) 87 })
72 } 88 }
73 } 89 }
74 } 90 }
75 }) 91 })
76 - return gridOptions 92 + const delList = (ids: string | number | string[] | number[]) => {
  93 + message.delConfirm().then(() => {
  94 + config?.delListApi && config?.delListApi(ids)
  95 + message.success(t('common.delSuccess'))
  96 + })
  97 + }
  98 + return {
  99 + gridOptions,
  100 + delList
  101 + }
77 } 102 }
yudao-ui-admin-vue3/src/views/system/post/index.vue
@@ -44,12 +44,11 @@ @@ -44,12 +44,11 @@
44 <XModal id="postModel" v-model="dialogVisible" :title="dialogTitle"> 44 <XModal id="postModel" v-model="dialogVisible" :title="dialogTitle">
45 <template #default> 45 <template #default>
46 <!-- 对话框(添加 / 修改) --> 46 <!-- 对话框(添加 / 修改) -->
47 - <vxe-form  
48 - ref="xForm" 47 + <Form
49 v-if="['create', 'update'].includes(actionType)" 48 v-if="['create', 'update'].includes(actionType)"
50 - :data="formData"  
51 - :items="formItems" 49 + :schema="allSchemas.formSchema"
52 :rules="rules" 50 :rules="rules"
  51 + ref="formRef"
53 /> 52 />
54 <Descriptions 53 <Descriptions
55 v-if="actionType === 'detail'" 54 v-if="actionType === 'detail'"
@@ -77,7 +76,7 @@ @@ -77,7 +76,7 @@
77 </XModal> 76 </XModal>
78 </template> 77 </template>
79 <script setup lang="ts"> 78 <script setup lang="ts">
80 -import { ref } from 'vue' 79 +import { ref, unref } from 'vue'
81 import dayjs from 'dayjs' 80 import dayjs from 'dayjs'
82 import { DICT_TYPE } from '@/utils/dict' 81 import { DICT_TYPE } from '@/utils/dict'
83 import * as PostApi from '@/api/system/post' 82 import * as PostApi from '@/api/system/post'
@@ -86,20 +85,22 @@ import { rules, allSchemas } from &#39;./post.data&#39; @@ -86,20 +85,22 @@ import { rules, allSchemas } from &#39;./post.data&#39;
86 import { useI18n } from '@/hooks/web/useI18n' 85 import { useI18n } from '@/hooks/web/useI18n'
87 import { useMessage } from '@/hooks/web/useMessage' 86 import { useMessage } from '@/hooks/web/useMessage'
88 import { useVxeGrid } from '@/hooks/web/useVxeGrid' 87 import { useVxeGrid } from '@/hooks/web/useVxeGrid'
89 -import { VxeFormEvents, VxeFormInstance, VxeFormItemProps, VxeGridInstance } from 'vxe-table' 88 +import { VxeFormEvents, VxeGridInstance } from 'vxe-table'
  89 +import { FormExpose } from '@/components/Form'
90 90
91 const { t } = useI18n() // 国际化 91 const { t } = useI18n() // 国际化
92 const message = useMessage() // 消息弹窗 92 const message = useMessage() // 消息弹窗
93 const xGrid = ref<VxeGridInstance>() 93 const xGrid = ref<VxeGridInstance>()
94 -const xForm = ref<VxeFormInstance>() 94 +const formRef = ref<FormExpose>() // 表单 Ref
95 const dialogVisible = ref(false) // 是否显示弹出层 95 const dialogVisible = ref(false) // 是否显示弹出层
96 const dialogTitle = ref('edit') // 弹出层标题 96 const dialogTitle = ref('edit') // 弹出层标题
97 const actionType = ref('') // 操作按钮的类型 97 const actionType = ref('') // 操作按钮的类型
98 const actionLoading = ref(false) // 按钮Loading 98 const actionLoading = ref(false) // 按钮Loading
99 99
100 -const gridOptions = useVxeGrid(allSchemas, PostApi.getPostPageApi)  
101 -const formData = ref<PostVO>()  
102 -const formItems = ref<VxeFormItemProps[]>(allSchemas.formSchema) 100 +const { gridOptions } = useVxeGrid<PostVO>({
  101 + allSchemas: allSchemas,
  102 + getListApi: PostApi.getPostPageApi
  103 +})
103 // 设置标题 104 // 设置标题
104 const setDialogTile = (type: string) => { 105 const setDialogTile = (type: string) => {
105 dialogTitle.value = t('action.' + type) 106 dialogTitle.value = t('action.' + type)
@@ -116,7 +117,8 @@ const handleDetail = (row: PostVO) =&gt; { @@ -116,7 +117,8 @@ const handleDetail = (row: PostVO) =&gt; {
116 // 新增操作 117 // 新增操作
117 const handleCreate = () => { 118 const handleCreate = () => {
118 setDialogTile('create') 119 setDialogTile('create')
119 - formData.value = undefined 120 + // 重置表单
  121 + unref(formRef)?.getElFormRef()?.resetFields()
120 } 122 }
121 123
122 // 修改操作 124 // 修改操作
@@ -124,10 +126,10 @@ const handleUpdate = async (rowId: number) =&gt; { @@ -124,10 +126,10 @@ const handleUpdate = async (rowId: number) =&gt; {
124 setDialogTile('update') 126 setDialogTile('update')
125 // 设置数据 127 // 设置数据
126 const res = await PostApi.getPostApi(rowId) 128 const res = await PostApi.getPostApi(rowId)
127 - formData.value = res 129 + unref(formRef)?.setValues(res)
128 } 130 }
129 // 删除操作 131 // 删除操作
130 -const handleDelete = (rowId: number) => { 132 +const handleDelete = async (rowId: number) => {
131 message 133 message
132 .delConfirm() 134 .delConfirm()
133 .then(async () => { 135 .then(async () => {
@@ -140,22 +142,28 @@ const handleDelete = (rowId: number) =&gt; { @@ -140,22 +142,28 @@ const handleDelete = (rowId: number) =&gt; {
140 } 142 }
141 // 提交按钮 143 // 提交按钮
142 const submitForm: VxeFormEvents.Submit = async () => { 144 const submitForm: VxeFormEvents.Submit = async () => {
143 - actionLoading.value = true  
144 - // 提交请求  
145 - try {  
146 - const data = formData.value as PostVO  
147 - if (actionType.value === 'create') {  
148 - await PostApi.createPostApi(data)  
149 - message.success(t('common.createSuccess'))  
150 - } else {  
151 - await PostApi.updatePostApi(data)  
152 - message.success(t('common.updateSuccess')) 145 + const elForm = unref(formRef)?.getElFormRef()
  146 + if (!elForm) return
  147 + elForm.validate(async (valid) => {
  148 + if (valid) {
  149 + actionLoading.value = true
  150 + // 提交请求
  151 + try {
  152 + const data = unref(formRef)?.formModel as PostVO
  153 + if (actionType.value === 'create') {
  154 + await PostApi.createPostApi(data)
  155 + message.success(t('common.createSuccess'))
  156 + } else {
  157 + await PostApi.updatePostApi(data)
  158 + message.success(t('common.updateSuccess'))
  159 + }
  160 + // 操作成功,重新加载列表
  161 + dialogVisible.value = false
  162 + } finally {
  163 + actionLoading.value = false
  164 + xGrid.value?.commitProxy('query')
  165 + }
153 } 166 }
154 - // 操作成功,重新加载列表  
155 - dialogVisible.value = false  
156 - } finally {  
157 - actionLoading.value = false  
158 - xGrid.value?.commitProxy('query')  
159 - } 167 + })
160 } 168 }
161 </script> 169 </script>
yudao-ui-admin-vue3/src/views/system/post/post.data.ts
@@ -57,8 +57,16 @@ const crudSchemas = reactive&lt;VxeCrudSchema[]&gt;([ @@ -57,8 +57,16 @@ const crudSchemas = reactive&lt;VxeCrudSchema[]&gt;([
57 } 57 }
58 }, 58 },
59 { 59 {
  60 + title: '备注',
  61 + field: 'remark',
  62 + table: {
  63 + show: false
  64 + }
  65 + },
  66 + {
60 title: t('common.createTime'), 67 title: t('common.createTime'),
61 field: 'createTime', 68 field: 'createTime',
  69 + formatter: 'formatDate',
62 form: { 70 form: {
63 show: false 71 show: false
64 } 72 }
@@ -66,10 +74,8 @@ const crudSchemas = reactive&lt;VxeCrudSchema[]&gt;([ @@ -66,10 +74,8 @@ const crudSchemas = reactive&lt;VxeCrudSchema[]&gt;([
66 { 74 {
67 title: t('table.action'), 75 title: t('table.action'),
68 field: 'action', 76 field: 'action',
69 - width: '240px',  
70 table: { 77 table: {
71 width: '240px', 78 width: '240px',
72 - showOverflow: true,  
73 slots: { 79 slots: {
74 default: 'action_default' 80 default: 'action_default'
75 } 81 }