# @qin-ui/antd-vue-pro

> 基于 **Ant Design Vue v4+** 和 **Vue 3.x** 的二次封装高级组件库，提供高度可配置、Schema 驱动的 `ProForm` 和 `ProTable`，助您摆脱繁琐的模板代码，快速搭建桌面端中后台应用。

<p align="center">
  <img src="https://img.shields.io/badge/Ant%20Design%20Vue-4.x-blue" alt="Ant Design Vue 4.x" />
  <img src="https://img.shields.io/badge/Vue-3.3%2B-brightgreen" alt="Vue 3.3+" />
  <img src="https://img.shields.io/badge/TypeScript-5.x-blue" alt="TypeScript" />
  <img src="https://img.shields.io/badge/License-MIT-green" alt="MIT" />
</p>

## 📝 [使用示例和文档详细内容](https://dufan3715.github.io/pro-components/)

---

## ✨ 核心特性

- 🛡️ **底层坚实**：基于 Ant Design Vue 4.x 构建，原生支持 Vue 3.3+。
- 🔥 **Schema 驱动**：使用声明式 JSON 配置即可快速生成表单，极大地减少了模板文件的编写。
- ⚙️ **动态自适应**：支持表单字段的动态隐藏、禁用与规则联动，表格列的动态控制与配置。
- 🧩 **极致扩展**：原生支持自定义渲染组件与插槽定制，提供 `ProComponentProvider` 进行全局默认属性覆盖。
- 📐 **完美类型推导**：基于 TypeScript 提供完备的强类型推导和自动补全，开发体验流畅。

---

## 📦 安装

确保您的项目中已安装 `ant-design-vue` (v4+) 和 `vue` (v3.3+)：

```bash
npm i @qin-ui/antd-vue-pro
# 或使用 pnpm
pnpm add @qin-ui/antd-vue-pro
```

> [!WARNING]
> **2.0+ 升级提示**：2.0 版本进行了底层重构，`useForm` 返回的 `formData` 从原本的 `ref` 包装调整为了真正的 `reactive` 响应式对象，获取和修改属性时无需使用 `.value`。

---

## 🤖 AI 辅助开发

本项目内置 AI 上下文初始化工具。安装后在项目根目录执行：

```bash
npx @qin-ui/antd-vue-pro init-ai
```

将在项目中生成双载体 AI 上下文，使 Cursor / Claude Code / Codex 等 AI 工具深度理解本库的 Schema 驱动用法与属性透传规则：

- `AGENTS.md` — 核心使用规则（跨工具开放约定，会话时自动注入，AI 默认加载）
- `.agents/skills/antd-vue-pro/SKILL.md` — skills 入口（速查 + 参考导航）
- `.agents/skills/antd-vue-pro/references/` — 完整使用文档与结构化 API 元数据

> 生成的 `AGENTS.md` 使用标记区块写入，重复执行 `init-ai` 可安全更新，不影响项目内其他库的指令。建议将生成的文件提交到 Git 仓库，团队共享 AI 上下文。

---

## 🚀 快速开始

### 1. 全局注册组件（可选）

```ts
import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css';
import AntdVuePro from '@qin-ui/antd-vue-pro';
import App from './App.vue';

const app = createApp(App);
app.use(Antd);
app.use(AntdVuePro); // 全局注册 ProForm, ProTable 和 ProComponentProvider
app.mount('#app');
```

### 2. 基础表单使用示例

```vue
<script setup lang="ts">
import { ProForm, useForm } from '@qin-ui/antd-vue-pro';

interface UserForm {
  username: string;
  age: number;
  gender: string;
}

// 1. 创建类型安全的表单实例
const form = useForm<UserForm>(
  { username: '张三', age: 18, gender: 'male' }, // 初始数据
  [
    {
      path: 'username',
      label: '用户名',
      component: 'input',
      rules: [{ required: true, message: '请输入用户名' }],
    },
    {
      path: 'age',
      label: '年龄',
      component: 'input-number',
      min: 1,
      max: 150,
    },
    {
      path: 'gender',
      label: '性别',
      component: 'select',
      options: [
        { label: '男', value: 'male' },
        { label: '女', value: 'female' },
      ],
    },
  ]
);

// 2. 提交表单校验与数据获取
const handleSubmit = async () => {
  try {
    await form.formRef.value?.validate();
    console.log('提交的数据：', form.formData);
  } catch (error) {
    console.error('校验失败：', error);
  }
};
</script>

<template>
  <div style="padding: 24px; max-width: 600px;">
    <ProForm :form="form" />
    <a-button type="primary" style="margin-top: 16px;" @click="handleSubmit">
      提交表单
    </a-button>
  </div>
</template>
```

---

## 🧱 属性分层透传（核心规则）

ProForm/ProTable 是渲染引擎，所有真实 UI 来自 ant-design-vue。**Field 上的属性会被"剥离到不同 DOM 层"，不是全塞给输入控件**。写错层就会失效，这是最容易踩的坑：

```
<a-col :span="8">            ← Grid 层（仅 grid 开启时）
  <a-form-item label="...">  ← FormItem 层
    <a-input placeholder>     ← 输入控件层
  </a-form-item>
</a-col>
```

| 属性                                                                                                                                                                                                                   | 落到哪一层                       | 说明                 |
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------- | :------------------- |
| `span` / `offset` / `push` / `pull` / `flex` / `xs`..`xxl`                                                                                                                                                             | `<a-col>` Grid 层                | 仅 `grid` 开启时生效 |
| `label` / `rules` / `tooltip` / `colon` / `labelCol` / `wrapperCol` / `extra` / `help` / `validateTrigger` / `validateFirst` / `valuePropName` / `normalize` / `formItemStyle` / `formItemClass` / `formItemDataAttrs` | `<a-form-item>` 层               | 表单项相关属性       |
| `disabled` / `placeholder` / `allowClear` / `options` / `mode` / `maxlength` / `componentStyle` / `componentClass` / `componentDataAttrs` + 该控件其余 ant-design-vue 原生属性                                         | 输入控件本身（`a-input` 等）     | 其余全部             |
| `component` / `hidden` / `modelProp` / `valueFormatter` / `fields` / `slots` / `formItemContainer` / `componentContainer` / `extraProps`                                                                               | ProForm 逻辑消费，**不绑到 DOM** | 框架级属性           |

> **规则**：`span` 给 Grid，`label`/`rules` 给 FormItem，其余给输入控件。输入控件的具体属性名/类型请以 [ant-design-vue 官方文档](https://antdv.com) 为准。

---

## 📚 组件 API 说明

### 1. ProComponentProvider

作为全局或局部范围的上下文配置器，通过传入 `component-vars` 属性来统一覆盖子组件的默认配置。

#### Props

| 参数名           | 说明                                    | 类型            | 默认值 |
| :--------------- | :-------------------------------------- | :-------------- | :----- |
| `component-vars` | 需要全局 provide 给子组件的默认属性配置 | `ComponentVars` | -      |

#### 内置默认预设（INJECT_CONFIG）

ProComponentProvider 内置了一套默认属性预设，**即使不配置 `component-vars` 也会生效**。Field 配置优先级最高，会覆盖这些预设。以下为各组件的内置默认值（写代码时需知晓，避免行为与预期不符）：

| component                                      | 默认预设                                                                                                                                                                                                                                                      |
| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `switch`                                       | `{ modelProp: 'checked' }` —— v-model 绑定 `checked` 而非 `value`                                                                                                                                                                                             |
| `input` / `input-password`                     | `{ maxlength: 100, allowClear: true, placeholder: '请输入' }`                                                                                                                                                                                                 |
| `textarea`                                     | `{ maxlength: 200, autoSize: { minRows: 3, maxRows: 6 }, showCount: true, allowClear: true, placeholder: '请输入' }`                                                                                                                                          |
| `input-number`                                 | `{ max: 1e15-1, min: -(1e15+1), controls: false, placeholder: '请输入', style: { width: '100%' } }`                                                                                                                                                           |
| `select` / `cascader`                          | `{ allowClear: true, placeholder: '请选择', getPopupContainer }`                                                                                                                                                                                              |
| `date-picker` / `range-picker` / `time-picker` | `{ allowClear: true, getPopupContainer, style: { width: '100%' } }`                                                                                                                                                                                           |
| `pro-form`                                     | `{ grid: { gutter: { xs: 8, sm: 16, md: 16, lg: 24 } } }`                                                                                                                                                                                                     |
| `pro-form-item`                                | `{ validateFirst: true, span: 8 }`                                                                                                                                                                                                                            |
| `pro-table`                                    | `{ pagination: { showTotal, showSizeChanger, pageSizeOptions: ['10', '20', '30', '40', '50', '100'], showQuickJumper: true }, searchFormConfig: { layout: 'grid', expand: { minExpandRows: 2, expandStatus: false } }, control: true, addIndexColumn: true }` |

> `modelProp` 控制 v-model 绑定的属性名，默认 `'value'`（即 `v-model:value`）。`switch` 经预设绑定为 `checked`，通常无需手动设置。

---

### 2. ProForm

基于 Ant Design Vue Form 深度封装的高级表单组件。

#### Props

| 参数名 | 说明                                                      | 类型                   | 默认值  |
| :----- | :-------------------------------------------------------- | :--------------------- | :------ |
| `form` | 由 `useForm` 返回的表单实例                               | `Form`                 | -       |
| `grid` | 是否启用栅格网格布局，支持传入 Grid 配置以配置自适应      | `boolean \| GridProps` | `false` |
| `...`  | 其余属性均继承自 Ant Design Vue `a-form` 组件的原生 Props | `FormProps`            | -       |

#### Events & Methods

- 所有事件（如 `finish`, `finishFailed` 等）和方法（如 `validate`, `resetFields`）均与 Ant Design Vue `a-form` 组件完全继承，且能直接透传绑定。

---

### 3. ProTable

基于 Ant Design Vue Table 深度封装的高级表格组件，将搜索表单、列配置、分页高度集成。

#### Props

| 参数名             | 说明                                                      | 类型                                   | 默认值  |
| :----------------- | :-------------------------------------------------------- | :------------------------------------- | :------ |
| `table`            | 由 `useTable` 返回的表格实例                              | `Table`                                | -       |
| `search`           | 触发表格查询的回调函数，需返回 Promise 或直接返回查询数据 | `(params: any) => Promise<any> \| any` | -       |
| `addIndexColumn`   | 是否自动在表格首列插入序号列                              | `boolean`                              | `false` |
| `immediateSearch`  | 表格挂载时（onMounted）是否立即触发一次 `search` 查询     | `boolean`                              | `false` |
| `control`          | 是否在表格右上角工具栏中展示尺寸调节和列动态显示控制按钮  | `boolean`                              | `true`  |
| `searchFormConfig` | 查询表单的布局配置参数                                    | `SearchFormConfig`                     | -       |
| `tableContainer`   | 表格的外部包裹容器，默认为 false                          | `Component \| false`                   | -       |
| `...`              | 其余参数继承自 Ant Design Vue `a-table` 的原生属性        | `TableProps`                           | -       |

#### Slots

| 插槽名        | 说明                                               |
| :------------ | :------------------------------------------------- |
| `search-form` | 自定义搜索栏表单内容                               |
| `button-bar`  | 自定义操作按钮组区域（位于搜索栏下方，表格左上方） |
| `toolbar`     | 自定义工具栏区域（位于表格右上方控制按钮旁）       |
| `table`       | 完全自定义渲染表格区域                             |

#### 数据流

ProTable 不会自动请求数据，**查询由你提供的 `search` 回调驱动**。内部串联逻辑：

```
点击搜索  -> 重置分页到第 1 页        -> 调用 search()
分页/排序变化 -> 更新 pageParam        -> 调用 search()
点击重置  -> resetQueryParams()       -> 调用 search()
挂载(immediateSearch) -> 立即触发一次   -> 调用 search()
```

`search` 回调内通常组装查询参数并赋值数据源：

```ts
const fetchData = async () => {
  const res = await api.list({
    ...table.searchForm.formData, // 搜索条件
    ...table.pageParam, // 分页
  });
  table.dataSource.value = res.data;
  table.setPageParam({ total: res.total });
};

// 重置按钮（ProTable 内部已串联 resetQueryParams -> search，一般无需手动处理）
```

---

## ⚙️ 核心 Hooks 说明

### 1. `useForm`

用于创建表单管理对象，整合了表单数据、字段规则和 ref 控制。

#### 入参定义

```ts
const form = useForm<D>(initFormData?, initFields?, root?)
```

- `initFormData`: 表单初始数据对象（`DeepPartial<D>`）
- `initFields`: 初始字段配置数组（`Field[]`）
- `root`: 是否创建根 Form 实例，默认为 `true`。若为 `false`，则内部会隐式 inject 父级表单上下文。

#### 返回值 (Form 实例)

| 属性/方法                      | 说明                                                                                                                           | 类型                             |
| :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------- | :------------------------------- |
| `formData`                     | 响应式表单数据对象（**2.0+ 中由 reactive 包装**）                                                                              | `Reactive<D>`                    |
| `fields`                       | 响应式表单字段配置数组引用                                                                                                     | `Ref<Field[]>`                   |
| `formRef`                      | 底层 Ant Design Vue `a-form` 的 DOM/组件引用实例                                                                               | `Ref<FormInstance \| undefined>` |
| `getFormData(path)`            | 安全获取指定字段路径（支持深层 'a.b'）的数据值                                                                                 | `(path) => any`                  |
| `setFormData(path, value)`     | 路径写入或函数式更新；传对象（`{...}`）批量覆盖整个表单；传函数 `(prev) => new` 批量更新                                       | `(path, val) => void`            |
| `getField(path, opts?)`        | 获取指定 path 的字段配置，支持查找函数定位，支持配置 `{ all: true }` 获取所有匹配项                                            | `(path, opts) => Field`          |
| `setField(path, patch, opts?)` | 默认合并更新字段配置；`{updateType:'rewrite'}` 覆盖；支持函数式 `setField(path, prev=>({...}))`；`{all:true}` 批量更新所有匹配 | `(path, patch, opts) => void`    |
| `deleteField(path, opts?)`     | 删除字段配置；`{all:true}` 删除所有匹配的字段                                                                                  | `(path, opts?) => void`          |
| `appendField(path, field)`     | 在指定字段后追加新字段（入参可为数组）；`undefined` 在末尾追加；`{all:true}` 所有匹配后追加                                    | `(path, field, opts?) => void`   |
| `prependField(path, field)`    | 在指定字段前插入新字段（入参可为数组）；`undefined` 在开头插入；`{all:true}` 所有匹配前插入                                    | `(path, field, opts?) => void`   |
| `getParentField(path, opts?)`  | 查找父级字段配置；`{all:true}` 返回所有匹配的父级字段                                                                          | `(path, opts?) => Field`         |

---

### 2. `useTable`

用于创建和管理表格实例，内置集成了列配置操作与搜索表单组件。

#### 入参参数

```ts
const table = useTable<D, T>({
  columns: [], // 初始列配置
  dataSource: [], // 静态初始数据源
  pageParam: {}, // 分页参数配置
  searchParam: {}, // 搜索栏初始数据
  searchFields: [], // 搜索栏字段 Schema 配置
});
```

#### 返回值 (Table 实例)

| 属性/方法                 | 说明                                                      | 类型                   |
| :------------------------ | :-------------------------------------------------------- | :--------------------- |
| `columns`                 | 响应式表格列配置数组                                      | `Ref<Column[]>`        |
| `dataSource`              | 响应式表格列表数据源                                      | `Ref<T[]>`             |
| `pageParam`               | 响应式分页参数对象（包含 `current`, `pageSize`, `total`） | `Reactive<PageParam>`  |
| `searchForm`              | 搜索栏表单关联的 `useForm` 实例，提供完美的表单操作 API   | `Form<D>`              |
| `setColumn(key, patch)`   | 合并或重置修改指定 key 的列配置属性（如 width、title 等） | `(key, patch) => void` |
| `deleteColumn(key)`       | 动态移除某一个指定 key 对应的表格列配置                   | `(key) => void`        |
| `appendColumn(key, col)`  | 在某一个列的后方动态追加配置列                            | `(key, col) => void`   |
| `prependColumn(key, col)` | 在某一个列的前方动态插入配置列                            | `(key, col) => void`   |
| `setPageParam(param)`     | 增量设置当前分页参数值，支持传入对象或更新函数            | `(param) => void`      |
| `resetQueryParams()`      | 重置搜索参数，并恢复分页至第 1 页                         | `() => void`           |

#### 列配置（Column）

`columns` 数组中每一项为 `Column<T>` 类型，**继承 ant-design-vue `ColumnType`**，因此所有原生列属性（`title` / `width` / `fixed` / `align` / `customRender` / `ellipsis` 等）均可用。在此基础上新增：

| 属性        | 说明                                                                                      | 类型                 | 默认值  |
| :---------- | :---------------------------------------------------------------------------------------- | :------------------- | :------ |
| `dataIndex` | 列数据路径（主要字段），类型安全，支持 `'name'` / `'address.city'` / `['address','city']` | `string \| string[]` | -       |
| `key`       | 列字段标识（辅助），仅当 `dataIndex` 无法满足时使用，匹配优先级低于 `dataIndex`           | `string`             | -       |
| `hidden`    | 是否隐藏该列（配合列动态控制）                                                            | `boolean`            | `false` |

---

## 📄 字段配置（`Field`）详解

在进行表单 Schema 编写时，`Field` 数组中的每一项都支持以下属性定义：

### 公共基础属性

| 属性名               | 说明                                                                          | 类型                          | 默认值    |
| :------------------- | :---------------------------------------------------------------------------- | :---------------------------- | :-------- |
| `path`               | 字段标识，需对应数据对象 `formData` 的 key，支持多级嵌套，例如 `address.city` | `string`                      | -         |
| `label`              | 字段中文标签，支持字符串或直接传入 VNode 组件进行自定义                       | `string \| Component \| Slot` | -         |
| `component`          | 调用的表单项组件的类型，支持内置类型键名或直接传入自定义 Vue 组件             | `string \| Component`         | `'input'` |
| `hidden`             | 字段是否被隐藏（在 DOM 中彻底不渲染，但数据保留），支持 Ref/Computed 响应式   | `boolean \| Ref<boolean>`     | `false`   |
| `disabled`           | 组件的禁用状态，支持 Ref/Computed 响应式                                      | `boolean \| Ref<boolean>`     | `false`   |
| `rules`              | 字段数据校验规则，遵循 ant-design-vue Form 校验格式                           | `Rule[]`                      | -         |
| `span`               | 栅格占位宽度（在 ProForm 开启 `grid` 网格布局后有效）                         | `number`                      | -         |
| `formItemStyle`      | 挂载在外部 `a-form-item` 节点上的额外 CSS 样式属性                            | `CSSProperties`               | -         |
| `formItemClass`      | 挂载在外部 `a-form-item` 节点上的自定义类名                                   | `string`                      | -         |
| `formItemContainer`  | 针对该表单项的最外层 DOM 包裹组件                                             | `Component`                   | -         |
| `formItemDataAttrs`  | 附加在 `a-form-item` DOM 节点上的自定义 data 属性                             | `Record<string, string>`      | -         |
| `componentStyle`     | 直接传递给内部表单输入组件的额外 CSS 样式属性                                 | `CSSProperties`               | -         |
| `componentClass`     | 直接传递给内部表单输入组件的自定义类名                                        | `string`                      | -         |
| `componentContainer` | 针对表单输入组件的包裹组件（位于 FormItem 与组件之间）                        | `Component`                   | -         |
| `componentDataAttrs` | 附加在内部输入组件 DOM 节点上的自定义 data 属性                               | `Record<string, string>`      | -         |
| `slots`              | 该表单项的插槽自定义内容，包含 formItem 插槽或组件插槽                        | `Record<string, Slot>`        | -         |
| `valueFormatter`     | 字段值转换处理器，可在输入更新或提取数据时做 get/set 转换                     | `ValueFormatter`              | -         |
| `modelProp`          | 双向绑定的数据属性名称（当使用自定义组件且非 value 绑定时）                   | `string`                      | `'value'` |
| `fields`             | 嵌套子表单项的 Schema 数组配置（用于分组或复杂嵌套表单）                      | `Field[]`                     | -         |
| `grid`               | 针对当前嵌套子表单项所使用的网格布局参数（仅当有 `fields` 时有效）            | `boolean \| GridProps`        | -         |

#### `valueFormatter` 字段值转换

控制表单值与组件值之间的转换（如日期 `dayjs` 与字符串互转）。在表单数据写入前（computed setter 中）执行，支持两种形态。**函数形态仅 set（写入）方向生效，读取时不转换；对象形态 get/set 双向生效：**

```ts
// 函数形态：(新值, 旧值) => 转换后的值，写回 formData
{ path: 'name', component: 'input', valueFormatter: (val, oldVal) => val?.trim() }

// 对象形态：get 读出时转换，set 写入时转换
{
  path: 'birthday',
  component: 'date-picker',
  valueFormatter: {
    get: (val) => (val ? dayjs(val) : null),                          // formData -> 组件显示
    set: (val) => (val ? dayjs(val).format('YYYY-MM-DD') : null),     // 组件 -> formData
  },
}
```

> ⚠️ `valueFormatter` 不支持响应式（不能包 `ref`/`computed`），与 `component` / `fields` / `slots` / `modelProp` 等同属不支持响应式的属性。

---

### 🔄 响应式联动

控制类属性（`disabled` / `hidden` / `rules` 等）支持三种响应式模式，按场景选最简的：

```ts
// A. computed() 声明式 -- 初始化时已知的联动（首选）
disabled: computed(() => !form.formData.enabled),
rules: computed(() => form.formData.hasLimit ? [{ required: true, message: '必填' }] : []),

// B. ref() -- 外部共享状态
const isDisabled = ref(false);
disabled: isDisabled,

// C. setField() 命令式 -- 事件驱动的运行时变更
form.setField('limitCount', { disabled: true });
```

> **规则**：初始化时已知的联动用 `computed()`，运行时事件触发的用 `setField()`，外部共享状态用 `ref()`。能用 `computed()` 解决就不要用 `setField()`。

#### 不支持响应式的属性

以下属性不能包 `ref`/`computed`（会失效或引发渲染异常），只能传静态值：

| 属性                                       | 原因                                                |
| :----------------------------------------- | :-------------------------------------------------- |
| `component`                                | 组件对象/函数，响应式代理会破坏渲染（需 `markRaw`） |
| `valueFormatter`                           | 纯转换函数，无需响应式                              |
| `fields`                                   | 嵌套字段数组结构，响应式代理会干扰内部解析          |
| `slots`                                    | 插槽内容，响应式代理会破坏渲染                      |
| `modelProp`                                | 字符串标识，无需响应式                              |
| `formItemContainer` / `componentContainer` | 容器组件，需 `markRaw`                              |

> 动态切换 `component` 或 `slots` 时，用 `setField()` 命令式更新，而非包 `computed`。

---

### 内置组件映射（`component` 可选值）

组件库默认封装了 Ant Design Vue 的高频交互组件，您可以在 `component` 属性中填入以下预设键名来自动调用：

| 内置键名           | 渲染对应的 Ant Design Vue 组件  |
| :----------------- | :------------------------------ |
| `'input'`          | `a-input` 文本输入框            |
| `'textarea'`       | `a-textarea` 文本域             |
| `'input-search'`   | `a-input-search` 搜索输入框     |
| `'input-password'` | `a-input-password` 密码框       |
| `'input-number'`   | `a-input-number` 数字输入框     |
| `'select'`         | `a-select` 下拉选择器           |
| `'cascader'`       | `a-cascader` 级联选择器         |
| `'date-picker'`    | `a-date-picker` 日期选择器      |
| `'range-picker'`   | `a-range-picker` 日期范围选择器 |
| `'time-picker'`    | `a-time-picker` 时间选择器      |
| `'checkbox-group'` | `a-checkbox-group` 复选框组     |
| `'radio-group'`    | `a-radio-group` 单选按钮组      |
| `'switch'`         | `a-switch` 开关切换器           |
| `'slider'`         | `a-slider` 滑动条               |
| `'tree-select'`    | `a-tree-select` 树形选择器      |
| `'transfer'`       | `a-transfer` 穿梭框             |
| `'custom'`         | 完全渲染自定义组件              |

---

### 🧩 自定义组件（4 种方式）

`Field.component` 的解析优先级（高 -> 低）：

`teleport 插槽注入` > `ProComponentProvider.componentMap` > `内置 componentMap` > `原始 component 值`

#### 方式 1：传入 SFC 单文件组件对象（推荐，单字段最常用）

`component` 直接传组件对象，**必须用 `markRaw` 包裹**：

```ts
import { markRaw } from 'vue';
import MyInput from './MyInput.vue';

const fields = [{ path: 'code', label: '验证码', component: markRaw(MyInput) }];
```

> ⚠️ **必须 `markRaw`**：不包会被 Vue 当成响应式对象深度代理，触发性能警告甚至渲染异常。类型上 `component` 接受 `RenderComponentType | Raw<RenderComponentType>`，`Raw<T>` 即 markRaw 的类型标记。此字段不支持响应式（不能包 `ref`/`computed`）。

#### 方式 2：传入 render 函数（单字段，需动态拼装 props 时）

`component` 传 `(props, ctx) => VNode`。`props` 含 v-model 绑定值与 path，`ctx.attrs` 含透传属性：

```ts
import { h } from 'vue';
import MyInput from './MyInput.vue';

const fields = [
  {
    path: 'code',
    label: '验证码',
    component: (p, ctx) => h(MyInput, { ...p, ...ctx.attrs }),
  },
];
```

#### 方式 3：ProComponentProvider 注入 componentMap（全局复用，推荐多字段场景）

在根用 `componentMap` 注册，Field 里用字符串引用。**可覆盖内置组件**（如 `input: MyInput` 替换全局 `input`）。

```vue
<script setup lang="ts">
import { ProComponentProvider } from '@qin-ui/antd-vue-pro';
import MyRichTextEditor from './components/MyRichTextEditor.vue';

const componentMap = {
  'rich-editor': MyRichTextEditor,
};
</script>

<template>
  <ProComponentProvider :component-map="componentMap">
    <AppLayout />
  </ProComponentProvider>
</template>
```

追加 TypeScript 全局声明获取强类型补全（项目任意 `.d.ts`）：

```ts
declare module '@qin-ui/antd-vue-pro' {
  interface ComponentMap {
    'rich-editor': typeof MyRichTextEditor;
  }
}
```

之后 `component: 'rich-editor'` 即获精准属性类型联想与校验。

#### 方式 4：模板 scoped slot（声明式，简单替换）

插槽名 = 字段 `path`，绑定参数通过 `v-bind="scoped"` 转发（teleport 机制，优先级最高）：

```vue
<ProForm :form="form">
  <template #agreement="scoped">
    <a-checkbox v-bind="scoped">同意协议</a-checkbox>
  </template>
</ProForm>
```

#### 选择建议

| 场景                         | 推荐方式                          |
| :--------------------------- | :-------------------------------- |
| 单字段复用一个 SFC           | 方式 1（`markRaw(SFC)`）          |
| 单字段、需动态拼装 props     | 方式 2（render 函数）             |
| 多处复用 / 替换内置组件      | 方式 3（componentMap + 声明扩充） |
| 简单声明式替换、不想写 `h()` | 方式 4（scoped slot）             |

#### 自定义组件需遵守的约定

- **v-model**：默认绑 `value`（`v-model:value`）。若组件用别的 prop（如 Switch 用 `checked`），通过字段 `modelProp` 指定，或在 `componentVars` 预设 `modelProp`。
- **接收 path**：组件会收到 `path` prop（字段路径），可用于透传或标识。
- **属性透传**：Field 上除框架级属性外（`component` / `hidden` / `modelProp` / `valueFormatter` / `fields` / `slots` / `formItemContainer` / `componentContainer` / `extraProps` 等），其余作为 attrs 透传给自定义组件。

---

## Peer Dependencies

| 依赖包名称       | 推荐版本要求 |
| :--------------- | :----------- |
| `vue`            | `^3.5.0`     |
| `ant-design-vue` | `^4.0.0`     |

---

## 🤝 贡献与反馈

欢迎在任何时候通过 [GitHub Issues](https://github.com/dufan3715/pro-components/issues) 提交对本子包的优化建议和反馈。

## 📄 开源许可证

基于 [MIT](LICENSE) 开源许可证。
