Quellcode durchsuchen

feat(custom): dynamicForm

linyuanjie vor 6 Tagen
Ursprung
Commit
92d1c422d2

+ 70 - 33
src/components/formParse/components/DynamicForm.tsx

@@ -1,47 +1,84 @@
 import { forwardRef, memo, useImperativeHandle } from 'react'
 import { Form, Input, Select } from 'antd'
 
-export interface DynamicFormRef {}
+export interface DynamicFormRef {
+  onSubmit: () => void
+}
 
 interface DynamicFormProps {
   formItems?: API.TmplItem[]
+  formData?: Record<string, any>
+  disabled?: boolean
+  setFormData: (data: Record<string, any>) => void
 }
 
 const DynamicForm = memo(
-  forwardRef<DynamicFormRef, DynamicFormProps>(({ formItems = [] }, ref) => {
-    useImperativeHandle(ref, () => {
-      return {}
-    })
-
-    console.log(formItems)
-
-    const renderField = (field: API.TmplItem) => {
-      const { type, label, placeholder, visible, valid } = field.itemStruct!
-      // if (hidden && hidden(form.getFieldsValue())) return null // 条件渲染
-      console.log(visible)
-      console.log(valid)
-
-      switch (type) {
-        case 'INPUT':
-          return (
-            <Form.Item name={name} label={label.text}>
-              <Input placeholder={placeholder} />
-            </Form.Item>
-          )
-        case 'SELECT':
-          return (
-            <Form.Item name={name} label={label.text}>
-              <Select placeholder={placeholder} />
-            </Form.Item>
-          )
-        // 其他组件类型...
-        default:
-          return null
+  forwardRef<DynamicFormRef, DynamicFormProps>(
+    ({ formItems = [], formData = {}, disabled = false, setFormData }, ref) => {
+      useImperativeHandle(ref, () => {
+        return {
+          onSubmit
+        }
+      })
+      console.log(formData)
+      console.log(formItems)
+      console.log(setFormData)
+
+      const renderField = (field: API.TmplItem) => {
+        const options = field.itemStruct
+        const { type, label, placeholder, visible, valid, expand, widgetId } = options!
+        // if (hidden && hidden(form.getFieldsValue())) return null // 条件渲染
+        console.log(visible)
+        console.log(valid)
+
+        switch (type) {
+          case 'INPUT':
+            return (
+              <Form.Item name={widgetId} label={label.text} key={widgetId}>
+                <Input
+                  placeholder={placeholder}
+                  maxLength={parseInt((expand as API.FD_COM['INPUT']).maxChars)}
+                  showCount
+                  prefix={(expand as API.FD_COM['INPUT']).prefix}
+                  suffix={(expand as API.FD_COM['INPUT']).suffix}
+                />
+              </Form.Item>
+            )
+          case 'SELECT':
+            return (
+              <Form.Item name={widgetId} label={label.text} key={widgetId}>
+                <Select placeholder={placeholder} />
+              </Form.Item>
+            )
+          // 其他组件类型...
+          default:
+            return null
+        }
       }
-    }
 
-    return <Form>{formItems.map(renderField)}</Form>
-  })
+      const [form] = Form.useForm()
+      const onSubmit = () => {
+        form.submit()
+      }
+      const onFinish = (values: any) => {
+        console.log('Finish:', values)
+      }
+      const onFinishFailed = (errorInfo: any) => {
+        console.log('Failed:', errorInfo)
+      }
+
+      return (
+        <Form
+          form={form}
+          layout='vertical'
+          disabled={disabled}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}>
+          {formItems.map(renderField)}
+        </Form>
+      )
+    }
+  )
 )
 
 export default DynamicForm

+ 28 - 18
src/components/formParse/index.tsx

@@ -1,8 +1,8 @@
-import { forwardRef, memo, useEffect, useImperativeHandle, useState } from 'react'
+import { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from 'react'
 import { cloneDeep } from 'lodash-es'
 import { getTenantApply, ITenantApplyInfo } from '@/api/services/riskcontrol/declare'
 import { orderStateMap } from './constants/orderState'
-import DynamicForm from './components/DynamicForm'
+import DynamicForm, { DynamicFormRef } from './components/DynamicForm'
 
 export interface FormParseRef {}
 
@@ -15,8 +15,8 @@ interface FormParseProps {
   expiry?: string
   isExpiry?: boolean
   className?: string
-  onFormDataChange: (data: Record<string, any>) => void
-  onFormRuleChange: (rule: any) => void
+  setFormData: (data: Record<string, any>) => void
+  setFormRule: (rule: any) => void
 }
 
 const checkStateMap = {
@@ -36,8 +36,8 @@ const FormParse = memo(
         state,
         expiry,
         isExpiry,
-        onFormDataChange,
-        onFormRuleChange
+        setFormData,
+        setFormRule
       },
       ref
     ) => {
@@ -91,7 +91,7 @@ const FormParse = memo(
         formItemsCopy?.forEach((item) => {
           // 初始化数据
           if (item.itemStruct?.type === 'FILE_PICKER') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length
                 ? item.itemDeli.map((deli) => ({
@@ -106,7 +106,7 @@ const FormParse = memo(
                 : []
             }))
           } else if (item.itemStruct?.type === 'INVOICE_PICKER') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length
                 ? item.itemDeli.map((deli) => ({
@@ -121,7 +121,7 @@ const FormParse = memo(
                 : []
             }))
           } else if (item.itemStruct?.type === 'FINANCE_PICKER') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length
                 ? item.itemDeli.map((deli) => ({
@@ -136,27 +136,27 @@ const FormParse = memo(
                 : []
             }))
           } else if (item.itemStruct?.type === 'INPUT') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length ? item.itemDeli[0].value : ''
             }))
           } else if (item.itemStruct?.type === 'NUMBER_INPUT') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length ? item.itemDeli[0].value : ''
             }))
           } else if (item.itemStruct?.type === 'AMOUNT_INPUT') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length ? item.itemDeli[0].value : ''
             }))
           } else if (item.itemStruct?.type === 'RADIO') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length ? item.itemDeli[0].value : ''
             }))
           } else if (item.itemStruct?.type === 'SELECT') {
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length
                 ? item.itemDeli[0].value
@@ -168,7 +168,7 @@ const FormParse = memo(
             const isRangeType = ['DATERANGE', 'DATETIMERANGE'].includes(
               (item.itemStruct.expand as API.FD_COM['DATETIME_PICKER']).dateType
             )
-            onFormDataChange((prev: Record<string, any>) => ({
+            setFormData((prev: Record<string, any>) => ({
               ...prev,
               [item.itemStruct!.widgetId!]: item.itemDeli?.length
                 ? item.itemDeli[0].value
@@ -311,14 +311,14 @@ const FormParse = memo(
               })
             })
             if (Array.isArray(formRule![item.itemStruct!.widgetId!]) && disabled) {
-              onFormRuleChange((prev: any) => ({
+              setFormRule((prev: any) => ({
                 ...prev,
                 [item.itemStruct!.widgetId!]: [
                   ...((formRule![item.itemStruct!.widgetId!] as []) || [])
                 ]
               }))
             } else {
-              onFormRuleChange((prev: any) => ({
+              setFormRule((prev: any) => ({
                 ...prev,
                 [item.itemStruct!.widgetId!]: rules as any
               }))
@@ -331,6 +331,8 @@ const FormParse = memo(
         initFn()
       }, [])
 
+      const DynamicFormInstanceRef = useRef<DynamicFormRef>(null)
+
       return (
         <div>
           {state && (
@@ -390,7 +392,15 @@ const FormParse = memo(
             <span className='ml-20 break-all'>原因说明:{declFormData?.remarks || '-'}</span>
           </div>
           {/* 动态生成表单 */}
-          {isInited && <DynamicForm formItems={formItemsCopy} />}
+          {isInited && (
+            <DynamicForm
+              ref={DynamicFormInstanceRef}
+              formItems={formItemsCopy}
+              formData={formData}
+              setFormData={setFormData}
+              disabled={disabled}
+            />
+          )}
         </div>
       )
     }

+ 20 - 17
src/pages/decl/index.tsx

@@ -9,6 +9,7 @@ import { DeclState, DeclStateText } from '@/api/services/riskcontrol/enum'
 import { Button, Divider, Input, Layout, Result } from 'antd'
 import { LoadingOutlined } from '@ant-design/icons'
 import FormParse, { type FormParseRef } from '@/components/formParse'
+import { DeclProvider } from './providers/DeclProvider'
 
 const { Search } = Input
 
@@ -122,23 +123,25 @@ function Decl() {
                 </div>
                 <Divider />
                 {declFormData?.formItems && (
-                  <FormParse
-                    ref={FormParseRef}
-                    formData={formData}
-                    onFormDataChange={setFormData}
-                    formRule={formRule}
-                    onFormRuleChange={setFormRule}
-                    declFormData={declFormData}
-                    state={DeclStateText[declFormData.declarationState!]}
-                    expiry={declFormData?.expiryDate}
-                    isExpiry={isExpiry}
-                    disabled={
-                      declFormData?.declarationState === DeclState.SUBMITTED ||
-                      declFormData?.declarationState === DeclState.CHECKED ||
-                      isExpiry
-                    }
-                    className='mt-10'
-                  />
+                  <DeclProvider>
+                    <FormParse
+                      ref={FormParseRef}
+                      formData={formData}
+                      setFormData={setFormData}
+                      formRule={formRule}
+                      setFormRule={setFormRule}
+                      declFormData={declFormData}
+                      state={DeclStateText[declFormData.declarationState!]}
+                      expiry={declFormData?.expiryDate}
+                      isExpiry={isExpiry}
+                      disabled={
+                        declFormData?.declarationState === DeclState.SUBMITTED ||
+                        declFormData?.declarationState === DeclState.CHECKED ||
+                        isExpiry
+                      }
+                      className='mt-10'
+                    />
+                  </DeclProvider>
                 )}
                 <div className='fixed right-[10px] top-[50%] -translate-y-[50%]'>
                   <img className='w-[300px]' src={imgOSS || imgQR} alt='' />

+ 12 - 0
src/pages/decl/providers/DeclProvider.tsx

@@ -0,0 +1,12 @@
+import { createContext, useContext } from 'react'
+import { DeclContextType } from '../types'
+
+const DeclContext = createContext<DeclContextType>({})
+
+export function DeclProvider(props: { children: React.ReactNode }) {
+  return <DeclContext.Provider value={{}}>{props.children}</DeclContext.Provider>
+}
+
+export function useDeclContext() {
+  return useContext(DeclContext)
+}

+ 1 - 0
src/pages/decl/types.ts

@@ -0,0 +1 @@
+export type DeclContextType = {}