@vue-ui-kit/ant 1.0.0

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.
Files changed (50) hide show
  1. package/dist/cjs/index.js +1 -0
  2. package/dist/declarations/antProxy.d.ts +239 -0
  3. package/dist/declarations/type.d.ts +1 -0
  4. package/dist/es/index.js +2471 -0
  5. package/dist/index.d.ts +12 -0
  6. package/dist/packages/components/PForm.vue.d.ts +28 -0
  7. package/dist/packages/components/PFormGroup.vue.d.ts +29 -0
  8. package/dist/packages/components/PGrid.vue.d.ts +40 -0
  9. package/dist/packages/components/PGroupBlock.vue.d.ts +16 -0
  10. package/dist/packages/components/PromisePicker.vue.d.ts +48 -0
  11. package/dist/packages/components/RenderAntCell.d.ts +10 -0
  12. package/dist/packages/components/RenderAntItem.d.ts +17 -0
  13. package/dist/packages/components/RenderDefaultSlots.d.ts +14 -0
  14. package/dist/packages/components/RenderItemSlots.d.ts +10 -0
  15. package/dist/packages/components/RenderTitleSlots.d.ts +6 -0
  16. package/dist/packages/hooks/useMessage.d.ts +8 -0
  17. package/dist/packages/renders/Icon.d.ts +4 -0
  18. package/dist/packages/renders/TableInput.vue.d.ts +44 -0
  19. package/dist/packages/store/renderStore.d.ts +59 -0
  20. package/dist/packages/utils/AFormatters.d.ts +19 -0
  21. package/dist/packages/utils/core.d.ts +8 -0
  22. package/dist/packages/utils/is.d.ts +2 -0
  23. package/dist/packages/utils/treeHelper.d.ts +19 -0
  24. package/dist/style.css +1 -0
  25. package/package.json +72 -0
  26. package/src/declarations/README.md +9 -0
  27. package/src/declarations/antProxy.ts +255 -0
  28. package/src/declarations/global.d.ts +133 -0
  29. package/src/declarations/type.ts +1 -0
  30. package/src/index.ts +25 -0
  31. package/src/packages/components/PForm.vue +108 -0
  32. package/src/packages/components/PFormGroup.vue +90 -0
  33. package/src/packages/components/PGrid.vue +472 -0
  34. package/src/packages/components/PGroupBlock.vue +12 -0
  35. package/src/packages/components/PromisePicker.vue +64 -0
  36. package/src/packages/components/RenderAntCell.tsx +29 -0
  37. package/src/packages/components/RenderAntItem.tsx +54 -0
  38. package/src/packages/components/RenderDefaultSlots.tsx +44 -0
  39. package/src/packages/components/RenderItemSlots.tsx +24 -0
  40. package/src/packages/components/RenderTitleSlots.tsx +15 -0
  41. package/src/packages/hooks/useMessage.ts +19 -0
  42. package/src/packages/renders/Icon.ts +8 -0
  43. package/src/packages/renders/TableInput.vue +107 -0
  44. package/src/packages/store/renderStore.tsx +515 -0
  45. package/src/packages/styles/index.scss +184 -0
  46. package/src/packages/styles/variables.scss +3 -0
  47. package/src/packages/utils/AFormatters.ts +64 -0
  48. package/src/packages/utils/core.ts +52 -0
  49. package/src/packages/utils/is.ts +2 -0
  50. package/src/packages/utils/treeHelper.ts +72 -0
@@ -0,0 +1,15 @@
1
+ import { defineComponent } from 'vue';
2
+ import { ColumnProps } from '#/antProxy';
3
+
4
+ export default defineComponent(
5
+ <D = Recordable,>(props: { column: ColumnProps<D> }) => {
6
+ const { column } = props;
7
+ return () => {
8
+ return column.slots?.title?.({ column }) ?? column.title;
9
+ };
10
+ },
11
+ {
12
+ name: 'RenderAntTitle',
13
+ props: ['column'],
14
+ },
15
+ );
@@ -0,0 +1,19 @@
1
+ import { Modal, message } from 'ant-design-vue';
2
+
3
+ export const $confirm = ({ title, content }) =>
4
+ new Promise<void>((resolve, reject) => {
5
+ Modal.confirm({
6
+ title,
7
+ content,
8
+ onOk: () => {
9
+ resolve();
10
+ },
11
+ onCancel: () => {
12
+ reject();
13
+ },
14
+ });
15
+ });
16
+ export const $success = message.success;
17
+ export const $error = message.error;
18
+ export const $info = message.info;
19
+ export const $warning = message.warning;
@@ -0,0 +1,8 @@
1
+ import { createVNode } from 'vue';
2
+ import * as $Icon from '@ant-design/icons-vue';
3
+ const Icon = (props: { icon: string }) => {
4
+ const { icon } = props;
5
+ const antIcon: { [key: string]: any } = $Icon;
6
+ return antIcon[icon] ? createVNode(antIcon[icon]) : antIcon[icon];
7
+ };
8
+ export default Icon;
@@ -0,0 +1,107 @@
1
+ <script lang="ts" setup name="TableInput" generic="D = Recordable">
2
+ import { computed, PropType, watch } from 'vue';
3
+ import { TableProps } from 'ant-design-vue';
4
+ import { ColumnProps } from '#/antProxy';
5
+ import { cleanCol } from '@/utils/core';
6
+ import RenderDefaultSlots from '@/components/RenderDefaultSlots';
7
+ import { merge } from 'lodash-es';
8
+
9
+ const props = defineProps({
10
+ modelValue: {
11
+ type: Array as PropType<D[]>,
12
+ default: () => [],
13
+ },
14
+ tableConfig: {
15
+ type: Object as PropType<TableProps>,
16
+ default: () => ({}),
17
+ },
18
+ editColumns: {
19
+ type: Array as PropType<ColumnProps[]>,
20
+ default: () => [],
21
+ },
22
+ });
23
+ const defaultTableConfig = {
24
+ size: 'small',
25
+ // sticky: true,
26
+ pagination: false,
27
+ };
28
+ watch(
29
+ () => props.modelValue,
30
+ () => {
31
+ emit('trigger');
32
+ },
33
+ { deep: true },
34
+ );
35
+ const tc = computed(() => merge({}, defaultTableConfig, props.tableConfig));
36
+ const emit = defineEmits(['update:modelValue', 'trigger']);
37
+ const innerValue = computed<Partial<D>[]>({
38
+ get: () => props.modelValue ?? ([] as Partial<D>[]),
39
+ set: (val: Partial<D>[]) => {
40
+ emit('update:modelValue', val);
41
+ },
42
+ });
43
+
44
+ const totalColumns = computed<ColumnProps[]>(() => [
45
+ ...props.editColumns,
46
+ {
47
+ title: '操作',
48
+ fixed: 'right',
49
+ width: 100,
50
+ cellRender: {
51
+ name: 'ButtonTree',
52
+ children: [
53
+ {
54
+ content: '删除',
55
+ type: 'link',
56
+ danger: true,
57
+ clickEvt: ({ rowIndex }) => deleteRow(rowIndex),
58
+ },
59
+ ],
60
+ },
61
+ },
62
+ ]);
63
+ const addRow = () => {
64
+ // innerValue.value.push({})
65
+ innerValue.value = [...innerValue.value, {}];
66
+ };
67
+ const deleteRow = (index: number) => {
68
+ // innerValue.value.splice(index, 1)
69
+ innerValue.value = innerValue.value.filter((_, i) => i !== index);
70
+ };
71
+ const slotDefaultColumns = computed(() => {
72
+ let count = 0;
73
+ return totalColumns.value.filter((col) => {
74
+ if ((col.slots && col.slots.default) || col.formatter || col.cellRender) {
75
+ if (!col.field) {
76
+ col.field = '__holder__' + count;
77
+ count++;
78
+ }
79
+ return true;
80
+ } else {
81
+ return false;
82
+ }
83
+ });
84
+ });
85
+ </script>
86
+ <template>
87
+ <div>
88
+ <a-table :data-source="innerValue" v-bind="tc" :columns="totalColumns.map((c) => cleanCol(c))">
89
+ <template v-if="slotDefaultColumns.length > 0" #bodyCell="{ column, record, index }">
90
+ <a-form-item-rest>
91
+ <render-default-slots
92
+ v-if="slotDefaultColumns.some((s) => column.key && s.field === column.key)"
93
+ :key="index"
94
+ :row-index="index"
95
+ :default-handler="{}"
96
+ :column="slotDefaultColumns.find((f) => column.key && f.field === column.key)!"
97
+ :row="record"
98
+ :table-data="innerValue as Recordable[]"
99
+ />
100
+ </a-form-item-rest>
101
+ </template>
102
+ </a-table>
103
+ <div class="text-right mt-4px">
104
+ <a-button type="primary" @click="addRow">+添加</a-button>
105
+ </div>
106
+ </div>
107
+ </template>
@@ -0,0 +1,515 @@
1
+ import { RenderFormParams, RenderOptions, RenderTableParams } from '#/antProxy';
2
+ import {
3
+ Button,
4
+ Dropdown,
5
+ RadioGroup,
6
+ CheckboxGroup,
7
+ TypographyParagraph,
8
+ Switch,
9
+ AutoComplete,
10
+ Cascader,
11
+ Checkbox,
12
+ Input,
13
+ InputNumber,
14
+ Select,
15
+ DatePicker,
16
+ RangePicker,
17
+ Mentions,
18
+ Rate,
19
+ Slider,
20
+ Textarea,
21
+ TimePicker,
22
+ TreeSelect,
23
+ } from 'ant-design-vue';
24
+ import { set, isFunction, merge, omit } from 'lodash-es';
25
+ import { ButtonProps } from 'ant-design-vue/lib/button';
26
+ import { noValue, valued } from '@/utils/is';
27
+ import TableInput from '@/renders/TableInput.vue';
28
+ import Icon from '@/renders/Icon';
29
+ import { computed } from 'vue';
30
+
31
+ interface BtnOptions extends ButtonProps {
32
+ content?: string;
33
+ getContent?: (p: RenderTableParams) => string;
34
+ dynamicClassName?: (p: RenderTableParams) => string;
35
+ dropdowns?: BtnOptions[];
36
+ clickEvt?: (p: RenderTableParams) => any;
37
+ }
38
+
39
+ const antDefaultProps = {
40
+ AInput: {
41
+ autocomplete: 'off',
42
+ },
43
+ $input: {
44
+ autocomplete: 'off',
45
+ allowClear: true,
46
+ },
47
+ AInputNumber: {
48
+ min: 0,
49
+ controls: false,
50
+ precision: 0,
51
+ },
52
+ $number: {
53
+ min: 0,
54
+ controls: false,
55
+ precision: 0,
56
+ },
57
+ $date: {
58
+ format: 'YYYY-MM-DD',
59
+ valueFormat: 'YYYY-MM-DD',
60
+ },
61
+ ADatePicker: {
62
+ format: 'YYYY-MM-DD',
63
+ valueFormat: 'YYYY-MM-DD',
64
+ },
65
+ $range: {
66
+ format: 'YYYY-MM-DD',
67
+ valueFormat: 'YYYY-MM-DD',
68
+ },
69
+ ARangePicker: {
70
+ format: 'YYYY-MM-DD',
71
+ valueFormat: 'YYYY-MM-DD',
72
+ },
73
+ $select: {
74
+ getPopupContainer: (triggerNode: HTMLElement) => triggerNode.parentNode,
75
+ allowClear: true,
76
+ showSearch: true,
77
+ filterOption: (input: string, option: IOption) =>
78
+ option.label && option.label.toLowerCase().includes(input.toLowerCase()),
79
+ },
80
+ ASelect: {
81
+ getPopupContainer: (triggerNode: HTMLElement) => triggerNode.parentNode,
82
+ allowClear: true,
83
+ showSearch: true,
84
+ filterOption: (input: string, option: IOption) =>
85
+ option.label && option.label.toLowerCase().includes(input.toLowerCase()),
86
+ },
87
+ };
88
+ const defaultProps: Recordable = {
89
+ PercentInput: {
90
+ controls: false,
91
+ min: 0,
92
+ max: 100,
93
+ addonAfter: '%',
94
+ },
95
+ };
96
+ const componentsMap = {
97
+ $input: Input,
98
+ AInput: Input,
99
+ $textarea: Textarea,
100
+ Textarea: Textarea,
101
+ $number: InputNumber,
102
+ AInputNumber: InputNumber,
103
+ $select: Select,
104
+ ASelect: Select,
105
+ $date: DatePicker,
106
+ ADatePicker: DatePicker,
107
+ $range: RangePicker,
108
+ ARangePicker: RangePicker,
109
+ AAutoComplete: AutoComplete,
110
+ $Cascader: Cascader,
111
+ ACascader: Cascader,
112
+ ACheckbox: Checkbox,
113
+ AMentions: Mentions,
114
+ ARate: Rate,
115
+ ASlider: Slider,
116
+ /*switch 用的是checked不是value🙄*/
117
+ /* '$switch': Switch,
118
+ 'ASwitch': Switch,*/
119
+ $time: TimePicker,
120
+ ATimePicker: TimePicker,
121
+ ATreeSelect: TreeSelect,
122
+ };
123
+ const renderBasic = (name: string) => {
124
+ const DynamicComponent = componentsMap[name];
125
+ return {
126
+ renderItemContent(
127
+ { props = {}, attrs = {}, events = {}, defaultValue }: RenderOptions,
128
+ { data, field }: RenderFormParams,
129
+ ) {
130
+ if (valued(defaultValue) && valued(field) && noValue(data[field!])) {
131
+ data[field!] = defaultValue;
132
+ }
133
+ return field ? (
134
+ <DynamicComponent
135
+ is={name}
136
+ v-model:value={data[field]}
137
+ {...attrs}
138
+ {...merge({}, antDefaultProps[name], props)}
139
+ onChange={(...arg) => {
140
+ events.change?.({ data, field }, ...arg);
141
+ }}
142
+ />
143
+ ) : (
144
+ <DynamicComponent is={name} {...props} />
145
+ );
146
+ },
147
+ renderDefault(
148
+ { props = antDefaultProps[name] ?? {}, attrs = {}, events = {}, defaultValue }: RenderOptions,
149
+ { data, row, field }: RenderTableParams,
150
+ ) {
151
+ if (valued(defaultValue) && valued(field) && noValue(row[field!])) {
152
+ row[field!] = defaultValue;
153
+ }
154
+ return field ? (
155
+ <DynamicComponent
156
+ is={name}
157
+ v-model:value={row[field]}
158
+ {...attrs}
159
+ {...merge({}, antDefaultProps[name], props)}
160
+ onChange={(...arg) => {
161
+ events.change?.({ data, row, field }, ...arg);
162
+ }}
163
+ />
164
+ ) : (
165
+ <DynamicComponent is={name} {...props} />
166
+ );
167
+ },
168
+ };
169
+ };
170
+
171
+ const renderBtn = (btnOpt: BtnOptions, params: RenderTableParams) =>
172
+ btnOpt.dropdowns && btnOpt.dropdowns.length > 0 ? (
173
+ <Dropdown>
174
+ {{
175
+ default: () => (
176
+ <Button
177
+ {...omit(btnOpt, [
178
+ 'dynamicClassName',
179
+ 'content',
180
+ 'getContent',
181
+ 'icon',
182
+ 'clickEvt',
183
+ 'dropdowns',
184
+ ])}
185
+ icon={btnOpt.icon ? <Icon icon={btnOpt.icon} /> : null}
186
+ >
187
+ {btnOpt.content || (btnOpt?.getContent?.(params) ?? '')}
188
+ </Button>
189
+ ),
190
+ overlay: () => (
191
+ <div class={`dropdown-wrapper ${btnOpt?.dynamicClassName?.(params) ?? ''}`}>
192
+ {btnOpt.dropdowns!.map((b) => renderBtn(b, params))}
193
+ </div>
194
+ ),
195
+ }}
196
+ </Dropdown>
197
+ ) : (
198
+ <Button
199
+ class={btnOpt?.dynamicClassName?.(params) || ''}
200
+ {...omit(btnOpt, [
201
+ 'dynamicClassName',
202
+ 'content',
203
+ 'getContent',
204
+ 'icon',
205
+ 'clickEvt',
206
+ 'dropdowns',
207
+ ])}
208
+ icon={btnOpt.icon ? <Icon icon={btnOpt.icon} /> : null}
209
+ onClick={() => {
210
+ if (btnOpt?.clickEvt) {
211
+ btnOpt.clickEvt(params);
212
+ }
213
+ }}
214
+ >
215
+ {btnOpt.content || (btnOpt?.getContent?.(params) ?? '')}
216
+ </Button>
217
+ );
218
+ const renders = {
219
+ ...Object.fromEntries(Object.keys(componentsMap).map((name) => [name, renderBasic(name)])),
220
+ //简单按钮
221
+ $button: {
222
+ renderItemContent(
223
+ { props = {}, events = {} }: RenderOptions,
224
+ { data, field }: RenderFormParams,
225
+ defaultHandler: {
226
+ [key: string]: (...args: any[]) => any;
227
+ },
228
+ ) {
229
+ return (
230
+ <Button
231
+ {...omit(props, ['content'])}
232
+ icon={props.icon ? <Icon icon={props.icon} /> : null}
233
+ onClick={() => {
234
+ events.click?.({ data, field });
235
+ if (props.htmlType === 'reset' && defaultHandler?.reset) {
236
+ defaultHandler.reset({ data, field });
237
+ }
238
+ }}
239
+ >
240
+ {props.content}
241
+ </Button>
242
+ );
243
+ },
244
+ renderDefault(
245
+ { props = {}, events = {} }: RenderOptions,
246
+ { row, field }: RenderTableParams,
247
+ defaultHandler: {
248
+ [key: string]: (...args: any[]) => any;
249
+ },
250
+ ) {
251
+ return (
252
+ <Button
253
+ {...omit(props, ['content'])}
254
+ icon={props.icon ? <Icon icon={props.icon} /> : null}
255
+ onClick={() => {
256
+ events.click?.({ row, field });
257
+ if (props.htmlType === 'reset' && defaultHandler?.reset) {
258
+ defaultHandler.reset({ row, field });
259
+ }
260
+ if (props.htmlType === 'pick' && defaultHandler?.pick) {
261
+ defaultHandler.pick({ row, field });
262
+ }
263
+ }}
264
+ >
265
+ {props.content}
266
+ </Button>
267
+ );
268
+ },
269
+ },
270
+ // 简单按钮组
271
+ $buttons: {
272
+ renderItemContent(
273
+ { props = {}, children = [] }: RenderOptions,
274
+ { data, field }: RenderFormParams,
275
+ defaultHandler: {
276
+ [key: string]: (...args: any[]) => any;
277
+ },
278
+ ) {
279
+ return (
280
+ <span class="align-gap-box w-fit">
281
+ {children.map((m) => (
282
+ <Button
283
+ {...omit(Object.assign(props, m.props), ['content'])}
284
+ icon={m.props.icon ? <Icon icon={m.props.icon} /> : null}
285
+ onClick={() => {
286
+ m.events?.click?.({ data, field });
287
+ if (m.props.htmlType === 'reset' && defaultHandler?.reset) {
288
+ defaultHandler.reset({ data, field });
289
+ }
290
+ }}
291
+ >
292
+ {m.props.content}
293
+ </Button>
294
+ ))}
295
+ </span>
296
+ );
297
+ },
298
+ renderDefault(
299
+ { props = {}, children = [] }: RenderOptions,
300
+ { data, row, field }: RenderTableParams,
301
+ ) {
302
+ return (
303
+ <span class="align-gap-box w-fit">
304
+ {children.map((m) => (
305
+ <Button
306
+ {...omit(Object.assign(props, m.props), ['content'])}
307
+ icon={m.props.icon ? <Icon icon={m.props.icon} /> : null}
308
+ onClick={() => {
309
+ m.events?.click?.({ data, row, field });
310
+ }}
311
+ >
312
+ {m.props.content}
313
+ </Button>
314
+ ))}
315
+ </span>
316
+ );
317
+ },
318
+ },
319
+ ButtonTree: {
320
+ renderDefault({ children = [], props = {} as Recordable }, params: RenderTableParams) {
321
+ return (
322
+ <span class={props.noGap ? 'align-no-gap-box' : 'align-gap-box'}>
323
+ {(children as BtnOptions[]).map((item) => renderBtn(item, params)) ?? []}
324
+ </span>
325
+ );
326
+ },
327
+ },
328
+ $radio: {
329
+ renderItemContent({ props = {}, options }: RenderOptions, { data, field }: RenderFormParams) {
330
+ return valued(field) ? (
331
+ <RadioGroup
332
+ v-model:value={data[field!]}
333
+ {...props}
334
+ options={props.options ?? options ?? []}
335
+ />
336
+ ) : null;
337
+ },
338
+ renderDefault({ props = {}, options }: RenderOptions, { row, field }: RenderTableParams) {
339
+ return valued(field) ? (
340
+ <RadioGroup
341
+ v-model:value={row[field!]}
342
+ {...props}
343
+ options={props.options ?? options ?? []}
344
+ />
345
+ ) : null;
346
+ },
347
+ },
348
+ $switch: {
349
+ renderItemContent(
350
+ { props = {}, events = {} }: RenderOptions,
351
+ { data, field }: RenderFormParams,
352
+ ) {
353
+ return valued(field) ? (
354
+ <Switch
355
+ v-model:checked={data[field!]}
356
+ {...props}
357
+ onChange={(...arg) => {
358
+ events.change?.({ data, field }, ...arg);
359
+ }}
360
+ />
361
+ ) : null;
362
+ },
363
+ },
364
+ $checkbox: {
365
+ renderItemContent(
366
+ { props = {}, options, events = {} }: RenderOptions,
367
+ { data, field }: RenderFormParams,
368
+ ) {
369
+ return valued(field) ? (
370
+ <CheckboxGroup
371
+ v-model:value={data[field!]}
372
+ {...props}
373
+ options={props.options ?? options ?? []}
374
+ onChange={(...arg) => {
375
+ events.change?.({ data, field }, ...arg);
376
+ }}
377
+ />
378
+ ) : null;
379
+ },
380
+ renderDefault({ props = {}, options }: RenderOptions, { row, field }: RenderTableParams) {
381
+ return valued(field) ? (
382
+ <CheckboxGroup
383
+ v-model:value={row[field!]}
384
+ {...props}
385
+ options={props.options ?? options ?? []}
386
+ />
387
+ ) : null;
388
+ },
389
+ },
390
+ $paragraph: {
391
+ renderDefault({ props = {} }: RenderOptions, { row, field }: RenderTableParams) {
392
+ const defaultProps = {
393
+ ellipsis: {
394
+ expandable: true,
395
+ rows: 3,
396
+ },
397
+ };
398
+ const content = props.getContent?.({ row, field }) ?? (valued(field) ? row[field!] : '');
399
+ return valued(field) ? (
400
+ <TypographyParagraph
401
+ {...merge({}, defaultProps, omit(props, ['content', 'getContent']))}
402
+ content={content}
403
+ />
404
+ ) : null;
405
+ },
406
+ },
407
+ $tableInput: {
408
+ renderItemContent(
409
+ { props = {}, handleTrigger }: RenderOptions,
410
+ { data, field }: RenderFormParams,
411
+ ) {
412
+ return valued(field) ? (
413
+ <TableInput
414
+ v-model={data[field!]}
415
+ onTrigger={() => {
416
+ if (handleTrigger && isFunction(handleTrigger)) {
417
+ handleTrigger(props.cusFields ?? field);
418
+ }
419
+ }}
420
+ editColumns={props.editColumns ?? []}
421
+ tableConfig={props.tableConfig ?? {}}
422
+ />
423
+ ) : null;
424
+ },
425
+ },
426
+ PercentInput: {
427
+ renderItemContent(
428
+ { props = {}, attrs = {} }: RenderOptions,
429
+ { data, field }: RenderFormParams,
430
+ ) {
431
+ const rate = props.parse ? 100 : 1;
432
+ if (valued(field)) {
433
+ const percentage = computed({
434
+ get: () => (data[field!] ?? 0) * rate,
435
+ set: (val) => {
436
+ data[field!] = (val ?? 0) / rate;
437
+ },
438
+ });
439
+ return (
440
+ <div class="flex items-center">
441
+ {props.info ? <span class="pr-4">{props.info}</span> : null}
442
+ <a-input-number
443
+ class="w-60px!"
444
+ {...attrs}
445
+ v-model:value={percentage.value}
446
+ {...merge({}, defaultProps.PercentInput, omit(props, ['info']))}
447
+ />
448
+ </div>
449
+ );
450
+ } else {
451
+ return null;
452
+ }
453
+ },
454
+ renderDefault({ props = {}, attrs = {} }: RenderOptions, { row, field }: RenderTableParams) {
455
+ const rate = props.parse ? 100 : 1;
456
+ if (valued(field)) {
457
+ const percentage = computed({
458
+ get: () => (row[field!] ?? 0) * rate,
459
+ set: (val) => {
460
+ set(row, field!, (val ?? 0) / rate);
461
+ },
462
+ });
463
+ return [
464
+ props.info ? <span class="pr-4">{props.info}</span> : null,
465
+ <a-input-number
466
+ class="w-60px!"
467
+ {...attrs}
468
+ v-model:value={percentage.value}
469
+ {...merge({}, defaultProps.PercentInput, omit(props, ['info']))}
470
+ />,
471
+ ];
472
+ } else {
473
+ return null;
474
+ }
475
+ },
476
+ },
477
+ TreeSelect: {
478
+ renderItemContent({ props = {} }: RenderOptions, { data, field }: RenderFormParams) {
479
+ return valued(field) ? <TreeSelect v-model:value={data[field!]} {...props} /> : null;
480
+ },
481
+ renderDefault({ props = {} }: RenderOptions, { row, field }: RenderTableParams) {
482
+ return valued(field) ? <TreeSelect v-model:value={row[field!]} {...props} /> : null;
483
+ },
484
+ },
485
+ };
486
+ export const addRender = (
487
+ name: string,
488
+ {
489
+ renderItemContent,
490
+ renderDefault,
491
+ }: {
492
+ renderItemContent?: (
493
+ options: RenderOptions,
494
+ params: RenderFormParams,
495
+ defaultHandler: Recordable,
496
+ ) => any;
497
+ renderDefault?: (
498
+ options: RenderOptions,
499
+ params: RenderTableParams,
500
+ defaultHandler: Recordable,
501
+ ) => any;
502
+ },
503
+ ) => {
504
+ if (renders.hasOwnProperty(name)) {
505
+ console.warn(`render ${name} already exists`);
506
+ }
507
+ renders[name] = {
508
+ renderItemContent,
509
+ renderDefault,
510
+ };
511
+ };
512
+ export default {
513
+ renders,
514
+ addRender,
515
+ };