Explorar o código

perf: vxe demo

xingyu4j %!s(int64=2) %!d(string=hai) anos
pai
achega
dc84ebde9d

+ 1 - 1
yudao-ui-admin-vue3/src/api/system/post/types.ts

@@ -5,7 +5,7 @@ export type PostVO = {
   sort: number
   status: number
   remark: string
-  createTime: string
+  createTime?: string
 }
 
 export type PostPageReqVO = {

+ 25 - 19
yudao-ui-admin-vue3/src/hooks/web/useVxeCrudSchemas.ts

@@ -3,6 +3,7 @@ import { getIntDictOptions } from '@/utils/dict'
 import { reactive } from 'vue'
 import {
   FormItemRenderOptions,
+  VxeColumnPropTypes,
   VxeFormItemProps,
   VxeGridPropTypes,
   VxeTableDefines
@@ -10,10 +11,13 @@ import {
 import { eachTree } from 'xe-utils'
 import { useI18n } from '@/hooks/web/useI18n'
 import { VxeTableColumn } from '@/types/table'
+import { FormSchema } from '@/types/form'
+import { ComponentOptions } from '@/types/components'
 
 export type VxeCrudSchema = Omit<VxeTableColumn, 'children'> & {
   field: string
   title?: string
+  formatter?: VxeColumnPropTypes.Formatter
   search?: CrudSearchParams
   table?: CrudTableParams
   form?: CrudFormParams
@@ -35,7 +39,7 @@ type CrudTableParams = {
 type CrudFormParams = {
   // 是否显示表单项
   show?: boolean
-} & Omit<VxeFormItemProps, 'field'>
+} & Omit<FormSchema, 'field'>
 
 type CrudDescriptionsParams = {
   // 是否显示表单项
@@ -47,10 +51,10 @@ type CrudPrintParams = {
   show?: boolean
 } & Omit<VxeTableDefines.ColumnInfo[], 'field'>
 
-interface VxeAllSchemas {
+export type VxeAllSchemas = {
   searchSchema: VxeFormItemProps[]
   tableSchema: VxeGridPropTypes.Columns
-  formSchema: VxeFormItemProps[]
+  formSchema: FormSchema[]
   detailSchema: DescriptionsSchema[]
   printSchema: VxeTableDefines.ColumnInfo[]
 }
@@ -160,6 +164,9 @@ const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Column
         field: schemaItem.field,
         title: schemaItem.table?.title || schemaItem.title
       }
+      if (schemaItem?.formatter) {
+        tableSchemaItem.formatter = schemaItem.formatter
+      }
 
       // 删除不必要的字段
       delete tableSchemaItem.show
@@ -171,32 +178,31 @@ const filterTableSchema = (crudSchema: VxeCrudSchema[]): VxeGridPropTypes.Column
 }
 
 // 过滤 form 结构
-const filterFormSchema = (crudSchema: VxeCrudSchema[]): VxeFormItemProps[] => {
-  const formSchema: VxeFormItemProps[] = []
-  const { t } = useI18n()
+const filterFormSchema = (crudSchema: VxeCrudSchema[]): FormSchema[] => {
+  const formSchema: FormSchema[] = []
+
   eachTree(crudSchema, (schemaItem: VxeCrudSchema) => {
     // 判断是否显示
     if (schemaItem?.form?.show !== false) {
-      let itemRenderName = schemaItem?.form?.itemRender?.name || '$input'
-      let itemRender: FormItemRenderOptions = {
-        name: itemRenderName,
-        props: { placeholder: t('common.inputText') }
-      }
+      let component = schemaItem?.form?.component || 'Input'
+      const options: ComponentOptions[] = []
+      let comonentProps = {}
       if (schemaItem.dictType) {
-        if (!(schemaItem.form && schemaItem.form.itemRender?.name)) itemRenderName = '$select'
-        itemRender = {
-          name: itemRenderName,
-          options: getIntDictOptions(schemaItem.dictType),
-          props: { placeholder: t('common.selectText') }
+        getIntDictOptions(schemaItem.dictType).forEach((dict) => {
+          options.push(dict)
+        })
+        comonentProps = {
+          options: options
         }
+        if (!(schemaItem.form && schemaItem.form.component)) component = 'Select'
       }
       const formSchemaItem = {
         // 默认为 input
-        itemRender: itemRender,
+        component: component,
+        componentProps: comonentProps,
         ...schemaItem.form,
-        span: schemaItem.form?.span || 12,
         field: schemaItem.field,
-        title: schemaItem.form?.title || schemaItem.title
+        label: schemaItem.form?.label || schemaItem.title
       }
 
       // 删除不必要的字段

+ 42 - 17
yudao-ui-admin-vue3/src/hooks/web/useVxeGrid.ts

@@ -1,6 +1,19 @@
 import { computed, reactive } from 'vue'
 import { VxeGridProps } from 'vxe-table'
 import { useAppStore } from '@/store/modules/app'
+import { VxeAllSchemas } from './useVxeCrudSchemas'
+import { useI18n } from '@/hooks/web/useI18n'
+import { useMessage } from '@/hooks/web/useMessage'
+
+const { t } = useI18n()
+const message = useMessage() // 消息弹窗
+
+interface UseVxeGridConfig<T = any> {
+  allSchemas: VxeAllSchemas
+  getListApi: (option: any) => Promise<T>
+  delListApi?: (option: any) => Promise<T>
+  exportListApi?: (option: any) => Promise<T>
+}
 
 const appStore = useAppStore()
 
@@ -14,36 +27,40 @@ const currentSize = computed(() => {
   }
 })
 
-export const useVxeGrid = (allSchemas, getPageApi) => {
+export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
   const gridOptions = reactive<VxeGridProps>({
-    loading: false,
+    loading: true,
     size: currentSize.value,
     height: 800,
     rowConfig: {
-      keyField: 'id',
-      isCurrent: true,
-      isHover: true
+      isCurrent: true, // 当鼠标点击行时,是否要高亮当前行
+      isHover: true // 当鼠标移到行时,是否要高亮当前行
+    },
+    showOverflow: 'tooltip', // 当内容溢出时显示为省略号
+    tooltipConfig: {
+      showAll: true // 开启全表工具提示
     },
     toolbarConfig: {
       custom: true,
       slots: { buttons: 'toolbar_buttons' }
     },
     printConfig: {
-      columns: allSchemas.printSchema
+      columns: config?.allSchemas.printSchema
     },
     formConfig: {
       titleWidth: 100,
       titleAlign: 'right',
-      items: allSchemas.searchSchema
+      items: config?.allSchemas.searchSchema
     },
-    columns: allSchemas.tableSchema,
+    columns: config?.allSchemas.tableSchema,
     pagerConfig: {
-      border: false,
-      background: false,
-      perfect: true,
-      pageSize: 10,
-      pagerCount: 7,
-      pageSizes: [5, 10, 15, 20, 50, 100, 200, 500],
+      border: false, // 带边框
+      background: true, // 带背景颜色
+      perfect: true, // 配套的样式
+      pageSize: 10, // 每页大小
+      pagerCount: 7, // 显示页码按钮的数量
+      autoHidden: true, // 当只有一页时自动隐藏
+      pageSizes: [5, 10, 15, 20, 50, 100, 200, 500], // 每页大小选项列表
       layouts: [
         'PrevJump',
         'PrevPage',
@@ -61,17 +78,25 @@ export const useVxeGrid = (allSchemas, getPageApi) => {
       props: { result: 'list', total: 'total' },
       ajax: {
         query: ({ page, form }) => {
-          gridOptions.loading = true
           const queryParams = Object.assign({}, form)
           queryParams.pageSize = page.pageSize
           queryParams.pageNo = page.currentPage
           gridOptions.loading = false
           return new Promise(async (resolve) => {
-            resolve(await getPageApi(queryParams))
+            resolve(await config?.getListApi(queryParams))
           })
         }
       }
     }
   })
-  return gridOptions
+  const delList = (ids: string | number | string[] | number[]) => {
+    message.delConfirm().then(() => {
+      config?.delListApi && config?.delListApi(ids)
+      message.success(t('common.delSuccess'))
+    })
+  }
+  return {
+    gridOptions,
+    delList
+  }
 }

+ 37 - 29
yudao-ui-admin-vue3/src/views/system/post/index.vue

@@ -44,12 +44,11 @@
   <XModal id="postModel" v-model="dialogVisible" :title="dialogTitle">
     <template #default>
       <!-- 对话框(添加 / 修改) -->
-      <vxe-form
-        ref="xForm"
+      <Form
         v-if="['create', 'update'].includes(actionType)"
-        :data="formData"
-        :items="formItems"
+        :schema="allSchemas.formSchema"
         :rules="rules"
+        ref="formRef"
       />
       <Descriptions
         v-if="actionType === 'detail'"
@@ -77,7 +76,7 @@
   </XModal>
 </template>
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref, unref } from 'vue'
 import dayjs from 'dayjs'
 import { DICT_TYPE } from '@/utils/dict'
 import * as PostApi from '@/api/system/post'
@@ -86,20 +85,22 @@ import { rules, allSchemas } from './post.data'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useMessage } from '@/hooks/web/useMessage'
 import { useVxeGrid } from '@/hooks/web/useVxeGrid'
-import { VxeFormEvents, VxeFormInstance, VxeFormItemProps, VxeGridInstance } from 'vxe-table'
+import { VxeFormEvents, VxeGridInstance } from 'vxe-table'
+import { FormExpose } from '@/components/Form'
 
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 const xGrid = ref<VxeGridInstance>()
-const xForm = ref<VxeFormInstance>()
+const formRef = ref<FormExpose>() // 表单 Ref
 const dialogVisible = ref(false) // 是否显示弹出层
 const dialogTitle = ref('edit') // 弹出层标题
 const actionType = ref('') // 操作按钮的类型
 const actionLoading = ref(false) // 按钮Loading
 
-const gridOptions = useVxeGrid(allSchemas, PostApi.getPostPageApi)
-const formData = ref<PostVO>()
-const formItems = ref<VxeFormItemProps[]>(allSchemas.formSchema)
+const { gridOptions } = useVxeGrid<PostVO>({
+  allSchemas: allSchemas,
+  getListApi: PostApi.getPostPageApi
+})
 // 设置标题
 const setDialogTile = (type: string) => {
   dialogTitle.value = t('action.' + type)
@@ -116,7 +117,8 @@ const handleDetail = (row: PostVO) => {
 // 新增操作
 const handleCreate = () => {
   setDialogTile('create')
-  formData.value = undefined
+  // 重置表单
+  unref(formRef)?.getElFormRef()?.resetFields()
 }
 
 // 修改操作
@@ -124,10 +126,10 @@ const handleUpdate = async (rowId: number) => {
   setDialogTile('update')
   // 设置数据
   const res = await PostApi.getPostApi(rowId)
-  formData.value = res
+  unref(formRef)?.setValues(res)
 }
 // 删除操作
-const handleDelete = (rowId: number) => {
+const handleDelete = async (rowId: number) => {
   message
     .delConfirm()
     .then(async () => {
@@ -140,22 +142,28 @@ const handleDelete = (rowId: number) => {
 }
 // 提交按钮
 const submitForm: VxeFormEvents.Submit = async () => {
-  actionLoading.value = true
-  // 提交请求
-  try {
-    const data = formData.value as PostVO
-    if (actionType.value === 'create') {
-      await PostApi.createPostApi(data)
-      message.success(t('common.createSuccess'))
-    } else {
-      await PostApi.updatePostApi(data)
-      message.success(t('common.updateSuccess'))
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
+    if (valid) {
+      actionLoading.value = true
+      // 提交请求
+      try {
+        const data = unref(formRef)?.formModel as PostVO
+        if (actionType.value === 'create') {
+          await PostApi.createPostApi(data)
+          message.success(t('common.createSuccess'))
+        } else {
+          await PostApi.updatePostApi(data)
+          message.success(t('common.updateSuccess'))
+        }
+        // 操作成功,重新加载列表
+        dialogVisible.value = false
+      } finally {
+        actionLoading.value = false
+        xGrid.value?.commitProxy('query')
+      }
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-  } finally {
-    actionLoading.value = false
-    xGrid.value?.commitProxy('query')
-  }
+  })
 }
 </script>

+ 8 - 2
yudao-ui-admin-vue3/src/views/system/post/post.data.ts

@@ -56,9 +56,17 @@ const crudSchemas = reactive<VxeCrudSchema[]>([
       show: true
     }
   },
+  {
+    title: '备注',
+    field: 'remark',
+    table: {
+      show: false
+    }
+  },
   {
     title: t('common.createTime'),
     field: 'createTime',
+    formatter: 'formatDate',
     form: {
       show: false
     }
@@ -66,10 +74,8 @@ const crudSchemas = reactive<VxeCrudSchema[]>([
   {
     title: t('table.action'),
     field: 'action',
-    width: '240px',
     table: {
       width: '240px',
-      showOverflow: true,
       slots: {
         default: 'action_default'
       }