@nocobase/plugin-ui-templates 2.0.2 → 2.0.5
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/LICENSE +201 -0
- package/README.md +99 -0
- package/dist/externalVersion.js +7 -7
- package/package.json +3 -3
- package/LICENSE.txt +0 -172
- package/src/client/__tests__/openViewActionExtensions.test.ts +0 -1208
- package/src/client/collections/flowModelTemplates.ts +0 -131
- package/src/client/components/FlowModelTemplatesPage.tsx +0 -78
- package/src/client/components/TemplateSelectOption.tsx +0 -106
- package/src/client/constants.ts +0 -10
- package/src/client/hooks/useFlowModelTemplateActions.tsx +0 -137
- package/src/client/index.ts +0 -52
- package/src/client/locale.ts +0 -40
- package/src/client/menuExtensions.tsx +0 -1091
- package/src/client/models/ReferenceBlockModel.tsx +0 -841
- package/src/client/models/ReferenceFormGridModel.tsx +0 -448
- package/src/client/models/SubModelTemplateImporterModel.tsx +0 -725
- package/src/client/models/__tests__/ReferenceBlockModel.test.tsx +0 -547
- package/src/client/models/__tests__/ReferenceFormGridModel.test.tsx +0 -965
- package/src/client/models/__tests__/SubModelTemplateImporterModel.test.ts +0 -529
- package/src/client/models/referenceShared.tsx +0 -107
- package/src/client/openViewActionExtensions.tsx +0 -986
- package/src/client/schemas/flowModelTemplates.ts +0 -264
- package/src/client/utils/__tests__/templateCopy.test.ts +0 -67
- package/src/client/utils/infiniteSelect.ts +0 -150
- package/src/client/utils/templateCompatibility.ts +0 -374
- package/src/client/utils/templateCopy.ts +0 -59
- package/src/client.ts +0 -10
- package/src/index.ts +0 -11
- package/src/locale/de-DE.json +0 -14
- package/src/locale/en-US.json +0 -72
- package/src/locale/es-ES.json +0 -14
- package/src/locale/fr-FR.json +0 -14
- package/src/locale/hu-HU.json +0 -14
- package/src/locale/id-ID.json +0 -14
- package/src/locale/it-IT.json +0 -14
- package/src/locale/ja-JP.json +0 -14
- package/src/locale/ko-KR.json +0 -14
- package/src/locale/nl-NL.json +0 -14
- package/src/locale/pt-BR.json +0 -14
- package/src/locale/ru-RU.json +0 -14
- package/src/locale/tr-TR.json +0 -14
- package/src/locale/uk-UA.json +0 -14
- package/src/locale/vi-VN.json +0 -14
- package/src/locale/zh-CN.json +0 -71
- package/src/locale/zh-TW.json +0 -14
- package/src/server/__tests__/template-usage.test.ts +0 -351
- package/src/server/collections/flowModelTemplateUsages.ts +0 -51
- package/src/server/collections/flowModelTemplates.ts +0 -76
- package/src/server/index.ts +0 -10
- package/src/server/plugin.ts +0 -236
- package/src/server/resources/flowModelTemplateUsages.ts +0 -61
- package/src/server/resources/flowModelTemplates.ts +0 -251
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file is part of the NocoBase (R) project.
|
|
3
|
-
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
-
* Authors: NocoBase Team.
|
|
5
|
-
*
|
|
6
|
-
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
-
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { ISchema } from '@nocobase/client';
|
|
11
|
-
import { uid } from '@nocobase/utils/client';
|
|
12
|
-
import { flowModelTemplatesCollection } from '../collections/flowModelTemplates';
|
|
13
|
-
import { tStr } from '../locale';
|
|
14
|
-
|
|
15
|
-
export const flowModelTemplateEditActionSchema: ISchema = {
|
|
16
|
-
type: 'void',
|
|
17
|
-
title: tStr('Edit'),
|
|
18
|
-
'x-component': 'Action.Link',
|
|
19
|
-
'x-component-props': {
|
|
20
|
-
openMode: 'drawer',
|
|
21
|
-
},
|
|
22
|
-
properties: {
|
|
23
|
-
drawer: {
|
|
24
|
-
type: 'void',
|
|
25
|
-
title: tStr('Edit template'),
|
|
26
|
-
'x-component': 'Action.Drawer',
|
|
27
|
-
'x-decorator': 'FormV2',
|
|
28
|
-
'x-use-decorator-props': 'useFlowModelTemplateEditFormProps',
|
|
29
|
-
properties: {
|
|
30
|
-
name: {
|
|
31
|
-
type: 'string',
|
|
32
|
-
title: tStr('Template name'),
|
|
33
|
-
'x-decorator': 'FormItem',
|
|
34
|
-
'x-component': 'Input',
|
|
35
|
-
required: true,
|
|
36
|
-
},
|
|
37
|
-
description: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
title: tStr('Template description'),
|
|
40
|
-
'x-decorator': 'FormItem',
|
|
41
|
-
'x-component': 'Input.TextArea',
|
|
42
|
-
'x-component-props': {
|
|
43
|
-
rows: 4,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
footer: {
|
|
47
|
-
type: 'void',
|
|
48
|
-
'x-component': 'Action.Drawer.Footer',
|
|
49
|
-
properties: {
|
|
50
|
-
cancel: {
|
|
51
|
-
title: '{{t("Cancel")}}',
|
|
52
|
-
'x-component': 'Action',
|
|
53
|
-
'x-component-props': {
|
|
54
|
-
useAction: '{{ cm.useCancelAction }}',
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
submit: {
|
|
58
|
-
title: '{{t("Submit")}}',
|
|
59
|
-
'x-component': 'Action',
|
|
60
|
-
'x-use-component-props': 'useFlowModelTemplateEditActionProps',
|
|
61
|
-
'x-component-props': {
|
|
62
|
-
type: 'primary',
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const createFlowModelTemplatesSchema = (filter?: Record<string, any>): ISchema => ({
|
|
73
|
-
type: 'void',
|
|
74
|
-
name: uid(),
|
|
75
|
-
'x-component': 'CardItem',
|
|
76
|
-
'x-decorator': 'TableBlockProvider',
|
|
77
|
-
'x-decorator-props': {
|
|
78
|
-
collection: flowModelTemplatesCollection.name,
|
|
79
|
-
action: 'list',
|
|
80
|
-
params: {
|
|
81
|
-
sort: '-createdAt',
|
|
82
|
-
pageSize: 50,
|
|
83
|
-
...(filter ? { filter } : {}),
|
|
84
|
-
},
|
|
85
|
-
showIndex: true,
|
|
86
|
-
rowKey: flowModelTemplatesCollection.filterTargetKey,
|
|
87
|
-
},
|
|
88
|
-
properties: {
|
|
89
|
-
actions: {
|
|
90
|
-
type: 'void',
|
|
91
|
-
'x-component': 'ActionBar',
|
|
92
|
-
'x-component-props': {
|
|
93
|
-
style: {
|
|
94
|
-
marginBottom: 16,
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
properties: {
|
|
98
|
-
filter: {
|
|
99
|
-
type: 'void',
|
|
100
|
-
title: '{{ t("Filter") }}',
|
|
101
|
-
default: {
|
|
102
|
-
$and: [{ name: { $includes: '' } }],
|
|
103
|
-
},
|
|
104
|
-
'x-action': 'filter',
|
|
105
|
-
'x-component': 'Filter.Action',
|
|
106
|
-
'x-use-component-props': 'useFilterActionProps',
|
|
107
|
-
'x-component-props': {
|
|
108
|
-
icon: 'FilterOutlined',
|
|
109
|
-
},
|
|
110
|
-
'x-align': 'left',
|
|
111
|
-
},
|
|
112
|
-
search: {
|
|
113
|
-
type: 'void',
|
|
114
|
-
'x-component': 'Input.Search',
|
|
115
|
-
'x-component-props': {
|
|
116
|
-
allowClear: true,
|
|
117
|
-
},
|
|
118
|
-
'x-use-component-props': 'useFlowModelTemplateSearchProps',
|
|
119
|
-
'x-align': 'left',
|
|
120
|
-
},
|
|
121
|
-
refresh: {
|
|
122
|
-
type: 'void',
|
|
123
|
-
title: '{{ t("Refresh") }}',
|
|
124
|
-
'x-component': 'Action',
|
|
125
|
-
'x-use-component-props': 'useRefreshActionProps',
|
|
126
|
-
'x-component-props': {
|
|
127
|
-
icon: 'ReloadOutlined',
|
|
128
|
-
},
|
|
129
|
-
'x-align': 'right',
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
table: {
|
|
134
|
-
type: 'array',
|
|
135
|
-
'x-component': 'TableV2',
|
|
136
|
-
'x-use-component-props': 'useTableBlockProps',
|
|
137
|
-
'x-component-props': {
|
|
138
|
-
rowKey: flowModelTemplatesCollection.filterTargetKey,
|
|
139
|
-
pagination: {
|
|
140
|
-
pageSize: 50,
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
properties: {
|
|
144
|
-
name: {
|
|
145
|
-
type: 'void',
|
|
146
|
-
title: tStr('Template name'),
|
|
147
|
-
'x-component': 'TableV2.Column',
|
|
148
|
-
'x-component-props': {
|
|
149
|
-
width: 200,
|
|
150
|
-
},
|
|
151
|
-
properties: {
|
|
152
|
-
name: {
|
|
153
|
-
type: 'string',
|
|
154
|
-
'x-component': 'CollectionField',
|
|
155
|
-
'x-pattern': 'readPretty',
|
|
156
|
-
'x-component-props': {
|
|
157
|
-
ellipsis: true,
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
description: {
|
|
163
|
-
type: 'void',
|
|
164
|
-
title: tStr('Template description'),
|
|
165
|
-
'x-component': 'TableV2.Column',
|
|
166
|
-
'x-component-props': {
|
|
167
|
-
width: 240,
|
|
168
|
-
},
|
|
169
|
-
properties: {
|
|
170
|
-
description: {
|
|
171
|
-
type: 'string',
|
|
172
|
-
'x-component': 'CollectionField',
|
|
173
|
-
'x-pattern': 'readPretty',
|
|
174
|
-
'x-component-props': {
|
|
175
|
-
ellipsis: true,
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
dataSourceKey: {
|
|
181
|
-
type: 'void',
|
|
182
|
-
title: 'Data source',
|
|
183
|
-
'x-component': 'TableV2.Column',
|
|
184
|
-
'x-component-props': {
|
|
185
|
-
width: 140,
|
|
186
|
-
},
|
|
187
|
-
properties: {
|
|
188
|
-
dataSourceKey: {
|
|
189
|
-
type: 'string',
|
|
190
|
-
'x-component': 'CollectionField',
|
|
191
|
-
'x-pattern': 'readPretty',
|
|
192
|
-
'x-component-props': {
|
|
193
|
-
ellipsis: true,
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
collectionName: {
|
|
199
|
-
type: 'void',
|
|
200
|
-
title: 'Collection',
|
|
201
|
-
'x-component': 'TableV2.Column',
|
|
202
|
-
'x-component-props': {
|
|
203
|
-
width: 160,
|
|
204
|
-
},
|
|
205
|
-
properties: {
|
|
206
|
-
collectionName: {
|
|
207
|
-
type: 'string',
|
|
208
|
-
'x-component': 'CollectionField',
|
|
209
|
-
'x-pattern': 'readPretty',
|
|
210
|
-
'x-component-props': {
|
|
211
|
-
ellipsis: true,
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
usageCount: {
|
|
217
|
-
type: 'void',
|
|
218
|
-
title: tStr('Usage count'),
|
|
219
|
-
'x-component': 'TableV2.Column',
|
|
220
|
-
'x-component-props': {
|
|
221
|
-
width: 120,
|
|
222
|
-
},
|
|
223
|
-
properties: {
|
|
224
|
-
usageCount: {
|
|
225
|
-
type: 'number',
|
|
226
|
-
'x-component': 'CollectionField',
|
|
227
|
-
'x-pattern': 'readPretty',
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
|
-
actions: {
|
|
232
|
-
type: 'void',
|
|
233
|
-
title: tStr('Actions'),
|
|
234
|
-
'x-component': 'TableV2.Column',
|
|
235
|
-
'x-component-props': {
|
|
236
|
-
width: 160,
|
|
237
|
-
align: 'left',
|
|
238
|
-
},
|
|
239
|
-
properties: {
|
|
240
|
-
actions: {
|
|
241
|
-
type: 'void',
|
|
242
|
-
'x-component': 'Space',
|
|
243
|
-
'x-component-props': {
|
|
244
|
-
split: '|',
|
|
245
|
-
},
|
|
246
|
-
properties: {
|
|
247
|
-
edit: flowModelTemplateEditActionSchema,
|
|
248
|
-
delete: {
|
|
249
|
-
type: 'void',
|
|
250
|
-
title: tStr('Delete'),
|
|
251
|
-
'x-component': 'Action.Link',
|
|
252
|
-
'x-use-component-props': 'useFlowModelTemplateDeleteActionProps',
|
|
253
|
-
'x-component-props': {
|
|
254
|
-
danger: true,
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
|
-
},
|
|
259
|
-
},
|
|
260
|
-
},
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file is part of the NocoBase (R) project.
|
|
3
|
-
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
-
* Authors: NocoBase Team.
|
|
5
|
-
*
|
|
6
|
-
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
-
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { describe, expect, it } from 'vitest';
|
|
11
|
-
import { FlowEngine, FlowModel } from '@nocobase/flow-engine';
|
|
12
|
-
import { patchGridOptionsFromTemplateRoot } from '../templateCopy';
|
|
13
|
-
|
|
14
|
-
describe('patchGridOptionsFromTemplateRoot', () => {
|
|
15
|
-
it('fills missing layout/linkageRules from template root', () => {
|
|
16
|
-
const engine = new FlowEngine();
|
|
17
|
-
class RootModel extends FlowModel {}
|
|
18
|
-
engine.registerModels({ RootModel });
|
|
19
|
-
|
|
20
|
-
const root = engine.createModel<RootModel>({
|
|
21
|
-
uid: 'tpl-root',
|
|
22
|
-
use: 'RootModel',
|
|
23
|
-
stepParams: {
|
|
24
|
-
formModelSettings: { layout: { layout: 'horizontal', labelWidth: 160 } },
|
|
25
|
-
eventSettings: { linkageRules: { value: [{ key: 'r1' }] } },
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const gridOptions: any = { uid: 'dup-grid', use: 'GridModel', stepParams: {} };
|
|
30
|
-
const merged = patchGridOptionsFromTemplateRoot(root, gridOptions);
|
|
31
|
-
expect(merged.patched).toBe(true);
|
|
32
|
-
expect(merged.options.stepParams.formModelSettings.layout).toEqual({ layout: 'horizontal', labelWidth: 160 });
|
|
33
|
-
expect(merged.options.stepParams.eventSettings.linkageRules).toEqual({ value: [{ key: 'r1' }] });
|
|
34
|
-
|
|
35
|
-
// should be deep-cloned (mutating merged options must not affect template root)
|
|
36
|
-
merged.options.stepParams.formModelSettings.layout.layout = 'vertical';
|
|
37
|
-
expect(root.getStepParams('formModelSettings', 'layout')).toEqual({ layout: 'horizontal', labelWidth: 160 });
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('does not override existing grid values', () => {
|
|
41
|
-
const engine = new FlowEngine();
|
|
42
|
-
class RootModel extends FlowModel {}
|
|
43
|
-
engine.registerModels({ RootModel });
|
|
44
|
-
|
|
45
|
-
const root = engine.createModel<RootModel>({
|
|
46
|
-
uid: 'tpl-root',
|
|
47
|
-
use: 'RootModel',
|
|
48
|
-
stepParams: {
|
|
49
|
-
formModelSettings: { layout: { layout: 'horizontal', labelWidth: 160 } },
|
|
50
|
-
eventSettings: { linkageRules: { value: [{ key: 'r1' }] } },
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const gridOptions: any = {
|
|
55
|
-
uid: 'dup-grid',
|
|
56
|
-
use: 'GridModel',
|
|
57
|
-
stepParams: {
|
|
58
|
-
formModelSettings: { layout: { layout: 'vertical', labelWidth: 120 } },
|
|
59
|
-
eventSettings: { linkageRules: { value: [] } },
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
const merged = patchGridOptionsFromTemplateRoot(root, gridOptions);
|
|
63
|
-
expect(merged.patched).toBe(false);
|
|
64
|
-
expect(merged.options.stepParams.formModelSettings.layout).toEqual({ layout: 'vertical', labelWidth: 120 });
|
|
65
|
-
expect(merged.options.stepParams.eventSettings.linkageRules).toEqual({ value: [] });
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file is part of the NocoBase (R) project.
|
|
3
|
-
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
-
* Authors: NocoBase Team.
|
|
5
|
-
*
|
|
6
|
-
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
-
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import debounce from 'lodash/debounce';
|
|
11
|
-
import { TEMPLATE_LIST_PAGE_SIZE } from './templateCompatibility';
|
|
12
|
-
|
|
13
|
-
export type PaginatedOptionsResult<T = any> = { options: T[]; hasMore: boolean };
|
|
14
|
-
|
|
15
|
-
export const defaultSelectOptionComparator = (a: any, b: any) => {
|
|
16
|
-
const da = a?.disabled ? 1 : 0;
|
|
17
|
-
const db = b?.disabled ? 1 : 0;
|
|
18
|
-
if (da !== db) return da - db;
|
|
19
|
-
return (a?.__idx ?? 0) - (b?.__idx ?? 0);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export function mergeSelectOptions(
|
|
23
|
-
prev: any[],
|
|
24
|
-
next: any[],
|
|
25
|
-
options?: { getKey?: (item: any) => string; comparator?: (a: any, b: any) => number },
|
|
26
|
-
) {
|
|
27
|
-
const getKey = options?.getKey || ((item: any) => String(item?.value || ''));
|
|
28
|
-
const comparator = options?.comparator || defaultSelectOptionComparator;
|
|
29
|
-
|
|
30
|
-
const map = new Map<string, any>();
|
|
31
|
-
for (const item of Array.isArray(prev) ? prev : []) {
|
|
32
|
-
const key = getKey(item);
|
|
33
|
-
if (!key) continue;
|
|
34
|
-
map.set(key, item);
|
|
35
|
-
}
|
|
36
|
-
for (const item of Array.isArray(next) ? next : []) {
|
|
37
|
-
const key = getKey(item);
|
|
38
|
-
if (!key) continue;
|
|
39
|
-
const existing = map.get(key);
|
|
40
|
-
map.set(key, existing ? { ...existing, ...item } : item);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const merged = Array.from(map.values());
|
|
44
|
-
merged.sort(comparator);
|
|
45
|
-
return merged;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function bindInfiniteScrollToFormilySelect(
|
|
49
|
-
field: any,
|
|
50
|
-
fetchPage: (keyword: string, page: number, pageSize: number) => Promise<PaginatedOptionsResult<any>>,
|
|
51
|
-
options?: {
|
|
52
|
-
pageSize?: number;
|
|
53
|
-
debounceMs?: number;
|
|
54
|
-
scrollThreshold?: number;
|
|
55
|
-
composingKey?: string;
|
|
56
|
-
comparator?: (a: any, b: any) => number;
|
|
57
|
-
},
|
|
58
|
-
) {
|
|
59
|
-
const pageSize = Math.max(1, Number(options?.pageSize || TEMPLATE_LIST_PAGE_SIZE));
|
|
60
|
-
const debounceMs = Math.max(0, Number(options?.debounceMs ?? 300));
|
|
61
|
-
const scrollThreshold = Math.max(0, Number(options?.scrollThreshold ?? 24));
|
|
62
|
-
const composingKey = String(options?.composingKey || '__templateComposing');
|
|
63
|
-
const comparator = options?.comparator || defaultSelectOptionComparator;
|
|
64
|
-
|
|
65
|
-
let requestVersion = 0;
|
|
66
|
-
let currentKeyword = '';
|
|
67
|
-
let currentPage = 0;
|
|
68
|
-
let currentHasMore = true;
|
|
69
|
-
let loadingMore = false;
|
|
70
|
-
|
|
71
|
-
const setComposing = (v: boolean) => {
|
|
72
|
-
try {
|
|
73
|
-
field.data = { ...(field.data || {}), [composingKey]: v };
|
|
74
|
-
} catch {
|
|
75
|
-
// ignore
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const isComposing = () => !!field.data?.[composingKey];
|
|
80
|
-
|
|
81
|
-
const resetAndLoad = async (keyword: string) => {
|
|
82
|
-
const nextVersion = (requestVersion || 0) + 1;
|
|
83
|
-
requestVersion = nextVersion;
|
|
84
|
-
currentKeyword = keyword;
|
|
85
|
-
currentPage = 0;
|
|
86
|
-
currentHasMore = true;
|
|
87
|
-
loadingMore = false;
|
|
88
|
-
field.loading = true;
|
|
89
|
-
try {
|
|
90
|
-
const { options: optionList, hasMore } = await fetchPage(keyword, 1, pageSize);
|
|
91
|
-
if (requestVersion !== nextVersion) return;
|
|
92
|
-
field.dataSource = mergeSelectOptions([], optionList, { comparator });
|
|
93
|
-
currentPage = 1;
|
|
94
|
-
currentHasMore = !!hasMore;
|
|
95
|
-
} finally {
|
|
96
|
-
if (requestVersion === nextVersion) {
|
|
97
|
-
field.loading = false;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const loadMore = async () => {
|
|
103
|
-
if (!currentHasMore || loadingMore) return;
|
|
104
|
-
const version = requestVersion;
|
|
105
|
-
const nextPage = Math.max(1, currentPage || 1) + 1;
|
|
106
|
-
loadingMore = true;
|
|
107
|
-
field.loading = true;
|
|
108
|
-
try {
|
|
109
|
-
const { options: optionList, hasMore } = await fetchPage(currentKeyword, nextPage, pageSize);
|
|
110
|
-
if (requestVersion !== version) return;
|
|
111
|
-
field.dataSource = mergeSelectOptions(field.dataSource || [], optionList, { comparator });
|
|
112
|
-
currentPage = nextPage;
|
|
113
|
-
currentHasMore = !!hasMore;
|
|
114
|
-
} finally {
|
|
115
|
-
loadingMore = false;
|
|
116
|
-
if (requestVersion === version) {
|
|
117
|
-
field.loading = false;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
field.componentProps.onDropdownVisibleChange = async (open: boolean) => {
|
|
123
|
-
if (!open) return;
|
|
124
|
-
await resetAndLoad('');
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const debouncedSearch = debounce(async (kw: string) => resetAndLoad(kw), debounceMs);
|
|
128
|
-
|
|
129
|
-
field.componentProps.onSearch = (value: string) => {
|
|
130
|
-
if (isComposing()) return;
|
|
131
|
-
const keyword = typeof value === 'string' ? value.trim() : '';
|
|
132
|
-
debouncedSearch(keyword);
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
field.componentProps.onCompositionStart = () => setComposing(true);
|
|
136
|
-
field.componentProps.onCompositionEnd = (e: any) => {
|
|
137
|
-
setComposing(false);
|
|
138
|
-
const keyword = typeof e?.target?.value === 'string' ? e.target.value.trim() : '';
|
|
139
|
-
debouncedSearch(keyword);
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
field.componentProps.onPopupScroll = (e: any) => {
|
|
143
|
-
const target = e?.target as HTMLElement | undefined;
|
|
144
|
-
if (!target) return;
|
|
145
|
-
if (target.scrollTop + target.clientHeight < target.scrollHeight - scrollThreshold) return;
|
|
146
|
-
loadMore();
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
return { resetAndLoad, loadMore, cancelSearch: () => debouncedSearch.cancel() };
|
|
150
|
-
}
|