Browse Source

perf: add useCrudSchemas demo

kailong321200875 2 years ago
parent
commit
ca3ce54630
4 changed files with 280 additions and 7 deletions
  1. 9 0
      mock/role/index.ts
  2. 41 7
      src/hooks/web/useCrudSchemas.ts
  3. 8 0
      src/router/index.ts
  4. 222 0
      src/views/hooks/useCrudSchemas.vue

+ 9 - 0
mock/role/index.ts

@@ -286,6 +286,14 @@ const adminList = [
         meta: {
           title: 'useWatermark'
         }
+      },
+      {
+        path: 'useCrudSchemas',
+        component: 'views/hooks/useCrudSchemas',
+        name: 'UseCrudSchemas',
+        meta: {
+          title: 'useCrudSchemas'
+        }
       }
     ]
   },
@@ -488,6 +496,7 @@ const testList: string[] = [
   '/Components/Sticky',
   '/hooks',
   '/hooks/useWatermark',
+  '/hooks/useCrudSchemas',
   '/level',
   '/level/menu1',
   '/level/menu1/menu1-1',

+ 41 - 7
src/hooks/web/useCrudSchemas.ts

@@ -18,8 +18,8 @@ type CrudSearchParams = {
   show?: boolean
   // 字典名称,会去取全局的字典
   dictName?: string
-  // 接口路径
-  dictUrl?: string
+  // 接口
+  api?: () => Promise<any>
 } & Omit<FormSchema, 'field'>
 
 type CrudTableParams = {
@@ -28,6 +28,10 @@ type CrudTableParams = {
 } & Omit<FormSchema, 'field'>
 
 type CrudFormParams = {
+  // 字典名称,会去取全局的字典
+  dictName?: string
+  // 接口
+  api?: () => Promise<any>
   // 是否显示表单项
   show?: boolean
 } & Omit<FormSchema, 'field'>
@@ -68,7 +72,7 @@ export const useCrudSchemas = (
   const tableColumns = filterTableSchema(crudSchema)
   allSchemas.tableColumns = tableColumns || []
 
-  const formSchema = filterFormSchema(crudSchema)
+  const formSchema = filterFormSchema(crudSchema, allSchemas)
   allSchemas.formSchema = formSchema
 
   const detailSchema = filterDescriptionsSchema(crudSchema)
@@ -157,27 +161,57 @@ const filterTableSchema = (crudSchema: CrudSchema[]): TableColumn[] => {
 }
 
 // 过滤 form 结构
-const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
+const filterFormSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
   const formSchema: FormSchema[] = []
 
+  // 获取字典列表队列
+  const formRequestTask: Array<() => Promise<void>> = []
+
   eachTree(crudSchema, (schemaItem: CrudSchema) => {
     // 判断是否显示
-    if (schemaItem?.form?.show !== false) {
+    if (schemaItem?.form?.show) {
       const formSchemaItem = {
         // 默认为 input
-        component: (schemaItem.form && schemaItem.form.component) || 'Input',
+        component: schemaItem.form.component || 'Input',
+        componentProps: {},
         ...schemaItem.form,
         field: schemaItem.field,
-        label: schemaItem.form?.label || schemaItem.label
+        label: schemaItem.search?.label || schemaItem.label
+      }
+
+      if (formSchemaItem.dictName) {
+        // 如果有 dictName 则证明是从字典中获取数据
+        const dictArr = dictStore.getDictObj[formSchemaItem.dictName]
+        formSchemaItem.componentProps!.options = filterOptions(dictArr)
+      } else if (formSchemaItem.api) {
+        formRequestTask.push(async () => {
+          const res = await (formSchemaItem.api as () => AxiosPromise)()
+          if (res) {
+            const index = findIndex(allSchemas.formSchema, (v: FormSchema) => {
+              return v.field === formSchemaItem.field
+            })
+            if (index !== -1) {
+              allSchemas.formSchema[index]!.componentProps!.options = filterOptions(
+                res,
+                formSchemaItem.componentProps.optionsAlias?.labelField
+              )
+            }
+          }
+        })
       }
 
       // 删除不必要的字段
       delete formSchemaItem.show
+      delete formSchemaItem.dictName
 
       formSchema.push(formSchemaItem)
     }
   })
 
+  for (const task of formRequestTask) {
+    task()
+  }
+
   return formSchema
 }
 

+ 8 - 0
src/router/index.ts

@@ -337,6 +337,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
         meta: {
           title: 'useWatermark'
         }
+      },
+      {
+        path: 'useCrudSchemas',
+        component: () => import('@/views/hooks/useCrudSchemas.vue'),
+        name: 'UseCrudSchemas',
+        meta: {
+          title: 'useCrudSchemas'
+        }
       }
     ]
   },

+ 222 - 0
src/views/hooks/useCrudSchemas.vue

@@ -0,0 +1,222 @@
+<script setup lang="ts">
+import { ContentWrap } from '@/components/ContentWrap'
+import { Search } from '@/components/Search'
+import { useI18n } from '@/hooks/web/useI18n'
+import { ElButton, ElTag } from 'element-plus'
+import { Table } from '@/components/Table'
+import { getTableListApi, delTableListApi } from '@/api/table'
+import { useTable } from '@/hooks/web/useTable'
+import { TableData } from '@/api/table/types'
+import { h, ref, reactive } from 'vue'
+import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
+import { useDictStore } from '@/store/modules/dict'
+import { getDictOneApi } from '@/api/common'
+
+const dictStore = useDictStore()
+
+const { register, tableObject, methods } = useTable<TableData>({
+  getListApi: getTableListApi,
+  delListApi: delTableListApi,
+  response: {
+    list: 'list',
+    total: 'total'
+  }
+})
+
+const { getList, setSearchParams } = methods
+
+getList()
+
+const { t } = useI18n()
+
+const crudSchemas = reactive<CrudSchema[]>([
+  {
+    field: 'index',
+    label: t('tableDemo.index'),
+    type: 'index',
+    form: {
+      show: false
+    },
+    detail: {
+      show: false
+    }
+  },
+  {
+    field: 'title',
+    label: t('tableDemo.title'),
+    search: {
+      show: true
+    },
+    form: {
+      colProps: {
+        span: 24
+      }
+    },
+    detail: {
+      span: 24
+    }
+  },
+  {
+    field: 'author',
+    label: t('tableDemo.author')
+  },
+  {
+    field: 'display_time',
+    label: t('tableDemo.displayTime'),
+    form: {
+      component: 'DatePicker',
+      componentProps: {
+        type: 'datetime',
+        valueFormat: 'YYYY-MM-DD HH:mm:ss'
+      }
+    }
+  },
+  {
+    field: 'importance',
+    label: t('tableDemo.importance'),
+    formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
+      return h(
+        ElTag,
+        {
+          type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
+        },
+        () =>
+          cellValue === 1
+            ? t('tableDemo.important')
+            : cellValue === 2
+            ? t('tableDemo.good')
+            : t('tableDemo.commonly')
+      )
+    },
+    search: {
+      show: true,
+      component: 'Select',
+      componentProps: {
+        options: dictStore.getDictObj.importance
+      }
+    },
+    form: {
+      component: 'Select',
+      componentProps: {
+        options: [
+          {
+            label: '重要',
+            value: 3
+          },
+          {
+            label: '良好',
+            value: 2
+          },
+          {
+            label: '一般',
+            value: 1
+          }
+        ]
+      }
+    }
+  },
+  {
+    field: 'importance2',
+    label: `${t('tableDemo.importance')}2`,
+    search: {
+      show: true,
+      component: 'Select',
+      dictName: 'importance'
+    }
+  },
+  {
+    field: 'importance3',
+    label: `${t('tableDemo.importance')}3`,
+    search: {
+      show: true,
+      component: 'Select',
+      api: async () => {
+        const res = await getDictOneApi()
+        return res.data
+      }
+    }
+  },
+  {
+    field: 'pageviews',
+    label: t('tableDemo.pageviews'),
+    form: {
+      component: 'InputNumber',
+      value: 0
+    }
+  },
+  {
+    field: 'content',
+    label: t('exampleDemo.content'),
+    table: {
+      show: false
+    },
+    form: {
+      component: 'Editor',
+      colProps: {
+        span: 24
+      }
+    },
+    detail: {
+      span: 24
+    }
+  },
+  {
+    field: 'action',
+    width: '260px',
+    label: t('tableDemo.action'),
+    form: {
+      show: false
+    },
+    detail: {
+      show: false
+    }
+  }
+])
+
+const { allSchemas } = useCrudSchemas(crudSchemas)
+
+const delLoading = ref(false)
+
+const delData = async (row: TableData | null, multiple: boolean) => {
+  tableObject.currentRow = row
+  const { delList, getSelections } = methods
+  const selections = await getSelections()
+  delLoading.value = true
+  await delList(
+    multiple ? selections.map((v) => v.id) : [tableObject.currentRow?.id as string],
+    multiple
+  ).finally(() => {
+    delLoading.value = false
+  })
+}
+</script>
+
+<template>
+  <ContentWrap>
+    <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
+
+    <div class="mb-10px">
+      <ElButton :loading="delLoading" type="danger" @click="delData(null, true)">
+        {{ t('exampleDemo.del') }}
+      </ElButton>
+    </div>
+
+    <Table
+      v-model:pageSize="tableObject.pageSize"
+      v-model:currentPage="tableObject.currentPage"
+      :columns="allSchemas.tableColumns"
+      :data="tableObject.tableList"
+      :loading="tableObject.loading"
+      :pagination="{
+        total: tableObject.total
+      }"
+      @register="register"
+    >
+      <template #action="{ row }">
+        <ElButton type="danger" @click="delData(row, false)">
+          {{ t('exampleDemo.del') }}
+        </ElButton>
+      </template>
+    </Table>
+  </ContentWrap>
+</template>