@skyfox2000/webui 1.0.14 → 1.2.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 (162) hide show
  1. package/lib/assets/modules/file-upload-CBUcsUnR.js +170 -0
  2. package/lib/assets/modules/form-validate-CgX7aR7T.js +297 -0
  3. package/lib/assets/modules/index-Civhd8xG.js +112 -0
  4. package/lib/assets/modules/index-DQMdt51R.js +726 -0
  5. package/lib/assets/modules/{index-BEWJ_qAH.js → index-DmWrkTXX.js} +1 -1
  6. package/lib/assets/modules/{menuTabs-BXdbFZor.js → menuTabs-BRYvFWA-.js} +131 -121
  7. package/lib/assets/modules/settingInfo-BZakNKIN.js +999 -0
  8. package/lib/assets/modules/uploadList-B7XoxGOh.js +278 -0
  9. package/lib/components/common/icon/index.vue.d.ts +1 -1
  10. package/lib/components/content/dialog/index.vue.d.ts +1 -1
  11. package/lib/components/content/drawer/index.vue.d.ts +1 -1
  12. package/lib/components/content/form/index.vue.d.ts +1 -1
  13. package/lib/components/content/search/index.vue.d.ts +1 -1
  14. package/lib/components/content/table/index.vue.d.ts +1 -1
  15. package/lib/components/content/table/tableOperate.vue.d.ts +1 -1
  16. package/lib/components/content/toolbar/icontool.vue.d.ts +1 -1
  17. package/lib/components/content/toolbar/index.vue.d.ts +1 -1
  18. package/lib/components/content/tree/index.vue.d.ts +1 -1
  19. package/lib/components/form/transfer/transferTable.vue.d.ts +1 -1
  20. package/lib/components/form/treeSelect/index.vue.d.ts +1 -1
  21. package/lib/components/form/upload/uploadList.vue.d.ts +1 -1
  22. package/lib/const/options.d.ts +32 -0
  23. package/lib/directives/enter-submit.d.ts +4 -0
  24. package/lib/directives/index.d.ts +2 -0
  25. package/lib/directives/permission.d.ts +5 -0
  26. package/lib/es/AceEditor/index.js +9 -8
  27. package/lib/es/BasicLayout/index.js +28 -24
  28. package/lib/es/Error403/index.js +15 -10
  29. package/lib/es/Error404/index.js +15 -10
  30. package/lib/es/ExcelForm/index.js +380 -175
  31. package/lib/es/UploadForm/index.js +23 -20
  32. package/lib/index.d.ts +42 -2
  33. package/lib/router/index.d.ts +16 -0
  34. package/lib/stores/appInfo.d.ts +34 -0
  35. package/lib/stores/hostInfo.d.ts +9 -0
  36. package/lib/stores/pageInfo.d.ts +18 -0
  37. package/lib/stores/pinia.d.ts +3 -0
  38. package/lib/stores/settingInfo.d.ts +8 -0
  39. package/lib/stores/userInfo.d.ts +21 -0
  40. package/lib/typings/data.d.ts +80 -0
  41. package/lib/typings/form.d.ts +171 -0
  42. package/lib/typings/menu.d.ts +7 -0
  43. package/lib/typings/option.d.ts +175 -0
  44. package/lib/typings/page.d.ts +69 -0
  45. package/lib/typings/table.d.ts +181 -0
  46. package/lib/typings/tools.d.ts +130 -0
  47. package/lib/typings/tree.d.ts +72 -0
  48. package/lib/typings/upload.d.ts +161 -0
  49. package/lib/typings/urls.d.ts +69 -0
  50. package/lib/utils/cache.d.ts +23 -0
  51. package/lib/utils/data.d.ts +6 -0
  52. package/lib/utils/download.d.ts +4 -0
  53. package/lib/utils/eventbus.d.ts +16 -0
  54. package/lib/utils/export-table.d.ts +12 -0
  55. package/lib/utils/file-upload.d.ts +15 -0
  56. package/lib/utils/form-excel.d.ts +30 -0
  57. package/lib/utils/form-validate.d.ts +29 -0
  58. package/lib/utils/form.d.ts +9 -0
  59. package/lib/utils/icon-loader.d.ts +125 -0
  60. package/lib/utils/isEmpty.d.ts +1 -0
  61. package/lib/utils/main-openapis.d.ts +9 -0
  62. package/lib/utils/menu.d.ts +6 -0
  63. package/lib/utils/options.d.ts +10 -0
  64. package/lib/utils/page.d.ts +25 -0
  65. package/lib/utils/table.d.ts +21 -0
  66. package/lib/utils/tools.d.ts +18 -0
  67. package/lib/utils/tree.d.ts +3 -0
  68. package/lib/vite-env.d.ts +8 -0
  69. package/lib/webui.css +1 -1
  70. package/lib/webui.es.js +890 -724
  71. package/package.json +7 -6
  72. package/src/components/common/icon/appicon.vue +1 -1
  73. package/src/components/common/icon/fullscreen.vue +2 -1
  74. package/src/components/common/icon/index.vue +1 -1
  75. package/src/components/common/icon/layoutIcon.vue +1 -1
  76. package/src/components/common/icon/projectIcon.vue +1 -1
  77. package/src/components/common/icon/toolIcon.vue +1 -1
  78. package/src/components/content/dialog/excelForm.vue +2 -2
  79. package/src/components/content/dialog/index.vue +1 -1
  80. package/src/components/content/dialog/uploadForm.vue +7 -6
  81. package/src/components/content/drawer/index.vue +43 -18
  82. package/src/components/content/form/formItem.vue +1 -1
  83. package/src/components/content/form/index.vue +1 -1
  84. package/src/components/content/search/index.vue +1 -1
  85. package/src/components/content/search/searchItem.vue +1 -1
  86. package/src/components/content/table/index.vue +3 -3
  87. package/src/components/content/table/tableOperate.vue +2 -2
  88. package/src/components/content/toolbar/icontool.vue +2 -2
  89. package/src/components/content/toolbar/index.vue +3 -2
  90. package/src/components/content/tree/index.vue +1 -1
  91. package/src/components/error/error403.vue +2 -2
  92. package/src/components/error/error404.vue +2 -2
  93. package/src/components/form/autoComplete/index.vue +1 -1
  94. package/src/components/form/cascader/index.vue +1 -2
  95. package/src/components/form/checkbox/index.vue +11 -5
  96. package/src/components/form/datePicker/index.vue +1 -1
  97. package/src/components/form/input/index.vue +1 -1
  98. package/src/components/form/input/inputNumber.vue +1 -1
  99. package/src/components/form/input/inputPassword.vue +1 -1
  100. package/src/components/form/radio/index.vue +1 -1
  101. package/src/components/form/radio/radioStatus.vue +1 -1
  102. package/src/components/form/rangePicker/index.vue +1 -1
  103. package/src/components/form/select/index.vue +1 -1
  104. package/src/components/form/switch/index.vue +7 -3
  105. package/src/components/form/textarea/index.vue +1 -1
  106. package/src/components/form/transfer/index.vue +1 -1
  107. package/src/components/form/transfer/transferTable.vue +42 -22
  108. package/src/components/form/treeSelect/index.vue +2 -3
  109. package/src/components/form/upload/uploadList.vue +1 -1
  110. package/src/components/layout/breadcrumb/index.vue +1 -1
  111. package/src/components/layout/header/headerExits.vue +1 -1
  112. package/src/components/layout/header/index.vue +1 -1
  113. package/src/components/layout/header/user.vue +2 -1
  114. package/src/components/layout/menu/index.vue +9 -3
  115. package/src/components/layout/menu/menuTabs.vue +10 -12
  116. package/src/components/layout/page/basicLayout.vue +1 -1
  117. package/src/const/options.ts +114 -0
  118. package/src/directives/enter-submit.ts +13 -0
  119. package/src/directives/index.ts +26 -0
  120. package/src/directives/permission.ts +144 -0
  121. package/src/index.ts +201 -0
  122. package/src/router/index.ts +196 -0
  123. package/src/stores/appInfo.ts +471 -0
  124. package/src/stores/hostInfo.ts +117 -0
  125. package/src/stores/pageInfo.ts +131 -0
  126. package/src/stores/pinia.ts +10 -0
  127. package/src/stores/settingInfo.ts +53 -0
  128. package/src/stores/userInfo.ts +392 -0
  129. package/src/typings/data.d.ts +81 -0
  130. package/src/typings/form.d.ts +172 -0
  131. package/src/typings/menu.d.ts +7 -0
  132. package/src/typings/option.d.ts +177 -0
  133. package/src/typings/page.d.ts +70 -0
  134. package/src/typings/table.d.ts +182 -0
  135. package/src/typings/tools.d.ts +131 -0
  136. package/src/typings/tree.d.ts +73 -0
  137. package/src/typings/upload.d.ts +162 -0
  138. package/src/typings/urls.d.ts +70 -0
  139. package/src/utils/cache.ts +175 -0
  140. package/src/utils/data.ts +189 -0
  141. package/src/utils/download.ts +80 -0
  142. package/src/utils/eventbus.ts +78 -0
  143. package/src/utils/export-table.ts +155 -0
  144. package/src/utils/file-upload.ts +304 -0
  145. package/src/utils/form-excel.ts +523 -0
  146. package/src/utils/form-validate.ts +368 -0
  147. package/src/utils/form.ts +188 -0
  148. package/src/utils/icon-loader.ts +412 -0
  149. package/src/utils/isEmpty.ts +18 -0
  150. package/src/utils/main-openapis.ts +72 -0
  151. package/src/utils/menu.ts +89 -0
  152. package/src/utils/options.ts +324 -0
  153. package/src/utils/page.ts +262 -0
  154. package/src/utils/table.ts +274 -0
  155. package/src/utils/tools.ts +362 -0
  156. package/src/utils/tree.ts +28 -0
  157. package/tsconfig.json +1 -8
  158. package/vite.config.ts +7 -4
  159. package/lib/assets/modules/index-BahGnrAq.js +0 -415
  160. package/lib/assets/modules/index-BoKIa2sr.js +0 -109
  161. package/lib/assets/modules/index-D47Ci-T3.js +0 -107
  162. package/lib/assets/modules/uploadList-Dzlg47V0.js +0 -182
@@ -0,0 +1,324 @@
1
+ import {
2
+ AnyData,
3
+ ApiResponse,
4
+ fieldMapping,
5
+ httpPost,
6
+ IUrlInfo,
7
+ parseFieldTemplate,
8
+ ReqParams,
9
+ ResStatus,
10
+ } from '@skyfox2000/fapi';
11
+ import { inject, ref, Ref, watch } from 'vue';
12
+ import { OptionProps, OptionItemProps, SelectValue } from '@/typings/option.d';
13
+ import { InputFactoryItems } from '@/typings/form.d';
14
+ import { ProviderKeys } from '@/typings/page.d';
15
+ import message from 'vue-m-message';
16
+ import eventBus from './eventbus';
17
+ import { formValidate } from './form-validate';
18
+ import { combineParams } from '@skyfox2000/microbase';
19
+
20
+ /**
21
+ * 自动初始化选择项
22
+ * @param autoload 是否自动加载
23
+ * @param props 选项外部属性值
24
+ * @param options 实际选择项
25
+ * @param inputFactory 本地工厂,用于统一处理事件
26
+ * @param url 选项接口
27
+ * @param params 选择参数
28
+ */
29
+ export const loadOption = (
30
+ autoload: boolean,
31
+ props: OptionProps,
32
+ options: Ref<OptionItemProps[]>,
33
+ inputFactory?: InputFactoryItems<any>,
34
+ url?: IUrlInfo,
35
+ // 自定义的额外参数
36
+ params?: ReqParams,
37
+ ) => {
38
+ if (inputFactory && props.reloadEvent) {
39
+ /// 接收事件,联动显示或者重新加载数据
40
+ inputFactory.reloadHandler = (_event: string, data: Record<string, AnyData> | AnyData[]) => {
41
+ optionEventHandler(url!, props, data, options);
42
+ };
43
+ eventBus.on(props.reloadEvent, inputFactory.reloadHandler);
44
+ }
45
+ if (props.data) {
46
+ watch(
47
+ () => props.data,
48
+ () => {
49
+ updateOptions(props, props.data!, options, true);
50
+ },
51
+ { deep: true, immediate: true },
52
+ );
53
+ } else if (url && url.url) {
54
+ if (autoload !== false) doQueryOptions(url, props, params ?? {}, options);
55
+ } else {
56
+ const labelText = ref<string>(inject(ProviderKeys.LabelText, ''));
57
+ message.error('`' + labelText.value + '` 未配置选项数据!', {
58
+ duration: 5000,
59
+ });
60
+ }
61
+ };
62
+
63
+ /**
64
+ * 组件选项数据更新
65
+ * @param props 选项外部属性值
66
+ * @param data 提供的下拉数据
67
+ * @param options 实际选择项
68
+ * @param mapping 是否需要转换字段
69
+ */
70
+ const updateOptions = (
71
+ props: OptionProps,
72
+ data: Record<string, AnyData>[],
73
+ options: Ref<OptionItemProps[]>,
74
+ mapping: boolean,
75
+ ) => {
76
+ if (!data || data.length === 0) {
77
+ options.value = [];
78
+ return;
79
+ }
80
+ if (mapping) {
81
+ // 转换字段
82
+ const fieldMap = {
83
+ ...props.fieldMap,
84
+ };
85
+ data = fieldMapping(fieldMap, data);
86
+ }
87
+
88
+ data = JSON.parse(JSON.stringify(data));
89
+ if (props.all) {
90
+ data.unshift({
91
+ label: '全部',
92
+ value: undefined,
93
+ });
94
+ }
95
+
96
+ options.value = data as OptionItemProps[];
97
+ };
98
+
99
+ /**
100
+ * 选项重载事件处理
101
+ * @param url 选项接口
102
+ * @param props 选项外部属性值
103
+ * @param data 提供的下拉数据
104
+ * @param options 实际选择项
105
+ */
106
+ const optionEventHandler = (
107
+ url: IUrlInfo,
108
+ props: OptionProps,
109
+ data: Record<string, AnyData> | AnyData[],
110
+ options: Ref<OptionItemProps[]>,
111
+ ) => {
112
+ if (Array.isArray(data)) {
113
+ updateOptions(props, data, options, true);
114
+ } else {
115
+ doQueryOptions(url, props, { Query: data }, options);
116
+ }
117
+ };
118
+
119
+ /**
120
+ * 卸载选择项
121
+ * @param props 选项外部属性值
122
+ * @param inputFactory 输入组件工厂
123
+ */
124
+ export const unloadOption = (props: OptionProps, inputFactory?: InputFactoryItems<any>) => {
125
+ if (inputFactory && props.reloadEvent && inputFactory.reloadHandler)
126
+ eventBus.off(props.reloadEvent, inputFactory.reloadHandler);
127
+ };
128
+
129
+ /**
130
+ *
131
+ * @param url 选项接口
132
+ * @param props 选项外部属性值
133
+ * @param params 查询条件
134
+ * @param options 实际选择项
135
+ */
136
+ const doQueryOptions = (url: IUrlInfo, props: OptionProps, params: ReqParams, options: Ref<OptionItemProps[]>) => {
137
+ const newParams: ReqParams = combineParams(url.params, params, props.params);
138
+ queryOptions(url, props.fieldMap, newParams).then((results) => {
139
+ // 使用url,由request负责转换,无需再次map转换
140
+ const data = results as OptionItemProps[];
141
+ updateOptions(props, data, options, false);
142
+ });
143
+ };
144
+
145
+ /**
146
+ * 请求查询选项
147
+ * @param url 选项接口
148
+ * @param fieldMap 选项数据转换
149
+ * @param params 选择参数
150
+ * @returns 选项列表
151
+ * @default 默认设置
152
+ * - cacheTime: 60000
153
+ * - fieldMap:
154
+ ** {
155
+ ** title: "Name",
156
+ ** label: "Name",
157
+ ** value: "Id",
158
+ ** key: "Id"
159
+ ** }
160
+ */
161
+ const queryOptions = <T>(
162
+ url: IUrlInfo,
163
+ fieldMap?: Record<string, string>,
164
+ params?: ReqParams,
165
+ ): Promise<T[] | undefined> => {
166
+ // 排除 fieldMap 属性
167
+ const { fieldMap: _, ...rest } = url;
168
+ const defaultUrl: IUrlInfo = {
169
+ url: '',
170
+ cacheTime: 60000,
171
+ fieldMap: {
172
+ ...fieldMap,
173
+ ...url.fieldMap,
174
+ },
175
+ };
176
+ const optionUrl = {
177
+ ...defaultUrl,
178
+ ...rest,
179
+ };
180
+ optionUrl.loadingText = false;
181
+ if (!params) params = {};
182
+ if (!params.Query) params.Query = {};
183
+ return httpPost<T>(optionUrl, params).then((result: ApiResponse<T> | null) => {
184
+ if (result?.status === ResStatus.SUCCESS) {
185
+ if (result.data) {
186
+ return result.data as T[];
187
+ }
188
+ }
189
+ return [];
190
+ });
191
+ };
192
+
193
+ /**
194
+ * 获取选中的选项对象或对象数组
195
+ * @param values 当前选择的值
196
+ * @param options 所有选项对象数组
197
+ * @returns 选中的选项对象或对象数组
198
+ */
199
+ export const getSelectedValues = (
200
+ values: undefined | string | number | (string | number | undefined)[],
201
+ options: OptionItemProps[],
202
+ ): OptionItemProps | OptionItemProps[] | undefined => {
203
+ // 如果 values 为 undefined,直接返回 undefined
204
+ if (values === undefined) return undefined;
205
+
206
+ // 如果 values 是数组,返回所有匹配的选项对象数组
207
+ if (Array.isArray(values)) {
208
+ return options.filter((option) => values.includes(option.value));
209
+ }
210
+ // 如果 values 是单个值,返回匹配的单个选项对象
211
+ else {
212
+ return options.find((option) => option.value === values);
213
+ }
214
+ };
215
+
216
+ // 辅助函数:根据路径设置值
217
+ const setNestedValue = (obj: Record<string, any>, path: string, value: any) => {
218
+ const parts = path.split('.');
219
+ let current = obj;
220
+ for (let i = 0; i < parts.length - 1; i++) {
221
+ const part = parts[i];
222
+ if (!current[part]) {
223
+ current[part] = {};
224
+ }
225
+ current = current[part];
226
+ }
227
+ current[parts[parts.length - 1]] = value;
228
+ };
229
+
230
+ /**
231
+ * 将选中的值根据 outFields 映射到 formData 上
232
+ * @param formData 需要更新的数据对象
233
+ * @param outFields 输出字段转换映射关系
234
+ * @param selectedValues 选中的选项对象或对象数组
235
+ */
236
+ export const outFormDataFields = (
237
+ formData: Record<string, any>,
238
+ outFields: Record<string, string>,
239
+ selectedValues?: OptionItemProps | OptionItemProps[] | null,
240
+ ) => {
241
+ // 如果 selectedValues 为 undefined,直接返回
242
+ if (selectedValues === undefined || selectedValues === null) {
243
+ Object.entries(outFields).forEach(([targetKey]) => {
244
+ setNestedValue(formData, targetKey, selectedValues);
245
+ });
246
+ return;
247
+ }
248
+
249
+ // 如果 selectedValues 是数组
250
+ if (Array.isArray(selectedValues)) {
251
+ // selectedValues.forEach((selectedValue) => {
252
+ // Object.entries(outFields).forEach(([targetKey, sourceKey]) => {
253
+ // const value = selectedValue[sourceKey];
254
+ // setNestedValue(formData, targetKey, value);
255
+ // });
256
+ // });
257
+ }
258
+ // 如果 selectedValues 是单个对象
259
+ else {
260
+ Object.entries(outFields).forEach(([targetKey, sourceKey]) => {
261
+ if (sourceKey.includes('${')) {
262
+ const value = parseFieldTemplate(sourceKey, selectedValues);
263
+ setNestedValue(formData, targetKey, value);
264
+ } else {
265
+ setNestedValue(formData, targetKey, selectedValues[sourceKey]);
266
+ }
267
+ });
268
+ }
269
+ };
270
+
271
+ /**
272
+ * 选项选中事件处理函数
273
+ * @param props 选项外部属性值
274
+ * @param values 选中的项目,支持单选或多项
275
+ * @param options 实际选择项
276
+ * @param inputFactory 输入组件工厂
277
+ */
278
+ export const onOptionChanged = (
279
+ props: OptionProps,
280
+ values: undefined | SelectValue,
281
+ options: Ref<OptionItemProps[]>,
282
+ inputFactory: InputFactoryItems<any>,
283
+ ): OptionItemProps | OptionItemProps[] | undefined => {
284
+ // 如果存在验证错误,重新检测
285
+ if (inputFactory.editorCtrl && inputFactory.errInfo?.value.errClass) {
286
+ formValidate(inputFactory.editorCtrl);
287
+ }
288
+
289
+ // 获取选中的选项对象或对象数组
290
+ const selectedValues = getSelectedValues(values, options.value);
291
+
292
+ // 如果配置了 formData 和 outFields,将选中的其它属性值映射到 formData 上
293
+ if (props.formData && props.outFields) {
294
+ outFormDataFields(props.formData, props.outFields, selectedValues);
295
+ }
296
+
297
+ if (props.changeEvent) {
298
+ if (Array.isArray(props.changeEvent)) {
299
+ props.changeEvent.every((changeEvent: string) => {
300
+ eventBus.emit(changeEvent, values, selectedValues);
301
+ });
302
+ } else {
303
+ eventBus.emit(props.changeEvent, values, selectedValues);
304
+ }
305
+ }
306
+ // 触发 inputFactory 的 change 事件
307
+ if (inputFactory.inputEmit) {
308
+ inputFactory.inputEmit('change', values, selectedValues);
309
+ }
310
+ return selectedValues;
311
+ };
312
+
313
+ /**
314
+ * 获取选中的选项文字内容
315
+ * @param selectedValues 选中的选项对象或对象数
316
+ * @returns 选中的选项文字内容
317
+ */
318
+ export const getSelectedLabels = (selectedValues: OptionItemProps | OptionItemProps[] | undefined): string[] => {
319
+ if (selectedValues === undefined) return [];
320
+ if (Array.isArray(selectedValues)) {
321
+ return selectedValues.map((option) => option.label);
322
+ }
323
+ return [selectedValues.label];
324
+ };
@@ -0,0 +1,262 @@
1
+ import { ApiUrls } from '@/typings/urls.d';
2
+ import { ValidateRule } from '@/typings/form.d';
3
+ import { EditorControl, EditorControlOption } from '@/typings/form.d';
4
+ import { GridControl, GridControlOption } from '@/typings/table.d';
5
+ import { PageControl, PageControlOption } from '@/typings/page.d';
6
+ import { TreeControl, TreeControlOption } from '@/typings/tree.d';
7
+ import { ref, watch, shallowRef } from 'vue';
8
+ import { queryTree } from './tree';
9
+ import { gridQueryFind, gridQueryList } from './table';
10
+
11
+ const defaultOptions: {
12
+ PageOption: PageControlOption;
13
+ GridOption: GridControlOption;
14
+ EditorOption: EditorControlOption;
15
+ TreeOption: TreeControlOption;
16
+ } = {
17
+ PageOption: {
18
+ primaryKey: 'Id',
19
+ statusKey: 'Enabled',
20
+ },
21
+ GridOption: {
22
+ autoload: true,
23
+ primaryKey: 'Id',
24
+ statusKey: 'Enabled',
25
+ remotePage: true,
26
+ tableSize: ref('small'),
27
+ selectable: ref(false),
28
+ searchBar: ref(true),
29
+ pageSize: ref(10),
30
+ rowExpand: ref(false),
31
+ buttons: ref(['New']),
32
+ tools: ['Reload', 'RowHeight', 'TableHeadset'],
33
+ operates: ['Edit', 'Delete'],
34
+ },
35
+ EditorOption: {
36
+ primaryKey: 'Id',
37
+ autoClose: true,
38
+ autoDetail: false,
39
+ saveBtnVisible: true,
40
+ saveAsBtnVisible: true,
41
+ },
42
+ TreeOption: {
43
+ autoload: true,
44
+ },
45
+ };
46
+
47
+ /**
48
+ * 设置页面控制工厂默认参数
49
+ * @param options 修改默认参数
50
+ */
51
+ export const initPageFactory = (options: {
52
+ pageOption?: PageControlOption;
53
+ gridOption?: GridControlOption;
54
+ editorOptions?: EditorControlOption;
55
+ treeOption?: TreeControlOption;
56
+ }) => {
57
+ defaultOptions.PageOption = {
58
+ ...defaultOptions.PageOption,
59
+ ...options.pageOption,
60
+ };
61
+ defaultOptions.GridOption = {
62
+ ...defaultOptions.GridOption,
63
+ ...options.gridOption,
64
+ };
65
+ defaultOptions.EditorOption = {
66
+ ...defaultOptions.EditorOption,
67
+ ...options.editorOptions,
68
+ };
69
+ defaultOptions.TreeOption = {
70
+ ...defaultOptions.TreeOption,
71
+ ...options.treeOption,
72
+ };
73
+ };
74
+
75
+ /**
76
+ * 编辑器工厂处理
77
+ *
78
+ * @param urls 接口地址
79
+ * @param pageCtrl 页面控制
80
+ * @param defaultData 默认数据
81
+ * @param formRules 表单验证规则
82
+ * @returns
83
+ */
84
+ export const useEditorFactory = <T, E>(
85
+ urls: ApiUrls,
86
+ pageCtrl: PageControl<T>,
87
+ defaultData?: Partial<E>,
88
+ formRules?: Record<string, ValidateRule>,
89
+ ) => {
90
+ /**
91
+ * 表单数据交互控制
92
+ */
93
+ const editorCtrl: EditorControl<E> = {
94
+ ...defaultOptions.EditorOption,
95
+ name: '',
96
+ default: defaultData ? JSON.parse(JSON.stringify(defaultData)) : undefined,
97
+ visible: ref(false),
98
+ page: pageCtrl,
99
+ formData: ref(defaultData ? JSON.parse(JSON.stringify(defaultData)) : undefined),
100
+ formRules: ref(formRules),
101
+ ruleResults: ref({}),
102
+ updateData: ref(undefined),
103
+ saveUrl: urls.urls.save,
104
+ detailUrl: urls.urls.detail,
105
+ isFormSaving: ref(false),
106
+ isFormLoading: ref(false),
107
+ };
108
+
109
+ return {
110
+ editorCtrl,
111
+ };
112
+ };
113
+
114
+ /**
115
+ * 表格控制工厂处理
116
+ *
117
+ * @param urls 接口地址
118
+ * @param pageCtrl 页面控制
119
+ * @param columns 表格列配置
120
+ * @returns
121
+ */
122
+ export const useGridFactory = <T, G>(urls: ApiUrls, pageCtrl: PageControl<T>, columns?: Record<string, any>[]) => {
123
+ /**
124
+ * 表格数据交互控制
125
+ */
126
+ const gridCtrl: GridControl<G> = {
127
+ ...defaultOptions.GridOption,
128
+ tableSize: ref(defaultOptions.GridOption.tableSize.value),
129
+ selectable: ref(defaultOptions.GridOption.selectable.value),
130
+ searchBar: ref(defaultOptions.GridOption.searchBar.value),
131
+ pageSize: ref(defaultOptions.GridOption.pageSize.value),
132
+ rowExpand: ref(defaultOptions.GridOption.rowExpand.value),
133
+ buttons: ref([...defaultOptions.GridOption.buttons.value]),
134
+ tools: [...defaultOptions.GridOption.tools],
135
+ operates: [...defaultOptions.GridOption.operates],
136
+
137
+ columns: ref(columns || []),
138
+ reload: ref(false),
139
+ pageNo: ref(1),
140
+ total: ref(0),
141
+ page: pageCtrl,
142
+ selectKeys: ref([]),
143
+ selectRows: ref([]),
144
+ rowData: ref(undefined),
145
+ gridQuery: {},
146
+ tableData: shallowRef(undefined),
147
+ expandRows: ref({}),
148
+ isGridLoading: ref(false),
149
+ isGridSaving: ref(false),
150
+ gridUrl: urls.urls.list || urls.urls.find,
151
+ updateUrl: urls.urls.update,
152
+ deleteUrl: urls.urls.delete,
153
+ };
154
+
155
+ // 监听重载状态
156
+ watch(
157
+ () => gridCtrl.reload.value,
158
+ (newVal) => {
159
+ if (newVal) {
160
+ // 使用 nextTick 或 setTimeout 延迟重置值
161
+ setTimeout(() => {
162
+ gridCtrl.reload.value = false;
163
+ }, 1);
164
+
165
+ if (gridCtrl.remotePage) gridQueryFind(gridCtrl);
166
+ else gridQueryList(gridCtrl);
167
+ }
168
+ },
169
+ );
170
+
171
+ return {
172
+ gridCtrl,
173
+ };
174
+ };
175
+
176
+ /**
177
+ * 树控制工厂处理
178
+ *
179
+ * @param urls 接口地址
180
+ * @param pageCtrl 页面控制
181
+ * @returns
182
+ */
183
+ export const useTreeFactory = <T>(urls: ApiUrls, pageCtrl: PageControl<T>) => {
184
+ /**
185
+ * 树数据交互控制
186
+ */
187
+ const treeCtrl: TreeControl = {
188
+ ...defaultOptions.TreeOption,
189
+ reload: ref(false),
190
+ page: pageCtrl,
191
+ node: ref(undefined),
192
+ url: urls.urls.tree,
193
+ data: shallowRef(undefined),
194
+ isTreeLoading: ref(false),
195
+ };
196
+
197
+ // 监听重载状态
198
+ watch(
199
+ () => treeCtrl.reload.value,
200
+ (newVal) => {
201
+ if (newVal) {
202
+ // 使用 nextTick 或 setTimeout 延迟重置值
203
+ setTimeout(() => {
204
+ treeCtrl.reload.value = false;
205
+ }, 1);
206
+ queryTree(treeCtrl);
207
+ }
208
+ },
209
+ );
210
+
211
+ return {
212
+ treeCtrl,
213
+ };
214
+ };
215
+
216
+ /**
217
+ * 页面控制工厂处理
218
+ *
219
+ * @param urls 接口地址
220
+ * @param defaultData 默认数据
221
+ * @param formRules 表单验证规则
222
+ * @returns
223
+ */
224
+ export const usePageFactory = <T>(
225
+ urls: ApiUrls,
226
+ defaultData?: Partial<T>,
227
+ formRules?: Record<string, ValidateRule>,
228
+ ) => {
229
+ // urls 参数处理
230
+ // api 默认
231
+ // authorize 默认
232
+ for (const key in urls.urls) {
233
+ if (urls.urls[key]) {
234
+ if (!urls.urls[key].api) urls.urls[key].api = urls.api;
235
+ if (urls.urls[key].authorize === undefined) urls.urls[key].authorize = urls.authorize;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * 页面交互主数据
241
+ * 通过统一的页面交互数据,能够更方便在页面组件中传递数据
242
+ */
243
+ const pageCtrl: PageControl<T> = {
244
+ ...defaultOptions.PageOption,
245
+ ...urls,
246
+ };
247
+
248
+ const { editorCtrl } = useEditorFactory<T, T>(urls, pageCtrl, defaultData, formRules);
249
+ const { gridCtrl } = useGridFactory<T, T>(urls, pageCtrl);
250
+
251
+ pageCtrl.editor = editorCtrl;
252
+ pageCtrl.grid = gridCtrl;
253
+ gridCtrl.editor = editorCtrl;
254
+ gridCtrl.tools = ['Reload', 'RowHeight', 'TableHeadset', 'Fullscreen'];
255
+ editorCtrl.grid = gridCtrl;
256
+
257
+ return {
258
+ pageCtrl,
259
+ editorCtrl,
260
+ gridCtrl,
261
+ };
262
+ };