# @qin-ui/antd-vue-pro

基于 ant-design-vue v4（`a-` 前缀）封装的 Schema 驱动组件库。
用 JS 配置对象描述 UI，不写 `<a-*>` 模板堆叠。ProForm/ProTable 是渲染引擎，所有真实 UI 来自 ant-design-vue。

## 安装与使用

```bash
pnpm add @qin-ui/antd-vue-pro   # peerDeps: ant-design-vue ^4, vue ^3.5
```

```ts
// 按需引入（推荐）
import { ProForm, ProTable, useForm, useTable } from '@qin-ui/antd-vue-pro';
```

## 核心心智模型

**1. 配置驱动**：`useForm(数据, Field[])` / `useTable({ columns, searchFields })` 生成实例，组件接收实例。

**2. 属性分层透传**（最关键）：Field 上的属性被"剥离到不同 DOM 层"，不是全塞给输入控件。写错层就失效：

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

> 规则：`span` 给 Grid，`label`/`rules` 给 FormItem，其余给输入控件。

## 速查

### component 映射（Field.component 字符串 -> ant-design-vue 组件）

`input`->Input · `textarea`->TextArea · `input-password`->InputPassword · `input-search`->InputSearch ·
`input-number`->InputNumber · `select`->Select · `cascader`->Cascader · `date-picker`->DatePicker ·
`range-picker`->RangePicker · `time-picker`->TimePicker · `checkbox-group`->CheckboxGroup ·
`radio-group`->RadioGroup · `switch`->Switch · `slider`->Slider · `tree-select`->TreeSelect ·
`transfer`->Transfer · `custom`->用户自定义组件

> 写 Field 中输入控件的具体属性前，**属性名/类型以 https://antdv.com 官方文档为准**。

### 隐式默认行为（INJECT_CONFIG，易踩坑）

由 `ProComponentProvider` 注入，优先级低于 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`。
> `date-picker` 支持按 picker 子类型分别预设：`date-picker.date` / `.week` / `.month` / `.year` / `.quarter`，默认值同上。
> `input-search` / `checkbox-group` / `radio-group` / `slider` / `tree-select` / `transfer` 无预设（`{}`）。

### 不支持响应式的属性（不能包 ref/computed）

`component` / `formItemContainer` / `componentContainer` / `valueFormatter` / `fields` / `slots` / `modelProp`。

## 实例成员速查

### useForm -- 表单实例

```ts
useForm(initFormData, Field[], root = true)   // 重载一（常用）：初始数据 + 字段配置
useForm(true | false)                          // 重载二：仅拿实例（root）
```

返回 `Form` 实例（**`formData` 是 reactive 对象，不用 `.value`**）：

| 成员                                                                                  | 说明                                                                                                                       |
| :------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------- |
| `form.formData`                                                                       | 响应式数据，可直接读写，支持深层路径 `formData.address.city`                                                               |
| `form.getFormData(path)`                                                              | 路径读取；无参返回 `undefined`                                                                                             |
| `form.setFormData(path, value)` / `setFormData(path, prev=>new)`                      | 路径写入，支持函数式                                                                                                       |
| `form.setFormData({...})` / `setFormData(prev => ({...prev, name:'新'}))`             | 批量覆盖整个表单，支持函数式（先清空再写入）                                                                               |
| `form.fields`                                                                         | 字段配置数组（Ref）                                                                                                        |
| `form.getField(path)` / `getField(fn)`                                                | 字段查找，支持路径或查找函数；`{all:true}` 返回所有匹配数组                                                                |
| `form.setField(path, patch)` / `setField(path, prev=>({...}))`                        | 字段增改查；默认合并，`{updateType:'rewrite'}` 覆盖；支持函数式更新；`{all:true}` 批量更新所有匹配                         |
| `form.deleteField` / `form.appendField` / `form.prependField` / `form.getParentField` | 字段增删查；均支持 `{all:true}`；`appendField(undefined, f)` 末尾追加、`prependField(undefined, f)` 开头插入，入参可为数组 |
| `form.formRef`                                                                        | 底层 ant Form 实例引用（Ref），`formRef.value?.validate()` / `.resetFields()`                                              |

### useTable -- 表格实例

```ts
useTable({ columns, dataSource, pageParam, searchParam, searchFields });
```

返回 `Table` 实例：

| 成员                                                                  | 说明                                                   |
| :-------------------------------------------------------------------- | :----------------------------------------------------- |
| `table.columns` / `table.dataSource`                                  | 列配置 / 数据源（Ref）                                 |
| `table.pageParam`                                                     | 分页参数（reactive）：`current` / `pageSize` / `total` |
| `table.searchForm`                                                    | 搜索表单实例（Form 类型，所有 useForm 方法可用）       |
| `table.setColumn` / `deleteColumn` / `appendColumn` / `prependColumn` | 列增删改查（用法同 setField，支持 `{all:true}`）       |
| `table.setPageParam(patch)`                                           | 设置分页参数                                           |
| `table.resetQueryParams()`                                            | 重置分页到第一页 + 恢复搜索条件到初始值                |

## 关键约定

### 自定义组件

`Field.component` 解析优先级（高 -> 低）：`teleport 插槽注入` > `ProComponentProvider.componentMap` > `内置 componentMap` > `原始 component 值`。

四种接入方式（完整代码见 skills）：

- **方式 1** `markRaw(SFC)`：单字段复用 SFC（**必须 markRaw**，否则被 Vue 深度代理触发性能警告）
- **方式 2** render 函数 `(props, ctx) => VNode`：需动态拼装 props
- **方式 3** `ProComponentProvider` 注入 `componentMap`：全局复用 / 覆盖内置组件，可追加 `declare module` 声明获强类型
- **方式 4** 模板 scoped slot：插槽名 = 字段 `path`，`v-bind="scoped"` 转发（teleport 机制，优先级最高）

约定：默认 v-model 绑 `value`，他 prop 用 `modelProp` 指定；组件会收到 `path` prop；除框架级属性外其余作 attrs 透传。

### valueFormatter -- 字段值转换

控制表单值与组件值之间的转换。**在表单数据写入前（computed setter 中）执行**，支持两种形态：

```ts
// 函数形态：(新值, 旧值) => 转换后的值，写回 formData。仅 set（写入）方向生效，读取时不转换
{ path: 'name', valueFormatter: (val, oldVal) => val?.trim() }

// 对象形态：get 读出时转换，set 写入时转换（双向）
{ path: 'birthday', component: 'date-picker',
  valueFormatter: { get: v => v ? dayjs(v) : null, set: v => v ? dayjs(v).format('YYYY-MM-DD') : null } }
```

### ProTable -- 配置驱动表格

透传所有 ant-design-vue `TableProps`（`& TableProps`），可直接写 `row-key` / `bordered` / `scroll` / `row-selection` 等原生属性；`size`、`loading` 是 v-model。

关键 prop：`table`（useTable 实例）、`search`（数据查询方法 `() => Promise`，ProTable 内部调用，非自动触发）、`addIndexColumn`、`immediateSearch`、`control`、`searchFormConfig`（含 `hidden`/`container`/`layout`/`expand`）、`tableContainer`。

**数据流**：搜索->重置分页到第 1 页->调 `search()`；分页/排序变化->更新 `pageParam`->调 `search()`；重置->`resetQueryParams()`->调 `search()`。

### Column -- 列配置

继承 ant-design-vue `ColumnType`，所有原生列属性可用。新增：`dataIndex`（列数据路径，主用，支持 `'name'` / `'address.city'` / `['address','city']`）、`key`（辅助标识，优先级更低）、`hidden`（隐藏该列，配合列控制）。

## 反模式

- ❌ 在 `<ProForm>` 内手写 `<a-form-item>` -- ProForm 从 Field 配置自动渲染。
- ❌ 猜透传属性名 -- 先查 antdv.com。
- ❌ 把 `span` 当输入控件属性。
- ❌ 传 SFC 给 `component` 不用 `markRaw`。
- ❌ 在 ProTable 上忘了传 `:search`，或期望它自动请求 -- 查询由你提供并驱动。

## 按需深查

完整 API（详细签名、参数表、完整示例、ProTable Slots、ProComponentProvider 用法）：

- `.agents/skills/antd-vue-pro/SKILL.md` — skills 入口（速查 + 参考导航）
- `.agents/skills/antd-vue-pro/references/README.md` — 完整使用文档与进阶示例
- `.agents/skills/antd-vue-pro/references/api.md` — 结构化 API 元数据
- `node_modules/@qin-ui/antd-vue-pro/README.md` — 完整用法与进阶示例
- ant-design-vue 组件属性查阅官方文档：https://antdv.com
