Browse Source

fix: 修复Form已知问题

kailong321200875 1 year ago
parent
commit
097b32e1a9

+ 19 - 19
package.json

@@ -27,10 +27,10 @@
   },
   "dependencies": {
     "@iconify/iconify": "^3.1.0",
-    "@vueuse/core": "^10.1.2",
+    "@vueuse/core": "^10.2.0",
     "@wangeditor/editor": "^5.1.23",
     "@wangeditor/editor-for-vue": "^5.1.10",
-    "@zxcvbn-ts/core": "^3.0.1",
+    "@zxcvbn-ts/core": "^3.0.2",
     "animate.css": "^4.1.1",
     "axios": "^1.4.0",
     "dayjs": "^1.11.8",
@@ -42,43 +42,43 @@
     "mitt": "^3.0.0",
     "mockjs": "^1.1.0",
     "nprogress": "^0.2.0",
-    "pinia": "^2.1.3",
+    "pinia": "^2.1.4",
     "pinia-plugin-persist": "^1.0.0",
     "qrcode": "^1.5.3",
     "qs": "^6.11.2",
-    "url": "^0.11.0",
+    "url": "^0.11.1",
     "vue": "3.3.4",
     "vue-i18n": "9.2.2",
     "vue-router": "^4.2.2",
-    "vue-types": "^5.0.3",
+    "vue-types": "^5.0.4",
     "web-storage-cache": "^1.1.1"
   },
   "devDependencies": {
     "@commitlint/cli": "^17.6.5",
     "@commitlint/config-conventional": "^17.6.5",
-    "@iconify/json": "^2.2.74",
+    "@iconify/json": "^2.2.80",
     "@intlify/unplugin-vue-i18n": "^0.11.0",
     "@purge-icons/generated": "^0.9.0",
     "@types/intro.js": "^5.1.1",
     "@types/lodash-es": "^4.17.7",
-    "@types/node": "^20.2.5",
+    "@types/node": "^20.3.1",
     "@types/nprogress": "^0.2.0",
     "@types/qrcode": "^1.5.0",
     "@types/qs": "^6.9.7",
-    "@typescript-eslint/eslint-plugin": "^5.59.9",
-    "@typescript-eslint/parser": "^5.59.9",
-    "@unocss/transformer-variant-group": "^0.53.0",
+    "@typescript-eslint/eslint-plugin": "^5.59.11",
+    "@typescript-eslint/parser": "^5.59.11",
+    "@unocss/transformer-variant-group": "^0.53.1",
     "@vitejs/plugin-legacy": "^4.0.4",
     "@vitejs/plugin-vue": "^4.2.3",
     "@vitejs/plugin-vue-jsx": "^3.0.1",
-    "@vue-macros/volar": "^0.10.2",
+    "@vue-macros/volar": "^0.11.0",
     "autoprefixer": "^10.4.14",
     "consola": "^3.1.0",
-    "eslint": "^8.42.0",
+    "eslint": "^8.43.0",
     "eslint-config-prettier": "^8.8.0",
     "eslint-define-config": "^1.20.0",
     "eslint-plugin-prettier": "^4.2.1",
-    "eslint-plugin-vue": "^9.14.1",
+    "eslint-plugin-vue": "^9.15.0",
     "husky": "^8.0.3",
     "less": "^4.1.3",
     "lint-staged": "^13.2.2",
@@ -88,17 +88,17 @@
     "postcss-less": "^6.0.0",
     "prettier": "^2.8.8",
     "rimraf": "^5.0.1",
-    "rollup": "^3.23.1",
-    "stylelint": "^15.7.0",
+    "rollup": "^3.25.1",
+    "stylelint": "^15.8.0",
     "stylelint-config-html": "^1.1.0",
     "stylelint-config-prettier": "^9.0.5",
     "stylelint-config-recommended": "^12.0.0",
     "stylelint-config-standard": "^33.0.0",
     "stylelint-order": "^6.0.3",
-    "terser": "^5.17.7",
+    "terser": "^5.18.0",
     "typescript": "5.1.3",
-    "unocss": "^0.53.0",
-    "unplugin-vue-define-options": "^1.3.7",
+    "unocss": "^0.53.1",
+    "unplugin-vue-define-options": "^1.3.8",
     "vite": "4.3.9",
     "vite-plugin-ejs": "^1.6.4",
     "vite-plugin-eslint": "^1.8.1",
@@ -107,7 +107,7 @@
     "vite-plugin-purge-icons": "^0.9.2",
     "vite-plugin-style-import": "2.0.0",
     "vite-plugin-svg-icons": "^2.0.1",
-    "vue-tsc": "^1.6.5"
+    "vue-tsc": "^1.8.0"
   },
   "engines": {
     "node": ">= 14.18.0"

+ 8 - 25
src/components/Form/src/Form.vue

@@ -1,14 +1,5 @@
 <script lang="tsx">
-import {
-  PropType,
-  defineComponent,
-  ref,
-  computed,
-  unref,
-  watch,
-  onMounted,
-  defineAsyncComponent
-} from 'vue'
+import { PropType, defineComponent, ref, computed, unref, watch, onMounted } from 'vue'
 import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus'
 import { componentMap } from './helper/componentMap'
 import { propTypes } from '@/utils/propTypes'
@@ -132,9 +123,9 @@ export default defineComponent({
       return unref(elFormRef) as ComponentRef<typeof ElForm>
     }
 
-    const getOptions = async (fn: Function) => {
+    const getOptions = async (fn: Function, field: string) => {
       const options = await fn()
-      console.log('=====:', options)
+      console.log(field, options)
     }
 
     expose({
@@ -195,12 +186,16 @@ export default defineComponent({
 
     // 渲染formItem
     const renderFormItem = (item: FormSchema) => {
+      // 如果有optionApi,优先使用optionApi
+      if (item.optionApi) {
+        // 内部自动调用接口,不影响其他渲染
+        getOptions(item.optionApi, item.field)
+      }
       const formItemSlots: Recordable = {
         default: () => {
           if (slots[item.field]) {
             return getSlot(slots, item.field, formModel.value)
           } else {
-            console.log(item.field)
             const Com = componentMap[item.component as string] as ReturnType<typeof defineComponent>
 
             const { autoSetPlaceholder } = unref(getProps)
@@ -211,11 +206,6 @@ export default defineComponent({
             }
             // // 如果是select组件,并且没有自定义模板,自动渲染options
             if (item.component === ComponentNameEnum.SELECT) {
-              // 如果有optionApi,优先使用optionApi
-              if (item.optionApi) {
-                // 内部自动调用接口,不影响其他渲染
-                getOptions(item.optionApi)
-              }
               slotsMap.default = !componentSlots.default
                 ? () => renderSelectOptions(item)
                 : () => {
@@ -290,13 +280,6 @@ export default defineComponent({
       return (
         <ElFormItem {...(item.formItemProps || {})} prop={item.field} label={item.label || ''}>
           {formItemSlots}
-          {/* {{
-            default: () => {
-              console.log(item.field)
-
-              return '2222'
-            }
-          }} */}
         </ElFormItem>
       )
     }

+ 20 - 0
src/components/Form/src/types/index.ts

@@ -53,6 +53,7 @@ type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K
 export type ComponentName = CamelCaseComponentName
 
 export interface InputComponentProps {
+  ref?: any
   maxlength?: number | string
   minlength?: number | string
   showWordLimit?: boolean
@@ -98,6 +99,7 @@ export interface InputComponentProps {
 }
 
 export interface AutocompleteComponentProps {
+  ref?: any
   placeholder?: string
   clearable?: boolean
   disabled?: boolean
@@ -130,6 +132,7 @@ export interface AutocompleteComponentProps {
 }
 
 export interface InputNumberComponentProps {
+  ref?: any
   min?: number
   max?: number
   step?: number
@@ -164,6 +167,7 @@ export interface SelectOption {
 }
 
 export interface SelectComponentProps {
+  ref?: any
   multiple?: boolean
   disabled?: boolean
   valueKey?: string
@@ -241,6 +245,7 @@ export interface SelectComponentProps {
 }
 
 export interface SelectV2ComponentProps {
+  ref?: any
   multiple?: boolean
   disabled?: boolean
   valueKey?: string
@@ -285,6 +290,7 @@ export interface SelectV2ComponentProps {
 }
 
 export interface CascaderComponentProps {
+  ref?: any
   options?: Record<string, unknown>[]
   props?: CascaderProps
   size?: ElementPlusSize
@@ -319,6 +325,7 @@ export interface CascaderComponentProps {
 }
 
 export interface SwitchComponentProps {
+  ref?: any
   disabled?: boolean
   loading?: boolean
   size?: ElementPlusSize
@@ -340,6 +347,7 @@ export interface SwitchComponentProps {
 }
 
 export interface RateComponentProps {
+  ref?: any
   max?: number
   size?: ElementPlusSize
   disabled?: boolean
@@ -367,6 +375,7 @@ export interface RateComponentProps {
 }
 
 export interface ColorPickerComponentProps {
+  ref?: any
   disabled?: boolean
   size?: ElementPlusSize
   showAlpha?: boolean
@@ -384,6 +393,7 @@ export interface ColorPickerComponentProps {
 }
 
 export interface TransferComponentProps {
+  ref?: any
   data?: any[]
   filterable?: boolean
   filterPlaceholder?: string
@@ -434,6 +444,7 @@ export interface RadioOption {
   [key: string]: any
 }
 export interface RadioGroupComponentProps {
+  ref?: any
   size?: ElementPlusSize
   disabled?: boolean
   textColor?: string
@@ -461,6 +472,7 @@ export interface RadioGroupComponentProps {
 }
 
 export interface RadioButtonComponentProps {
+  ref?: any
   size?: ElementPlusSize
   disabled?: boolean
   textColor?: string
@@ -506,6 +518,7 @@ export interface CheckboxOption {
 }
 
 export interface CheckboxGroupComponentProps {
+  ref?: any
   size?: ElementPlusSize
   disabled?: boolean
   min?: number
@@ -534,6 +547,7 @@ export interface CheckboxGroupComponentProps {
 }
 
 export interface DividerComponentProps {
+  ref?: any
   min?: number
   max?: number
   disabled?: boolean
@@ -565,6 +579,7 @@ export interface DividerComponentProps {
 }
 
 export interface DatePickerComponentProps {
+  ref?: any
   readonly?: boolean
   disabled?: boolean
   size?: ElementPlusSize
@@ -616,6 +631,7 @@ export interface DatePickerComponentProps {
 }
 
 export interface DateTimePickerComponentProps {
+  ref?: any
   readonly?: boolean
   disabled?: boolean
   editable?: boolean
@@ -656,6 +672,7 @@ export interface DateTimePickerComponentProps {
 }
 
 export interface TimePickerComponentProps {
+  ref?: any
   readonly?: boolean
   disabled?: boolean
   editable?: boolean
@@ -692,6 +709,7 @@ export interface TimePickerComponentProps {
 }
 
 export interface TimeSelectComponentProps {
+  ref?: any
   disabled?: boolean
   editable?: boolean
   clearable?: boolean
@@ -716,6 +734,7 @@ export interface TimeSelectComponentProps {
 }
 
 export interface EditorComponentProps {
+  ref?: any
   editorConfig?: IEditorConfig
   style?: CSSProperties
 }
@@ -796,6 +815,7 @@ export interface FormSchema {
     | DateTimePickerComponentProps
     | TimePickerComponentProps
     | EditorComponentProps
+    | any
 
   /**
    * formItem组件属性,具体可以查看element-plus文档

+ 8 - 8
src/router/index.ts

@@ -148,16 +148,16 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
             meta: {
               title: t('router.defaultForm')
             }
+          },
+          {
+            path: 'use-form',
+            component: () => import('@/views/Components/Form/UseFormDemo.vue'),
+            name: 'UseForm',
+            meta: {
+              title: 'UseForm'
+            }
           }
           // {
-          //   path: 'use-form',
-          //   component: () => import('@/views/Components/Form/UseFormDemo.vue'),
-          //   name: 'UseForm',
-          //   meta: {
-          //     title: 'UseForm'
-          //   }
-          // }
-          // {
           //   path: 'ref-form',
           //   component: () => import('@/views/Components/Form/RefForm.vue'),
           //   name: 'RefForm',

+ 1001 - 1010
src/views/Components/Form/DefaultForm.vue

@@ -1,6 +1,6 @@
 <script setup lang="tsx">
 import { Form } from '@/components/Form'
-import { reactive, ref, onMounted, computed, unref } from 'vue'
+import { reactive, ref, onMounted, computed } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useIcon } from '@/hooks/web/useIcon'
 import { ContentWrap } from '@/components/ContentWrap'
@@ -383,1027 +383,1018 @@ const schema = reactive<FormSchema[]>([
       parser: (value) => value.replace(/\$\s?|(,*)/g, '')
     }
   },
-  // {
-  //   field: 'field3',
-  //   label: `${t('formDemo.icon')}1`,
-  //   component: 'Input',
-  //   componentProps: {
-  //     suffixIcon: useIcon({ icon: 'ep:calendar' }),
-  //     prefixIcon: useIcon({ icon: 'ep:share' })
-  //   }
-  // },
-  // {
-  //   field: 'field4',
-  //   label: `${t('formDemo.icon')}2`,
-  //   component: 'Input',
-  //   componentProps: {
-  //     slots: {
-  //       suffix: () => {
-  //         return useIcon({ icon: 'ep:share' })
-  //       },
-  //       prefix: () => useIcon({ icon: 'ep:calendar' })
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field5',
-  //   label: t('formDemo.mixed'),
-  //   component: 'Input',
-  //   componentProps: {
-  //     slots: {
-  //       prepend: () => useIcon({ icon: 'ep:calendar' }),
-  //       append: () => useIcon({ icon: 'ep:share' })
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'input-field7',
-  //   label: t('formDemo.password'),
-  //   component: 'Input',
-  //   componentProps: {
-  //     showPassword: true
-  //   }
-  // },
-  // {
-  //   field: 'field6',
-  //   label: t('formDemo.textarea'),
-  //   component: 'Input',
-  //   componentProps: {
-  //     type: 'textarea',
-  //     rows: 2
-  //   }
-  // },
-  // {
-  //   field: 'field7',
-  //   label: t('formDemo.autocomplete'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field8',
-  //   label: t('formDemo.default'),
-  //   component: 'Autocomplete',
-  //   componentProps: {
-  //     fetchSuggestions: querySearch,
-  //     on: {
-  //       select: handleSelect
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field9',
-  //   label: t('formDemo.slot'),
-  //   component: 'Autocomplete',
-  //   componentProps: {
-  //     fetchSuggestions: querySearch,
-  //     on: {
-  //       select: handleSelect
-  //     },
-  //     slots: {
-  //       default: ({ item }) => {
-  //         return (
-  //           <>
-  //             <div class="value">{item?.value}</div>
-  //             <span class="link">{item?.link}</span>
-  //           </>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'autocomplete-field10',
-  //   label: t('formDemo.remoteSearch'),
-  //   component: 'Autocomplete',
-  //   componentProps: {
-  //     fetchSuggestions: querySearchAsync,
-  //     on: {
-  //       select: handleSelect
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field10',
-  //   component: 'Divider',
-  //   label: t('formDemo.inputNumber')
-  // },
-  // {
-  //   field: 'field11',
-  //   label: t('formDemo.default'),
-  //   component: 'InputNumber',
-  //   value: 0
-  // },
-  // {
-  //   field: 'field12',
-  //   label: t('formDemo.position'),
-  //   component: 'InputNumber',
-  //   componentProps: {
-  //     controlsPosition: 'right'
-  //   },
-  //   value: 10
-  // },
-  // {
-  //   field: 'field13',
-  //   label: t('formDemo.select'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field14',
-  //   label: t('formDemo.default'),
-  //   component: 'Select',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         disabled: true,
-  //         label: 'option1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option2',
-  //         value: '2'
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field15',
-  //   label: t('formDemo.slot'),
-  //   component: 'Select',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         label: 'option1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option2',
-  //         value: '2'
-  //       }
-  //     ],
-  //     slots: {
-  //       default: (options: SelectOption[]) => {
-  //         if (options.length) {
-  //           return options?.map((v) => {
-  //             return <ElOption key={v.value} label={v.label} value={v.value} />
-  //           })
-  //         } else {
-  //           return null
-  //         }
-  //       },
-  //       prefix: () => useIcon({ icon: 'ep:calendar' }),
-  //       empty: () => {
-  //         return useIcon({ icon: 'ep:share' })
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'select-field18',
-  //   label: t('formDemo.optionSlot'),
-  //   component: 'Select',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         value: 'Beijing',
-  //         label: 'Beijing'
-  //       },
-  //       {
-  //         value: 'Shanghai',
-  //         label: 'Shanghai'
-  //       },
-  //       {
-  //         value: 'Nanjing',
-  //         label: 'Nanjing'
-  //       },
-  //       {
-  //         value: 'Chengdu',
-  //         label: 'Chengdu'
-  //       },
-  //       {
-  //         value: 'Shenzhen',
-  //         label: 'Shenzhen'
-  //       },
-  //       {
-  //         value: 'Guangzhou',
-  //         label: 'Guangzhou'
-  //       }
-  //     ],
-  //     slots: {
-  //       optionDefault: (option: SelectOption) => {
-  //         return (
-  //           <>
-  //             <span style="float: left">{option.label}</span>
-  //             <span style="float: right; color: var(--el-text-color-secondary); font-size: 13px;">
-  //               {option.value}
-  //             </span>
-  //           </>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field16',
-  //   label: t('formDemo.selectGroup'),
-  //   component: 'Select',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         label: 'option1',
-  //         options: [
-  //           {
-  //             disabled: true,
-  //             label: 'option1-1',
-  //             value: '1-1'
-  //           },
-  //           {
-  //             label: 'option1-2',
-  //             value: '1-2'
-  //           }
-  //         ]
-  //       },
-  //       {
-  //         label: 'option2',
-  //         options: [
-  //           {
-  //             label: 'option2-1',
-  //             value: '2-1'
-  //           },
-  //           {
-  //             label: 'option2-2',
-  //             value: '2-2'
-  //           }
-  //         ]
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field17',
-  //   label: `${t('formDemo.selectGroup')} ${t('formDemo.slot')}`,
-  //   component: 'Select',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         label: 'option1',
-  //         options: [
-  //           {
-  //             label: 'option1-1',
-  //             value: '1-1'
-  //           },
-  //           {
-  //             label: 'option1-2',
-  //             value: '1-2'
-  //           }
-  //         ]
-  //       },
-  //       {
-  //         label: 'option2',
-  //         options: [
-  //           {
-  //             label: 'option2-1',
-  //             value: '2-1'
-  //           },
-  //           {
-  //             label: 'option2-2',
-  //             value: '2-2'
-  //           }
-  //         ]
-  //       }
-  //     ],
-  //     slots: {
-  //       optionGroupDefault: (option: SelectOption) => {
-  //         return (
-  //           <ElOptionGroup key={option.label} label={`${option.label} ${option.label}`}>
-  //             {option?.options?.map((v) => {
-  //               return <ElOption key={v.value} label={v.label} value={v.value} />
-  //             })}
-  //           </ElOptionGroup>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field18',
-  //   label: `${t('formDemo.selectV2')}`,
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field19',
-  //   label: t('formDemo.default'),
-  //   component: 'SelectV2',
-  //   componentProps: {
-  //     value: undefined,
-  //     options: options.value
-  //   }
-  // },
-  // {
-  //   field: 'field20',
-  //   label: t('formDemo.slot'),
-  //   component: 'SelectV2',
-  //   componentProps: {
-  //     options: options.value,
-  //     slots: {
-  //       default: (option: SelectOption) => {
-  //         return (
-  //           <>
-  //             <span style="margin-right: 8px">{option?.label}</span>
-  //             <span style="color: var(--el-text-color-secondary); font-size: 13px">
-  //               {option?.value}
-  //             </span>
-  //           </>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field21',
-  //   label: t('formDemo.selectGroup'),
-  //   component: 'SelectV2',
-  //   componentProps: {
-  //     options: options2.value
-  //   }
-  // },
-  // {
-  //   field: 'field22',
-  //   label: `${t('formDemo.selectGroup')} ${t('formDemo.slot')}`,
-  //   component: 'SelectV2',
-  //   componentProps: {
-  //     options: options2.value,
-  //     slots: {
-  //       default: (option: SelectOption) => {
-  //         return (
-  //           <>
-  //             <span style="margin-right: 8px">{option?.label}</span>
-  //             <span style="color: var(--el-text-color-secondary); font-size: 13px">
-  //               {option?.value}
-  //             </span>
-  //           </>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field23',
-  //   label: t('formDemo.cascader'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field24',
-  //   label: t('formDemo.default'),
-  //   component: 'Cascader',
-  //   componentProps: {
-  //     options: options3,
-  //     props: {
-  //       multiple: true
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field25',
-  //   label: t('formDemo.slot'),
-  //   component: 'Cascader',
-  //   componentProps: {
-  //     options: options3,
-  //     slots: {
-  //       default: ({ data, node }) => {
-  //         return (
-  //           <>
-  //             <span>{data.label}</span>
-  //             {!node.isLeaf ? <span> ({data.children.length}) </span> : null}
-  //           </>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field26',
-  //   label: t('formDemo.switch'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field27',
-  //   label: t('formDemo.default'),
-  //   component: 'Switch',
-  //   value: false
-  // },
-  // {
-  //   field: 'field28',
-  //   label: t('formDemo.icon'),
-  //   component: 'Switch',
-  //   value: false,
-  //   componentProps: {
-  //     activeIcon: useIcon({ icon: 'ep:check' }),
-  //     inactiveIcon: useIcon({ icon: 'ep:close' })
-  //   }
-  // },
-  // {
-  //   field: 'field29',
-  //   label: t('formDemo.rate'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field30',
-  //   label: t('formDemo.default'),
-  //   component: 'Rate',
-  //   value: 0
-  // },
-  // {
-  //   field: 'field31',
-  //   label: t('formDemo.icon'),
-  //   component: 'Rate',
-  //   value: null,
-  //   componentProps: {
-  //     voidIcon: useIcon({ icon: 'ep:chat-round' }),
-  //     icons: [
-  //       useIcon({ icon: 'ep:chat-round' }),
-  //       useIcon({ icon: 'ep:chat-line-round' }),
-  //       useIcon({ icon: 'ep:chat-dot-round' })
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field32',
-  //   label: t('formDemo.colorPicker'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field33',
-  //   label: t('formDemo.default'),
-  //   component: 'ColorPicker'
-  // },
-  // {
-  //   field: 'field34',
-  //   label: t('formDemo.transfer'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field35',
-  //   label: t('formDemo.default'),
-  //   component: 'Transfer',
-  //   componentProps: {
-  //     props: {
-  //       key: 'value',
-  //       label: 'desc'
-  //     },
-  //     data: generateData()
-  //   },
-  //   value: [],
-  //   colProps: {
-  //     span: 24
-  //   }
-  // },
-  // {
-  //   field: 'field36',
-  //   label: t('formDemo.slot'),
-  //   component: 'Transfer',
-  //   componentProps: {
-  //     props: {
-  //       key: 'value',
-  //       label: 'desc'
-  //     },
-  //     filterable: true,
-  //     leftDefaultChecked: [2, 3],
-  //     rightDefaultChecked: [1],
-  //     titles: ['Source', 'Target'],
-  //     buttonTexts: ['To Left', 'To Right'],
-  //     format: {
-  //       noChecked: '${total}',
-  //       hasChecked: '${checked}/${total}'
-  //     },
-  //     data: generateData(),
-  //     slots: {
-  //       default: ({ option }) => {
-  //         return (
-  //           <span>
-  //             {option.value} - {option.desc}
-  //           </span>
-  //         )
-  //       },
-  //       leftFooter: () => {
-  //         return (
-  //           <ElButton class="transfer-footer" size="small">
-  //             Operation
-  //           </ElButton>
-  //         )
-  //       },
-  //       rightFooter: () => {
-  //         return (
-  //           <ElButton class="transfer-footer" size="small">
-  //             Operation
-  //           </ElButton>
-  //         )
-  //       }
-  //     }
-  //   },
-  //   value: [1],
-  //   colProps: {
-  //     span: 24
-  //   }
-  // },
-  // {
-  //   field: 'field37',
-  //   label: `${t('formDemo.render')}`,
-  //   component: 'Transfer',
-  //   componentProps: {
-  //     props: {
-  //       key: 'value',
-  //       label: 'desc',
-  //       disabled: 'disabled'
-  //     },
-  //     leftDefaultChecked: [2, 3],
-  //     rightDefaultChecked: [1],
-  //     data: generateData(),
-  //     renderContent: (h, option) => {
-  //       return h('span', null, `${option.value} - ${option.desc}`)
-  //     }
-  //   },
-  //   value: [1],
-  //   colProps: {
-  //     span: 24
-  //   }
-  // },
-  // {
-  //   field: 'field38',
-  //   label: t('formDemo.radio'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field39-2',
-  //   label: t('formDemo.radioGroup'),
-  //   component: 'RadioGroup',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         // disabled: true,
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field39-3',
-  //   label: `${t('formDemo.radioGroup')} ${t('formDemo.slot')}`,
-  //   component: 'RadioGroup',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         // disabled: true,
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       }
-  //     ],
-  //     slots: {
-  //       default: (options: RadioOption[]) => {
-  //         return options?.map((v) => {
-  //           return (
-  //             <ElRadio label={v.value}>
-  //               {v.label}({v.value})
-  //             </ElRadio>
-  //           )
-  //         })
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field40',
-  //   label: t('formDemo.button'),
-  //   component: 'RadioButton',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field40-1',
-  //   label: `${t('formDemo.button')} ${t('formDemo.slot')}`,
-  //   component: 'RadioButton',
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       }
-  //     ],
-  //     slots: {
-  //       default: (options: RadioOption[]) => {
-  //         return options?.map((v) => {
-  //           return (
-  //             <ElRadioButton label={v.value}>
-  //               {v.label}({v.value})
-  //             </ElRadioButton>
-  //           )
-  //         })
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field41',
-  //   label: t('formDemo.checkbox'),
-  //   component: 'Divider'
-  // },
-  // {
-  //   field: 'field42-2',
-  //   label: t('formDemo.checkboxGroup'),
-  //   component: 'CheckboxGroup',
-  //   value: [],
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       },
-  //       {
-  //         label: 'option-3',
-  //         value: '3'
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field42-3',
-  //   label: `${t('formDemo.checkboxGroup')} ${t('formDemo.slot')}`,
-  //   component: 'CheckboxGroup',
-  //   value: [],
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       },
-  //       {
-  //         label: 'option-3',
-  //         value: '3'
-  //       }
-  //     ],
-  //     slots: {
-  //       default: (options: CheckboxOption[]) => {
-  //         return options?.map((v) => {
-  //           return (
-  //             <ElCheckbox label={v.value}>
-  //               {v.label}({v.value})
-  //             </ElCheckbox>
-  //           )
-  //         })
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field43',
-  //   label: t('formDemo.button'),
-  //   component: 'CheckboxButton',
-  //   value: [],
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         disabled: true,
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       },
-  //       {
-  //         label: 'option-3',
-  //         value: '23'
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field43-1',
-  //   label: `${t('formDemo.button')} ${t('formDemo.slot')}`,
-  //   component: 'CheckboxButton',
-  //   value: [],
-  //   componentProps: {
-  //     options: [
-  //       {
-  //         disabled: true,
-  //         label: 'option-1',
-  //         value: '1'
-  //       },
-  //       {
-  //         label: 'option-2',
-  //         value: '2'
-  //       },
-  //       {
-  //         label: 'option-3',
-  //         value: '23'
-  //       }
-  //     ],
-  //     slots: {
-  //       default: (options: CheckboxOption[]) => {
-  //         return options?.map((v) => {
-  //           return (
-  //             <ElCheckboxButton label={v.value}>
-  //               {v.label}({v.value})
-  //             </ElCheckboxButton>
-  //           )
-  //         })
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field44',
-  //   component: 'Divider',
-  //   label: t('formDemo.slider')
-  // },
-  // {
-  //   field: 'field45',
-  //   component: 'Slider',
-  //   label: t('formDemo.default'),
-  //   value: 0
-  // },
-  // {
-  //   field: 'field46',
-  //   component: 'Divider',
-  //   label: t('formDemo.datePicker')
-  // },
-  // {
-  //   field: 'field47',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.default'),
-  //   componentProps: {
-  //     type: 'date'
-  //   }
-  // },
-  // {
-  //   field: 'field48',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.shortcuts'),
-  //   componentProps: {
-  //     type: 'date',
-  //     disabledDate: (time: Date) => {
-  //       return time.getTime() > Date.now()
-  //     },
-  //     shortcuts: [
-  //       {
-  //         text: t('formDemo.today'),
-  //         value: new Date()
-  //       },
-  //       {
-  //         text: t('formDemo.yesterday'),
-  //         value: () => {
-  //           const date = new Date()
-  //           date.setTime(date.getTime() - 3600 * 1000 * 24)
-  //           return date
-  //         }
-  //       },
-  //       {
-  //         text: t('formDemo.aWeekAgo'),
-  //         value: () => {
-  //           const date = new Date()
-  //           date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
-  //           return date
-  //         }
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field47-1',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.slot'),
-  //   value: '2021-10-29',
-  //   componentProps: {
-  //     type: 'date',
-  //     slots: {
-  //       default: (cell: any) => {
-  //         return (
-  //           <div class={{ cell: true, current: cell.isCurrent }}>
-  //             <span class="text">{cell.text}</span>
-  //             {isHoliday(cell) ? <span class="holiday" /> : null}
-  //           </div>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
-  // {
-  //   field: 'field49',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.week'),
-  //   componentProps: {
-  //     type: 'week',
-  //     format: `[${t('formDemo.week')}]`
-  //   }
-  // },
-  // {
-  //   field: 'field50',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.year'),
-  //   componentProps: {
-  //     type: 'year'
-  //   }
-  // },
-  // {
-  //   field: 'field51',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.month'),
-  //   componentProps: {
-  //     type: 'month'
-  //   }
-  // },
-  // {
-  //   field: 'field52',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.dates'),
-  //   componentProps: {
-  //     type: 'dates'
-  //   }
-  // },
-  // {
-  //   field: 'field53',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.daterange'),
-  //   componentProps: {
-  //     type: 'daterange'
-  //   }
-  // },
-  // {
-  //   field: 'field54',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.monthrange'),
-  //   componentProps: {
-  //     type: 'monthrange'
-  //   }
-  // },
-  // {
-  //   field: 'field56',
-  //   component: 'Divider',
-  //   label: t('formDemo.dateTimePicker')
-  // },
-  // {
-  //   field: 'field57',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.default'),
-  //   componentProps: {
-  //     type: 'datetime'
-  //   }
-  // },
-  // {
-  //   field: 'field58',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.shortcuts'),
-  //   componentProps: {
-  //     type: 'datetime',
-  //     shortcuts: [
-  //       {
-  //         text: t('formDemo.today'),
-  //         value: new Date()
-  //       },
-  //       {
-  //         text: t('formDemo.yesterday'),
-  //         value: () => {
-  //           const date = new Date()
-  //           date.setTime(date.getTime() - 3600 * 1000 * 24)
-  //           return date
-  //         }
-  //       },
-  //       {
-  //         text: t('formDemo.aWeekAgo'),
-  //         value: () => {
-  //           const date = new Date()
-  //           date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
-  //           return date
-  //         }
-  //       }
-  //     ]
-  //   }
-  // },
-  // {
-  //   field: 'field59',
-  //   component: 'DatePicker',
-  //   label: t('formDemo.dateTimerange'),
-  //   componentProps: {
-  //     type: 'datetimerange'
-  //   }
-  // },
-  // {
-  //   field: 'field60',
-  //   component: 'Divider',
-  //   label: t('formDemo.timePicker')
-  // },
-  // {
-  //   field: 'field61',
-  //   component: 'TimePicker',
-  //   label: t('formDemo.default')
-  // },
-  // {
-  //   field: 'field62',
-  //   component: 'Divider',
-  //   label: t('formDemo.timeSelect')
-  // },
-  // {
-  //   field: 'field63',
-  //   component: 'TimeSelect',
-  //   label: t('formDemo.default')
-  // },
-  // {
-  //   field: 'field64',
-  //   component: 'Divider',
-  //   label: t('formDemo.richText')
-  // },
-  // {
-  //   field: 'field65',
-  //   component: 'Editor',
-  //   value: 'hello world',
-  //   label: t('formDemo.default'),
-  //   colProps: {
-  //     span: 24
-  //   }
-  // },
-  // {
-  //   field: 'field66',
-  //   component: 'Divider',
-  //   label: t('formDemo.inputPassword')
-  // },
-  // {
-  //   field: 'field67',
-  //   component: 'InputPassword',
-  //   label: t('formDemo.default'),
-  //   componentProps: {
-  //     strength: true
-  //   }
-  // },
-  // {
-  //   field: 'field68',
-  //   component: 'Divider',
-  //   label: `${t('formDemo.form')} ${t('formDemo.slot')}`
-  // },
-  // {
-  //   field: 'field69',
-  //   component: 'Input',
-  //   label: `label`,
-  //   formItemProps: {
-  //     slots: {
-  //       label: ({ label }) => {
-  //         return (
-  //           <div class="custom-label">
-  //             <span class="label-text">custom {label}</span>
-  //           </div>
-  //         )
-  //       }
-  //     }
-  //   }
-  // },
   {
-    field: 'field70',
+    field: 'field3',
+    label: `${t('formDemo.icon')}1`,
+    component: 'Input',
+    componentProps: {
+      suffixIcon: useIcon({ icon: 'ep:calendar' }),
+      prefixIcon: useIcon({ icon: 'ep:share' })
+    }
+  },
+  {
+    field: 'field4',
+    label: `${t('formDemo.icon')}2`,
+    component: 'Input',
+    componentProps: {
+      slots: {
+        suffix: () => {
+          return useIcon({ icon: 'ep:share' })
+        },
+        prefix: () => useIcon({ icon: 'ep:calendar' })
+      }
+    }
+  },
+  {
+    field: 'field5',
+    label: t('formDemo.mixed'),
+    component: 'Input',
+    componentProps: {
+      slots: {
+        prepend: () => useIcon({ icon: 'ep:calendar' }),
+        append: () => useIcon({ icon: 'ep:share' })
+      }
+    }
+  },
+  {
+    field: 'input-field7',
+    label: t('formDemo.password'),
+    component: 'Input',
+    componentProps: {
+      showPassword: true
+    }
+  },
+  {
+    field: 'field6',
+    label: t('formDemo.textarea'),
+    component: 'Input',
+    componentProps: {
+      type: 'textarea',
+      rows: 2
+    }
+  },
+  {
+    field: 'field7',
+    label: t('formDemo.autocomplete'),
+    component: 'Divider'
+  },
+  {
+    field: 'field8',
+    label: t('formDemo.default'),
+    component: 'Autocomplete',
+    componentProps: {
+      fetchSuggestions: querySearch,
+      on: {
+        select: handleSelect
+      }
+    }
+  },
+  {
+    field: 'field9',
+    label: t('formDemo.slot'),
+    component: 'Autocomplete',
+    componentProps: {
+      fetchSuggestions: querySearch,
+      on: {
+        select: handleSelect
+      },
+      slots: {
+        default: ({ item }) => {
+          return (
+            <>
+              <div class="value">{item?.value}</div>
+              <span class="link">{item?.link}</span>
+            </>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'autocomplete-field10',
+    label: t('formDemo.remoteSearch'),
+    component: 'Autocomplete',
+    componentProps: {
+      fetchSuggestions: querySearchAsync,
+      on: {
+        select: handleSelect
+      }
+    }
+  },
+  {
+    field: 'field10',
     component: 'Divider',
-    label: `${t('formDemo.remoteLoading')}`
+    label: t('formDemo.inputNumber')
   },
   {
-    field: 'field71',
-    label: `${t('formDemo.select')}`,
+    field: 'field11',
+    label: t('formDemo.default'),
+    component: 'InputNumber',
+    value: 0
+  },
+  {
+    field: 'field12',
+    label: t('formDemo.position'),
+    component: 'InputNumber',
+    componentProps: {
+      controlsPosition: 'right'
+    },
+    value: 10
+  },
+  {
+    field: 'field13',
+    label: t('formDemo.select'),
+    component: 'Divider'
+  },
+  {
+    field: 'field14',
+    label: t('formDemo.default'),
+    component: 'Select',
+    componentProps: {
+      options: [
+        {
+          disabled: true,
+          label: 'option1',
+          value: '1'
+        },
+        {
+          label: 'option2',
+          value: '2'
+        }
+      ]
+    }
+  },
+  {
+    field: 'field15',
+    label: t('formDemo.slot'),
     component: 'Select',
     componentProps: {
       options: [
         {
-          label: 'option1-1',
-          value: '1-1'
+          label: 'option1',
+          value: '1'
+        },
+        {
+          label: 'option2',
+          value: '2'
+        }
+      ],
+      slots: {
+        default: (options: SelectOption[]) => {
+          if (options.length) {
+            return options?.map((v) => {
+              return <ElOption key={v.value} label={v.label} value={v.value} />
+            })
+          } else {
+            return null
+          }
+        },
+        prefix: () => useIcon({ icon: 'ep:calendar' }),
+        empty: () => {
+          return useIcon({ icon: 'ep:share' })
+        }
+      }
+    }
+  },
+  {
+    field: 'select-field18',
+    label: t('formDemo.optionSlot'),
+    component: 'Select',
+    componentProps: {
+      options: [
+        {
+          value: 'Beijing',
+          label: 'Beijing'
+        },
+        {
+          value: 'Shanghai',
+          label: 'Shanghai'
+        },
+        {
+          value: 'Nanjing',
+          label: 'Nanjing'
+        },
+        {
+          value: 'Chengdu',
+          label: 'Chengdu'
+        },
+        {
+          value: 'Shenzhen',
+          label: 'Shenzhen'
+        },
+        {
+          value: 'Guangzhou',
+          label: 'Guangzhou'
+        }
+      ],
+      slots: {
+        optionDefault: (option: SelectOption) => {
+          return (
+            <>
+              <span style="float: left">{option.label}</span>
+              <span style="float: right; color: var(--el-text-color-secondary); font-size: 13px;">
+                {option.value}
+              </span>
+            </>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'field16',
+    label: t('formDemo.selectGroup'),
+    component: 'Select',
+    componentProps: {
+      options: [
+        {
+          label: 'option1',
+          options: [
+            {
+              disabled: true,
+              label: 'option1-1',
+              value: '1-1'
+            },
+            {
+              label: 'option1-2',
+              value: '1-2'
+            }
+          ]
+        },
+        {
+          label: 'option2',
+          options: [
+            {
+              label: 'option2-1',
+              value: '2-1'
+            },
+            {
+              label: 'option2-2',
+              value: '2-2'
+            }
+          ]
+        }
+      ]
+    }
+  },
+  {
+    field: 'field17',
+    label: `${t('formDemo.selectGroup')} ${t('formDemo.slot')}`,
+    component: 'Select',
+    componentProps: {
+      options: [
+        {
+          label: 'option1',
+          options: [
+            {
+              label: 'option1-1',
+              value: '1-1'
+            },
+            {
+              label: 'option1-2',
+              value: '1-2'
+            }
+          ]
+        },
+        {
+          label: 'option2',
+          options: [
+            {
+              label: 'option2-1',
+              value: '2-1'
+            },
+            {
+              label: 'option2-2',
+              value: '2-2'
+            }
+          ]
+        }
+      ],
+      slots: {
+        optionGroupDefault: (option: SelectOption) => {
+          return (
+            <ElOptionGroup key={option.label} label={`${option.label} ${option.label}`}>
+              {option?.options?.map((v) => {
+                return <ElOption key={v.value} label={v.label} value={v.value} />
+              })}
+            </ElOptionGroup>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'field18',
+    label: `${t('formDemo.selectV2')}`,
+    component: 'Divider'
+  },
+  {
+    field: 'field19',
+    label: t('formDemo.default'),
+    component: 'SelectV2',
+    componentProps: {
+      value: undefined,
+      options: options.value
+    }
+  },
+  {
+    field: 'field20',
+    label: t('formDemo.slot'),
+    component: 'SelectV2',
+    componentProps: {
+      options: options.value,
+      slots: {
+        default: (option: SelectOption) => {
+          return (
+            <>
+              <span style="margin-right: 8px">{option?.label}</span>
+              <span style="color: var(--el-text-color-secondary); font-size: 13px">
+                {option?.value}
+              </span>
+            </>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'field21',
+    label: t('formDemo.selectGroup'),
+    component: 'SelectV2',
+    componentProps: {
+      options: options2.value
+    }
+  },
+  {
+    field: 'field22',
+    label: `${t('formDemo.selectGroup')} ${t('formDemo.slot')}`,
+    component: 'SelectV2',
+    componentProps: {
+      options: options2.value,
+      slots: {
+        default: (option: SelectOption) => {
+          return (
+            <>
+              <span style="margin-right: 8px">{option?.label}</span>
+              <span style="color: var(--el-text-color-secondary); font-size: 13px">
+                {option?.value}
+              </span>
+            </>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'field23',
+    label: t('formDemo.cascader'),
+    component: 'Divider'
+  },
+  {
+    field: 'field24',
+    label: t('formDemo.default'),
+    component: 'Cascader',
+    componentProps: {
+      options: options3,
+      props: {
+        multiple: true
+      }
+    }
+  },
+  {
+    field: 'field25',
+    label: t('formDemo.slot'),
+    component: 'Cascader',
+    componentProps: {
+      options: options3,
+      slots: {
+        default: ({ data, node }) => {
+          return (
+            <>
+              <span>{data.label}</span>
+              {!node.isLeaf ? <span> ({data.children.length}) </span> : null}
+            </>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'field26',
+    label: t('formDemo.switch'),
+    component: 'Divider'
+  },
+  {
+    field: 'field27',
+    label: t('formDemo.default'),
+    component: 'Switch',
+    value: false
+  },
+  {
+    field: 'field28',
+    label: t('formDemo.icon'),
+    component: 'Switch',
+    value: false,
+    componentProps: {
+      activeIcon: useIcon({ icon: 'ep:check' }),
+      inactiveIcon: useIcon({ icon: 'ep:close' })
+    }
+  },
+  {
+    field: 'field29',
+    label: t('formDemo.rate'),
+    component: 'Divider'
+  },
+  {
+    field: 'field30',
+    label: t('formDemo.default'),
+    component: 'Rate',
+    value: 0
+  },
+  {
+    field: 'field31',
+    label: t('formDemo.icon'),
+    component: 'Rate',
+    value: null,
+    componentProps: {
+      voidIcon: useIcon({ icon: 'ep:chat-round' }),
+      icons: [
+        useIcon({ icon: 'ep:chat-round' }),
+        useIcon({ icon: 'ep:chat-line-round' }),
+        useIcon({ icon: 'ep:chat-dot-round' })
+      ]
+    }
+  },
+  {
+    field: 'field32',
+    label: t('formDemo.colorPicker'),
+    component: 'Divider'
+  },
+  {
+    field: 'field33',
+    label: t('formDemo.default'),
+    component: 'ColorPicker'
+  },
+  {
+    field: 'field34',
+    label: t('formDemo.transfer'),
+    component: 'Divider'
+  },
+  {
+    field: 'field35',
+    label: t('formDemo.default'),
+    component: 'Transfer',
+    componentProps: {
+      props: {
+        key: 'value',
+        label: 'desc'
+      },
+      data: generateData()
+    },
+    value: [],
+    colProps: {
+      span: 24
+    }
+  },
+  {
+    field: 'field36',
+    label: t('formDemo.slot'),
+    component: 'Transfer',
+    componentProps: {
+      props: {
+        key: 'value',
+        label: 'desc'
+      },
+      filterable: true,
+      leftDefaultChecked: [2, 3],
+      rightDefaultChecked: [1],
+      titles: ['Source', 'Target'],
+      buttonTexts: ['To Left', 'To Right'],
+      format: {
+        noChecked: '${total}',
+        hasChecked: '${checked}/${total}'
+      },
+      data: generateData(),
+      slots: {
+        default: ({ option }) => {
+          return (
+            <span>
+              {option.value} - {option.desc}
+            </span>
+          )
+        },
+        leftFooter: () => {
+          return (
+            <ElButton class="transfer-footer" size="small">
+              Operation
+            </ElButton>
+          )
+        },
+        rightFooter: () => {
+          return (
+            <ElButton class="transfer-footer" size="small">
+              Operation
+            </ElButton>
+          )
+        }
+      }
+    },
+    value: [1],
+    colProps: {
+      span: 24
+    }
+  },
+  {
+    field: 'field37',
+    label: `${t('formDemo.render')}`,
+    component: 'Transfer',
+    componentProps: {
+      props: {
+        key: 'value',
+        label: 'desc',
+        disabled: 'disabled'
+      },
+      leftDefaultChecked: [2, 3],
+      rightDefaultChecked: [1],
+      data: generateData(),
+      renderContent: (h, option) => {
+        return h('span', null, `${option.value} - ${option.desc}`)
+      }
+    },
+    value: [1],
+    colProps: {
+      span: 24
+    }
+  },
+  {
+    field: 'field38',
+    label: t('formDemo.radio'),
+    component: 'Divider'
+  },
+  {
+    field: 'field39-2',
+    label: t('formDemo.radioGroup'),
+    component: 'RadioGroup',
+    componentProps: {
+      options: [
+        {
+          // disabled: true,
+          label: 'option-1',
+          value: '1'
+        },
+        {
+          label: 'option-2',
+          value: '2'
+        }
+      ]
+    }
+  },
+  {
+    field: 'field39-3',
+    label: `${t('formDemo.radioGroup')} ${t('formDemo.slot')}`,
+    component: 'RadioGroup',
+    componentProps: {
+      options: [
+        {
+          // disabled: true,
+          label: 'option-1',
+          value: '1'
+        },
+        {
+          label: 'option-2',
+          value: '2'
+        }
+      ],
+      slots: {
+        default: (options: RadioOption[]) => {
+          return options?.map((v) => {
+            return (
+              <ElRadio label={v.value}>
+                {v.label}({v.value})
+              </ElRadio>
+            )
+          })
+        }
+      }
+    }
+  },
+  {
+    field: 'field40',
+    label: t('formDemo.button'),
+    component: 'RadioButton',
+    componentProps: {
+      options: [
+        {
+          label: 'option-1',
+          value: '1'
         },
         {
-          label: 'option1-2',
-          value: '1-2'
+          label: 'option-2',
+          value: '2'
         }
       ]
+    }
+  },
+  {
+    field: 'field40-1',
+    label: `${t('formDemo.button')} ${t('formDemo.slot')}`,
+    component: 'RadioButton',
+    componentProps: {
+      options: [
+        {
+          label: 'option-1',
+          value: '1'
+        },
+        {
+          label: 'option-2',
+          value: '2'
+        }
+      ],
+      slots: {
+        default: (options: RadioOption[]) => {
+          return options?.map((v) => {
+            return (
+              <ElRadioButton label={v.value}>
+                {v.label}({v.value})
+              </ElRadioButton>
+            )
+          })
+        }
+      }
+    }
+  },
+  {
+    field: 'field41',
+    label: t('formDemo.checkbox'),
+    component: 'Divider'
+  },
+  {
+    field: 'field42-2',
+    label: t('formDemo.checkboxGroup'),
+    component: 'CheckboxGroup',
+    value: [],
+    componentProps: {
+      options: [
+        {
+          label: 'option-1',
+          value: '1'
+        },
+        {
+          label: 'option-2',
+          value: '2'
+        },
+        {
+          label: 'option-3',
+          value: '3'
+        }
+      ]
+    }
+  },
+  {
+    field: 'field42-3',
+    label: `${t('formDemo.checkboxGroup')} ${t('formDemo.slot')}`,
+    component: 'CheckboxGroup',
+    value: [],
+    componentProps: {
+      options: [
+        {
+          label: 'option-1',
+          value: '1'
+        },
+        {
+          label: 'option-2',
+          value: '2'
+        },
+        {
+          label: 'option-3',
+          value: '3'
+        }
+      ],
+      slots: {
+        default: (options: CheckboxOption[]) => {
+          return options?.map((v) => {
+            return (
+              <ElCheckbox label={v.value}>
+                {v.label}({v.value})
+              </ElCheckbox>
+            )
+          })
+        }
+      }
+    }
+  },
+  {
+    field: 'field43',
+    label: t('formDemo.button'),
+    component: 'CheckboxButton',
+    value: [],
+    componentProps: {
+      options: [
+        {
+          disabled: true,
+          label: 'option-1',
+          value: '1'
+        },
+        {
+          label: 'option-2',
+          value: '2'
+        },
+        {
+          label: 'option-3',
+          value: '23'
+        }
+      ]
+    }
+  },
+  {
+    field: 'field43-1',
+    label: `${t('formDemo.button')} ${t('formDemo.slot')}`,
+    component: 'CheckboxButton',
+    value: [],
+    componentProps: {
+      options: [
+        {
+          disabled: true,
+          label: 'option-1',
+          value: '1'
+        },
+        {
+          label: 'option-2',
+          value: '2'
+        },
+        {
+          label: 'option-3',
+          value: '23'
+        }
+      ],
+      slots: {
+        default: (options: CheckboxOption[]) => {
+          return options?.map((v) => {
+            return (
+              <ElCheckboxButton label={v.value}>
+                {v.label}({v.value})
+              </ElCheckboxButton>
+            )
+          })
+        }
+      }
+    }
+  },
+  {
+    field: 'field44',
+    component: 'Divider',
+    label: t('formDemo.slider')
+  },
+  {
+    field: 'field45',
+    component: 'Slider',
+    label: t('formDemo.default'),
+    value: 0
+  },
+  {
+    field: 'field46',
+    component: 'Divider',
+    label: t('formDemo.datePicker')
+  },
+  {
+    field: 'field47',
+    component: 'DatePicker',
+    label: t('formDemo.default'),
+    componentProps: {
+      type: 'date'
+    }
+  },
+  {
+    field: 'field48',
+    component: 'DatePicker',
+    label: t('formDemo.shortcuts'),
+    componentProps: {
+      type: 'date',
+      disabledDate: (time: Date) => {
+        return time.getTime() > Date.now()
+      },
+      shortcuts: [
+        {
+          text: t('formDemo.today'),
+          value: new Date()
+        },
+        {
+          text: t('formDemo.yesterday'),
+          value: () => {
+            const date = new Date()
+            date.setTime(date.getTime() - 3600 * 1000 * 24)
+            return date
+          }
+        },
+        {
+          text: t('formDemo.aWeekAgo'),
+          value: () => {
+            const date = new Date()
+            date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+            return date
+          }
+        }
+      ]
+    }
+  },
+  {
+    field: 'field47-1',
+    component: 'DatePicker',
+    label: t('formDemo.slot'),
+    value: '2021-10-29',
+    componentProps: {
+      type: 'date',
+      slots: {
+        default: (cell: any) => {
+          return (
+            <div class={{ cell: true, current: cell.isCurrent }}>
+              <span class="text">{cell.text}</span>
+              {isHoliday(cell) ? <span class="holiday" /> : null}
+            </div>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'field49',
+    component: 'DatePicker',
+    label: t('formDemo.week'),
+    componentProps: {
+      type: 'week',
+      format: `[${t('formDemo.week')}]`
+    }
+  },
+  {
+    field: 'field50',
+    component: 'DatePicker',
+    label: t('formDemo.year'),
+    componentProps: {
+      type: 'year'
+    }
+  },
+  {
+    field: 'field51',
+    component: 'DatePicker',
+    label: t('formDemo.month'),
+    componentProps: {
+      type: 'month'
+    }
+  },
+  {
+    field: 'field52',
+    component: 'DatePicker',
+    label: t('formDemo.dates'),
+    componentProps: {
+      type: 'dates'
+    }
+  },
+  {
+    field: 'field53',
+    component: 'DatePicker',
+    label: t('formDemo.daterange'),
+    componentProps: {
+      type: 'daterange'
+    }
+  },
+  {
+    field: 'field54',
+    component: 'DatePicker',
+    label: t('formDemo.monthrange'),
+    componentProps: {
+      type: 'monthrange'
+    }
+  },
+  {
+    field: 'field56',
+    component: 'Divider',
+    label: t('formDemo.dateTimePicker')
+  },
+  {
+    field: 'field57',
+    component: 'DatePicker',
+    label: t('formDemo.default'),
+    componentProps: {
+      type: 'datetime'
+    }
+  },
+  {
+    field: 'field58',
+    component: 'DatePicker',
+    label: t('formDemo.shortcuts'),
+    componentProps: {
+      type: 'datetime',
+      shortcuts: [
+        {
+          text: t('formDemo.today'),
+          value: new Date()
+        },
+        {
+          text: t('formDemo.yesterday'),
+          value: () => {
+            const date = new Date()
+            date.setTime(date.getTime() - 3600 * 1000 * 24)
+            return date
+          }
+        },
+        {
+          text: t('formDemo.aWeekAgo'),
+          value: () => {
+            const date = new Date()
+            date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+            return date
+          }
+        }
+      ]
+    }
+  },
+  {
+    field: 'field59',
+    component: 'DatePicker',
+    label: t('formDemo.dateTimerange'),
+    componentProps: {
+      type: 'datetimerange'
+    }
+  },
+  {
+    field: 'field60',
+    component: 'Divider',
+    label: t('formDemo.timePicker')
+  },
+  {
+    field: 'field61',
+    component: 'TimePicker',
+    label: t('formDemo.default')
+  },
+  {
+    field: 'field62',
+    component: 'Divider',
+    label: t('formDemo.timeSelect')
+  },
+  {
+    field: 'field63',
+    component: 'TimeSelect',
+    label: t('formDemo.default')
+  },
+  {
+    field: 'field64',
+    component: 'Divider',
+    label: t('formDemo.richText')
+  },
+  {
+    field: 'field65',
+    component: 'Editor',
+    value: 'hello world',
+    label: t('formDemo.default'),
+    colProps: {
+      span: 24
+    }
+  },
+  {
+    field: 'field66',
+    component: 'Divider',
+    label: t('formDemo.inputPassword')
+  },
+  {
+    field: 'field67',
+    component: 'InputPassword',
+    label: t('formDemo.default'),
+    componentProps: {
+      strength: true
+    }
+  },
+  {
+    field: 'field68',
+    component: 'Divider',
+    label: `${t('formDemo.form')} ${t('formDemo.slot')}`
+  },
+  {
+    field: 'field69',
+    component: 'Input',
+    label: `label`,
+    formItemProps: {
+      slots: {
+        label: ({ label }) => {
+          return (
+            <div class="custom-label">
+              <span class="label-text">custom {label}</span>
+            </div>
+          )
+        }
+      }
+    }
+  },
+  {
+    field: 'field70',
+    component: 'Divider',
+    label: `${t('formDemo.remoteLoading')}`
+  },
+  {
+    field: 'field71',
+    label: `${t('formDemo.select')}`,
+    component: 'Select',
+    componentProps: {
+      options: []
     },
     // 远程加载option
     optionApi: async () => {

+ 0 - 270
src/views/Components/Form/RefForm.vue

@@ -1,270 +0,0 @@
-<script setup lang="ts">
-import { Form, FormExpose } from '@/components/Form'
-import { ContentWrap } from '@/components/ContentWrap'
-import { useI18n } from '@/hooks/web/useI18n'
-import { reactive, unref, ref } from 'vue'
-import { ElButton } from 'element-plus'
-import { useValidator } from '@/hooks/web/useValidator'
-import { getDictOneApi } from '@/api/common'
-import { FormSchema } from '@/types/form'
-
-const { required } = useValidator()
-
-const { t } = useI18n()
-
-const schema = reactive<FormSchema[]>([
-  {
-    field: 'field1',
-    label: t('formDemo.input'),
-    component: 'Input',
-    formItemProps: {
-      rules: [required()]
-    }
-  },
-  {
-    field: 'field2',
-    label: t('formDemo.select'),
-    component: 'Select',
-    componentProps: {
-      options: [
-        {
-          label: 'option1',
-          value: '1'
-        },
-        {
-          label: 'option2',
-          value: '2'
-        }
-      ]
-    }
-  },
-  {
-    field: 'field3',
-    label: t('formDemo.radio'),
-    component: 'Radio',
-    componentProps: {
-      options: [
-        {
-          label: 'option-1',
-          value: '1'
-        },
-        {
-          label: 'option-2',
-          value: '2'
-        }
-      ]
-    }
-  },
-  {
-    field: 'field4',
-    label: t('formDemo.checkbox'),
-    component: 'Checkbox',
-    value: [],
-    componentProps: {
-      options: [
-        {
-          label: 'option-1',
-          value: '1'
-        },
-        {
-          label: 'option-2',
-          value: '2'
-        },
-        {
-          label: 'option-3',
-          value: '3'
-        }
-      ]
-    }
-  },
-  {
-    field: 'field5',
-    component: 'DatePicker',
-    label: t('formDemo.datePicker'),
-    componentProps: {
-      type: 'date'
-    }
-  },
-  {
-    field: 'field6',
-    component: 'TimeSelect',
-    label: t('formDemo.timeSelect')
-  }
-])
-
-const formRef = ref<FormExpose>()
-
-const changeLabelWidth = (width: number | string) => {
-  unref(formRef)?.setProps({
-    labelWidth: width
-  })
-}
-
-const changeSize = (size: string) => {
-  unref(formRef)?.setProps({
-    size
-  })
-}
-
-const changeDisabled = (bool: boolean) => {
-  unref(formRef)?.setProps({
-    disabled: bool
-  })
-}
-
-const changeSchema = (del: boolean) => {
-  if (del) {
-    unref(formRef)?.delSchema('field2')
-  } else if (!del && schema[1].field !== 'field2') {
-    unref(formRef)?.addSchema(
-      {
-        field: 'field2',
-        label: t('formDemo.select'),
-        component: 'Select',
-        componentProps: {
-          options: [
-            {
-              label: 'option1',
-              value: '1'
-            },
-            {
-              label: 'option2',
-              value: '2'
-            }
-          ]
-        }
-      },
-      1
-    )
-  }
-}
-
-const setValue = (reset: boolean) => {
-  const elFormRef = unref(formRef)?.getElFormRef()
-  if (reset) {
-    elFormRef?.resetFields()
-  } else {
-    unref(formRef)?.setValues({
-      field1: 'field1',
-      field2: '2',
-      field3: '2',
-      field4: ['1', '3'],
-      field5: '2022-01-27',
-      field6: '17:00'
-    })
-  }
-}
-
-const index = ref(7)
-
-const setLabel = () => {
-  unref(formRef)?.setSchema([
-    {
-      field: 'field2',
-      path: 'label',
-      value: `${t('formDemo.select')} ${index.value}`
-    },
-    {
-      field: 'field2',
-      path: 'componentProps.options',
-      value: [
-        {
-          label: 'option-1',
-          value: '1'
-        },
-        {
-          label: 'option-2',
-          value: '2'
-        },
-        {
-          label: 'option-3',
-          value: '3'
-        }
-      ]
-    }
-  ])
-  index.value++
-}
-
-const addItem = () => {
-  if (unref(index) % 2 === 0) {
-    unref(formRef)?.addSchema({
-      field: `field${unref(index)}`,
-      label: `${t('formDemo.input')}${unref(index)}`,
-      component: 'Input'
-    })
-  } else {
-    unref(formRef)?.addSchema(
-      {
-        field: `field${unref(index)}`,
-        label: `${t('formDemo.input')}${unref(index)}`,
-        component: 'Input'
-      },
-      unref(index)
-    )
-  }
-  index.value++
-}
-
-const formValidation = () => {
-  const elFormRef = unref(formRef)?.getElFormRef()
-  elFormRef?.validate()?.catch(() => {})
-}
-
-const verifyReset = () => {
-  const elFormRef = unref(formRef)?.getElFormRef()
-  elFormRef?.resetFields()
-}
-
-const getDictOne = async () => {
-  const res = await getDictOneApi()
-  if (res) {
-    unref(formRef)?.setSchema([
-      {
-        field: 'field2',
-        path: 'componentProps.options',
-        value: res.data
-      }
-    ])
-  }
-}
-</script>
-
-<template>
-  <ContentWrap :title="`RefForm ${t('formDemo.operate')}`">
-    <ElButton @click="changeLabelWidth(150)">{{ t('formDemo.change') }} labelWidth</ElButton>
-    <ElButton @click="changeLabelWidth('auto')">{{ t('formDemo.restore') }} labelWidth</ElButton>
-
-    <ElButton @click="changeSize('large')">{{ t('formDemo.change') }} size</ElButton>
-    <ElButton @click="changeSize('default')">{{ t('formDemo.restore') }} size</ElButton>
-
-    <ElButton @click="changeDisabled(true)">{{ t('formDemo.disabled') }}</ElButton>
-    <ElButton @click="changeDisabled(false)">{{ t('formDemo.disablement') }}</ElButton>
-
-    <ElButton @click="changeSchema(true)">
-      {{ t('formDemo.delete') }} {{ t('formDemo.select') }}
-    </ElButton>
-    <ElButton @click="changeSchema(false)">
-      {{ t('formDemo.add') }} {{ t('formDemo.select') }}
-    </ElButton>
-
-    <ElButton @click="setValue(false)">{{ t('formDemo.setValue') }}</ElButton>
-    <ElButton @click="setValue(true)">{{ t('formDemo.resetValue') }}</ElButton>
-
-    <ElButton @click="setLabel">
-      {{ t('formDemo.set') }} {{ t('formDemo.select') }} label
-    </ElButton>
-
-    <ElButton @click="addItem"> {{ t('formDemo.add') }} {{ t('formDemo.subitem') }} </ElButton>
-
-    <ElButton @click="formValidation"> {{ t('formDemo.formValidation') }} </ElButton>
-    <ElButton @click="verifyReset"> {{ t('formDemo.verifyReset') }} </ElButton>
-
-    <ElButton @click="getDictOne">
-      {{ t('searchDemo.dynamicOptions') }}
-    </ElButton>
-  </ContentWrap>
-  <ContentWrap :title="`RefForm ${t('formDemo.example')}`">
-    <Form :schema="schema" ref="formRef" />
-  </ContentWrap>
-</template>

+ 12 - 9
src/views/Components/Form/UseFormDemo.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { Form } from '@/components/Form'
+import { Form, FormSchema } from '@/components/Form'
 import { ContentWrap } from '@/components/ContentWrap'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useForm } from '@/hooks/web/useForm'
@@ -7,7 +7,6 @@ import { reactive, unref, ref } from 'vue'
 import { ElButton } from 'element-plus'
 import { useValidator } from '@/hooks/web/useValidator'
 import { getDictOneApi } from '@/api/common'
-import { FormSchema } from '@/types/form'
 
 const { required } = useValidator()
 
@@ -42,7 +41,7 @@ const schema = reactive<FormSchema[]>([
   {
     field: 'field3',
     label: t('formDemo.radio'),
-    component: 'Radio',
+    component: 'RadioGroup',
     componentProps: {
       options: [
         {
@@ -59,7 +58,7 @@ const schema = reactive<FormSchema[]>([
   {
     field: 'field4',
     label: t('formDemo.checkbox'),
-    component: 'Checkbox',
+    component: 'CheckboxGroup',
     value: [],
     componentProps: {
       options: [
@@ -93,9 +92,7 @@ const schema = reactive<FormSchema[]>([
   }
 ])
 
-const { register, methods, elFormRef } = useForm({
-  schema
-})
+const { register, methods, elFormRef } = useForm()
 
 const changeLabelWidth = (width: number | string) => {
   const { setProps } = methods
@@ -241,7 +238,7 @@ const getDictOne = async () => {
 </script>
 
 <template>
-  <ContentWrap :title="`UseForm ${t('formDemo.operate')}`">
+  <ContentWrap :title="`UseForm ${t('formDemo.operate')}`" style="margin-bottom: 20px">
     <ElButton @click="changeLabelWidth(150)">{{ t('formDemo.change') }} labelWidth</ElButton>
     <ElButton @click="changeLabelWidth('auto')">{{ t('formDemo.restore') }} labelWidth</ElButton>
 
@@ -275,6 +272,12 @@ const getDictOne = async () => {
     </ElButton>
   </ContentWrap>
   <ContentWrap :title="`UseForm ${t('formDemo.example')}`">
-    <Form @register="register" />
+    <Form :schema="schema" @register="register" />
   </ContentWrap>
 </template>
+
+<style lang="less" scoped>
+.el-button + .el-button {
+  margin-top: 10px;
+}
+</style>