From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/hooks/web/useCrudSchemas.ts |  326 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 326 insertions(+), 0 deletions(-)

diff --git a/src/hooks/web/useCrudSchemas.ts b/src/hooks/web/useCrudSchemas.ts
new file mode 100644
index 0000000..458b57e
--- /dev/null
+++ b/src/hooks/web/useCrudSchemas.ts
@@ -0,0 +1,326 @@
+import { reactive } from 'vue'
+import { AxiosPromise } from 'axios'
+import { findIndex } from '@/utils'
+import { eachTree, filter, treeMap } from '@/utils/tree'
+import { getBoolDictOptions, getDictOptions, getIntDictOptions } from '@/utils/dict'
+
+import { FormSchema } from '@/types/form'
+import { TableColumn } from '@/types/table'
+import { DescriptionsSchema } from '@/types/descriptions'
+import { ComponentOptions, ComponentProps } from '@/types/components'
+import { DictTag } from '@/components/DictTag'
+import { cloneDeep, merge } from 'lodash-es'
+
+export type CrudSchema = Omit<TableColumn, 'children'> & {
+  isSearch?: boolean // 鏄惁鍦ㄦ煡璇㈡樉绀�
+  search?: CrudSearchParams // 鏌ヨ鐨勮缁嗛厤缃�
+  isTable?: boolean // 鏄惁鍦ㄥ垪琛ㄦ樉绀�
+  table?: CrudTableParams // 鍒楄〃鐨勮缁嗛厤缃�
+  isForm?: boolean // 鏄惁鍦ㄨ〃鍗曟樉绀�
+  form?: CrudFormParams // 琛ㄥ崟鐨勮缁嗛厤缃�
+  isDetail?: boolean // 鏄惁鍦ㄨ鎯呮樉绀�
+  detail?: CrudDescriptionsParams // 璇︽儏鐨勮缁嗛厤缃�
+  children?: CrudSchema[]
+  dictType?: string // 瀛楀吀绫诲瀷
+  dictClass?: 'string' | 'number' | 'boolean' // 瀛楀吀鏁版嵁绫诲瀷 string | number | boolean
+}
+
+type CrudSearchParams = {
+  // 鏄惁鏄剧ず鍦ㄦ煡璇㈤」
+  show?: boolean
+  // 鎺ュ彛
+  api?: () => Promise<any>
+  // 鎼滅储瀛楁
+  field?: string
+} & Omit<FormSchema, 'field'>
+
+type CrudTableParams = {
+  // 鏄惁鏄剧ず琛ㄥご
+  show?: boolean
+  // 鍒楀閰嶇疆
+  width?: number | string
+  // 鍒楁槸鍚﹀浐瀹氬湪宸︿晶鎴栬�呭彸渚�
+  fixed?: 'left' | 'right'
+} & Omit<FormSchema, 'field'>
+type CrudFormParams = {
+  // 鏄惁鏄剧ず琛ㄥ崟椤�
+  show?: boolean
+  // 鎺ュ彛
+  api?: () => Promise<any>
+} & Omit<FormSchema, 'field'>
+
+type CrudDescriptionsParams = {
+  // 鏄惁鏄剧ず琛ㄥ崟椤�
+  show?: boolean
+} & Omit<DescriptionsSchema, 'field'>
+
+interface AllSchemas {
+  searchSchema: FormSchema[]
+  tableColumns: TableColumn[]
+  formSchema: FormSchema[]
+  detailSchema: DescriptionsSchema[]
+}
+
+const { t } = useI18n()
+
+// 杩囨护鎵�鏈夌粨鏋�
+export const useCrudSchemas = (
+  crudSchema: CrudSchema[]
+): {
+  allSchemas: AllSchemas
+} => {
+  // 鎵�鏈夌粨鏋勬暟鎹�
+  const allSchemas = reactive<AllSchemas>({
+    searchSchema: [],
+    tableColumns: [],
+    formSchema: [],
+    detailSchema: []
+  })
+
+  const searchSchema = filterSearchSchema(crudSchema, allSchemas)
+  allSchemas.searchSchema = searchSchema || []
+
+  const tableColumns = filterTableSchema(crudSchema)
+  allSchemas.tableColumns = tableColumns || []
+
+  const formSchema = filterFormSchema(crudSchema, allSchemas)
+  allSchemas.formSchema = formSchema
+
+  const detailSchema = filterDescriptionsSchema(crudSchema)
+  allSchemas.detailSchema = detailSchema
+
+  return {
+    allSchemas
+  }
+}
+
+// 杩囨护 Search 缁撴瀯
+const filterSearchSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
+  const searchSchema: FormSchema[] = []
+
+  // 鑾峰彇瀛楀吀鍒楄〃闃熷垪
+  const searchRequestTask: Array<() => Promise<void>> = []
+  eachTree(crudSchema, (schemaItem: CrudSchema) => {
+    // 鍒ゆ柇鏄惁鏄剧ず
+    if (schemaItem?.isSearch || schemaItem.search?.show) {
+      let component = schemaItem?.search?.component || 'Input'
+      const options: ComponentOptions[] = []
+      let comonentProps: ComponentProps = {}
+      if (schemaItem.dictType) {
+        const allOptions: ComponentOptions = { label: '鍏ㄩ儴', value: '' }
+        options.push(allOptions)
+        getDictOptions(schemaItem.dictType).forEach((dict) => {
+          options.push(dict)
+        })
+        comonentProps = {
+          options: options
+        }
+        if (!schemaItem.search?.component) component = 'Select'
+      }
+
+      // updated by AKing: 瑙e喅浜嗗綋浣跨敤榛樿鐨刣ict閫夐」鏃讹紝form涓簨浠朵笉鑳借Е鍙戠殑闂
+      const searchSchemaItem = merge(
+        {
+          // 榛樿涓� input
+          component,
+          ...schemaItem.search,
+          field: schemaItem.field,
+          label: schemaItem.search?.label || schemaItem.label
+        },
+        { componentProps: comonentProps }
+      )
+      if (searchSchemaItem.api) {
+        searchRequestTask.push(async () => {
+          const res = await (searchSchemaItem.api as () => AxiosPromise)()
+          if (res) {
+            const index = findIndex(allSchemas.searchSchema, (v: FormSchema) => {
+              return v.field === searchSchemaItem.field
+            })
+            if (index !== -1) {
+              allSchemas.searchSchema[index]!.componentProps!.options = filterOptions(
+                res,
+                searchSchemaItem.componentProps.optionsAlias?.labelField
+              )
+            }
+          }
+        })
+      }
+      // 鍒犻櫎涓嶅繀瑕佺殑瀛楁
+      delete searchSchemaItem.show
+
+      searchSchema.push(searchSchemaItem)
+    }
+  })
+  for (const task of searchRequestTask) {
+    task()
+  }
+  return searchSchema
+}
+
+// 杩囨护 table 缁撴瀯
+const filterTableSchema = (crudSchema: CrudSchema[]): TableColumn[] => {
+  const tableColumns = treeMap<CrudSchema>(crudSchema, {
+    conversion: (schema: CrudSchema) => {
+      if (schema?.isTable !== false && schema?.table?.show !== false) {
+        // add by 鑺嬭壙锛氬鍔犲 dict 瀛楀吀鏁版嵁鐨勬敮鎸�
+        if (!schema.formatter && schema.dictType) {
+          schema.formatter = (_: Recordable, __: TableColumn, cellValue: any) => {
+            return h(DictTag, {
+              type: schema.dictType!, // ! 琛ㄧず涓�瀹氫笉涓虹┖
+              value: cellValue
+            })
+          }
+        }
+        return {
+          ...schema.table,
+          ...schema
+        }
+      }
+    }
+  })
+
+  // 绗竴娆¤繃婊や細鏈� undefined 鎵�浠ラ渶瑕佷簩娆¤繃婊�
+  return filter<TableColumn>(tableColumns as TableColumn[], (data) => {
+    if (data.children === void 0) {
+      delete data.children
+    }
+    return !!data.field
+  })
+}
+
+// 杩囨护 form 缁撴瀯
+const filterFormSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
+  const formSchema: FormSchema[] = []
+
+  // 鑾峰彇瀛楀吀鍒楄〃闃熷垪
+  const formRequestTask: Array<() => Promise<void>> = []
+
+  eachTree(crudSchema, (schemaItem: CrudSchema) => {
+    // 鍒ゆ柇鏄惁鏄剧ず
+    if (schemaItem?.isForm !== false && schemaItem?.form?.show !== false) {
+      let component = schemaItem?.form?.component || 'Input'
+      let defaultValue: any = ''
+      if (schemaItem.form?.value) {
+        defaultValue = schemaItem.form?.value
+      } else {
+        if (component === 'InputNumber') {
+          defaultValue = 0
+        }
+      }
+      let comonentProps: ComponentProps = {}
+      if (schemaItem.dictType) {
+        const options: ComponentOptions[] = []
+        if (schemaItem.dictClass && schemaItem.dictClass === 'number') {
+          getIntDictOptions(schemaItem.dictType).forEach((dict) => {
+            options.push(dict)
+          })
+        } else if (schemaItem.dictClass && schemaItem.dictClass === 'boolean') {
+          getBoolDictOptions(schemaItem.dictType).forEach((dict) => {
+            options.push(dict)
+          })
+        } else {
+          getDictOptions(schemaItem.dictType).forEach((dict) => {
+            options.push(dict)
+          })
+        }
+        comonentProps = {
+          options: options
+        }
+        if (!(schemaItem.form && schemaItem.form.component)) component = 'Select'
+      }
+
+      // updated by AKing: 瑙e喅浜嗗綋浣跨敤榛樿鐨刣ict閫夐」鏃讹紝form涓簨浠朵笉鑳借Е鍙戠殑闂
+      const formSchemaItem = merge(
+        {
+          // 榛樿涓� input
+          component,
+          value: defaultValue,
+          ...schemaItem.form,
+          field: schemaItem.field,
+          label: schemaItem.form?.label || schemaItem.label
+        },
+        { componentProps: comonentProps }
+      )
+
+      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
+
+      formSchema.push(formSchemaItem)
+    }
+  })
+
+  for (const task of formRequestTask) {
+    task()
+  }
+  return formSchema
+}
+
+// 杩囨护 descriptions 缁撴瀯
+const filterDescriptionsSchema = (crudSchema: CrudSchema[]): DescriptionsSchema[] => {
+  const descriptionsSchema: FormSchema[] = []
+
+  eachTree(crudSchema, (schemaItem: CrudSchema) => {
+    // 鍒ゆ柇鏄惁鏄剧ず
+    if (schemaItem?.isDetail !== false && schemaItem.detail?.show !== false) {
+      const descriptionsSchemaItem = {
+        ...schemaItem.detail,
+        field: schemaItem.field,
+        label: schemaItem.detail?.label || schemaItem.label
+      }
+      if (schemaItem.dictType) {
+        descriptionsSchemaItem.dictType = schemaItem.dictType
+      }
+      if (schemaItem.detail?.dateFormat || schemaItem.formatter == 'formatDate') {
+        // 浼樺厛浣跨敤 detail 涓嬬殑閰嶇疆锛屽鏋滄病鏈夐粯璁や负 YYYY-MM-DD HH:mm:ss
+        descriptionsSchemaItem.dateFormat = schemaItem?.detail?.dateFormat
+          ? schemaItem?.detail?.dateFormat
+          : 'YYYY-MM-DD HH:mm:ss'
+      }
+
+      // 鍒犻櫎涓嶅繀瑕佺殑瀛楁
+      delete descriptionsSchemaItem.show
+
+      descriptionsSchema.push(descriptionsSchemaItem)
+    }
+  })
+
+  return descriptionsSchema
+}
+
+// 缁檕ptions娣诲姞鍥介檯鍖�
+const filterOptions = (options: Recordable, labelField?: string) => {
+  return options?.map((v: Recordable) => {
+    if (labelField) {
+      v['labelField'] = t(v.labelField)
+    } else {
+      v['label'] = t(v.label)
+    }
+    return v
+  })
+}
+
+// 灏� tableColumns 鎸囧畾 fields 鏀惧埌鏈�鍓嶉潰
+export const sortTableColumns = (tableColumns: TableColumn[], field: string) => {
+  const fieldIndex = tableColumns.findIndex((item) => item.field === field)
+  const fieldColumn = cloneDeep(tableColumns[fieldIndex])
+  tableColumns.splice(fieldIndex, 1)
+  // 娣诲姞鍒板紑澶�
+  tableColumns.unshift(fieldColumn)
+}

--
Gitblit v1.8.0