# ProForm 表单

基于[uiw Form](https://uiwjs.github.io/#/components/form)封装。
- ✅  支持原uiw/Form的提交方式并可以更简洁的生成表单
- ✅  支持多个表单同时提交
- ✅  支持动态添加表单
- ✅  支持只读模式表单

## 何时使用
- 用于创建一个实体或收集信息。
- 需要对输入的数据类型进行校验时。

<!--ProForm-->
## 类型
> 通过formType表单类型
### 卡片类型
```jsx mdx:preview
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
const Demo = () => {
    return (
     <div>
       <ProForm
         title="卡片表单"
         formType="card"
         onChange={(initial, current) => {
          console.log('onChange', initial, current);
         }}
         colProps={{span:12}}
         formDatas={ [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
             },
              {
              label: 'radio',
              widget: 'radio',
              key: 'radio',
              widgetProps: {
                disabled: false
              },
              option: [
                { label: '男', value: 'man' },
                { label: '女', value: 'girl' }
              ],
            },
          ]}
       />
    </div>
  );
}
export default Demo
```

### 折叠类型
```jsx mdx:preview
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
const Demo = () => {
    return (
     <div>
       <ProForm
         title="折叠表单"
         formType="collapse"
         formDatas={ [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
             },
          ]}
       />
    </div>
  );
}
export default Demo
```

### 纯表单类型
> pure类型下将不再展示title
```jsx mdx:preview
import ReactDOM from 'react-dom';
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
const Demo = () => {
    return (
     <div>
       <ProForm
         formType="pure"
         formDatas={ [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
             },
          ]}
       />
    </div>
  );
}
export default Demo
```

## 布局
### 基本布局
> 通过span(继承于uiw/Graid/Col)
```jsx mdx:preview
import ReactDOM from 'react-dom';
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
const Demo = () => {
    return (
     <div>
       <ProForm
         formType="pure"
         formDatas={ [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
             },
               {
               label: 'input',
               key: 'input2',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"12",
             },
               {
               label: 'input',
               key: 'input3',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"12",
             },
             {
               label: 'input',
               key: 'input4',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"8",
             },
             {
               label: 'input',
               key: 'input5',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"8",
             },
             {
               label: 'input',
               key: 'input6',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"8",
             },
          ]}
       />
    </div>
  );
}
export default Demo
```

### 基本布局 横排

```jsx mdx:preview
import ReactDOM from 'react-dom';
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
const Demo = () => {
  return (
    <div>
      <ProForm
        formType="pure"
        formType="card"
        layout="horizontal"
        formDatas={[
          {
            label: 'input',
            key: 'input',
            widget: 'input',
            initialValue: '',
            widgetProps: {},
            span:"24",
          },
            {
            label: 'input',
            key: 'input2',
            widget: 'input',
            initialValue: '',
            widgetProps: {},
            span:"12",
          },
            {
            label: 'input',
            key: 'input3',
            widget: 'input',
            initialValue: '',
            widgetProps: {},
            span:"12",
          },
          {
            label: 'input',
            key: 'input4',
            widget: 'input',
            initialValue: '',
            widgetProps: {},
            span:"8",
          },
          {
            label: 'input',
            key: 'input5',
            widget: 'input',
            initialValue: '',
            widgetProps: {},
            span:"8",
          },
          {
            label: 'input',
            key: 'input6',
            widget: 'input',
            initialValue: '',
            widgetProps: {},
            span:"8",
          },
        ]}
       />
    </div>
  );
}
export default Demo
```
### 只读布局
> 通过readSpan(继承于uiw/Descriptions.Item)

```jsx mdx:preview
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
const Demo = () => {
    return (
     <div>
       <ProForm
         readOnly={true}
         formType="pure"
         className="bbb"
         formDatas={ [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               readSpan:3,
             },
               {
               label: 'input',
               key: 'input2',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               readSpan:3,
             },
               {
               label: 'input',
               key: 'input3',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               readSpan:3,
             },
             {
               label: 'input',
               key: 'input4',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               readSpan:3,
             },
             {
               label: 'input',
               key: 'input5',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               readSpan:2
             },
             {
               label: 'input',
               key: 'input6',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               readSpan:1,
             },
          ]}
       />
    </div>
  );
}
export default Demo
```



## 基本使用
> 与uiw/form使用保持一致
```jsx mdx:preview
import ReactDOM from 'react-dom';
import React, { useState } from 'react';
import { ProForm } from '@uiw-admin/components'
import { Button,Notify,Slider } from 'uiw'
const Demo = () => {
  const [state,setState] = React.useState({})
   const [option] = React.useState([
    { value: 1, label: '苹果' },
    { value: 2, label: '西瓜' },
    { value: 3, label: '香蕉' },
    { value: 4, label: '东北大冻梨' },
    { value: 5, label: '香蕉' },
    { value: 6, label: '葡萄' },
    { value: 6, label: '哈密瓜' },
   ])
   const [loading, setLoading] = React.useState(false)
   // 模拟搜索
  const handleSearch = ( type = '' , name = '' ) => {
    if (type === 'searchSelect') {
      setLoading(true)
      setTimeout(() => {
        setLoading(false)
      }, 2000)
    }
  }
    return (
    <>
      <ProForm
        // 表单类型
        formType="collapse"
        title="基本使用(与uiw/form使用保持一致)"
        // 自定义组件
        customWidgetsList={{
          slider: Slider,
        }}
        // 是否展示uiw/form提交按钮
        showSaveButton
        // 是否展示uiw/form重置按钮
        showResetButton
        // 提交后验证
        onSubmit={(initial, current) => {
          const errorObj = {};
          if (!current?.input) {
            errorObj.input = 'input不能为空';
          }
          if (Object.keys(errorObj).length > 0) {
            const err = new Error();
            err.filed = errorObj;
            Notify.error({ title: '提交失败！' });
            throw err;
          }
          setState(current)
          // 调用请求接口
        }}
        formDatas={[
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               help:"input不能为空",
               rules: [
                 { required:true, message: 'input不能为空' }
               ]
             },
             {
              label: 'textarea',
              key: 'textarea',
              widget: 'textarea',
              span:24,
              colstyle:{ maxWidth:800 }
             },
             {
              label: 'select',
              key: 'select',
              widget: 'select',
              option: [
                { value: 1, label: '苹果' },
                { value: 2, label: '西瓜' },
                { value: 3, label: '香蕉' },
                { value: 4, label: '东北大冻梨' }
              ],
            },
            {
              label: 'switch',
              key: 'switch',
              widget: 'switch',
            },
            {
              label: 'radio',
              widget: 'radio',
              key: 'radio',
              option: [
                { label: '男', value: 'man' },
                { label: '女', value: 'girl' }
              ],
            },
            {
              label: '多选框',
              widget: 'checkbox',
              key: 'checkbox',
              option: [
                { label: '四川菜', value: 'sichuan' },
                { label: '湖北菜', value: 'hubei' }
              ],
            },
            {
              label: '年月日时分秒',
              key: 'dateInputsecond',
              widget: 'dateInput',
              widgetProps: {
                format: 'YYYY-MM-DD HH:mm:ss'
              },
            },
            {
              label: '年月日',
              key: 'dateInput',
              widget: 'dateInput',
              widgetProps: {
                format: 'YYYY-MM-DD'
              },
            },
            {
              label: '年月',
              key: 'monthPicker',
              widget: 'monthPicker',
               widgetProps: {
                format: 'YYYY-MM'
              },
            },
            {
              label: '时分秒',
              key: 'timePicker',
              widget: 'timePicker',
            },
            {
              label: 'searchSelect',
              key: 'searchSelect',
              widget: 'searchSelect',
              option: option,
              widgetProps: {
                mode:"multiple",
                onSearch: handleSearch.bind(this,'searchSelect'),
                onChange: (value) => console.log('changevalue', value),
                onSelect: (value) => console.log('selectvalue', value),
                loading: loading,
                allowClear: true,
                showSearch: true,
                style:{ width:"100%" }
              },
            },
            {
              label: '评分',
              key: 'rate',
              widget: 'rate',
            },
            // 只读模式下支持读取React.ReactNode
            {
              label: '自定义组件',
              key: 'slider',
              widget: 'slider',
              readSpan: 2,
              span:"24"
            },
            {
              label: '上传组件',
              key: 'upload',
              widget: 'upload',
              span: '24',
              readSpan: 3,
              widgetProps: {
                uploadType: 'card',
                multiple: true,
                maxNumber: 2,
              showFileIcon: {
                showPreviewIcon: true,
                showRemoveIcon: true,
              },
            },
            },
            {
              label: 'searchTree',
              key: 'searchTree',
              widget: 'searchTree',
              span: '24',
              readSpan: 3,
              widgetProps:{
                allowClear:true,
                onSearch:(searchValue)=>console.log('SearchTree-> SearchTreeOption',searchValue),
                onChange:(selectedAll, selectd, isChecked)=>console.log('SearchTree-> onChange',selectedAll, selectd, isChecked)
              },
              initialValue:[],
              option:[
                {
                  label: '上海市',
                  key: '1-0-0',
                  children:[
                    { label: '黄浦区', key: '1-0-1' },
                    { label: '卢湾区', key: '1-0-2' },
                    {
                      label: '徐汇区',
                      key: '1-0-3',
                      children:[
                        { label: '半淞园路街道', key: '1-1-0' },
                        { label: '南京东路街道', key: '1-2-0' },
                        { label: '外滩街道', key: '1-3-0' },
                      ]
                    },
                  ]
                }
              ]
            }
          ]}
       />
        <div style={{ maxWidth: 200 }}>
          <pre style={{ padding: '10px 0 0 10px' }}>{JSON.stringify(state, null, 2)}</pre>
        </div>
    </>
  )
}
export default Demo
```

## 通过useForm
> (提交,重置,设置)
> - 我们可以通过useForm注册form表单实例进行验证;重置;设置。(submitvalidate;getError;getFieldValues;setFields;resetForm...)
> - 我们也可以通过传递rules配置验证规则(支持正则,required,回调验证)

```jsx mdx:preview
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
import { Button } from 'uiw'
const Demo = () => {
  const [state,setState] = React.useState({
    input:'',
    upload: []
  })
  const form = useForm()

  return (
    <div>
      <ProForm
        form={form}
        title="通过form api进行表单提交"
        formType="card"
        formDatas={[
          {
            label: 'input',
            key: 'input',
            widget: 'input',
            initialValue: state.input,
            widgetProps: {},
            span:"24",
            rules: [
            { required:true, message: 'input不能为空' },
            { pattern: new RegExp(/[1][3][0-9]{9}$/), message: "请输入正确手机号" },
            ]
          },
          {
            label: 'upload',
            key: 'upload',
            widget: 'upload',
            initialValue: state.upload,
            widgetProps:{
              uploadType: 'card',
            },
          },
        ]}
      />
      <Button 
        style={{ marginTop:10,width:80 }} 
        type="primary" 
        onClick={async () => {
          // 触发验证
          await form.submitvalidate();
          // 获取错误信息
          const errors = form.getError();
          if(errors && Object.keys(errors).length > 0 ) return;
          const value = form.getFieldValues?.();
          setState(value);
          // 调用请求接口
        }}
      >
        保存
      </Button>
      <Button 
        style={{ marginTop:10,width:80 }} 
        type="primary" 
        onClick={()=>{
          form.resetForm()
          setState({})
        }}
      >
        重置
      </Button>
      <Button 
        style={{ marginTop:10,width:80 }} 
        type="primary" 
        onClick={()=> {
          form.setFields({
            input:'1234',
            upload:[ { dataURL: 'https://avatars2.githubusercontent.com/u/1680273?s=40&v=4', name: 'uiw.png' }]
          })
          setState({
            input:'1234',
            upload:[ { dataURL: 'https://avatars2.githubusercontent.com/u/1680273?s=40&v=4', name: 'uiw.png' }]
          })
        } }
      >
        设置
      </Button>
      <div style={{ maxWidth: 500 }}>
        <pre style={{ padding: '10px 0 0 10px' }}>{JSON.stringify(state, null, 2)}</pre>
      </div>
    </div>
  );
}
export default Demo
```

## 多个表单
### 基础提交
```jsx mdx:preview
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
import { Button } from 'uiw'
const Demo = () => {
  const [state,setState] = React.useState({})
  const form = useForm()
  const form2 = useForm()

  return (
     <div>
       <ProForm
         form={form}
         title="表单一"
         formType="card"
         formDatas={ [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
               rules: [
                { required: true, message: '请输入' },
                { pattern: new RegExp(/[1][3][0-9]{9}$/), message: "请输入正确手机号" },
               ]
             },
          ]}
       />
        <div style={{ marginTop:15 }} />
        <ProForm
         formType="pure"
         form={form2}
         title="表单二"
         formType="card"
         formDatas={ [
             {
               label: 'input2',
               key: 'input2',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
               rules: [
                { 
                  validator: (value = '') => {
                    if(!value) return false
                    return true
                  },
                  message: "请输入"
                },
               ]
             },
             {
               label: 'input3',
               key: 'input3',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
               rules: [
                { 
                  validator: (value = '') => {
                    if(!value) return "请输入"
                    return true
                  },
                },
               ]
             },
          ]}
       />
       <Button 
        style={{ marginTop:10,width:80 }} 
        type="primary" 
        onClick={ async ()=>{
          // 触发验证
          await form?.submitvalidate()
          await form2?.submitvalidate()
          // 获取错误信息
          const errors = form.getError()
          const errors2 = form2.getError()

          if(errors && Object.keys(errors).length > 0 ) return
          if(errors2 && Object.keys(errors2).length > 0 ) return
          // 获取表单值
          const value = form.getFieldValues?.()
          const value2 = form2.getFieldValues?.()
          const params = {...value,...value2}
          setState(params)
          // 调用请求接口
       }}>
         保存
      </Button>
      <div style={{ maxWidth: 500 }}>
        <pre style={{ padding: '10px 0 0 10px' }}>{JSON.stringify(state, null, 2)}</pre>
      </div>
    </div>
  );
}
export default Demo
```

### promise提交
> (通过validateFieldsAndGetValue方法先验证后获取值)
```jsx mdx:preview
import React from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
import { Button } from 'uiw'
const Demo = () => {
  const [state,setState] = React.useState({})
  const form = useForm()
  const form2 = useForm()

  const asyncAwaitFormList = (arr=[]) => {
    return (
      arr && arr.length>0 &&  Promise.all(arr).then((vals) =>{
        return vals
      })
    )
  };

  return (
     <div>
       <ProForm
         form={form}
         title="表单一"
         formType="card"
         formDatas={ [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
               rules: [
                { required: true, message: '请输入' },
                { pattern: new RegExp(/[1][3][0-9]{9}$/), message: "请输入正确手机号" },
               ]
             },
          ]}
       />
        <div style={{ marginTop:15 }} />
        <ProForm
         formType="pure"
         form={form2}
         title="表单二"
         formType="card"
         formDatas={ [
             {
               label: 'input2',
               key: 'input2',
               widget: 'input',
               initialValue: '',
               widgetProps: {},
               span:"24",
               rules: [
                { 
                  validator: (value = '') => {
                    if(!value) return false
                    return true
                  },
                  message: "请输入"
                },
               ]
             },
          ]}
       />
       <Button 
        style={{ marginTop:10,width:80 }} 
        type="primary" 
        onClick={ async ()=>{
          // 触发验证获取值
          const values = await asyncAwaitFormList([form?.validateFieldsAndGetValue(),form2?.validateFieldsAndGetValue()])
          let obj = {};
          values.forEach((item) => Object.assign(obj, item));
          setState(obj)
          // 调用请求接口
       }}>
         保存
      </Button>
      <div style={{ maxWidth: 500 }}>
        <pre style={{ padding: '10px 0 0 10px' }}>{JSON.stringify(state, null, 2)}</pre>
      </div>
    </div>
  );
}
export default Demo
```
## 动态添加表单
### uiw/form提交
```jsx mdx:preview
import React, { useState,useRef } from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
import { Button,Card } from 'uiw'

const Demo = () => {
  const form = useForm()
  const formRefList = useRef([])
  const [state,setState] = useState([])
  const [items,setItems] = useState([])
  const [option,setOption] = React.useState([])
  const [loading, setLoading] = React.useState(false)
  // 过滤删除为null的ref
  const formList = formRefList?.current.filter(n => n) || []

   const asyncAwaitFormList = (arr=[]) => {
    return (
      arr && arr.length>0 &&  Promise.all(arr).then((vals) =>{
        return vals
      })
    )
  };

  const addItems = (attr)=>[
     {
      label: '司机手机号',
      key: 'phone',
      widget: 'input',
      initialValue: '',
      required:true,
      rules: [
        { required: true, message: '请输入' },
      ]
    },
    {
      label: 'searchSelect',
      key: 'searchSelect',
      widget: 'searchSelect',
      option: attr.searchSelect.option,
      widgetProps: {
        mode:"multiple",
        onSearch: attr.searchSelect.onSearch,
        loading: attr.searchSelect.loading,
        allowClear: true,
        showSearch: true,
        style:{ width:"100%" }
     },
    },
  ]

  const handleAddFormItems = (type,idx)=>{
    if(type==='add'){
       items.push(addItems)
    }
    if(type==='delete'){
      items.splice(idx,1)
    }
    setItems([...items])
  }

   // 模拟搜索
  const handleSearch = ( type = '' , name = '' ) => {
    if (type === 'searchSelect') {
      setLoading(true)
      setOption([
        { value: 1, label: '苹果' },
        { value: 2, label: '西瓜' },
        { value: 3, label: '香蕉' },
        { value: 4, label: '东北大冻梨' },
      ])
      setTimeout(() => {
        setLoading(false)
      }, 2000)
    }
  }

  const handleSave = async ()=>{
    const validateList = await formList.map(itm => itm.validateFieldsAndGetValue()) || []
    const values = await asyncAwaitFormList(validateList)
    setState(values)
    // 调用接口
  }

  return (
     <div>
      {items.map((item, idx) => {
          return (
           <Card 
            title={`表单${idx + 1}`} 
            key={idx} 
            style={{ marginBottom:10 }} 
            extra={<span onClick={handleAddFormItems.bind(this,'delete',idx)}>删除</span>}
            >
             <ProForm
              ref={(e) =>(formRefList.current[idx] = e)}
              // 表单类型
              formType="pure"
              form={form}
              cardProps={{
                noHover: true,
              }}
              // 更新表单的值
              buttonsContainer={{ justifyContent: 'flex-start' }}
              formDatas={item({
                searchSelect:{
                  option:option,
                  onSearch: handleSearch.bind(this,'searchSelect'),
                  loading:loading
                }
              })}
            />
          </Card>
          )
        })}
       <Button 
        style={{ marginTop:10,width:80 }}  
        type="primary"  
        onClick={handleAddFormItems.bind(this,'add')}>
         新增
        </Button>
       <Button 
        style={{ marginTop:10,width:80 }} 
        type="primary" 
        onClick={() => handleSave()}>
        保存
      </Button>
      <div style={{ maxWidth: 500 }}>
        <pre style={{ padding: '10px 0 0 10px' }}>{JSON.stringify(state, null, 2)}</pre>
      </div>
    </div>
  );
}
export default Demo
```
### promise提交
```jsx mdx:preview
import ReactDOM from 'react-dom';
import React, { useState,useRef } from 'react';
import { ProForm,useForm } from '@uiw-admin/components'
import { Button,Card } from 'uiw'

const Demo = () => {
  const form = useForm()
  const formRefList = useRef([])
  const [state,setState] = useState([])
  const [items,setItems] = useState([])
  const [option,setOption] = React.useState([])
  const [loading, setLoading] = React.useState(false)
  // 过滤删除为null的ref
  const formList = formRefList?.current.filter(n => n) || []

   const asyncAwaitFormList = (arr=[]) => {
    return (
      arr && arr.length>0 &&  Promise.all(arr).then((vals) =>{
        return vals
      })
    )
  };

  const addItems = (attr)=>[
     {
      label: '司机手机号',
      key: 'phone',
      widget: 'input',
      initialValue: '',
      rules: [
        { required: true, message: '请输入' },
      ]
    },
    {
      label: 'searchSelect',
      key: 'searchSelect',
      widget: 'searchSelect',
      option: attr.searchSelect.option,
      widgetProps: {
        mode:"multiple",
        onSearch: attr.searchSelect.onSearch,
        loading: attr.searchSelect.loading,
        allowClear: true,
        showSearch: true,
        style:{ width:"100%" }
     },
    },
  ]

  const handleAddFormItems = (type,idx)=>{
    if(type==='add'){
       items.push(addItems)
    }
    if(type==='delete'){
      items.splice(idx,1)
    }
    setItems([...items])
  }

   // 模拟搜索
  const handleSearch = ( type = '' , name = '' ) => {
    if (type === 'searchSelect') {
      setLoading(true)
      setOption([
        { value: 1, label: '苹果' },
        { value: 2, label: '西瓜' },
        { value: 3, label: '香蕉' },
        { value: 4, label: '东北大冻梨' },
      ])
      setTimeout(() => {
        setLoading(false)
      }, 2000)
    }
  }

  const handleSave = async ()=>{
    const validateList = formList.map(itm=> itm.validateFieldsAndGetValue()) || []
    const values = await asyncAwaitFormList(validateList)
    setState(values)
    // 调用接口
  }

  return (
    <div>
      {items.map((item, idx) => {
        return (
          <Card 
          title={`表单${idx + 1}`} 
          key={idx} 
          style={{ marginBottom:10 }} 
          extra={<span onClick={handleAddFormItems.bind(this,'delete',idx)}>删除</span>}
          >
            <ProForm
              className="aaa"
              ref={(e) =>(formRefList.current[idx] = e)}
              // 表单类型
              formType="pure"
              form={form}
              cardProps={{
                noHover: true,
              }}
              // 更新表单的值
              buttonsContainer={{ justifyContent: 'flex-start' }}
              formDatas={item({
                searchSelect:{
                  option:option,
                  onSearch: handleSearch.bind(this,'searchSelect'),
                  loading:loading
                }
              })}
            />
          </Card>
        )
      })}
      <Button 
        style={{ marginTop:10,width:80 }}  
        type="primary"  
        onClick={handleAddFormItems.bind(this,'add')}>
        新增
      </Button>
      <Button 
        style={{ marginTop:10,width:80 }} 
        type="primary" 
        onClick={() => handleSave()}>
        保存
      </Button>
      <div style={{ maxWidth: 500 }}>
        <pre style={{ padding: '10px 0 0 10px' }}>{JSON.stringify(state, null, 2)}</pre>
      </div>
    </div>
  );
}
export default Demo
```
## 只读模式
```jsx mdx:preview
import ReactDOM from 'react-dom';
import { ProForm,useForm } from '@uiw-admin/components'
import { formatter } from 'uiw'
import React, { useState } from 'react';
const Demo = () => {
  const [ queryInfo ] = useState({
    input:"Jason",
    textarea:"Jason",
    select:"Jason",
    dateInputsecond: '2021-1-21 23:59:59',
    dateInput: '2021-1-21',
    monthPicker: '2021-1',
    timePicker: '2021-1-21 22:59:59',
    searchSelect:["Jason"],
    rate:2
  })
  const form = useForm()
    return (
       <ProForm
        form={form}
         readOnly={true}
         title="只读模式"
         formType="pure"
         layout="horizontal"
         // 只读模式下调整 一行的 DescriptionItems 数量,其余参数参考uiw/Descriptions
         readOnlyProps={{ column:2 }}
         formDatas={
           [
             {
               label: 'input',
               key: 'input',
               widget: 'input',
               // 只读模式下支持读取React.ReactNode
               initialValue: queryInfo?.input,
             },
             {
               label: 'textarea',
               key: 'textarea',
               widget: 'textarea',
               initialValue: queryInfo?.textarea,
             },
             {
               label: 'select',
               key: 'select',
               widget: 'select',
               option:[{label:"Jason",value:"Jason"}],
               initialValue: queryInfo?.select,
             },
             {
              label: 'dateInput',
              key: 'dateInputsecond',
              widget: 'dateInput',
              widgetProps: {
                // 年月日时分秒
                format: 'YYYY-MM-DD HH:mm:ss'
              },
              initialValue: queryInfo?.dateInputsecond
            },
            {
              label: 'dateInput',
              key: 'dateInput',
              widget: 'dateInput',
              widgetProps: {
                // 年月日
                format: 'YYYY-MM-DD'
              },
              initialValue: queryInfo?.dateInput
            },
            {
              label: 'monthPicker',
              key: 'monthPicker',
              widget: 'monthPicker',
              widgetProps: {
                // 年月
                format: 'YYYY-MM'
              },
              initialValue: queryInfo?.monthPicker
            },
            {
              label: 'timePicker',
              key: 'timePicker',
              widget: 'timePicker',
              initialValue: queryInfo.timePicker && new Date(queryInfo.timePicker)
            },
            {
              label: 'searchSelect',
              key: 'searchSelect',
              widget: 'searchSelect',
              widgetProps:{
                mode:"multiple",
              },
              option:[{label:"Jason",value:"Jason"}],
              initialValue:queryInfo.searchSelect || []
            },
            {
              label: 'rate',
              key: 'rate',
              widget: 'rate',
              initialValue:queryInfo.rate
            },
            {
              label: 'upload',
              key: 'upload',
              widget: 'upload',
              widgetProps:{
                uploadType: 'card',
              },
              initialValue: [
                {
                  dataURL: 'https://avatars2.githubusercontent.com/u/1680273?s=40&v=4',
                  name: 'uiw.png',
                },
              ]
            },
           ]}
       />
  );
}
export default Demo
```



## 自定义表单组件

> 给组件传`value`, `onChange`  一个是值 一个是组件更改数据回调

```jsx mdx:preview
import { ProForm,useForm } from '@uiw-admin/components'
import { formatter, Input, Button } from 'uiw'
import React, { useState } from 'react';

const Inputs = ({value, onChange}) => {
  return (
    <>
      <Button style={{ marginRight: 10, width: 200 }}>按钮</Button>
      <Input
        placeholder="请输入内容"
        value={value}
        onChange={e => { onChange(e.target.value) }} />
    </>
  )
}

const Demo = () => {
  const [ queryInfo ] = useState({
    input:"Jason",
  })
  const form = useForm()
    return (
       <ProForm
        customWidgetsList={{inputs: Inputs}}
        form={form}
        title="只读模式"
        formType="pure"
        formDatas={[
          {
            label: '自定义组件',
            key: 'input',
            widget: 'inputs',
            // 只读模式下支持读取React.ReactNode
            initialValue: queryInfo.input,
          },
        ]}
      />
  );
}
export default Demo
```

## Props
> 继承uiw-Form

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| title | 标题  | `string`  | - |
| formType | 表单类型 | `collapse` `card`  `pure`  | `card` |
| layout | 表单布局 | `horizontal \| vertical`  | `vertical` |
| form | useForm返回值,替换原有submitRef作用可进行表单验证 | `UseFormProps` | - |
| readOnly | `是否是只读模式模式`  | `boolean`  | false  |
| readOnlyProps | 只读模式 参考Descriptions参数 | `DescriptionsProps`  | `{}` |
| formDatas | 表单项集合  | `FormItemsProps[]` | `[]` |
| showSaveButton | 展示提交按钮 | `boolean` | `false`  |
| showResetButton | 展示重置按钮 | `boolean` | `false`  |
| saveButtonProps  | 提交按钮api;继承于uiw/button | `ButtonProps` | -  |
| resetButtonProps   | 重置按钮api;继承于uiw/button | `ButtonProps` | - |
| buttonsContainer   | buttons容器样式(可调整button布局)  | `React.CSSProperties`  | -      |
| customWidgetsList  | 可配置自定义组件  | `{ [key: string]: any }` | `{}` |
| cardProps | uiw`Card` API | `CardProps` | `{}` |
| collapseProps | uiw`Collapse` API  | `CollapseProps` | `{}` |
| collapsePanelProps | uiw`Collapse.Panel` API | `CollapsePanelProps` | `{}` |
| colProps | uiw`Col` API,公共属性 | `colProps` | - |
| onSubmit | 提交表单回调 需配合btns，继承uiw/form submit | `(initial: Record<string, any>, current: Record<string, any>) => void` | - |
| onChange | 表单值变化回调，继承uiw/form onChange  | `(initial: Record<string, any>, current: Record<string, any>) => void` | - |
| onSubmitError | 调用 onSubmit 抛出的任何错误。从字段名称返回对象映射。 继承uiw/form onSubmitError | `(error: any) => void` |  - |


### saveButtonProps resetButtonProps

更多属性文档请参考 [uiw/button](https://uiwjs.github.io/#/components/button)

| 参数     | 说明     | 类型                     | 默认值 |
| -------- | -------- | ------------------------ | ------ |
| label    | 按钮标题     | string           | 提交/重置      |



### FormItemsProps
> 继承uiw-FormItem

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| label  | 表单项名称  | `string`  | -  |
| key| 表单项key  | `string`  | - |
| widget | 表单项类型 | `sring` | - |
| initialValue | 表单项值，可以是默认值 | `any \| any[]` | - |
| option | 数据化选项内容, widget为 radio、checkbox、select 生效 | `OptionsProps[]` | - |
| widgetProps  | 表单组件其余参数,参考uiw表单组件 | `any` | - |
| hide | 是否显示  | `boolean`  | true   |
| span | 非只读模式下,可以通过指定 24 列中每列的宽度来创建基本网格系统 | `string` | `'8'` |
| readSpan     | 只读模式下包含列的数量 参考Descriptions.Item  | `number` | `1` |
| rules | 验证规则 | `RulesProps[]` | - |
| colstyle  | Col(uiw/Grid)样式  | `React.CSSProperties` | - |


### RulesProps
| 参数     | 说明     | 类型                     | 默认值 |
| -------- | -------- | ------------------------ | ------ |
| message | 验证提示消息 | `string` | - |
| pattern  | 验证正则 | `RegExp` | - |
| validator | 自定义验证规则 | `(value: any \| any[]) => boolean\|string` | - | 
| required | 是否必填 | `boolean` | - | 

### OptionsProps
| 参数 | 说明 | 类型  | 默认值 |
| --- | --- | --- | --- |
| label | 必传。名称 | `string` | - |
| value | 必传。key | `string \| number` | - |
| disabled | 是否禁用 | `boolean` | - |

## useForm

### response
> - v5.2.14(~~clickRef~~) 
> - v5.2.18(~~formStateList~~) (~~setFormStateList~~) (~~errorsRef~~) 

| 参数     | 说明     | 类型                     | 默认值 |
| -------- | -------- | ------------------------ | ------ |
| submitvalidate | 表单验证 | `()=>void` | - | 
| resetForm | 重置表单值 | `()=>void` | - | 
| onSubmit | 表单提交 | `(e: React.FormEvent)=>void` | - |   
| getFieldValues | 获取表单值 | `()=>void` | - |  
| getError | 获取表单错误 | `()=>void` | - |  
| setFields | 设置表单的值 | `(fields: FormState['current'])=>void` | `[]` |      
| validateFieldsAndGetValue | 验证并获取值 | `()=>Promise<any>` | `[]` |   

## 注意
> [继承于uiw/Form,请参考uiw/From以及表单组件](https://uiwjs.github.io/#/components/form),
 默认集成了`Input`, `InputNumber`, `Checkbox`, `Switch`, `Textarea`,`DateInput`, `TimePicker`,
 `MonthPicker`, `SearchSelect`, `Select`, `Radio`, `selectMultiple`, `Rate`, `Upload`。
<!--rehype:style=border-left: 8px solid #ffe564;background-color: #ffe56440;padding: 12px 16px;-->

## 贡献者

感谢所有的贡献者，欢迎开发者为开源项目贡献力量。

<a href="https://github.com/uiwjs/uiw-admin/graphs/contributors">
  <img src="https://uiwjs.github.io/uiw-admin/CONTRIBUTORS.svg" />
</a>

## License

Licensed under the MIT License.
