123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- import { forwardRef, memo, useEffect, useImperativeHandle } from 'react'
- import useUserStore from '@/store/userStore'
- import { dictMapping, useNoAuthDict } from '@/hooks/useDict'
- import { DatePicker, Form, Input, InputNumber, Select, Upload } from 'antd'
- import { PlusOutlined } from '@ant-design/icons'
- const { RangePicker } = DatePicker
- export interface DynamicFormRef {
- onSubmit: () => void
- }
- interface DynamicFormProps {
- formItems?: API.TmplItem[]
- formData?: Record<string, any>
- formRule?: any
- disabled?: boolean
- setFormData: (data: Record<string, any>) => void
- }
- const DynamicForm = memo(
- forwardRef<DynamicFormRef, DynamicFormProps>(
- ({ formItems = [], formData = {}, formRule = {}, disabled = false, setFormData }, ref) => {
- useImperativeHandle(ref, () => {
- return {
- onSubmit
- }
- })
- console.log(formRule)
- const { dictArray: inputUnitTypeOptions, dictRequestFn: getInputUnitTypeOptions } =
- useNoAuthDict('input_unit_type')
- useEffect(() => {
- getInputUnitTypeOptions()
- }, [])
- useEffect(() => {
- console.log(inputUnitTypeOptions)
- }, [inputUnitTypeOptions])
- const [form] = Form.useForm()
- const onSubmit = () => {
- form.submit()
- }
- const onFinish = (values: any) => {
- console.log('Finish:', values)
- }
- const onFinishFailed = (errorInfo: any) => {
- console.log('Failed:', errorInfo)
- }
- console.log('formData', formData)
- console.log(formItems)
- console.log(setFormData)
- // 表单项生成器
- const FieldWrapper = (props: { children: React.ReactNode }) => {
- return (
- <div className='px-[20px] py-[16px] mb-[16px] rounded-[10px] bg-[#ecf5ff]'>
- {props.children}
- </div>
- )
- }
- const renderField = (field: API.TmplItem) => {
- const options = field.itemStruct
- const { type, label, desc, placeholder, visible, expand, widgetId } = options!
- if (!visible) return null // 条件渲染
- const labelContent = (
- <div>
- <div>{label.text}</div>
- {desc && (
- <div className='text-text-secondary mt-[4px]' style={{ fontSize: '12px' }}>
- {desc}
- </div>
- )}
- </div>
- )
- switch (type) {
- case 'INPUT': {
- const expandVal = expand as API.FD_COM['INPUT']
- return (
- <FieldWrapper key={widgetId}>
- <Form.Item
- name={widgetId}
- label={labelContent}
- rules={formRule[widgetId!]}
- hasFeedback
- style={{ marginBottom: 0 }}>
- <Input
- placeholder={placeholder}
- prefix={expandVal.prefix}
- suffix={expandVal.suffix}
- showCount
- allowClear
- />
- </Form.Item>
- </FieldWrapper>
- )
- }
- case 'NUMBER_INPUT': {
- const expandVal = expand as API.FD_COM['NUMBER_INPUT']
- const min = typeof expandVal.min === 'number' ? expandVal.min : undefined
- const max = typeof expandVal.max === 'number' ? expandVal.max : undefined
- const decimalDigits = expandVal.decimalPlacesNumber || 0
- return (
- <FieldWrapper key={widgetId}>
- <Form.Item name={widgetId} label={labelContent} style={{ marginBottom: 0 }}>
- <InputNumber
- className='!w-full'
- placeholder={`${min !== undefined ? '最小值:' + min.toFixed(decimalDigits) + ';' : ''}${
- max !== undefined ? '最大值:' + max.toFixed(decimalDigits) + ';' : ''
- }${'小数位数:' + decimalDigits + ';'}`}
- maxLength={parseInt(expandVal.maxChars)}
- prefix={expandVal.prefix}
- suffix={
- (expandVal.suffix ||
- (expandVal.featureType === 'NUMBER' && expandVal.unit)) &&
- (expandVal.featureType === 'NUMBER' && expandVal.unit !== 'NONE'
- ? expandVal.unit
- : expandVal.suffix)
- }
- min={min}
- max={max}
- precision={decimalDigits}
- />
- </Form.Item>
- </FieldWrapper>
- )
- }
- case 'AMOUNT_INPUT': {
- const expandVal = expand as API.FD_COM['NUMBER_INPUT']
- const min = typeof expandVal.min === 'number' ? expandVal.min : undefined
- const max = typeof expandVal.max === 'number' ? expandVal.max : undefined
- const decimalDigits = expandVal.decimalPlacesNumber || 0
- return (
- <FieldWrapper key={widgetId}>
- <Form.Item name={widgetId} label={labelContent} style={{ marginBottom: 0 }}>
- <InputNumber
- className='!w-full'
- placeholder={`${min !== undefined ? '最小值:' + min.toFixed(decimalDigits) + ';' : ''}${
- max !== undefined ? '最大值:' + max.toFixed(decimalDigits) + ';' : ''
- }${'小数位数:' + decimalDigits + ';'}`}
- maxLength={parseInt(expandVal.maxChars)}
- prefix={expandVal.prefix}
- suffix={
- (expandVal.suffix || expandVal.unit) &&
- (expandVal.unit
- ? dictMapping({ unit: expandVal.unit }, 'unit', inputUnitTypeOptions)
- : expandVal.suffix)
- }
- min={min}
- max={max}
- precision={decimalDigits}
- />
- </Form.Item>
- </FieldWrapper>
- )
- }
- case 'SELECT': {
- const expandVal = expand as API.FD_COM['SELECT']
- return (
- <FieldWrapper key={widgetId}>
- <Form.Item name={widgetId} label={labelContent} style={{ marginBottom: 0 }}>
- <Select
- mode={expandVal.multiple ? 'multiple' : undefined}
- placeholder={placeholder}
- options={expandVal.userInput}
- allowClear
- />
- </Form.Item>
- </FieldWrapper>
- )
- }
- case 'DATETIME_PICKER': {
- const expandVal = expand as API.FD_COM['DATETIME_PICKER']
- const datePickerType = expandVal.dateType.toLowerCase()
- const datePickerTypeMap = {
- year: { picker: 'year', showTime: false, dateFormat: 'YYYY' },
- month: { picker: 'month', showTime: false, dateFormat: 'YYYY-MM' },
- date: { picker: undefined, showTime: false, dateFormat: 'YYYY-MM-DD' },
- week: { picker: 'week', showTime: false, dateFormat: 'YYYY-WW' },
- datetime: { picker: undefined, showTime: true, dateFormat: 'YYYY-MM-DD HH:mm:ss' },
- daterange: { picker: 'range', showTime: false, dateFormat: 'YYYY-MM-DD' },
- datetimerange: { picker: 'range', showTime: true, dateFormat: 'YYYY-MM-DD HH:mm:ss' }
- }
- if (!datePickerType.includes('range')) {
- return (
- <FieldWrapper key={widgetId}>
- <Form.Item name={widgetId} label={labelContent} style={{ marginBottom: 0 }}>
- <DatePicker
- className='w-full'
- picker={
- datePickerTypeMap[datePickerType as keyof typeof datePickerTypeMap]
- .picker as any
- }
- showTime={
- datePickerTypeMap[datePickerType as keyof typeof datePickerTypeMap].showTime
- }
- format={
- datePickerTypeMap[datePickerType as keyof typeof datePickerTypeMap]
- .dateFormat
- }
- />
- </Form.Item>
- </FieldWrapper>
- )
- } else {
- return (
- <FieldWrapper key={widgetId}>
- <Form.Item name={widgetId} label={labelContent} style={{ marginBottom: 0 }}>
- <RangePicker
- className='w-full'
- picker={
- datePickerTypeMap[datePickerType as keyof typeof datePickerTypeMap]
- .picker as any
- }
- showTime={
- datePickerTypeMap[datePickerType as keyof typeof datePickerTypeMap].showTime
- }
- format={
- datePickerTypeMap[datePickerType as keyof typeof datePickerTypeMap]
- .dateFormat
- }
- />
- </Form.Item>
- </FieldWrapper>
- )
- }
- }
- case 'FILE_PICKER': {
- const expandVal = expand as API.FD_COM['FILE_PICKER']
- const uploadUrl = '/cms/file/submit'
- const userStore = useUserStore()
- const headers = {
- Authorization: 'Bearer ' + userStore.access_token,
- 'X-Tenant-Id': String(userStore.userInfo.tenantId),
- 'X-Target-Folder': 'DECLARATION',
- 'X-Client-Type': 'TO_B',
- 'X-Terminal-Type': ''
- }
- const limitType = (() => {
- const accept = expandVal.accept || ''
- const multiAcceptList = expandVal.multiAcceptList || []
- if (accept && multiAcceptList.length !== 0) {
- if (multiAcceptList[0] === 'ATTACHMENT') {
- return undefined
- } else {
- return multiAcceptList.join(',')
- }
- } else if (accept) {
- if (accept === 'ATTACHMENT') {
- return undefined
- } else {
- return accept
- }
- } else if (multiAcceptList.length !== 0) {
- if (multiAcceptList[0] === 'ATTACHMENT') {
- return undefined
- } else {
- return multiAcceptList.join(',')
- }
- } else {
- return undefined
- }
- })()
- const normFile = (e: any) => {
- console.log(e)
- if (Array.isArray(e)) return e
- return e?.fileList || []
- }
- console.log(limitType)
- const handlePreview = (file: any) => {
- console.log(file)
- // window.open(file.url)
- }
- const handleChange = (file: any) => {
- console.log(file)
- }
- const uploadButton = (
- <button style={{ border: 0, background: 'none' }} type='button'>
- <PlusOutlined />
- <div style={{ marginTop: 8 }}>点击上传</div>
- </button>
- )
- return (
- <FieldWrapper key={widgetId}>
- <Form.Item
- name={widgetId}
- label={labelContent}
- style={{ marginBottom: 0 }}
- valuePropName='fileList'
- getValueFromEvent={normFile}>
- <Upload
- action={import.meta.env.VITE_APP_ENV === 'dev' ? '/api' + uploadUrl : uploadUrl}
- headers={headers}
- listType='picture-card'
- accept={limitType}
- maxCount={expandVal.limit}
- onPreview={handlePreview}
- onChange={handleChange}>
- {uploadButton}
- </Upload>
- </Form.Item>
- </FieldWrapper>
- )
- }
- // 其他组件类型...
- default:
- return null
- }
- }
- return (
- <Form
- form={form}
- layout='vertical'
- initialValues={formData}
- disabled={disabled}
- onFinish={onFinish}
- onFinishFailed={onFinishFailed}>
- {formItems.map(renderField)}
- </Form>
- )
- }
- )
- )
- export default DynamicForm
|