# XFormGroup 表单组组件

## 组件概述

XFormGroup 是一个基于 Vue 3 + TypeScript + Vant 4 开发的表单组组件，支持多标签页表单展示，可以通过配置实现复杂的表单组合。组件支持两种模式：普通表单模式和插槽（slot）模式。

## 功能特性

- 🏷️ **多标签页支持**：使用 Vant Tabs 组件实现标签页切换
- 🔧 **插槽模式**：支持通过 slot 自定义表单内容
- 📝 **表单验证**：支持表单数据验证和提交
- 🎯 **动态配置**：通过配置文件动态生成表单结构
- 🔄 **数据绑定**：支持表单数据的双向绑定
- 📱 **移动端优化**：基于 Vant 4 组件库，专为移动端设计

## 基础用法

```vue
// 见 FormGroupDemo.vue
```

## Props 参数详解

### configName

- **类型**: `string`
- **默认值**: `''`
- **说明**: 表单配置名称，用于从后端获取表单配置信息
- **示例**: `'appapplyuserinfoFormGroup'`

### serviceName

- **类型**: `string | undefined`
- **默认值**: `undefined`
- **说明**: 服务名称，用于指定后端服务
- **示例**: `'af-apply'`

### groupFormData

- **类型**: `object`
- **默认值**: `() => ({})`
- **说明**: 表单组数据，用于初始化表单数据
- **示例**:

```js
// -{
// -  userInfo: { name: '张三', age: 25 },
// -  deviceInfo: { deviceId: '001', status: 'active' }
// -}
```

### mode

- **类型**: `string`
- **默认值**: `'查询'`
- **说明**: `表单模式，控制表单的显示和操作模式`
- **可选值**: `'查询'` | `'新增'` | `'编辑'` | `'查看'`

## 插槽（Slot）使用详解

### 插槽模式配置

当配置中的 `formGroupType` 为 `'slot'` 时，组件会渲染插槽内容而不是默认的 XForm 组件。

#### 插槽参数

插槽会接收以下参数：

- **userItem/deviceItem**: 当前标签页的配置项
- **userFormData/deviceFormData**: 当前标签页对应的表单数据
- **setRef**: 注册表单实例的函数
- **removeRef**: 注销表单实例的函数

### 完整使用示例

#### 1. 主页面组件

> 见 [FormGroupDemo.vue](FormGroupDemo.vue)

#### 2. 用户信息表单组件

> 见 [UserForm.vue](UserForm.vue)

#### 3. 设备信息表单组件

> 见 [DeviceForm.vue](DeviceForm.vue)

#### 4. 配置结构示例

```json
{
  "groups": [
    {
      "groupName": "userInfo",
      "describe": "用户信息",
      "tableName": "用户信息表",
      "formGroupType": "slot",
      "slotName": "user",
      "showSubmitBtn": false
    },
    {
      "groupName": "deviceInfo",
      "describe": "设备信息",
      "tableName": "设备信息表",
      "formGroupType": "slot",
      "slotName": "device",
      "showSubmitBtn": true
    }
  ],
  "showSubmitBtn": true
}
```

#### 5. setRef 和 removeRef 工作原理

```js
// XFormGroup 组件内部的实现逻辑
const xFormListRef = ref([])

function setRef(refValue) {
  if (refValue && !xFormListRef.value.includes(refValue)) {
    xFormListRef.value.push(refValue)
    console.log('注册表单实例:', refValue.formGroupName)
  }
}

function removeRef(refValue) {
  const idx = xFormListRef.value.indexOf(refValue)
  if (idx !== -1) {
    xFormListRef.value.splice(idx, 1)
    console.log('注销表单实例:', refValue.formGroupName)
  }
}

async function submit() {
  const allFormData = {}
  for (const formInstance of xFormListRef.value) {
    try {
      await formInstance.validate()
      if (formInstance.formGroupName && typeof formInstance.getFormData === 'function') {
        allFormData[formInstance.formGroupName] = formInstance.getFormData()
      }
    }
    catch (error) {
      console.error('表单验证失败:', error)
      return
    }
  }
  emit('submit', allFormData)
}
```

### 关键要点

1. **必须实现的方法**：
   - `validate()`: 表单验证方法
   - `getFormData()`: 获取表单数据方法
   - `formGroupName`: 表单组名称
2. **生命周期管理**：
   - 在 `onMounted` 时调用 `setRef` 注册
   - 在 `onUnmounted` 时调用 `removeRef` 注销
3. **数据传递**：
   - 通过 `defineExpose` 暴露方法给父组件
   - 通过 `props` 接收父组件传递的参数
4. **插槽使用**：
   - 插槽名称必须与配置中的 `slotName` 一致
   - 必须传递 `setRef` 和 `removeRef` 给子组件

## 事件

### submit

- **参数**: `formData: object`
- **说明**: 表单提交事件，当用户点击提交按钮时触发
- **示例**:

```javascript
function handleSubmit(formData) {
  console.log('表单数据:', formData)
  // 处理表单提交逻辑
}
```

## 方法

### init(params: Form)

- **参数**: `params` - 初始化参数对象
- **说明**: 手动初始化组件，可以动态改变配置
- **示例**:

```javascript
formGroup.value.init({
  configName: 'newConfig',
  serviceName: 'newService',
  groupFormData: { ...any },
  mode: '新增'
})
```

### setRef(refValue)

- **参数**: `refValue` - 表单实例
- **说明**: 注册表单实例到组件中，用于统一管理和提交

### removeRef(refValue)

- **参数**: `refValue` - 表单实例
- **说明**: 从组件中注销表单实例

## 配置结构说明

### 基础配置结构

```json
{
  "groups": [
    {
      "groupName": "userInfo",
      "describe": "用户信息",
      "tableName": "用户信息表",
      "formGroupType": "form",
      "slotName": "user",
      "showSubmitBtn": false
    },
    {
      "groupName": "deviceInfo",
      "describe": "设备信息",
      "tableName": "设备信息表",
      "formGroupType": "slot",
      "slotName": "device",
      "showSubmitBtn": true
    }
  ],
  "showSubmitBtn": true
}
```

### 配置项说明

| 字段名        | 类型    | 说明                                        |
| ------------- | ------- | ------------------------------------------- |
| groupName     | string  | 分组名称，用于数据分组                      |
| describe      | string  | 标签页显示标题                              |
| tableName     | string  | 表名，当 describe 为空时作为标题            |
| formGroupType | string  | 表单类型，'form' 为普通表单，'slot' 为插槽  |
| slotName      | string  | 插槽名称，当 formGroupType 为 'slot' 时使用 |
| showSubmitBtn | boolean | 是否显示提交按钮                            |

## 样式定制

组件使用 Less 预处理器，可以通过以下方式定制样式：

```less
#x-form-group {
  background-color: #f7f8fa;
  padding-bottom: 10px;

  .x-form-group-item {
    margin: 20px 0;
  }

  // 自定义标签页样式
  :deep(.van-tabs__nav) {
    background-color: #fff;
  }

  // 自定义按钮样式
  :deep(.van-button--primary) {
    background-color: #1989fa;
  }
}
```

## 注意事项

1. **插槽注册**: 使用插槽模式时，子组件必须通过 `setRef` 和 `removeRef` 注册到父组件
2. **数据同步**: 插槽组件需要实现 `getFormData` 方法返回表单数据
3. **表单验证**: 插槽组件可以实现 `validate` 方法进行表单验证
4. **生命周期**: 插槽组件需要在 `onMounted` 时注册，`onUnmounted` 时注销
5. **配置加载**: 组件会在 `onBeforeMount` 时自动加载配置，也可以通过 `init` 方法手动初始化

```

## 这个文档详细介绍了 XFormGroup 组件的使用方法，特别是插槽的使用方式和各个参数的详细说明。开发者可以根据这个文档快速上手使用该组件。
```
