# EpForm 表单容器

基于 el-form 封装，支持通过配置生成表单。

## 基本用法

```vue
<template>
  <EpForm
    ref="epForm"
    v-model="formData"
    :formItemList="formItemList"
  />
</template>

<script setup lang="tsx">
import { reactive, ref, useTemplateRef } from 'vue'
import type { FormProps } from 'el-plus'

const epForm = useTemplateRef('epForm')
const formData = reactive({})

const formItemList = ref<FormProps['formItemList']>([
  {
    prop: 'name',
    label: '名称',
    required: true,
  },
  {
    prop: 'type',
    label: '类型',
    type: 'EpSelect',
    props: {
      options: [
        { label: '类型1', value: '1' },
        { label: '类型2', value: '2' },
      ],
    },
  },
])
</script>
```
## 表单数据

**不需要预定义表单字段**，`reactive({})` 即可，组件会自动管理字段值。

```typescript
// ✅ 正确：无需预定义字段
const formData = reactive({})

// ❌ 错误：不需要提前声明所有字段
const formData = reactive({
  name: '',
  status: '',
  applicant: '',
  // ...
})
```

**仅需预定义以下特殊字段：**

| 场景 | 需预定义的字段 | 示例 |
|------|---------------|------|
| 日期范围 | 开始和结束两个独立字段 | `orderDateStart: ''`, `orderDateEnd: ''` |
| 表格数组 | 空数组 | `detailList: []` |
| 附件数组 | 空数组 | `fileList: []` |

## Props

| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| v-model | 表单数据 | `Record<string, any>` | `{}` |
| formItemList | 表单项配置 | [`FormItemProps[]`](#formitemprops-配置) | `[]` |
| col | 每行列数 | `number` | `4` |
| isShowFold | 是否显示折叠 | `boolean` | `false` |
| showFieldCount | 折叠时显示数量 | `number` | `8` |
| labelWidth | 标签宽度 ^el^ | `string \| number` | `100` |
| labelPosition | 标签位置 ^el^ | `'left' \| 'right' \| 'top'` | - |
| size | 表单尺寸 ^el^ | `'large' \| 'default' \| 'small'` | `'small'` |
| scrollIntoViewOptions | 滚动到错误项配置 ^el^ | `object` | `{ inline: 'center' }` |

> ^el^ 表示继承自 [el-form](https://element-plus.org/zh-CN/component/form.html) 的属性

## FormItemProps 配置

| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| type | 组件类型 | `string` | `'EpInput'` |
| prop | 字段名 | `string` | - |
| label | 标签文本 | `string` | - |
| col | 占用列数 | `number` | - |
| disabled | 是否禁用 | `boolean` | `false` |
| show | 是否显示（支持函数） | `boolean \| () => boolean` | `true` |
| hide | 是否隐藏（支持函数） | `boolean \| () => boolean` | `false` |
| required | 是否必填 | `boolean` | `false` |
| rules | 校验规则 | `FormItemRule[]` | - |
| props | 传递给组件的属性 | `object` | - |
| render | 自定义渲染 | `() => VNode` | - |
| labelRender | 自定义标签渲染 | `({ label }) => VNode` | - |
| isShowLabel | 是否显示标签 | `boolean` | `true` |
| class | 样式类名 | `string` | - |
| style | 行内样式 | `string \| CSSProperties` | - |
| onChange | 值变化事件 | `(val, item?) => void` | - |

## Expose 方法

| 方法 | 说明 | 类型 |
|------|------|------|
| validate | 表单验证 | `() => Promise<boolean>` |
| resetFields | 重置表单 | `() => void` |
| clearValidate | 清除验证 | `(props?: string[]) => void` |
| getFormItemRenderRef | 获取表单项组件 ref | `(ref: string) => any` |

## 组件自由组合示例

在 formItemList 中可自由组合其他组件：
- type：组件名字，优先使用 Ep 前缀的组件，如 EpInput、EpSelect 等，其次使用 Element Plus 的组件，如 ElInput、ElSelect 等。
- 外层: EpFormItem的属性
- props：传递给组件的属性
- 事件：组件的事件，以 `on` 开头，如 onClick、onChange 等


```tsx
const formItemList = computed<FormProps['formItemList']>(() => [
  // 标题分组
  {
    col: 24,
    type: 'EpTitle',
    props: {
      title: '基本信息',
    },
  },
  // 输入框
  {
    prop: 'name',
    label: '名称',
    required: true,
  },
  // 下拉选择
  {
    prop: 'type',
    label: '类型',
    type: 'EpSelect',
    props: {
      options: [],
    },
  },
  // 日期范围
  {
    prop: 'orderDate',
    label: '日期范围',
    type: 'EpDatePickerRange',
    props: {
      start: formData.orderDateStart,
      end: formData.orderDateEnd,
    },
    'onUpdate:start': (val) => {
      formData.orderDateStart = val
    },
    'onUpdate:end': (val) => {
      formData.orderDateEnd = val
    },
  },
  // 表格嵌套
  {
    col: 24,
    type: 'EpTable',
    props: {
      ref: 'detailTable',
      data: formData.detailList,
      columns: [],
    },
  },
  // 附件
  {
    col: 24,
    type: 'EpAttachment',
    props: {
      modelValue: formData.fileList,
      openType: 'normal',
    },
  },
  // 页脚信息
  {
    col: 24,
    type:'EpFooterInfo',
    props: {
      modelValue: formData,
    },
  }
])
```

## 验证示例

```ts
const handleSave = async () => {
  const valid = await epForm.value?.validate()
  if (valid) {
    // 验证通过，提交数据
  }
}
```

## 获取嵌套组件 ref

```ts
// 获取 formItemList 中 props.ref='detailTable' 的组件
const table = epForm.value?.getFormItemRenderRef('detailTable')
const rows = table?.getSelectionRows()
```
