@qin-ui/antd-vue-pro 2.2.3 → 2.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI-CONTEXT.md +82 -255
- package/README.md +27 -26
- package/api.json +1 -1
- package/bin/init-ai.mjs +133 -41
- package/package.json +3 -3
package/AI-CONTEXT.md
CHANGED
|
@@ -3,34 +3,35 @@
|
|
|
3
3
|
基于 ant-design-vue v4(`a-` 前缀)封装的 Schema 驱动组件库。
|
|
4
4
|
用 JS 配置对象描述 UI,不写 `<a-*>` 模板堆叠。ProForm/ProTable 是渲染引擎,所有真实 UI 来自 ant-design-vue。
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## 安装与使用
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
9
|
pnpm add @qin-ui/antd-vue-pro # peerDeps: ant-design-vue ^4, vue ^3.5
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
```ts
|
|
13
|
-
|
|
14
|
-
import '@qin-ui/antd-vue-pro
|
|
15
|
-
app.use(AntdVuePro); // 全局注册 ProForm / ProTable / ProComponentProvider
|
|
13
|
+
// 按需引入(推荐)
|
|
14
|
+
import { ProForm, ProTable, useForm, useTable } from '@qin-ui/antd-vue-pro';
|
|
16
15
|
```
|
|
17
16
|
|
|
18
|
-
##
|
|
17
|
+
## 核心心智模型
|
|
19
18
|
|
|
20
19
|
**1. 配置驱动**:`useForm(数据, Field[])` / `useTable({ columns, searchFields })` 生成实例,组件接收实例。
|
|
21
20
|
|
|
22
21
|
**2. 属性分层透传**(最关键):Field 上的属性被"剥离到不同 DOM 层",不是全塞给输入控件。写错层就失效:
|
|
23
22
|
|
|
24
|
-
| 属性
|
|
25
|
-
|
|
|
26
|
-
| `span`/`offset`/`push`/`pull`/`flex`/`xs..xxl`
|
|
27
|
-
| `label`/`rules`/`tooltip`/`colon`/`labelAlign`/`labelCol`/`wrapperCol`/`extra`/`help`/`validateFirst`/`validateTrigger`/`valuePropName`/`normalize`/`formItemClass`/`formItemStyle`/`formItemDataAttrs` | `<a-form-item>` 层 | 表单项 |
|
|
28
|
-
| `disabled`/`placeholder`/`allowClear`/`options`/`mode`/`maxlength`/`componentClass`/`componentStyle`/`componentDataAttrs` + 该控件其余 ant 原生属性
|
|
29
|
-
| `component`/`hidden`/`modelProp`/`valueFormatter`/`fields`/`slots`/`formItemContainer`/`componentContainer`/`extraProps`
|
|
23
|
+
| 属性 | 落到哪一层 | 说明 |
|
|
24
|
+
| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------- | :------------- |
|
|
25
|
+
| `span`/`offset`/`push`/`pull`/`flex`/`xs..xxl` | `<a-col>` Grid 层 | 仅 grid 开启时 |
|
|
26
|
+
| `label`/`rules`/`tooltip`/`colon`/`labelAlign`/`labelCol`/`wrapperCol`/`extra`/`help`/`validateFirst`/`validateTrigger`/`valuePropName`/`normalize`/`required`/`formItemClass`/`formItemStyle`/`formItemDataAttrs` | `<a-form-item>` 层 | 表单项 |
|
|
27
|
+
| `disabled`/`placeholder`/`allowClear`/`options`/`mode`/`maxlength`/`componentClass`/`componentStyle`/`componentDataAttrs` + 该控件其余 ant 原生属性 | 输入控件本身(a-input 等) | 其余全部 |
|
|
28
|
+
| `component`/`hidden`/`modelProp`/`valueFormatter`/`fields`/`slots`/`formItemContainer`/`componentContainer`/`extraProps` | ProForm 逻辑消费,**不绑到 DOM** | 框架级 |
|
|
30
29
|
|
|
31
30
|
> 规则:`span` 给 Grid,`label`/`rules` 给 FormItem,其余给输入控件。
|
|
32
31
|
|
|
33
|
-
##
|
|
32
|
+
## 速查
|
|
33
|
+
|
|
34
|
+
### component 映射(Field.component 字符串 -> ant-design-vue 组件)
|
|
34
35
|
|
|
35
36
|
`input`->Input · `textarea`->TextArea · `input-password`->InputPassword · `input-search`->InputSearch ·
|
|
36
37
|
`input-number`->InputNumber · `select`->Select · `cascader`->Cascader · `date-picker`->DatePicker ·
|
|
@@ -40,288 +41,109 @@ app.use(AntdVuePro); // 全局注册 ProForm / ProTable / ProComponentProvider
|
|
|
40
41
|
|
|
41
42
|
> 写 Field 中输入控件的具体属性前,**属性名/类型以 https://antdv.com 官方文档为准**。
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
### 隐式默认行为(INJECT_CONFIG,易踩坑)
|
|
44
45
|
|
|
45
46
|
由 `ProComponentProvider` 注入,优先级低于 Field 配置。**不写也有这些默认值,需知晓以免行为与预期不符:**
|
|
46
47
|
|
|
47
|
-
| component | 默认预设
|
|
48
|
-
| :--------------------------------------------- |
|
|
49
|
-
| `switch` | `{ modelProp: 'checked' }` -> v-model 绑 `checked` 而非 `value`
|
|
50
|
-
| `input` / `input-password` | `{ maxlength: 100, allowClear: true, placeholder: '请输入' }`
|
|
51
|
-
| `textarea` | `{ maxlength: 200, autoSize: {minRows:3,maxRows:6}, showCount: true, allowClear: true, placeholder: '请输入' }`
|
|
52
|
-
| `input-number` | `{ max: 1e15-1, min: -(1e15+1), controls: false, placeholder: '请输入', style:{width:'100%'} }`
|
|
53
|
-
| `select` / `cascader` | `{ allowClear: true, placeholder: '请选择', getPopupContainer }`
|
|
54
|
-
| `date-picker` / `range-picker` / `time-picker` | `{ allowClear: true, getPopupContainer, style:{width:'100%'} }`
|
|
55
|
-
| `pro-form` | `{ grid: { gutter: {xs:8, sm:16, md:16, lg:24} } }`
|
|
56
|
-
| `pro-form-item` | `{ validateFirst: true, span: 8 }`
|
|
57
|
-
| `pro-table` | `{ pagination:{showTotal, showSizeChanger, pageSizeOptions:['10'
|
|
48
|
+
| component | 默认预设 |
|
|
49
|
+
| :--------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `switch` | `{ modelProp: 'checked' }` -> v-model 绑 `checked` 而非 `value` |
|
|
51
|
+
| `input` / `input-password` | `{ maxlength: 100, allowClear: true, placeholder: '请输入' }` |
|
|
52
|
+
| `textarea` | `{ maxlength: 200, autoSize: {minRows:3,maxRows:6}, showCount: true, allowClear: true, placeholder: '请输入' }` |
|
|
53
|
+
| `input-number` | `{ max: 1e15-1, min: -(1e15+1), controls: false, placeholder: '请输入', style:{width:'100%'} }` |
|
|
54
|
+
| `select` / `cascader` | `{ allowClear: true, placeholder: '请选择', getPopupContainer }` |
|
|
55
|
+
| `date-picker` / `range-picker` / `time-picker` | `{ allowClear: true, getPopupContainer, style:{width:'100%'} }` |
|
|
56
|
+
| `pro-form` | `{ grid: { gutter: {xs:8, sm:16, md:16, lg:24} } }` |
|
|
57
|
+
| `pro-form-item` | `{ validateFirst: true, span: 8 }` |
|
|
58
|
+
| `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 }` |
|
|
58
59
|
|
|
59
60
|
> `modelProp` 控制 v-model 绑定名,默认 `'value'`->`v-model:value`。
|
|
61
|
+
> `date-picker` 支持按 picker 子类型分别预设:`date-picker.date` / `.week` / `.month` / `.year` / `.quarter`,默认值同上。
|
|
62
|
+
> `input-search` / `checkbox-group` / `radio-group` / `slider` / `tree-select` / `transfer` 无预设(`{}`)。
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
// 重载一(常用):初始数据 + 字段配置
|
|
65
|
-
const form = useForm<User>(
|
|
66
|
-
{ name: '张三', age: 25 }, // initFormData
|
|
67
|
-
[
|
|
68
|
-
{
|
|
69
|
-
path: 'name',
|
|
70
|
-
label: '姓名',
|
|
71
|
-
component: 'input',
|
|
72
|
-
rules: [{ required: true }],
|
|
73
|
-
},
|
|
74
|
-
] // Field[]
|
|
75
|
-
);
|
|
76
|
-
// 重载二:仅拿实例(root=true/false)
|
|
77
|
-
const form = useForm<User>(true);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
返回 `Form` 实例(**2.0+ `formData` 是 reactive 对象,不用 `.value`**):
|
|
81
|
-
|
|
82
|
-
| 成员 | 说明 |
|
|
83
|
-
| :------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------- |
|
|
84
|
-
| `form.formData` | 响应式数据,可直接读写,支持深层路径 `formData.address.city` |
|
|
85
|
-
| `form.getFormData(path)` / `form.setFormData(path, value)` | 路径读写;setFormData 还支持 `setFormData(path, prev=>new)` 和 `setFormData({...})` 批量覆盖 |
|
|
86
|
-
| `form.fields` | 字段配置数组(Ref) |
|
|
87
|
-
| `form.getField(path)` / `form.setField(path, patch)` | 字段增改查;setField 默认合并,`{updateType:'rewrite'}` 覆盖 |
|
|
88
|
-
| `form.deleteField` / `form.appendField` / `form.prependField` / `form.getParentField` | 字段增删 |
|
|
89
|
-
| `form.formRef` | 底层 ant Form 实例引用(Ref),`formRef.value?.validate()` / `.resetFields()` |
|
|
90
|
-
|
|
91
|
-
## ProForm 最小示例
|
|
92
|
-
|
|
93
|
-
```vue
|
|
94
|
-
<script setup lang="ts">
|
|
95
|
-
import { ProForm, useForm } from '@qin-ui/antd-vue-pro';
|
|
96
|
-
interface User {
|
|
97
|
-
username: string;
|
|
98
|
-
age: number;
|
|
99
|
-
gender: string;
|
|
100
|
-
}
|
|
101
|
-
const form = useForm<User>({ username: '', age: 18, gender: 'male' }, [
|
|
102
|
-
{
|
|
103
|
-
path: 'username',
|
|
104
|
-
component: 'input',
|
|
105
|
-
label: '用户名',
|
|
106
|
-
rules: [{ required: true }],
|
|
107
|
-
},
|
|
108
|
-
{ path: 'age', component: 'input-number', label: '年龄', min: 1, max: 150 },
|
|
109
|
-
{
|
|
110
|
-
path: 'gender',
|
|
111
|
-
component: 'select',
|
|
112
|
-
label: '性别',
|
|
113
|
-
options: [
|
|
114
|
-
{ label: '男', value: 'male' },
|
|
115
|
-
{ label: '女', value: 'female' },
|
|
116
|
-
],
|
|
117
|
-
},
|
|
118
|
-
]);
|
|
119
|
-
const submit = async () => {
|
|
120
|
-
await form.formRef.value?.validate();
|
|
121
|
-
console.log(form.formData);
|
|
122
|
-
};
|
|
123
|
-
</script>
|
|
124
|
-
<template>
|
|
125
|
-
<ProForm :form="form" />
|
|
126
|
-
<a-button type="primary" @click="submit">提交</a-button>
|
|
127
|
-
</template>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## 自定义组件(4 种方式)
|
|
64
|
+
### 不支持响应式的属性(不能包 ref/computed)
|
|
131
65
|
|
|
132
|
-
`
|
|
133
|
-
`teleport 插槽注入` > `ProComponentProvider.componentMap` > `内置 componentMap` > `原始 component 值`
|
|
66
|
+
`component` / `formItemContainer` / `componentContainer` / `valueFormatter` / `fields` / `slots` / `modelProp`。
|
|
134
67
|
|
|
135
|
-
|
|
68
|
+
## 实例成员速查
|
|
136
69
|
|
|
137
|
-
|
|
70
|
+
### useForm -- 表单实例
|
|
138
71
|
|
|
139
72
|
```ts
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
{ path: 'code', label: '验证码', component: markRaw(MyInput) }
|
|
73
|
+
useForm(initFormData, Field[], root = true) // 重载一(常用):初始数据 + 字段配置
|
|
74
|
+
useForm(true | false) // 重载二:仅拿实例(root)
|
|
143
75
|
```
|
|
144
76
|
|
|
145
|
-
|
|
146
|
-
> 类型上 `component` 接受 `RenderComponentType | Raw<RenderComponentType>`,`Raw<T>` 即 markRaw 的类型标记。
|
|
147
|
-
> 此字段不支持响应式(不能包 ref/computed)。
|
|
77
|
+
返回 `Form` 实例(**`formData` 是 reactive 对象,不用 `.value`**):
|
|
148
78
|
|
|
149
|
-
|
|
79
|
+
| 成员 | 说明 |
|
|
80
|
+
| :------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------- |
|
|
81
|
+
| `form.formData` | 响应式数据,可直接读写,支持深层路径 `formData.address.city` |
|
|
82
|
+
| `form.getFormData(path)` | 路径读取;无参返回 `undefined` |
|
|
83
|
+
| `form.setFormData(path, value)` / `setFormData(path, prev=>new)` | 路径写入,支持函数式 |
|
|
84
|
+
| `form.setFormData({...})` / `setFormData(prev => ({...prev, name:'新'}))` | 批量覆盖整个表单,支持函数式(先清空再写入) |
|
|
85
|
+
| `form.fields` | 字段配置数组(Ref) |
|
|
86
|
+
| `form.getField(path)` / `getField(fn)` | 字段查找,支持路径或查找函数;`{all:true}` 返回所有匹配数组 |
|
|
87
|
+
| `form.setField(path, patch)` / `setField(path, prev=>({...}))` | 字段增改查;默认合并,`{updateType:'rewrite'}` 覆盖;支持函数式更新;`{all:true}` 批量更新所有匹配 |
|
|
88
|
+
| `form.deleteField` / `form.appendField` / `form.prependField` / `form.getParentField` | 字段增删查;均支持 `{all:true}`;`appendField(undefined, f)` 末尾追加、`prependField(undefined, f)` 开头插入,入参可为数组 |
|
|
89
|
+
| `form.formRef` | 底层 ant Form 实例引用(Ref),`formRef.value?.validate()` / `.resetFields()` |
|
|
150
90
|
|
|
151
|
-
|
|
91
|
+
### useTable -- 表格实例
|
|
152
92
|
|
|
153
93
|
```ts
|
|
154
|
-
|
|
155
|
-
import MyInput from './MyInput.vue';
|
|
156
|
-
{ path: 'code', label: '验证码', component: (p, ctx) => h(MyInput, { ...p, ...ctx.attrs }) }
|
|
94
|
+
useTable({ columns, dataSource, pageParam, searchParam, searchFields });
|
|
157
95
|
```
|
|
158
96
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
在根用 `componentMap` 注册,Field 里用字符串引用。**可覆盖内置组件**(如 `input: MyInput` 替换全局 input)。
|
|
162
|
-
|
|
163
|
-
```vue
|
|
164
|
-
<script setup lang="ts">
|
|
165
|
-
import { ProComponentProvider } from '@qin-ui/antd-vue-pro';
|
|
166
|
-
import MyRichTextEditor from './components/MyRichTextEditor.vue';
|
|
167
|
-
const componentMap = { 'rich-editor': MyRichTextEditor };
|
|
168
|
-
</script>
|
|
169
|
-
<template>
|
|
170
|
-
<ProComponentProvider :component-map="componentMap">
|
|
171
|
-
<ProForm :form="form" />
|
|
172
|
-
</ProComponentProvider>
|
|
173
|
-
</template>
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**追加全局声明获取强类型补全**(项目任意 `.d.ts`):
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
declare module '@qin-ui/antd-vue-pro' {
|
|
180
|
-
interface ComponentMap {
|
|
181
|
-
'rich-editor': typeof MyRichTextEditor;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
// 之后 component: 'rich-editor' 即获精准属性类型联想
|
|
185
|
-
```
|
|
97
|
+
返回 `Table` 实例:
|
|
186
98
|
|
|
187
|
-
|
|
99
|
+
| 成员 | 说明 |
|
|
100
|
+
| :-------------------------------------------------------------------- | :----------------------------------------------------- |
|
|
101
|
+
| `table.columns` / `table.dataSource` | 列配置 / 数据源(Ref) |
|
|
102
|
+
| `table.pageParam` | 分页参数(reactive):`current` / `pageSize` / `total` |
|
|
103
|
+
| `table.searchForm` | 搜索表单实例(Form 类型,所有 useForm 方法可用) |
|
|
104
|
+
| `table.setColumn` / `deleteColumn` / `appendColumn` / `prependColumn` | 列增删改查(用法同 setField,支持 `{all:true}`) |
|
|
105
|
+
| `table.setPageParam(patch)` | 设置分页参数 |
|
|
106
|
+
| `table.resetQueryParams()` | 重置分页到第一页 + 恢复搜索条件到初始值 |
|
|
188
107
|
|
|
189
|
-
|
|
108
|
+
## 关键约定
|
|
190
109
|
|
|
191
|
-
|
|
192
|
-
<ProForm :form="form">
|
|
193
|
-
<template #agreement="scoped">
|
|
194
|
-
<a-checkbox v-bind="scoped">同意协议</a-checkbox>
|
|
195
|
-
</template>
|
|
196
|
-
</ProForm>
|
|
197
|
-
```
|
|
110
|
+
### 自定义组件
|
|
198
111
|
|
|
199
|
-
|
|
112
|
+
`Field.component` 解析优先级(高 -> 低):`teleport 插槽注入` > `ProComponentProvider.componentMap` > `内置 componentMap` > `原始 component 值`。
|
|
200
113
|
|
|
201
|
-
|
|
202
|
-
- 单字段、需动态拼装 props -> 方式 2(render 函数)
|
|
203
|
-
- 多处复用 / 替换内置组件 -> 方式 3(componentMap + 声明扩充)
|
|
204
|
-
- 简单声明式替换、不想写 h() -> 方式 4(scoped slot)
|
|
114
|
+
四种接入方式(完整代码见 skills):
|
|
205
115
|
|
|
206
|
-
|
|
116
|
+
- **方式 1** `markRaw(SFC)`:单字段复用 SFC(**必须 markRaw**,否则被 Vue 深度代理触发性能警告)
|
|
117
|
+
- **方式 2** render 函数 `(props, ctx) => VNode`:需动态拼装 props
|
|
118
|
+
- **方式 3** `ProComponentProvider` 注入 `componentMap`:全局复用 / 覆盖内置组件,可追加 `declare module` 声明获强类型
|
|
119
|
+
- **方式 4** 模板 scoped slot:插槽名 = 字段 `path`,`v-bind="scoped"` 转发(teleport 机制,优先级最高)
|
|
207
120
|
|
|
208
|
-
|
|
209
|
-
- **接收 path**:组件会收到 `path` prop(字段路径)
|
|
210
|
-
- **属性透传**:Field 上除框架级属性外(component/hidden/modelProp/valueFormatter/fields/slots/formItemContainer/componentContainer/extraProps 等),其余作为 attrs 透传给自定义组件
|
|
121
|
+
约定:默认 v-model 绑 `value`,他 prop 用 `modelProp` 指定;组件会收到 `path` prop;除框架级属性外其余作 attrs 透传。
|
|
211
122
|
|
|
212
|
-
|
|
123
|
+
### valueFormatter -- 字段值转换
|
|
213
124
|
|
|
214
|
-
|
|
125
|
+
控制表单值与组件值之间的转换。**在表单数据写入前(computed setter 中)执行**,支持两种形态:
|
|
215
126
|
|
|
216
127
|
```ts
|
|
217
|
-
// 函数形态:(新值, 旧值) => 转换后的值,写回 formData
|
|
128
|
+
// 函数形态:(新值, 旧值) => 转换后的值,写回 formData。仅 set(写入)方向生效,读取时不转换
|
|
218
129
|
{ path: 'name', valueFormatter: (val, oldVal) => val?.trim() }
|
|
219
130
|
|
|
220
|
-
// 对象形态:get 读出时转换,set
|
|
131
|
+
// 对象形态:get 读出时转换,set 写入时转换(双向)
|
|
221
132
|
{ path: 'birthday', component: 'date-picker',
|
|
222
|
-
valueFormatter: {
|
|
223
|
-
get: (val) => val ? dayjs(val) : null, // formData -> 组件显示
|
|
224
|
-
set: (val) => val ? dayjs(val).format('YYYY-MM-DD') : null, // 组件 -> formData
|
|
225
|
-
} }
|
|
133
|
+
valueFormatter: { get: v => v ? dayjs(v) : null, set: v => v ? dayjs(v).format('YYYY-MM-DD') : null } }
|
|
226
134
|
```
|
|
227
135
|
|
|
228
|
-
|
|
136
|
+
### ProTable -- 配置驱动表格
|
|
229
137
|
|
|
230
|
-
|
|
231
|
-
const table = useTable<SearchParams, User>({
|
|
232
|
-
columns: [{ dataIndex: 'name', title: '姓名', width: 120 }],
|
|
233
|
-
dataSource: [],
|
|
234
|
-
pageParam: { current: 1, pageSize: 10, total: 0 }, // 默认值
|
|
235
|
-
searchParam: { keyword: '', status: '' },
|
|
236
|
-
searchFields: [ // 与 ProForm 同一套 Field[] 格式
|
|
237
|
-
{ path: 'keyword', component: 'input', label: '关键词' },
|
|
238
|
-
{ path: 'status', component: 'select', label: '状态', options: [...] },
|
|
239
|
-
],
|
|
240
|
-
});
|
|
241
|
-
```
|
|
138
|
+
透传所有 ant-design-vue `TableProps`(`& TableProps`),可直接写 `row-key` / `bordered` / `scroll` / `row-selection` 等原生属性;`size`、`loading` 是 v-model。
|
|
242
139
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
| 成员 | 说明 |
|
|
246
|
-
| :-------------------------------------------------------------------- | :----------------------------------------------------- |
|
|
247
|
-
| `table.columns` | 列配置(Ref) |
|
|
248
|
-
| `table.dataSource` | 表格数据源(Ref) |
|
|
249
|
-
| `table.pageParam` | 分页参数(reactive):`current` / `pageSize` / `total` |
|
|
250
|
-
| `table.searchForm` | 搜索表单实例(Form 类型,所有 useForm 方法可用) |
|
|
251
|
-
| `table.setColumn` / `deleteColumn` / `appendColumn` / `prependColumn` | 列增删改查(用法同 setField) |
|
|
252
|
-
| `table.setPageParam(patch)` | 设置分页参数 |
|
|
253
|
-
| `table.resetQueryParams()` | 重置分页到第一页 + 恢复搜索条件到初始值 |
|
|
254
|
-
|
|
255
|
-
## ProTable -- 配置驱动表格
|
|
256
|
-
|
|
257
|
-
**关键:ProTable 透传所有 ant-design-vue TableProps**(`& TableProps`),可直接写 `row-key` / `bordered` / `scroll` / `row-selection` 等原生属性;`size`、`loading` 是 v-model。
|
|
258
|
-
|
|
259
|
-
| prop | 说明 |
|
|
260
|
-
| :----------------- | :-------------------------------------------------------------- |
|
|
261
|
-
| `table` | useTable 实例 |
|
|
262
|
-
| `search` | 数据查询方法 `() => Promise`,ProTable 内部调用它(非自动触发) |
|
|
263
|
-
| `addIndexColumn` | 首列插入 index 列 |
|
|
264
|
-
| `immediateSearch` | onMounted 时立即触发一次 search |
|
|
265
|
-
| `control` | 是否显示 size/列控制按钮,可 `{sizeControl, columnControl}` |
|
|
266
|
-
| `searchFormConfig` | 搜索栏配置,含 `hidden`(隐藏搜索区)、`container` |
|
|
267
|
-
| `tableContainer` | 表格区容器 |
|
|
140
|
+
关键 prop:`table`(useTable 实例)、`search`(数据查询方法 `() => Promise`,ProTable 内部调用,非自动触发)、`addIndexColumn`、`immediateSearch`、`control`、`searchFormConfig`(含 `hidden`/`container`/`layout`/`expand`)、`tableContainer`。
|
|
268
141
|
|
|
269
142
|
**数据流**:搜索->重置分页到第 1 页->调 `search()`;分页/排序变化->更新 `pageParam`->调 `search()`;重置->`resetQueryParams()`->调 `search()`。
|
|
270
143
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
继承 ant-design-vue `ColumnType`,**所有原生列属性可用**(`title` / `width` / `fixed` / `align` / `customRender` / `ellipsis`…)。新增:
|
|
274
|
-
|
|
275
|
-
- `dataIndex`:列数据路径(主用),类型安全,支持 `'name'` / `'address.city'` / `['address','city']`
|
|
276
|
-
- `key`:辅助标识(dataIndex 不满足时用,优先级更低)
|
|
277
|
-
- `hidden`:隐藏该列(配合列控制)
|
|
278
|
-
|
|
279
|
-
## ProTable 最小示例
|
|
280
|
-
|
|
281
|
-
```vue
|
|
282
|
-
<script setup lang="ts">
|
|
283
|
-
import { ProTable, useTable } from '@qin-ui/antd-vue-pro';
|
|
284
|
-
interface User {
|
|
285
|
-
id: number;
|
|
286
|
-
name: string;
|
|
287
|
-
status: string;
|
|
288
|
-
}
|
|
289
|
-
interface Search {
|
|
290
|
-
keyword: string;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const table = useTable<Search, User>({
|
|
294
|
-
columns: [
|
|
295
|
-
{ dataIndex: 'name', title: '姓名', width: 120 },
|
|
296
|
-
{ dataIndex: 'status', title: '状态' },
|
|
297
|
-
],
|
|
298
|
-
searchFields: [{ path: 'keyword', component: 'input', label: '关键词' }],
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
const fetchData = async () => {
|
|
302
|
-
// 组装查询参数:搜索条件 + 分页
|
|
303
|
-
const res = await api.list({
|
|
304
|
-
...table.searchForm.formData,
|
|
305
|
-
...table.pageParam,
|
|
306
|
-
});
|
|
307
|
-
table.dataSource.value = res.data;
|
|
308
|
-
table.setPageParam({ total: res.total });
|
|
309
|
-
};
|
|
310
|
-
</script>
|
|
311
|
-
<template>
|
|
312
|
-
<ProTable :table="table" :search="fetchData" row-key="id" immediate-search />
|
|
313
|
-
</template>
|
|
314
|
-
```
|
|
144
|
+
### Column -- 列配置
|
|
315
145
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
```ts
|
|
319
|
-
disabled: computed(() => !form.formData.enabled), // A 声明式,初始化时已知(首选)
|
|
320
|
-
const isDisabled = ref(false); // B 外部共享状态
|
|
321
|
-
form.setField('limitCount', { disabled: true }); // C 命令式,事件驱动
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
> **不支持响应式**(不能包 ref/computed)的属性:`component` / `formItemContainer` / `componentContainer` / `valueFormatter` / `fields` / `slots` / `modelProp`。
|
|
146
|
+
继承 ant-design-vue `ColumnType`,所有原生列属性可用。新增:`dataIndex`(列数据路径,主用,支持 `'name'` / `'address.city'` / `['address','city']`)、`key`(辅助标识,优先级更低)、`hidden`(隐藏该列,配合列控制)。
|
|
325
147
|
|
|
326
148
|
## 反模式
|
|
327
149
|
|
|
@@ -333,5 +155,10 @@ form.setField('limitCount', { disabled: true }); // C 命令式,事件驱
|
|
|
333
155
|
|
|
334
156
|
## 按需深查
|
|
335
157
|
|
|
336
|
-
|
|
337
|
-
|
|
158
|
+
完整 API(详细签名、参数表、完整示例、ProTable Slots、ProComponentProvider 用法):
|
|
159
|
+
|
|
160
|
+
- `.agents/skills/antd-vue-pro/SKILL.md` — skills 入口(速查 + 参考导航)
|
|
161
|
+
- `.agents/skills/antd-vue-pro/references/README.md` — 完整使用文档与进阶示例
|
|
162
|
+
- `.agents/skills/antd-vue-pro/references/api.md` — 结构化 API 元数据
|
|
163
|
+
- `node_modules/@qin-ui/antd-vue-pro/README.md` — 完整用法与进阶示例
|
|
164
|
+
- ant-design-vue 组件属性查阅官方文档:https://antdv.com
|
package/README.md
CHANGED
|
@@ -49,7 +49,8 @@ npx @qin-ui/antd-vue-pro init-ai
|
|
|
49
49
|
将在项目中生成双载体 AI 上下文,使 Cursor / Claude Code / Codex 等 AI 工具深度理解本库的 Schema 驱动用法与属性透传规则:
|
|
50
50
|
|
|
51
51
|
- `AGENTS.md` — 核心使用规则(跨工具开放约定,会话时自动注入,AI 默认加载)
|
|
52
|
-
- `.agents/skills/antd-vue-pro.md` —
|
|
52
|
+
- `.agents/skills/antd-vue-pro/SKILL.md` — skills 入口(速查 + 参考导航)
|
|
53
|
+
- `.agents/skills/antd-vue-pro/references/` — 完整使用文档与结构化 API 元数据
|
|
53
54
|
|
|
54
55
|
> 生成的 `AGENTS.md` 使用标记区块写入,重复执行 `init-ai` 可安全更新,不影响项目内其他库的指令。建议将生成的文件提交到 Git 仓库,团队共享 AI 上下文。
|
|
55
56
|
|
|
@@ -175,17 +176,17 @@ ProForm/ProTable 是渲染引擎,所有真实 UI 来自 ant-design-vue。**Fie
|
|
|
175
176
|
|
|
176
177
|
ProComponentProvider 内置了一套默认属性预设,**即使不配置 `component-vars` 也会生效**。Field 配置优先级最高,会覆盖这些预设。以下为各组件的内置默认值(写代码时需知晓,避免行为与预期不符):
|
|
177
178
|
|
|
178
|
-
| component | 默认预设
|
|
179
|
-
| :--------------------------------------------- |
|
|
180
|
-
| `switch` | `{ modelProp: 'checked' }` —— v-model 绑定 `checked` 而非 `value`
|
|
181
|
-
| `input` / `input-password` | `{ maxlength: 100, allowClear: true, placeholder: '请输入' }`
|
|
182
|
-
| `textarea` | `{ maxlength: 200, autoSize: { minRows: 3, maxRows: 6 }, showCount: true, allowClear: true, placeholder: '请输入' }`
|
|
183
|
-
| `input-number` | `{ max: 1e15-1, min: -(1e15+1), controls: false, placeholder: '请输入', style: { width: '100%' } }`
|
|
184
|
-
| `select` / `cascader` | `{ allowClear: true, placeholder: '请选择', getPopupContainer }`
|
|
185
|
-
| `date-picker` / `range-picker` / `time-picker` | `{ allowClear: true, getPopupContainer, style: { width: '100%' } }`
|
|
186
|
-
| `pro-form` | `{ grid: { gutter: { xs: 8, sm: 16, md: 16, lg: 24 } } }`
|
|
187
|
-
| `pro-form-item` | `{ validateFirst: true, span: 8 }`
|
|
188
|
-
| `pro-table` | `{ pagination: { showTotal, showSizeChanger, pageSizeOptions: ['10'
|
|
179
|
+
| component | 默认预设 |
|
|
180
|
+
| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
181
|
+
| `switch` | `{ modelProp: 'checked' }` —— v-model 绑定 `checked` 而非 `value` |
|
|
182
|
+
| `input` / `input-password` | `{ maxlength: 100, allowClear: true, placeholder: '请输入' }` |
|
|
183
|
+
| `textarea` | `{ maxlength: 200, autoSize: { minRows: 3, maxRows: 6 }, showCount: true, allowClear: true, placeholder: '请输入' }` |
|
|
184
|
+
| `input-number` | `{ max: 1e15-1, min: -(1e15+1), controls: false, placeholder: '请输入', style: { width: '100%' } }` |
|
|
185
|
+
| `select` / `cascader` | `{ allowClear: true, placeholder: '请选择', getPopupContainer }` |
|
|
186
|
+
| `date-picker` / `range-picker` / `time-picker` | `{ allowClear: true, getPopupContainer, style: { width: '100%' } }` |
|
|
187
|
+
| `pro-form` | `{ grid: { gutter: { xs: 8, sm: 16, md: 16, lg: 24 } } }` |
|
|
188
|
+
| `pro-form-item` | `{ validateFirst: true, span: 8 }` |
|
|
189
|
+
| `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 }` |
|
|
189
190
|
|
|
190
191
|
> `modelProp` 控制 v-model 绑定的属性名,默认 `'value'`(即 `v-model:value`)。`switch` 经预设绑定为 `checked`,通常无需手动设置。
|
|
191
192
|
|
|
@@ -281,19 +282,19 @@ const form = useForm<D>(initFormData?, initFields?, root?)
|
|
|
281
282
|
|
|
282
283
|
#### 返回值 (Form 实例)
|
|
283
284
|
|
|
284
|
-
| 属性/方法 | 说明
|
|
285
|
-
| :----------------------------- |
|
|
286
|
-
| `formData` | 响应式表单数据对象(**2.0+ 中由 reactive 包装**)
|
|
287
|
-
| `fields` | 响应式表单字段配置数组引用
|
|
288
|
-
| `formRef` | 底层 Ant Design Vue `a-form` 的 DOM/组件引用实例
|
|
289
|
-
| `getFormData(path)` | 安全获取指定字段路径(支持深层 'a.b')的数据值
|
|
290
|
-
| `setFormData(path,
|
|
291
|
-
| `getField(path, opts?)` | 获取指定 path 的字段配置,支持查找函数定位,支持配置 `{ all: true }` 获取所有匹配项
|
|
292
|
-
| `setField(path, patch, opts?)` |
|
|
293
|
-
| `deleteField(path)`
|
|
294
|
-
| `appendField(path, field)` |
|
|
295
|
-
| `prependField(path, field)` |
|
|
296
|
-
| `getParentField(path)`
|
|
285
|
+
| 属性/方法 | 说明 | 类型 |
|
|
286
|
+
| :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------- | :------------------------------- |
|
|
287
|
+
| `formData` | 响应式表单数据对象(**2.0+ 中由 reactive 包装**) | `Reactive<D>` |
|
|
288
|
+
| `fields` | 响应式表单字段配置数组引用 | `Ref<Field[]>` |
|
|
289
|
+
| `formRef` | 底层 Ant Design Vue `a-form` 的 DOM/组件引用实例 | `Ref<FormInstance \| undefined>` |
|
|
290
|
+
| `getFormData(path)` | 安全获取指定字段路径(支持深层 'a.b')的数据值 | `(path) => any` |
|
|
291
|
+
| `setFormData(path, value)` | 路径写入或函数式更新;传对象(`{...}`)批量覆盖整个表单;传函数 `(prev) => new` 批量更新 | `(path, val) => void` |
|
|
292
|
+
| `getField(path, opts?)` | 获取指定 path 的字段配置,支持查找函数定位,支持配置 `{ all: true }` 获取所有匹配项 | `(path, opts) => Field` |
|
|
293
|
+
| `setField(path, patch, opts?)` | 默认合并更新字段配置;`{updateType:'rewrite'}` 覆盖;支持函数式 `setField(path, prev=>({...}))`;`{all:true}` 批量更新所有匹配 | `(path, patch, opts) => void` |
|
|
294
|
+
| `deleteField(path, opts?)` | 删除字段配置;`{all:true}` 删除所有匹配的字段 | `(path, opts?) => void` |
|
|
295
|
+
| `appendField(path, field)` | 在指定字段后追加新字段(入参可为数组);`undefined` 在末尾追加;`{all:true}` 所有匹配后追加 | `(path, field, opts?) => void` |
|
|
296
|
+
| `prependField(path, field)` | 在指定字段前插入新字段(入参可为数组);`undefined` 在开头插入;`{all:true}` 所有匹配前插入 | `(path, field, opts?) => void` |
|
|
297
|
+
| `getParentField(path, opts?)` | 查找父级字段配置;`{all:true}` 返回所有匹配的父级字段 | `(path, opts?) => Field` |
|
|
297
298
|
|
|
298
299
|
---
|
|
299
300
|
|
|
@@ -371,7 +372,7 @@ const table = useTable<D, T>({
|
|
|
371
372
|
|
|
372
373
|
#### `valueFormatter` 字段值转换
|
|
373
374
|
|
|
374
|
-
控制表单值与组件值之间的转换(如日期 `dayjs`
|
|
375
|
+
控制表单值与组件值之间的转换(如日期 `dayjs` 与字符串互转)。在表单数据写入前(computed setter 中)执行,支持两种形态。**函数形态仅 set(写入)方向生效,读取时不转换;对象形态 get/set 双向生效:**
|
|
375
376
|
|
|
376
377
|
```ts
|
|
377
378
|
// 函数形态:(新值, 旧值) => 转换后的值,写回 formData
|
package/api.json
CHANGED
package/bin/init-ai.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* global process -- Node.js CLI 脚本 */
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* @qin-ui/antd-vue-pro AI 上下文初始化 CLI 工具
|
|
5
6
|
*
|
|
6
7
|
* 在消费方项目中生成双载体 AI 上下文:
|
|
7
|
-
* 1. 根目录 AGENTS.md
|
|
8
|
-
* 2. .agents/skills/{pkg}.md
|
|
8
|
+
* 1. 根目录 AGENTS.md -- 核心使用规则,跨工具自动注入(主载体)
|
|
9
|
+
* 2. .agents/skills/{pkg}/SKILL.md + references/ -- 分层参考文档,支持 skills 发现的工具按需逐层调取(参考载体)
|
|
9
10
|
*
|
|
10
11
|
* 用法:
|
|
11
12
|
* npx @qin-ui/antd-vue-pro init-ai
|
|
@@ -50,7 +51,10 @@ function readPackageFile(filename) {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
function getAiContextContent() {
|
|
53
|
-
return
|
|
54
|
+
return (
|
|
55
|
+
readPackageFile('AI-CONTEXT.md') ||
|
|
56
|
+
`# ${PKG_NAME}\n\n> 基于 Vue 3 的配置驱动组件库。`
|
|
57
|
+
);
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
function getReadmeContent() {
|
|
@@ -142,46 +146,82 @@ function writeAgentsMd(cwd) {
|
|
|
142
146
|
// ==================== Skills(参考载体,按需调取)====================
|
|
143
147
|
|
|
144
148
|
/**
|
|
145
|
-
* 生成
|
|
146
|
-
*
|
|
149
|
+
* 生成 SKILL.md 内容
|
|
150
|
+
* = skill frontmatter + AI-CONTEXT.md 速查内容 + references 导航
|
|
151
|
+
* 供支持 skills 发现的工具按需调取,精准定位后查阅 references
|
|
147
152
|
*/
|
|
148
|
-
function
|
|
149
|
-
const
|
|
150
|
-
const apiJson = getApiJsonContent();
|
|
151
|
-
|
|
153
|
+
function getSkillMainContent() {
|
|
154
|
+
const aiContext = getAiContextContent();
|
|
152
155
|
const sections = [];
|
|
153
156
|
|
|
154
157
|
// skill frontmatter
|
|
155
158
|
sections.push('---');
|
|
156
159
|
sections.push(`name: ${PKG_SHORT}`);
|
|
157
160
|
sections.push(
|
|
158
|
-
`description: ${PKG_NAME}
|
|
161
|
+
`description: ${PKG_NAME} 使用指南 - 组件、Hooks、类型、Field/Column 配置。Schema 驱动的配置式组件库。当需要组件映射、默认预设、属性透传规则或完整用法时按需调取。`
|
|
159
162
|
);
|
|
160
163
|
sections.push('---');
|
|
161
164
|
sections.push('');
|
|
162
165
|
|
|
163
|
-
|
|
164
|
-
sections.push(
|
|
166
|
+
// AI-CONTEXT.md 速查内容(与 AGENTS.md 主载体同源,确保一致)
|
|
167
|
+
sections.push(aiContext);
|
|
168
|
+
sections.push('');
|
|
165
169
|
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
// references 导航
|
|
171
|
+
sections.push('---');
|
|
172
|
+
sections.push('');
|
|
173
|
+
sections.push('## 参考文档');
|
|
174
|
+
sections.push('');
|
|
175
|
+
sections.push(
|
|
176
|
+
`以下文件位于 \`.agents/skills/${PKG_SHORT}/references/\`,可在需要精确细节时进一步查阅:`
|
|
177
|
+
);
|
|
178
|
+
sections.push('');
|
|
179
|
+
sections.push(
|
|
180
|
+
`- [references/README.md](references/README.md) — 完整使用文档与进阶示例`
|
|
181
|
+
);
|
|
182
|
+
sections.push(
|
|
183
|
+
`- [references/api.md](references/api.md) — 结构化 API 元数据(函数签名、参数类型、返回值,提取自源码 JSDoc)`
|
|
184
|
+
);
|
|
185
|
+
sections.push(`- 底层组件属性查阅 ant-design-vue 官方文档:https://antdv.com`);
|
|
186
|
+
sections.push('');
|
|
187
|
+
|
|
188
|
+
return sections.join('\n');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 生成 references/api.md 内容(结构化 API 元数据 + skill frontmatter)
|
|
193
|
+
* 从 api.json 提取 @public 标记的 JSDoc,含签名、参数、返回值、示例
|
|
194
|
+
*/
|
|
195
|
+
function getSkillApiContent() {
|
|
196
|
+
const apiJson = getApiJsonContent();
|
|
197
|
+
const sections = [];
|
|
198
|
+
|
|
199
|
+
// skill frontmatter
|
|
200
|
+
sections.push('---');
|
|
201
|
+
sections.push(`name: ${PKG_SHORT}-api`);
|
|
202
|
+
sections.push(
|
|
203
|
+
`description: ${PKG_NAME} 结构化 API 元数据 - 函数签名、参数类型、返回值、示例。从源码 JSDoc(@public 标记)自动提取。`
|
|
204
|
+
);
|
|
205
|
+
sections.push('---');
|
|
206
|
+
sections.push('');
|
|
207
|
+
|
|
208
|
+
sections.push(`# ${PKG_NAME} - 结构化 API 元数据`, '');
|
|
209
|
+
sections.push(
|
|
210
|
+
`> 自动提取自源码 JSDoc(\`@public\` 标记)。版本: ${PKG_JSON.version}`,
|
|
211
|
+
''
|
|
212
|
+
);
|
|
171
213
|
|
|
172
214
|
// 结构化 API 元数据
|
|
173
215
|
if (apiJson && apiJson.api && apiJson.api.length > 0) {
|
|
174
|
-
sections.push('---', '');
|
|
175
|
-
sections.push('## 结构化 API 元数据(自动提取自源码 JSDoc)', '');
|
|
176
|
-
|
|
177
216
|
for (const item of apiJson.api) {
|
|
178
|
-
const typeLabel =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
217
|
+
const typeLabel =
|
|
218
|
+
{
|
|
219
|
+
component: '组件',
|
|
220
|
+
function: '函数/Hook',
|
|
221
|
+
type: '类型',
|
|
222
|
+
interface: '接口',
|
|
223
|
+
constant: '常量',
|
|
224
|
+
}[item.type] || '';
|
|
185
225
|
|
|
186
226
|
sections.push(`### ${typeLabel} \`${item.name}\``);
|
|
187
227
|
sections.push('');
|
|
@@ -216,7 +256,9 @@ function getSkillContent() {
|
|
|
216
256
|
sections.push('| 参数名 | 类型 | 可选 | 描述 |');
|
|
217
257
|
sections.push('| :--- | :--- | :--- | :--- |');
|
|
218
258
|
for (const p of item.params) {
|
|
219
|
-
sections.push(
|
|
259
|
+
sections.push(
|
|
260
|
+
`| \`${p.name}\` | \`${p.type}\` | ${p.optional ? '是' : '否'} | ${p.description} |`
|
|
261
|
+
);
|
|
220
262
|
}
|
|
221
263
|
}
|
|
222
264
|
|
|
@@ -259,10 +301,14 @@ ${bold('说明:')}
|
|
|
259
301
|
AGENTS.md 核心使用规则(跨工具自动注入)
|
|
260
302
|
.agents/
|
|
261
303
|
skills/
|
|
262
|
-
${PKG_SHORT}
|
|
304
|
+
${PKG_SHORT}/
|
|
305
|
+
SKILL.md skills 入口(速查 + 导航)
|
|
306
|
+
references/
|
|
307
|
+
README.md 完整使用文档
|
|
308
|
+
api.md 结构化 API 元数据
|
|
263
309
|
|
|
264
310
|
${dim('AGENTS.md 是跨工具开放约定,Codex / Claude Code / Cursor 等会话时自动注入。')}
|
|
265
|
-
${dim('.agents/skills/ 供支持 skills
|
|
311
|
+
${dim('.agents/skills/ 供支持 skills 发现的工具按需逐层调取。')}
|
|
266
312
|
|
|
267
313
|
${bold('选项:')}
|
|
268
314
|
--help 显示帮助信息
|
|
@@ -293,30 +339,76 @@ function main() {
|
|
|
293
339
|
// 1. 生成 AGENTS.md(主载体)
|
|
294
340
|
console.log(bold('📋 主载体:AGENTS.md(自动注入)'));
|
|
295
341
|
writeAgentsMd(process.cwd());
|
|
296
|
-
console.log(
|
|
342
|
+
console.log(
|
|
343
|
+
dim(' -> 核心使用规则,Codex/Claude Code/Cursor 等会话自动加载')
|
|
344
|
+
);
|
|
297
345
|
console.log('');
|
|
298
346
|
|
|
299
|
-
// 2. 生成 Skills
|
|
347
|
+
// 2. 生成 Skills(标准结构:SKILL.md + references/)
|
|
300
348
|
console.log(bold('📖 参考载体:.agents/skills/(按需调取)'));
|
|
349
|
+
const skillDir = path.join(process.cwd(), '.agents/skills', PKG_SHORT);
|
|
350
|
+
const skillRefsDir = path.join(skillDir, 'references');
|
|
351
|
+
|
|
352
|
+
// SKILL.md(入口:frontmatter + 速查内容 + 参考导航)
|
|
301
353
|
writeFileWithLog(
|
|
302
|
-
path.join(
|
|
303
|
-
|
|
304
|
-
`.agents/skills/${PKG_SHORT}.md`
|
|
354
|
+
path.join(skillDir, 'SKILL.md'),
|
|
355
|
+
getSkillMainContent(),
|
|
356
|
+
`.agents/skills/${PKG_SHORT}/SKILL.md`
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
// references/README.md(完整使用文档)
|
|
360
|
+
const readme = getReadmeContent();
|
|
361
|
+
if (readme) {
|
|
362
|
+
writeFileWithLog(
|
|
363
|
+
path.join(skillRefsDir, 'README.md'),
|
|
364
|
+
readme,
|
|
365
|
+
`.agents/skills/${PKG_SHORT}/references/README.md`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// references/api.md(结构化 API 元数据)
|
|
370
|
+
const apiJson = getApiJsonContent();
|
|
371
|
+
if (apiJson && apiJson.api && apiJson.api.length > 0) {
|
|
372
|
+
writeFileWithLog(
|
|
373
|
+
path.join(skillRefsDir, 'api.md'),
|
|
374
|
+
getSkillApiContent(),
|
|
375
|
+
`.agents/skills/${PKG_SHORT}/references/api.md`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
console.log(
|
|
380
|
+
dim(' -> SKILL.md 入口 + references/ 完整文档,skills 工具按需逐层调取')
|
|
305
381
|
);
|
|
306
|
-
console.log(dim(' -> 完整 README + 结构化 API 元数据,skills 工具按需调取'));
|
|
307
382
|
console.log('');
|
|
308
383
|
|
|
309
384
|
// 3. 完成提示
|
|
310
385
|
console.log(green('✅ 完成!已生成双载体 AI 上下文文件。'));
|
|
311
386
|
console.log('');
|
|
312
387
|
console.log(`${bold('📂 生成的文件:')}`);
|
|
313
|
-
console.log(
|
|
314
|
-
|
|
315
|
-
|
|
388
|
+
console.log(
|
|
389
|
+
` ${cyan('AGENTS.md')} ${dim('← 核心规则(AI 自动读取)')}`
|
|
390
|
+
);
|
|
391
|
+
console.log(` ${cyan('.agents/skills/' + PKG_SHORT + '/')}`);
|
|
392
|
+
console.log(
|
|
393
|
+
` ├── ${cyan('SKILL.md')} ${dim('← skills 入口(速查 + 导航)')}`
|
|
394
|
+
);
|
|
395
|
+
console.log(` └── ${cyan('references/')}`);
|
|
396
|
+
console.log(
|
|
397
|
+
` ├── ${cyan('README.md')} ${dim('← 完整使用文档')}`
|
|
398
|
+
);
|
|
399
|
+
if (apiJson && apiJson.api && apiJson.api.length > 0) {
|
|
400
|
+
console.log(
|
|
401
|
+
` └── ${cyan('api.md')} ${dim('← 结构化 API 元数据')}`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
316
404
|
console.log('');
|
|
317
405
|
console.log(`${bold('🔄 说明:')}`);
|
|
318
|
-
console.log(
|
|
319
|
-
|
|
406
|
+
console.log(
|
|
407
|
+
` - AGENTS.md 已用标记区块写入,重复执行 init-ai 可安全更新(不破坏其他库的指令)`
|
|
408
|
+
);
|
|
409
|
+
console.log(
|
|
410
|
+
` - 编写 Field 中输入控件属性前,查阅 ant-design-vue 官方文档:${cyan('https://antdv.com')}`
|
|
411
|
+
);
|
|
320
412
|
console.log('');
|
|
321
413
|
}
|
|
322
414
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qin-ui/antd-vue-pro",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"description": "二次封装antd vue组件",
|
|
5
5
|
"bin": {
|
|
6
6
|
"antd-vue-pro": "./bin/init-ai.mjs"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"scroll-into-view-if-needed": "^3.1.0",
|
|
45
45
|
"vue-component-type-helpers": "^3.2.5",
|
|
46
|
-
"@qin-ui/pro-components-core": "^1.0.
|
|
46
|
+
"@qin-ui/pro-components-core": "^1.0.4"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"ant-design-vue": "^4"
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"pro-table"
|
|
73
73
|
],
|
|
74
74
|
"scripts": {
|
|
75
|
-
"prebuild": "tsx ../../scripts/generate-api-json.ts antd-vue-pro",
|
|
75
|
+
"prebuild": "tsx ../../scripts/generate-api-json.ts antd-vue-pro && tsx ../../scripts/generate-init-ai.ts antd-vue-pro",
|
|
76
76
|
"build": "vue-tsc --noEmit && vite build"
|
|
77
77
|
}
|
|
78
78
|
}
|