github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/hooks/web/useCrudSchemas.ts (about)

     1  import { reactive } from 'vue'
     2  import { eachTree, treeMap, filter } from '@/utils/tree'
     3  import { findIndex } from '@/utils'
     4  import { useDictStoreWithOut } from '@/store/modules/dict'
     5  import { useI18n } from '@/hooks/web/useI18n'
     6  import type { AxiosPromise } from 'axios'
     7  import { FormSchema } from '@/types/form'
     8  import { TableColumn } from '@/types/table'
     9  import { DescriptionsSchema } from '@/types/descriptions'
    10  
    11  export type CrudSchema = Omit<TableColumn, 'children'> & {
    12    search?: CrudSearchParams
    13    table?: CrudTableParams
    14    form?: CrudFormParams
    15    detail?: CrudDescriptionsParams
    16    children?: CrudSchema[]
    17  }
    18  
    19  type CrudSearchParams = {
    20    // 是否显示在查询项
    21    show?: boolean
    22    // 字典名称,会去取全局的字典
    23    dictName?: string
    24    // 接口
    25    api?: () => Promise<any>
    26    // 搜索字段
    27    field?: string
    28  } & Omit<FormSchema, 'field'>
    29  
    30  type CrudTableParams = {
    31    // 是否显示表头
    32    show?: boolean
    33  } & Omit<FormSchema, 'field'>
    34  
    35  type CrudFormParams = {
    36    // 字典名称,会去取全局的字典
    37    dictName?: string
    38    // 接口
    39    api?: () => Promise<any>
    40    // 是否显示表单项
    41    show?: boolean
    42  } & Omit<FormSchema, 'field'>
    43  
    44  type CrudDescriptionsParams = {
    45    // 是否显示表单项
    46    show?: boolean
    47  } & Omit<DescriptionsSchema, 'field'>
    48  
    49  const dictStore = useDictStoreWithOut()
    50  
    51  const { t } = useI18n()
    52  
    53  interface AllSchemas {
    54    searchSchema: FormSchema[]
    55    tableColumns: TableColumn[]
    56    formSchema: FormSchema[]
    57    detailSchema: DescriptionsSchema[]
    58  }
    59  
    60  // 过滤所有结构
    61  export const useCrudSchemas = (
    62    crudSchema: CrudSchema[]
    63  ): {
    64    allSchemas: AllSchemas
    65  } => {
    66    // 所有结构数据
    67    const allSchemas = reactive<AllSchemas>({
    68      searchSchema: [],
    69      tableColumns: [],
    70      formSchema: [],
    71      detailSchema: []
    72    })
    73  
    74    const searchSchema = filterSearchSchema(crudSchema, allSchemas)
    75    allSchemas.searchSchema = searchSchema || []
    76  
    77    const tableColumns = filterTableSchema(crudSchema)
    78    allSchemas.tableColumns = tableColumns || []
    79  
    80    const formSchema = filterFormSchema(crudSchema, allSchemas)
    81    allSchemas.formSchema = formSchema
    82  
    83    const detailSchema = filterDescriptionsSchema(crudSchema)
    84    allSchemas.detailSchema = detailSchema
    85  
    86    return {
    87      allSchemas
    88    }
    89  }
    90  
    91  // 过滤 Search 结构
    92  const filterSearchSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
    93    const searchSchema: FormSchema[] = []
    94  
    95    // 获取字典列表队列
    96    const searchRequestTask: Array<() => Promise<void>> = []
    97  
    98    eachTree(crudSchema, (schemaItem: CrudSchema) => {
    99      // 判断是否显示
   100      if (schemaItem?.search?.show) {
   101        const searchSchemaItem = {
   102          // 默认为 input
   103          component: schemaItem.search.component || 'Input',
   104          componentProps: {},
   105          ...schemaItem.search,
   106          field: schemaItem?.search?.field || schemaItem.field,
   107          label: schemaItem.search?.label || schemaItem.label
   108        }
   109  
   110        if (searchSchemaItem.dictName) {
   111          // 如果有 dictName 则证明是从字典中获取数据
   112          const dictArr = dictStore.getDictObj[searchSchemaItem.dictName]
   113          searchSchemaItem.componentProps!.options = filterOptions(dictArr)
   114        } else if (searchSchemaItem.api) {
   115          searchRequestTask.push(async () => {
   116            const res = await (searchSchemaItem.api as () => AxiosPromise)()
   117            if (res) {
   118              const index = findIndex(allSchemas.searchSchema, (v: FormSchema) => {
   119                return v.field === searchSchemaItem.field
   120              })
   121              if (index !== -1) {
   122                allSchemas.searchSchema[index]!.componentProps!.options = filterOptions(
   123                  res,
   124                  searchSchemaItem.componentProps.optionsAlias?.labelField
   125                )
   126              }
   127            }
   128          })
   129        }
   130  
   131        // 删除不必要的字段
   132        delete searchSchemaItem.show
   133        delete searchSchemaItem.dictName
   134  
   135        searchSchema.push(searchSchemaItem)
   136      }
   137    })
   138  
   139    for (const task of searchRequestTask) {
   140      task()
   141    }
   142  
   143    return searchSchema
   144  }
   145  
   146  // 过滤 table 结构
   147  const filterTableSchema = (crudSchema: CrudSchema[]): TableColumn[] => {
   148    const tableColumns = treeMap<CrudSchema>(crudSchema, {
   149      conversion: (schema: CrudSchema) => {
   150        if (schema?.table?.show !== false) {
   151          return {
   152            ...schema.table,
   153            ...schema
   154          }
   155        }
   156      }
   157    })
   158  
   159    // 第一次过滤会有 undefined 所以需要二次过滤
   160    return filter<TableColumn>(tableColumns as TableColumn[], (data) => {
   161      if (data.children === void 0) {
   162        delete data.children
   163      }
   164      return !!data.field
   165    })
   166  }
   167  
   168  // 过滤 form 结构
   169  const filterFormSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
   170    const formSchema: FormSchema[] = []
   171  
   172    // 获取字典列表队列
   173    const formRequestTask: Array<() => Promise<void>> = []
   174  
   175    eachTree(crudSchema, (schemaItem: CrudSchema) => {
   176      // 判断是否显示
   177      if (schemaItem?.form?.show !== false) {
   178        const formSchemaItem = {
   179          // 默认为 input
   180          component: schemaItem?.form?.component || 'Input',
   181          componentProps: {},
   182          ...schemaItem.form,
   183          field: schemaItem.field,
   184          label: schemaItem.search?.label || schemaItem.label
   185        }
   186  
   187        if (formSchemaItem.dictName) {
   188          // 如果有 dictName 则证明是从字典中获取数据
   189          const dictArr = dictStore.getDictObj[formSchemaItem.dictName]
   190          formSchemaItem.componentProps!.options = filterOptions(dictArr)
   191        } else if (formSchemaItem.api) {
   192          formRequestTask.push(async () => {
   193            const res = await (formSchemaItem.api as () => AxiosPromise)()
   194            if (res) {
   195              const index = findIndex(allSchemas.formSchema, (v: FormSchema) => {
   196                return v.field === formSchemaItem.field
   197              })
   198              if (index !== -1) {
   199                allSchemas.formSchema[index]!.componentProps!.options = filterOptions(
   200                  res,
   201                  formSchemaItem.componentProps.optionsAlias?.labelField
   202                )
   203              }
   204            }
   205          })
   206        }
   207  
   208        // 删除不必要的字段
   209        delete formSchemaItem.show
   210        delete formSchemaItem.dictName
   211  
   212        formSchema.push(formSchemaItem)
   213      }
   214    })
   215  
   216    for (const task of formRequestTask) {
   217      task()
   218    }
   219    return formSchema
   220  }
   221  
   222  // 过滤 descriptions 结构
   223  const filterDescriptionsSchema = (crudSchema: CrudSchema[]): DescriptionsSchema[] => {
   224    const descriptionsSchema: FormSchema[] = []
   225  
   226    eachTree(crudSchema, (schemaItem: CrudSchema) => {
   227      // 判断是否显示
   228      if (schemaItem?.detail?.show !== false) {
   229        const descriptionsSchemaItem = {
   230          ...schemaItem.detail,
   231          field: schemaItem.field,
   232          label: schemaItem.detail?.label || schemaItem.label
   233        }
   234  
   235        // 删除不必要的字段
   236        delete descriptionsSchemaItem.show
   237  
   238        descriptionsSchema.push(descriptionsSchemaItem)
   239      }
   240    })
   241  
   242    return descriptionsSchema
   243  }
   244  
   245  // 给options添加国际化
   246  const filterOptions = (options: Recordable, labelField?: string) => {
   247    return options?.map((v: Recordable) => {
   248      if (labelField) {
   249        v['labelField'] = t(v.labelField)
   250      } else {
   251        v['label'] = t(v.label)
   252      }
   253      return v
   254    })
   255  }