@vue-ui-kit/ant 1.7.1 → 1.7.2

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/README.md CHANGED
@@ -1,426 +1,426 @@
1
- <div align="center">
2
- English | [简体中文](./README.zh.md)
3
- </div>
4
-
5
- # Vue UI Kit Documentation
6
-
7
- A Vue 3 UI component library based on Ant Design Vue, providing enhanced form, grid, and utility components.
8
-
9
- ## Installation
10
-
11
- ```bash
12
- npm install @vue-ui-kit/ant
13
- # or
14
- yarn add @vue-ui-kit/ant
15
- # or
16
- pnpm add @vue-ui-kit/ant
17
- ```
18
-
19
- ```ts
20
- /*main.ts*/
21
- import { createApp } from 'vue';
22
- import App from './App.vue';
23
- import Antd from 'ant-design-vue';
24
- import UIKit from '@vue-ui-kit/ant';
25
- import '@vue-ui-kit/ant/scss';
26
- /*Create renderer (recommended to use tsx)*/
27
- import { setupKit } from './setup/kit.tsx';
28
-
29
- /*Create formatter*/
30
- UIKit.addFormatter({
31
- test: ({ row, column, cellValue }) => 'test:...' + 'field:' + column.field + '...v:' + cellvalue,
32
- });
33
- createApp(App).use(Antd).use(UIKit).mount('#app');
34
- ```
35
-
36
- ```tsx
37
- /*kit.tsx*/
38
- import UIKit from '@vue-ui-kit/ant';
39
- import { TypographyParagraph, Switch } from 'ant-design-vue';
40
-
41
- export const setupKit = () => {
42
- /*Register $paragraph as cell renderer*/
43
- UIKit.addRender('$paragraph', {
44
- renderDefault({ props = {} }: RenderOptions, { row, field }: RenderTableParams) {
45
- const content = props.getContent?.({ row, field }) ?? (valued(field) ? row[field!] : '');
46
- return valued(field) ? (
47
- <TypographyParagraph
48
- {...merge({}, defaultProps.$paragraph, omit(props, ['content', 'getContent']))}
49
- content={content}
50
- />
51
- ) : null;
52
- },
53
- });
54
- /*Register $switch as form renderer*/
55
- UIKit.addRender('$switch', {
56
- renderItemContent(
57
- { props = {}, events = {} }: RenderOptions,
58
- { data, field }: RenderFormParams,
59
- ) {
60
- return valued(field) ? (
61
- <Switch
62
- v-model:checked={data[field!]}
63
- {...props}
64
- onChange={(...arg) => {
65
- events.change?.({ data, field }, ...arg);
66
- }}
67
- />
68
- ) : null;
69
- },
70
- });
71
- };
72
-
73
- /*
74
- * Built-in renderers:
75
- *
76
- $input: Input,
77
- AInput: Input,
78
- $textarea: Textarea,
79
- Textarea: Textarea,
80
- $number: InputNumber,
81
- AInputNumber: InputNumber,
82
- $select: Select,
83
- ASelect: Select,
84
- $date: DatePicker,
85
- ADatePicker: DatePicker,
86
- $range: RangePicker,
87
- ARangePicker: RangePicker,
88
- AAutoComplete: AutoComplete,
89
- $Cascader: Cascader,
90
- ACascader: Cascader,
91
- ACheckbox: Checkbox,
92
- AMentions: Mentions,
93
- ARate: Rate,
94
- ASlider: Slider,
95
- $time: TimePicker,
96
- ATimePicker: TimePicker,
97
- ATreeSelect: TreeSelect,
98
- *
99
- * */
100
- ```
101
-
102
- ## Requirements
103
-
104
- - Node.js >= 16
105
- - Vue >= 3.2.0
106
- - ant-design-vue >= 4.0.0
107
- - @ant-design/icons-vue >= 7.0.0
108
-
109
- ## Components
110
-
111
- ### PForm
112
-
113
- Enhanced Form component with simplified configuration and dynamic fields.
114
-
115
- #### Props
116
-
117
- | Prop | Type | Description |
118
- | ----------- | ------------------ | ------------------------------ |
119
- | items | `PFormItemProps[]` | Form items configuration array |
120
- | customReset | `() => void` | Custom reset function |
121
- | others | `FormProps` | All ant-design-vue Form props |
122
-
123
- #### PFormItemProps
124
-
125
- | Prop | Type | Description | Default |
126
- | --- | --- | --- | --- |
127
- | field | `string` | Form field name | - |
128
- | title | `string` | Field label | - |
129
- | span | `number` | Grid span | - |
130
- | colon | `boolean` | Show colon | true |
131
- | forceRequired | `boolean` | Show required mark (without validation) | false |
132
- | align | `'left' \| 'right' \| 'center'` | Text alignment | 'left' |
133
- | col | `ColProps` | Grid column properties | - |
134
- | rule | `Rule[]` | Validation rules | - |
135
- | tooltipConfig | `TooltipConfig` | Tooltip configuration | - |
136
-
137
- #### Example
138
-
139
- ```vue
140
- <script setup lang="tsx">
141
- import { computed, ref } from 'vue';
142
- import { TextAdAccount } from '...somewhere';
143
- import { PFormProps } from '@vue-ui-kit/ant';
144
-
145
- const createFormData = ref<TextAdAccount>({
146
- account_code: '',
147
- key_id: '',
148
- org_id: '',
149
- secret_key: '',
150
- });
151
- const createFormSetting = computed<PFormProps<TestAdAccount>>(() => ({
152
- rules: {
153
- account_code: [{ required: true, message: 'Please select Test account', trigger: 'change' }],
154
- org_id: [
155
- { required: true, message: 'Please select authorization organization', trigger: 'change' },
156
- ],
157
- secret_key: [{ required: true, message: 'Please enter Secret Key', trigger: 'change' }],
158
- key_id: [{ required: true, message: 'Please enter Key ID', trigger: 'change' }],
159
- },
160
- items: [
161
- {
162
- title: 'Channel',
163
- span: 24,
164
- itemRender: {
165
- name: 'readonly',
166
- props: {
167
- getText: () => 'Test',
168
- },
169
- },
170
- },
171
- {
172
- field: 'account_code',
173
- title: 'Account',
174
- span: 24,
175
- itemRender: {
176
- name: '$select',
177
- props: {
178
- options: [
179
- { label: 'Test Account 1', value: '1' },
180
- { label: 'Test Account 2', value: '2' },
181
- ],
182
- },
183
- events: {
184
- change: ({ data }) => {
185
- data.org_id = '';
186
- },
187
- },
188
- },
189
- tooltipConfig: {
190
- title: 'Account refers to the email used to log in to the Test backend',
191
- },
192
- },
193
- {
194
- field: 'org_id',
195
- title: 'Authorization Org',
196
- span: 24,
197
- slots: {
198
- default: ({ data }) => <my-custom-input v-model={data.org_id}></my-custom-input>,
199
- },
200
- tooltipConfig: {
201
- title: 'Organization name, ID, and Core ID under the corresponding account',
202
- },
203
- },
204
- {
205
- field: 'secret_key',
206
- title: 'Secret Key',
207
- span: 24,
208
- itemRender: {
209
- name: '$input',
210
- },
211
- tooltipConfig: {
212
- title: 'I am a tooltip',
213
- },
214
- },
215
- {
216
- field: 'key_id',
217
- title: 'Key ID',
218
- span: 24,
219
- itemRender: {
220
- name: '$input',
221
- },
222
- tooltipConfig: {
223
- title: 'I am a tooltip',
224
- },
225
- },
226
- ],
227
- }));
228
- </script>
229
- <template>
230
- <p-form ref="cf" :data="createFormData" v-bind="createFormSetting" />
231
- </template>
232
- ```
233
-
234
- ### PGrid
235
-
236
- Advanced grid component with built-in data management and toolbar functionality.
237
-
238
- #### Props
239
-
240
- | Prop | Type | Description | Default |
241
- | ------------- | -------------------- | ----------------------------- | ------- |
242
- | rowKey | `string` | Unique identifier field | 'id' |
243
- | columns | `ColumnProps[]` | Table columns configuration | - |
244
- | formConfig | `PFormProps` | Search form configuration | - |
245
- | toolbarConfig | `ToolbarConfig` | Toolbar buttons configuration | - |
246
- | pageConfig | `PageConfig` | Pagination configuration | - |
247
- | proxyConfig | `ProxyConfig` | Data fetching configuration | - |
248
- | selectConfig | `SelectConfig` | Row selection configuration | - |
249
- | scrollMode | `'outer' \| 'inner'` | Scroll mode | 'outer' |
250
- | fitHeight | `number` | Auto-fit height adjustment | - |
251
-
252
- #### Example
253
-
254
- ```vue
255
- <script setup lang="ts">
256
- import { ColumnProps, getButtonResponsive, labelColDict, PGridProps } from '@vue-ui-kit/ant';
257
- import { computed } from 'vue';
258
- import { hasAuth } from '...somewhere';
259
- import { getChannelPage, deleteChannel, deleteChannels } from '...somewhere';
260
- import type { Channel, ChannelParam } from '...somewhere';
261
-
262
- const gridSetting = computed<PGridProps<Channel, ChannelParam>>(() => ({
263
- selectConfig: {
264
- multiple: true,
265
- },
266
- toolbarConfig: {
267
- buttons: [
268
- {
269
- code: 'multiDelete',
270
- content: t('批量删除'),
271
- type: 'danger',
272
- },
273
- ],
274
- },
275
- columns: [
276
- {
277
- field: 'id',
278
- title: 'ID',
279
- width: 110,
280
- },
281
- {
282
- field: 'name',
283
- title: 'Channel Name',
284
- width: 140,
285
- },
286
- {
287
- field: 'short_name',
288
- title: 'Short Name',
289
- width: 140,
290
- },
291
- {
292
- field: 'operator',
293
- title: 'Operator',
294
- width: 120,
295
- },
296
- {
297
- field: 'update_time',
298
- title: 'Last Modified',
299
- width: 180,
300
- },
301
- ...(hasAuth('common_channel_admin')
302
- ? ([
303
- {
304
- title: 'Actions',
305
- fixed: 'right',
306
- width: 160,
307
- cellRender: {
308
- name: 'ButtonTree',
309
- children: [
310
- {
311
- content: 'Edit',
312
- type: 'link',
313
- clickEvt: ({ row }: { row: Channel }) => doEdit(row),
314
- },
315
- {
316
- content: 'Delete',
317
- type: 'link',
318
- danger: true,
319
- clickEvt: ({ row }: { row: Channel }) => confirmDelete(row),
320
- },
321
- ],
322
- },
323
- },
324
- ] as ColumnProps<Channel>[])
325
- : []),
326
- ],
327
- formConfig: {
328
- items: [
329
- {
330
- field: 'name',
331
- title: 'Channel Name',
332
- labelCol: labelColDict[4],
333
- itemRender: {
334
- name: '$input',
335
- props: {
336
- placeholder: 'Please enter channel name',
337
- },
338
- },
339
- },
340
- {
341
- col: getButtonResponsive(1),
342
- align: 'right',
343
- itemRender: {
344
- name: '$buttons',
345
- children: [
346
- {
347
- props: {
348
- content: 'Search',
349
- htmlType: 'submit',
350
- type: 'primary',
351
- },
352
- },
353
- {
354
- props: {
355
- content: 'Reset',
356
- htmlType: 'reset',
357
- },
358
- },
359
- ],
360
- },
361
- },
362
- ],
363
- },
364
- pageConfig: {
365
- pageSize: 10,
366
- },
367
- proxyConfig: {
368
- response: {
369
- total: 'total',
370
- result: 'list',
371
- },
372
- ajax: {
373
- query: ({ form, page }) =>
374
- getChannelPage({
375
- ...form,
376
- ...page,
377
- } as ChannelParam),
378
- multiDelete: deleteChannels,
379
- },
380
- },
381
- }));
382
- </script>
383
- <template>
384
- <p-grid ref="gridEl" v-bind="gridSetting" />
385
- </template>
386
- ```
387
-
388
- ### PFormGroup
389
-
390
- Form group component for organizing form fields into collapsible sections.
391
-
392
- #### Props
393
-
394
- | Prop | Type | Description |
395
- | -------------- | ---------------------- | ----------------------------- |
396
- | getFormSetting | `(data) => PFormProps` | Function to get form settings |
397
- | source | `object` | Form data source |
398
-
399
- ## Q&A
400
-
401
- ### 1. When using computed + v-bind to generate dynamic tables + forms, form option updates cause table re-rendering. How to solve this?
402
-
403
- Answer: Separate the formConfig into another computed property
404
-
405
- ```vue
406
- <p-grid v-bind="gridSetting" :form-config="computedFormConfig" />
407
- ```
408
-
409
- ### 2. Does the table ajax currently only support multiDelete and table data fetching?
410
-
411
- Answer: Edit details in most cases cannot correspond one-to-one with the table, so there's no development significance. Multi-row deletion needs to be used together with:
412
-
413
- ```ts
414
- selectConfig: {
415
- multiple: true,
416
- },
417
- toolbarConfig: {
418
- buttons: {
419
- code: "multipleDelete"
420
- }
421
- }
422
- ```
423
-
424
- ### 3. Why is the computed approach recommended?
425
-
426
- Answer: It simplifies all dynamic logic, that's all. For complex scenarios, you can try using reactive and maintain it yourself, but in most cases, computed is more convenient.
1
+ <div align="center">
2
+ English | [简体中文](./README.zh.md)
3
+ </div>
4
+
5
+ # Vue UI Kit Documentation
6
+
7
+ A Vue 3 UI component library based on Ant Design Vue, providing enhanced form, grid, and utility components.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @vue-ui-kit/ant
13
+ # or
14
+ yarn add @vue-ui-kit/ant
15
+ # or
16
+ pnpm add @vue-ui-kit/ant
17
+ ```
18
+
19
+ ```ts
20
+ /*main.ts*/
21
+ import { createApp } from 'vue';
22
+ import App from './App.vue';
23
+ import Antd from 'ant-design-vue';
24
+ import UIKit from '@vue-ui-kit/ant';
25
+ import '@vue-ui-kit/ant/scss';
26
+ /*Create renderer (recommended to use tsx)*/
27
+ import { setupKit } from './setup/kit.tsx';
28
+
29
+ /*Create formatter*/
30
+ UIKit.addFormatter({
31
+ test: ({ row, column, cellValue }) => 'test:...' + 'field:' + column.field + '...v:' + cellvalue,
32
+ });
33
+ createApp(App).use(Antd).use(UIKit).mount('#app');
34
+ ```
35
+
36
+ ```tsx
37
+ /*kit.tsx*/
38
+ import UIKit from '@vue-ui-kit/ant';
39
+ import { TypographyParagraph, Switch } from 'ant-design-vue';
40
+
41
+ export const setupKit = () => {
42
+ /*Register $paragraph as cell renderer*/
43
+ UIKit.addRender('$paragraph', {
44
+ renderDefault({ props = {} }: RenderOptions, { row, field }: RenderTableParams) {
45
+ const content = props.getContent?.({ row, field }) ?? (valued(field) ? row[field!] : '');
46
+ return valued(field) ? (
47
+ <TypographyParagraph
48
+ {...merge({}, defaultProps.$paragraph, omit(props, ['content', 'getContent']))}
49
+ content={content}
50
+ />
51
+ ) : null;
52
+ },
53
+ });
54
+ /*Register $switch as form renderer*/
55
+ UIKit.addRender('$switch', {
56
+ renderItemContent(
57
+ { props = {}, events = {} }: RenderOptions,
58
+ { data, field }: RenderFormParams,
59
+ ) {
60
+ return valued(field) ? (
61
+ <Switch
62
+ v-model:checked={data[field!]}
63
+ {...props}
64
+ onChange={(...arg) => {
65
+ events.change?.({ data, field }, ...arg);
66
+ }}
67
+ />
68
+ ) : null;
69
+ },
70
+ });
71
+ };
72
+
73
+ /*
74
+ * Built-in renderers:
75
+ *
76
+ $input: Input,
77
+ AInput: Input,
78
+ $textarea: Textarea,
79
+ Textarea: Textarea,
80
+ $number: InputNumber,
81
+ AInputNumber: InputNumber,
82
+ $select: Select,
83
+ ASelect: Select,
84
+ $date: DatePicker,
85
+ ADatePicker: DatePicker,
86
+ $range: RangePicker,
87
+ ARangePicker: RangePicker,
88
+ AAutoComplete: AutoComplete,
89
+ $Cascader: Cascader,
90
+ ACascader: Cascader,
91
+ ACheckbox: Checkbox,
92
+ AMentions: Mentions,
93
+ ARate: Rate,
94
+ ASlider: Slider,
95
+ $time: TimePicker,
96
+ ATimePicker: TimePicker,
97
+ ATreeSelect: TreeSelect,
98
+ *
99
+ * */
100
+ ```
101
+
102
+ ## Requirements
103
+
104
+ - Node.js >= 16
105
+ - Vue >= 3.2.0
106
+ - ant-design-vue >= 4.0.0
107
+ - @ant-design/icons-vue >= 7.0.0
108
+
109
+ ## Components
110
+
111
+ ### PForm
112
+
113
+ Enhanced Form component with simplified configuration and dynamic fields.
114
+
115
+ #### Props
116
+
117
+ | Prop | Type | Description |
118
+ | ----------- | ------------------ | ------------------------------ |
119
+ | items | `PFormItemProps[]` | Form items configuration array |
120
+ | customReset | `() => void` | Custom reset function |
121
+ | others | `FormProps` | All ant-design-vue Form props |
122
+
123
+ #### PFormItemProps
124
+
125
+ | Prop | Type | Description | Default |
126
+ | --- | --- | --- | --- |
127
+ | field | `string` | Form field name | - |
128
+ | title | `string` | Field label | - |
129
+ | span | `number` | Grid span | - |
130
+ | colon | `boolean` | Show colon | true |
131
+ | forceRequired | `boolean` | Show required mark (without validation) | false |
132
+ | align | `'left' \| 'right' \| 'center'` | Text alignment | 'left' |
133
+ | col | `ColProps` | Grid column properties | - |
134
+ | rule | `Rule[]` | Validation rules | - |
135
+ | tooltipConfig | `TooltipConfig` | Tooltip configuration | - |
136
+
137
+ #### Example
138
+
139
+ ```vue
140
+ <script setup lang="tsx">
141
+ import { computed, ref } from 'vue';
142
+ import { TextAdAccount } from '...somewhere';
143
+ import { PFormProps } from '@vue-ui-kit/ant';
144
+
145
+ const createFormData = ref<TextAdAccount>({
146
+ account_code: '',
147
+ key_id: '',
148
+ org_id: '',
149
+ secret_key: '',
150
+ });
151
+ const createFormSetting = computed<PFormProps<TestAdAccount>>(() => ({
152
+ rules: {
153
+ account_code: [{ required: true, message: 'Please select Test account', trigger: 'change' }],
154
+ org_id: [
155
+ { required: true, message: 'Please select authorization organization', trigger: 'change' },
156
+ ],
157
+ secret_key: [{ required: true, message: 'Please enter Secret Key', trigger: 'change' }],
158
+ key_id: [{ required: true, message: 'Please enter Key ID', trigger: 'change' }],
159
+ },
160
+ items: [
161
+ {
162
+ title: 'Channel',
163
+ span: 24,
164
+ itemRender: {
165
+ name: 'readonly',
166
+ props: {
167
+ getText: () => 'Test',
168
+ },
169
+ },
170
+ },
171
+ {
172
+ field: 'account_code',
173
+ title: 'Account',
174
+ span: 24,
175
+ itemRender: {
176
+ name: '$select',
177
+ props: {
178
+ options: [
179
+ { label: 'Test Account 1', value: '1' },
180
+ { label: 'Test Account 2', value: '2' },
181
+ ],
182
+ },
183
+ events: {
184
+ change: ({ data }) => {
185
+ data.org_id = '';
186
+ },
187
+ },
188
+ },
189
+ tooltipConfig: {
190
+ title: 'Account refers to the email used to log in to the Test backend',
191
+ },
192
+ },
193
+ {
194
+ field: 'org_id',
195
+ title: 'Authorization Org',
196
+ span: 24,
197
+ slots: {
198
+ default: ({ data }) => <my-custom-input v-model={data.org_id}></my-custom-input>,
199
+ },
200
+ tooltipConfig: {
201
+ title: 'Organization name, ID, and Core ID under the corresponding account',
202
+ },
203
+ },
204
+ {
205
+ field: 'secret_key',
206
+ title: 'Secret Key',
207
+ span: 24,
208
+ itemRender: {
209
+ name: '$input',
210
+ },
211
+ tooltipConfig: {
212
+ title: 'I am a tooltip',
213
+ },
214
+ },
215
+ {
216
+ field: 'key_id',
217
+ title: 'Key ID',
218
+ span: 24,
219
+ itemRender: {
220
+ name: '$input',
221
+ },
222
+ tooltipConfig: {
223
+ title: 'I am a tooltip',
224
+ },
225
+ },
226
+ ],
227
+ }));
228
+ </script>
229
+ <template>
230
+ <p-form ref="cf" :data="createFormData" v-bind="createFormSetting" />
231
+ </template>
232
+ ```
233
+
234
+ ### PGrid
235
+
236
+ Advanced grid component with built-in data management and toolbar functionality.
237
+
238
+ #### Props
239
+
240
+ | Prop | Type | Description | Default |
241
+ | ------------- | -------------------- | ----------------------------- | ------- |
242
+ | rowKey | `string` | Unique identifier field | 'id' |
243
+ | columns | `ColumnProps[]` | Table columns configuration | - |
244
+ | formConfig | `PFormProps` | Search form configuration | - |
245
+ | toolbarConfig | `ToolbarConfig` | Toolbar buttons configuration | - |
246
+ | pageConfig | `PageConfig` | Pagination configuration | - |
247
+ | proxyConfig | `ProxyConfig` | Data fetching configuration | - |
248
+ | selectConfig | `SelectConfig` | Row selection configuration | - |
249
+ | scrollMode | `'outer' \| 'inner'` | Scroll mode | 'outer' |
250
+ | fitHeight | `number` | Auto-fit height adjustment | - |
251
+
252
+ #### Example
253
+
254
+ ```vue
255
+ <script setup lang="ts">
256
+ import { ColumnProps, getButtonResponsive, labelColDict, PGridProps } from '@vue-ui-kit/ant';
257
+ import { computed } from 'vue';
258
+ import { hasAuth } from '...somewhere';
259
+ import { getChannelPage, deleteChannel, deleteChannels } from '...somewhere';
260
+ import type { Channel, ChannelParam } from '...somewhere';
261
+
262
+ const gridSetting = computed<PGridProps<Channel, ChannelParam>>(() => ({
263
+ selectConfig: {
264
+ multiple: true,
265
+ },
266
+ toolbarConfig: {
267
+ buttons: [
268
+ {
269
+ code: 'multiDelete',
270
+ content: t('批量删除'),
271
+ type: 'danger',
272
+ },
273
+ ],
274
+ },
275
+ columns: [
276
+ {
277
+ field: 'id',
278
+ title: 'ID',
279
+ width: 110,
280
+ },
281
+ {
282
+ field: 'name',
283
+ title: 'Channel Name',
284
+ width: 140,
285
+ },
286
+ {
287
+ field: 'short_name',
288
+ title: 'Short Name',
289
+ width: 140,
290
+ },
291
+ {
292
+ field: 'operator',
293
+ title: 'Operator',
294
+ width: 120,
295
+ },
296
+ {
297
+ field: 'update_time',
298
+ title: 'Last Modified',
299
+ width: 180,
300
+ },
301
+ ...(hasAuth('common_channel_admin')
302
+ ? ([
303
+ {
304
+ title: 'Actions',
305
+ fixed: 'right',
306
+ width: 160,
307
+ cellRender: {
308
+ name: 'ButtonTree',
309
+ children: [
310
+ {
311
+ content: 'Edit',
312
+ type: 'link',
313
+ clickEvt: ({ row }: { row: Channel }) => doEdit(row),
314
+ },
315
+ {
316
+ content: 'Delete',
317
+ type: 'link',
318
+ danger: true,
319
+ clickEvt: ({ row }: { row: Channel }) => confirmDelete(row),
320
+ },
321
+ ],
322
+ },
323
+ },
324
+ ] as ColumnProps<Channel>[])
325
+ : []),
326
+ ],
327
+ formConfig: {
328
+ items: [
329
+ {
330
+ field: 'name',
331
+ title: 'Channel Name',
332
+ labelCol: labelColDict[4],
333
+ itemRender: {
334
+ name: '$input',
335
+ props: {
336
+ placeholder: 'Please enter channel name',
337
+ },
338
+ },
339
+ },
340
+ {
341
+ col: getButtonResponsive(1),
342
+ align: 'right',
343
+ itemRender: {
344
+ name: '$buttons',
345
+ children: [
346
+ {
347
+ props: {
348
+ content: 'Search',
349
+ htmlType: 'submit',
350
+ type: 'primary',
351
+ },
352
+ },
353
+ {
354
+ props: {
355
+ content: 'Reset',
356
+ htmlType: 'reset',
357
+ },
358
+ },
359
+ ],
360
+ },
361
+ },
362
+ ],
363
+ },
364
+ pageConfig: {
365
+ pageSize: 10,
366
+ },
367
+ proxyConfig: {
368
+ response: {
369
+ total: 'total',
370
+ result: 'list',
371
+ },
372
+ ajax: {
373
+ query: ({ form, page }) =>
374
+ getChannelPage({
375
+ ...form,
376
+ ...page,
377
+ } as ChannelParam),
378
+ multiDelete: deleteChannels,
379
+ },
380
+ },
381
+ }));
382
+ </script>
383
+ <template>
384
+ <p-grid ref="gridEl" v-bind="gridSetting" />
385
+ </template>
386
+ ```
387
+
388
+ ### PFormGroup
389
+
390
+ Form group component for organizing form fields into collapsible sections.
391
+
392
+ #### Props
393
+
394
+ | Prop | Type | Description |
395
+ | -------------- | ---------------------- | ----------------------------- |
396
+ | getFormSetting | `(data) => PFormProps` | Function to get form settings |
397
+ | source | `object` | Form data source |
398
+
399
+ ## Q&A
400
+
401
+ ### 1. When using computed + v-bind to generate dynamic tables + forms, form option updates cause table re-rendering. How to solve this?
402
+
403
+ Answer: Separate the formConfig into another computed property
404
+
405
+ ```vue
406
+ <p-grid v-bind="gridSetting" :form-config="computedFormConfig" />
407
+ ```
408
+
409
+ ### 2. Does the table ajax currently only support multiDelete and table data fetching?
410
+
411
+ Answer: Edit details in most cases cannot correspond one-to-one with the table, so there's no development significance. Multi-row deletion needs to be used together with:
412
+
413
+ ```ts
414
+ selectConfig: {
415
+ multiple: true,
416
+ },
417
+ toolbarConfig: {
418
+ buttons: {
419
+ code: "multipleDelete"
420
+ }
421
+ }
422
+ ```
423
+
424
+ ### 3. Why is the computed approach recommended?
425
+
426
+ Answer: It simplifies all dynamic logic, that's all. For complex scenarios, you can try using reactive and maintain it yourself, but in most cases, computed is more convenient.