# FormPreview 使用指南

## 📖 概述

`FormPreview` 是一个独立的表单预览组件，从 `FormDesigner` 中提取出来，可在任何地方使用。它支持完整的表单交互、验证和联动规则。

## ✨ 特点

- ✅ **完全独立**：可在任何页面使用，不依赖 FormDesigner
- ✅ **支持所有字段类型**：input, select, textarea, date, grid, cascader 等
- ✅ **支持验证规则**：required, pattern, min/max, email, phone 等
- ✅ **支持联动规则**：显示/隐藏、禁用/启用、必填控制、值联动
- ✅ **支持动态数据源**：API 数据源、预定义数据源
- ✅ **非受控组件**：内部管理状态，无冲突
- ✅ **简单易用**：只需传入 `fields` 和 `formConfig`

## 📦 导入

```typescript
import { FormPreview, FormPreviewRef } from '@/components/FormDesigner';
import type { FieldConfig, FormConfig } from '@/components/FormDesigner';
```

## 🚀 基础用法

### 1. 最简单的使用

```tsx
import React, { useRef } from 'react';
import { FormPreview, FormPreviewRef } from '@/components/FormDesigner';

const MyComponent = () => {
  const previewRef = useRef<FormPreviewRef>(null);
  
  // 从后端获取表单定义
  const formSchema = await getFormDefinitionById(id);
  
  return (
    <FormPreview 
      ref={previewRef}
      fields={formSchema.fields}
      formConfig={formSchema.formConfig}
    />
  );
};
```

### 2. 在 Modal 中使用

```tsx
import React from 'react';
import { Modal } from 'antd';
import { FormPreview } from '@/components/FormDesigner';

const FormPreviewModal = ({ open, onClose, formDefinition }) => {
  if (!formDefinition) return null;

  const { schema } = formDefinition;

  return (
    <Modal
      title={`预览表单：${formDefinition.name}`}
      open={open}
      onCancel={onClose}
      footer={null}
      width={schema.formConfig.formWidth || 600}
      styles={{
        body: {
          maxHeight: '70vh',
          overflowY: 'auto',
          padding: 0,
        }
      }}
    >
      <FormPreview
        fields={schema.fields}
        formConfig={schema.formConfig}
      />
    </Modal>
  );
};
```

### 3. 使用 Ref 方法

```tsx
import React, { useRef } from 'react';
import { Button } from 'antd';
import { FormPreview, FormPreviewRef } from '@/components/FormDesigner';

const MyComponent = () => {
  const previewRef = useRef<FormPreviewRef>(null);
  
  const handleSubmit = async () => {
    // 触发表单验证和提交
    await previewRef.current?.submit();
  };
  
  const handleReset = () => {
    // 重置表单
    previewRef.current?.reset();
  };
  
  return (
    <div>
      <FormPreview 
        ref={previewRef}
        fields={fields}
        formConfig={formConfig}
      />
      
      <div style={{ marginTop: 16 }}>
        <Button type="primary" onClick={handleSubmit}>提交</Button>
        <Button onClick={handleReset} style={{ marginLeft: 8 }}>重置</Button>
      </div>
    </div>
  );
};
```

## 📝 Props 说明

### FormPreviewProps

| 属性 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `fields` | `FieldConfig[]` | ✅ | 字段列表 |
| `formConfig` | `FormConfig` | ✅ | 表单配置 |

### FormPreviewRef 方法

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `submit()` | 无 | `Promise<void>` | 提交表单（触发验证） |
| `reset()` | 无 | `void` | 重置表单 |

## 🔧 数据格式

### FormConfig 示例

```typescript
const formConfig: FormConfig = {
  title: "部署申请表单",         // 表单标题（可选）
  formWidth: 600,                // 表单弹窗宽度，单位px
  labelAlign: "right",           // 标签对齐：left | right | top
  size: "middle"                 // 表单尺寸：small | middle | large
};
```

### Fields 示例

```typescript
const fields: FieldConfig[] = [
  // 基础输入框
  {
    id: "field_1",
    type: "input",
    label: "应用名称",
    name: "appName",
    placeholder: "请输入应用名称",
    required: true,
    validationRules: [
      { type: "required", message: "应用名称不能为空" },
      { type: "maxLength", value: 50, message: "不能超过50个字符" }
    ]
  },
  
  // 下拉选择（静态选项）
  {
    id: "field_2",
    type: "select",
    label: "环境选择",
    name: "environment",
    required: true,
    dataSourceType: "static",
    options: [
      { label: "开发环境", value: "dev" },
      { label: "测试环境", value: "test" },
      { label: "生产环境", value: "prod" }
    ]
  },
  
  // 下拉选择（API 数据源）
  {
    id: "field_3",
    type: "select",
    label: "Jenkins服务器",
    name: "jenkinsServer",
    required: true,
    dataSourceType: "api",
    apiDataSource: {
      url: "/api/v1/jenkins-servers/list",
      method: "GET",
      params: { enabled: true },
      labelField: "name",
      valueField: "id"
    }
  },
  
  // 下拉选择（预定义数据源）
  {
    id: "field_4",
    type: "select",
    label: "项目组",
    name: "projectGroup",
    required: true,
    dataSourceType: "predefined",
    predefinedDataSource: {
      sourceType: "PROJECT_GROUPS"
    }
  },
  
  // 栅格布局
  {
    id: "field_5",
    type: "grid",
    label: "基础信息",
    name: "grid_basic",
    columns: 2,
    columnSpans: [12, 12],
    gutter: 16,
    children: [
      // 第一列
      [
        {
          id: "field_6",
          type: "input",
          label: "创建人",
          name: "creator",
          required: true
        }
      ],
      // 第二列
      [
        {
          id: "field_7",
          type: "date",
          label: "创建日期",
          name: "createDate",
          required: true
        }
      ]
    ]
  }
];
```

## 🌟 实际应用场景

### 场景1：工作流设计页面预览启动表单

```tsx
// src/pages/Workflow/Design/components/FormPreviewModal.tsx
import { FormPreview } from '@/components/FormDesigner';

const FormPreviewModal = ({ formDefinition, open, onClose }) => {
  const { schema } = formDefinition;
  
  return (
    <Modal open={open} onCancel={onClose} width={schema.formConfig.formWidth}>
      <FormPreview 
        fields={schema.fields}
        formConfig={schema.formConfig}
      />
    </Modal>
  );
};
```

### 场景2：表单设计器内部预览

```tsx
// src/components/FormDesigner/Designer.tsx
const FormDesigner = () => {
  const [previewVisible, setPreviewVisible] = useState(false);
  const [fields, setFields] = useState<FieldConfig[]>([]);
  const [formConfig, setFormConfig] = useState<FormConfig>({});
  
  return (
    <>
      <Button onClick={() => setPreviewVisible(true)}>预览</Button>
      
      <Modal open={previewVisible} onCancel={() => setPreviewVisible(false)}>
        <FormPreview fields={fields} formConfig={formConfig} />
      </Modal>
    </>
  );
};
```

### 场景3：独立的表单预览页面

```tsx
// src/pages/Form/Preview/index.tsx
import { useParams } from 'react-router-dom';
import { FormPreview } from '@/components/FormDesigner';

const FormPreviewPage = () => {
  const { id } = useParams();
  const [formSchema, setFormSchema] = useState(null);
  
  useEffect(() => {
    const loadForm = async () => {
      const data = await getFormDefinitionById(id);
      setFormSchema(data.schema);
    };
    loadForm();
  }, [id]);
  
  if (!formSchema) return <div>加载中...</div>;
  
  return (
    <div className="container">
      <h1>表单预览</h1>
      <FormPreview 
        fields={formSchema.fields}
        formConfig={formSchema.formConfig}
      />
    </div>
  );
};
```

## ⚠️ 重要说明

### 1. 非受控组件

`FormPreview` 是**非受控组件**，内部通过 `Ant Design Form` 管理状态：

- ✅ **不要**传递 `value` 和 `onChange`（会导致冲突）
- ✅ **不要**尝试从外部控制字段值
- ✅ 使用 `ref` 方法获取表单值或提交表单

### 2. 数据格式统一

无论在哪里使用，数据格式都是一致的：

```typescript
<FormPreview 
  fields={formSchema.fields}     // FieldConfig[]
  formConfig={formSchema.formConfig}  // FormConfig
/>
```

### 3. 与 FormRenderer 的区别

| 特性 | FormPreview | FormRenderer |
|------|-------------|--------------|
| 推荐使用 | ✅ 是 | ❌ 已废弃 |
| 受控模式 | ❌ 非受控 | ⚠️ 部分受控（有问题） |
| 下拉框可选中 | ✅ 正常 | ❌ 有bug |
| 使用场景 | 预览、交互 | 已废弃 |

**建议**：所有新代码都使用 `FormPreview`，不要再使用 `FormRenderer`。

## 📚 相关文档

- [FormDesigner 文档](./README.md)
- [字段类型定义](./types.ts)
- [工作流扩展字段](./extensions/workflow/README.md)

