@skyfox2000/webui 1.2.12 → 1.3.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 (45) hide show
  1. package/lib/assets/modules/{file-upload-CGyzCx7I.js → file-upload-C4GVmWjB.js} +1 -1
  2. package/lib/assets/modules/{form-excel-DWirWVPA.js → form-excel-Cr2hcL1s.js} +3 -3
  3. package/lib/assets/modules/{index-Czk7DDWM.js → index-D5onbqkl.js} +2 -2
  4. package/lib/assets/modules/{index-C1zkNPmi.js → index-DjBruVH-.js} +1 -1
  5. package/lib/assets/modules/{menuTabs-BOax-dro.js → menuTabs-B9fCWfN1.js} +36 -36
  6. package/lib/assets/modules/{toolIcon-vJF7OgP6.js → toolIcon-DKTf30Tq.js} +1 -1
  7. package/lib/assets/modules/{uploadList-DaUjVXLU.js → uploadList-CY57np42.js} +980 -923
  8. package/lib/assets/modules/uploadList-D2lisNHt.js +327 -0
  9. package/lib/components/form/autoComplete/index.vue.d.ts +15 -52
  10. package/lib/components/form/cascader/index.vue.d.ts +16 -56
  11. package/lib/components/form/checkbox/index.vue.d.ts +15 -54
  12. package/lib/components/form/index.d.ts +1 -1
  13. package/lib/components/form/propEditor/index.vue.d.ts +1 -7
  14. package/lib/components/form/radio/index.vue.d.ts +15 -54
  15. package/lib/components/form/select/index.vue.d.ts +15 -60
  16. package/lib/components/form/switch/index.vue.d.ts +62 -29
  17. package/lib/es/AceEditor/index.js +3 -3
  18. package/lib/es/BasicLayout/index.js +6 -6
  19. package/lib/es/Error403/index.js +1 -1
  20. package/lib/es/Error404/index.js +1 -1
  21. package/lib/es/ExcelForm/index.js +37 -37
  22. package/lib/es/UploadForm/index.js +4 -4
  23. package/lib/index.d.ts +1 -1
  24. package/lib/typings/form.d.ts +19 -0
  25. package/lib/typings/option.d.ts +93 -74
  26. package/lib/utils/options.d.ts +4 -7
  27. package/lib/utils/page.d.ts +5 -0
  28. package/lib/webui.css +1 -1
  29. package/lib/webui.es.js +861 -851
  30. package/package.json +14 -14
  31. package/src/components/form/autoComplete/index.vue +29 -16
  32. package/src/components/form/cascader/index.vue +25 -9
  33. package/src/components/form/checkbox/index.vue +26 -10
  34. package/src/components/form/index.ts +1 -1
  35. package/src/components/form/propEditor/index.vue +6 -21
  36. package/src/components/form/radio/index.vue +26 -10
  37. package/src/components/form/select/index.vue +38 -40
  38. package/src/components/form/switch/index.vue +23 -5
  39. package/src/index.ts +8 -1
  40. package/src/typings/form.d.ts +19 -0
  41. package/src/typings/option.d.ts +93 -73
  42. package/src/utils/form-excel.ts +2 -2
  43. package/src/utils/options.ts +58 -62
  44. package/src/utils/page.ts +41 -0
  45. package/lib/assets/modules/uploadList-BW23uSvi.js +0 -369
@@ -1,4 +1,6 @@
1
1
  import { AnyData, IUrlInfo, ReqParams } from '@skyfox2000/fapi';
2
+ import { Ref, ShallowRef } from 'vue';
3
+ import { InputFactoryItems } from './form.d';
2
4
 
3
5
  type RawValue = string | number;
4
6
  export type SelectValue = RawValue | RawValue[];
@@ -20,37 +22,13 @@ export interface OptionItemProps {
20
22
  */
21
23
  export interface OptionProps {
22
24
  /**
23
- * 自动接口加载数据
24
- * - 默认为true
25
- */
26
- autoload?: boolean;
27
- /**
28
- * 是否显示全部选项
29
- * - 默认为false
30
- */
31
- all?: boolean;
32
- /**
33
- * 选择项数据
34
- */
35
- data?: Record<string, any>[];
36
- /**
37
- * 字段转换控制
38
- * - Key:目的字段
39
- * - Value:源字段,支持模板 ${}
40
- */
41
- fieldMap?: Record<string, string>;
42
- /**
43
- * 接口定义
25
+ * 选项数据接口
44
26
  */
45
27
  url?: IUrlInfo;
46
28
  /**
47
- * 重载接口,默认false
48
- */
49
- reload?: boolean;
50
- /**
51
- * 接口自定义QOD参数
29
+ * 自定义选项数据, 优先级高于optionCtrl.data
52
30
  */
53
- params?: ReqParams;
31
+ data?: OptionItemProps[];
54
32
  /**
55
33
  * 表单数据
56
34
  */
@@ -80,6 +58,10 @@ export interface OptionProps {
80
58
  * - 第一个参数为事件名,第二个参数为事件参数模板,支持模板 ${selectedValues}
81
59
  */
82
60
  changeEvent?: [string | string[], string];
61
+ /**
62
+ * 选项控制器
63
+ */
64
+ optionCtrl?: OptionControl;
83
65
  }
84
66
 
85
67
  import type { PropType } from 'vue';
@@ -89,59 +71,17 @@ import type { PropType } from 'vue';
89
71
  */
90
72
  export const OptionCommProps = {
91
73
  /**
92
- * 自动接口加载数据
93
- * - 默认为true
94
- */
95
- autoload: {
96
- type: Boolean as PropType<boolean>,
97
- required: false,
98
- default: true,
99
- },
100
- /**
101
- * 是否显示全部选项
102
- * - 默认为false
103
- */
104
- all: {
105
- type: Boolean as PropType<boolean>,
106
- required: false,
107
- default: false,
108
- },
109
- /**
110
- * 选择项数据
111
- */
112
- data: {
113
- type: Array as PropType<Record<string, any>[]>,
114
- required: false,
115
- },
116
- /**
117
- * 字段转换控制
118
- * - Key:目的字段
119
- * - Value:源字段,支持模板 ${}
120
- */
121
- fieldMap: {
122
- type: Object as PropType<Record<string, string>>,
123
- required: false,
124
- },
125
- /**
126
- * 接口定义
74
+ * 选项数据接口
127
75
  */
128
76
  url: {
129
77
  type: Object as PropType<IUrlInfo>,
130
78
  required: false,
131
79
  },
132
80
  /**
133
- * 重载接口,默认false
81
+ * 选项数据
134
82
  */
135
- reload: {
136
- type: Boolean as PropType<boolean>,
137
- required: false,
138
- default: false,
139
- },
140
- /**
141
- * 接口自定义QOD参数
142
- */
143
- params: {
144
- type: Object as PropType<ReqParams>,
83
+ data: {
84
+ type: Array as PropType<OptionItemProps[]>,
145
85
  required: false,
146
86
  },
147
87
  /**
@@ -188,4 +128,84 @@ export const OptionCommProps = {
188
128
  type: Array as PropType<[string | string[], string]>,
189
129
  required: false,
190
130
  },
131
+ optionCtrl: {
132
+ type: Object as PropType<OptionControl>,
133
+ required: false,
134
+ },
135
+ };
136
+
137
+ /**
138
+ * 表格控制默认设置
139
+ */
140
+ export type OptionControlOption = {
141
+ /**
142
+ * 是否显示全部选项
143
+ * - 默认为false
144
+ */
145
+ all: boolean;
146
+ /**
147
+ * 全部选项值
148
+ * 自定义全部选项的值
149
+ * 如果all为true,则显示全部选项
150
+ * 未设置allValue,则默认[0, 1]
151
+ */
152
+ allValue: string | number | string[] | number[] | undefined;
153
+ /**
154
+ * 自动加载数据
155
+ */
156
+ autoload: boolean;
157
+ };
158
+
159
+ /**
160
+ * 选项数据交互标准定义
161
+ */
162
+ export type OptionControl = OptionControlOption & {
163
+ /**
164
+ * 输入项工厂
165
+ */
166
+ inputFactory?: ShallowRef<InputFactoryItems<any>>;
167
+ /**
168
+ * 重新加载数据
169
+ */
170
+ reload: Ref<boolean>;
171
+ /**
172
+ * 当前查询条件
173
+ */
174
+ optionQuery?: ReqParams;
175
+ /**
176
+ * 当前数据
177
+ */
178
+ data: ShallowRef<OptionItemProps[] | undefined>;
179
+ /**
180
+ * 选项数据
181
+ */
182
+ options: Ref<OptionItemProps[]>;
183
+ /**
184
+ * 基础选中数据
185
+ */
186
+ selected: Ref<string | number | string[] | number[] | undefined>;
187
+ /**
188
+ * 选中数据
189
+ */
190
+ selectedOptions: Ref<OptionItemProps[]>;
191
+ /**
192
+ * 字段转换控制
193
+ * - Key:目的字段
194
+ * - Value:源字段,支持模板 ${}
195
+ */
196
+ fieldMap?: Record<string, string>;
197
+ /**
198
+ * 查询接口
199
+ * - 优先使用
200
+ * - 或使用PageData.urls.option
201
+ */
202
+ url?: IUrlInfo;
203
+ /**
204
+ * 额外查询参数
205
+ */
206
+ params?: ReqParams;
207
+ /**
208
+ * 是否正在加载中
209
+ */
210
+ isOptionLoading: Ref<boolean>;
191
211
  };
@@ -33,7 +33,7 @@ export type ExcelMarkInfo = {
33
33
  export const processExcelFile = async (excelBuffer: ArrayBuffer) => {
34
34
  // 动态导入 exceljs
35
35
  const ExcelJS = await import('exceljs');
36
- const workbook = new ExcelJS.Workbook();
36
+ const workbook = new ExcelJS.default.Workbook();
37
37
  await workbook.xlsx.load(excelBuffer);
38
38
 
39
39
  // 获取第一个工作表
@@ -168,7 +168,7 @@ export const createMarkedExcelBlob = async (
168
168
  }
169
169
 
170
170
  // 创建一个新的工作簿和工作表
171
- const newWorkbook = new ExcelJS.Workbook();
171
+ const newWorkbook = new ExcelJS.default.Workbook();
172
172
  const newWorksheet = newWorkbook.addWorksheet('Sheet1');
173
173
 
174
174
  // 默认列宽
@@ -9,8 +9,7 @@ import {
9
9
  ResStatus,
10
10
  } from '@skyfox2000/fapi';
11
11
  import { inject, ref, Ref, watch } from 'vue';
12
- import { OptionProps, OptionItemProps, SelectValue } from '@/typings/option.d';
13
- import { InputFactoryItems } from '@/typings/form.d';
12
+ import { OptionItemProps, SelectValue, OptionControl, OptionProps } from '@/typings/option.d';
14
13
  import { ProviderKeys } from '@/typings/page.d';
15
14
  import message from 'vue-m-message';
16
15
  import eventBus from './eventbus';
@@ -19,40 +18,30 @@ import { combineParams } from '@skyfox2000/microbase';
19
18
 
20
19
  /**
21
20
  * 自动初始化选择项
22
- * @param autoload 是否自动加载
23
- * @param props 选项外部属性值
24
- * @param options 实际选择项
25
- * @param inputFactory 本地工厂,用于统一处理事件
26
- * @param url 选项接口
27
- * @param params 选择参数
21
+ * @param optionCtrl 选项控制器
28
22
  */
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) {
23
+ export const loadOption = (optionCtrl: OptionControl, props?: OptionProps) => {
24
+ if (optionCtrl.inputFactory && props?.reloadEvent) {
25
+ const inputFactory = optionCtrl.inputFactory.value;
39
26
  /// 接收事件,联动显示或者重新加载数据
40
27
  inputFactory.reloadHandler = (_event: string, params: Record<string, AnyData> | AnyData[]) => {
41
- optionEventHandler(url!, props, params, options);
28
+ optionEventHandler(optionCtrl.url!, optionCtrl, params, optionCtrl.options);
42
29
  };
43
30
  eventBus.on(props.reloadEvent, inputFactory.reloadHandler);
44
31
  }
45
32
 
46
- if (props.data) {
33
+ if (props?.data) {
34
+ // 监听自定义选项数据, 优先级高于optionCtrl.data
47
35
  watch(
48
36
  () => props.data,
49
37
  () => {
50
- updateOptions(props, props.data!, options, true);
38
+ updateOptions(optionCtrl, props.data!, optionCtrl.options, true);
51
39
  },
52
40
  { deep: true, immediate: true },
53
41
  );
54
- } else if (url && url.url) {
55
- if (autoload !== false) doQueryOptions(url, props, params ?? {}, options);
42
+ } else if (optionCtrl.url && optionCtrl.url.url) {
43
+ if (optionCtrl.autoload !== false)
44
+ doQueryOptions(optionCtrl.url, optionCtrl, optionCtrl.params ?? {}, optionCtrl.options);
56
45
  } else {
57
46
  const labelText = ref<string>(inject(ProviderKeys.LabelText, ''));
58
47
  message.error('`' + labelText.value + '` 未配置选项数据!', {
@@ -63,34 +52,30 @@ export const loadOption = (
63
52
 
64
53
  /**
65
54
  * 组件选项数据更新
66
- * @param props 选项外部属性值
55
+ * @param optionCtrl 选项控制器
67
56
  * @param data 提供的下拉数据
68
57
  * @param options 实际选择项
69
58
  * @param mapping 是否需要转换字段
70
59
  */
71
60
  const updateOptions = (
72
- props: OptionProps,
61
+ optionCtrl: OptionControl,
73
62
  data: Record<string, AnyData>[],
74
63
  options: Ref<OptionItemProps[]>,
75
64
  mapping: boolean,
76
65
  ) => {
77
- if (!data || data.length === 0) {
78
- options.value = [];
79
- return;
80
- }
81
66
  if (mapping) {
82
67
  // 转换字段
83
68
  const fieldMap = {
84
- ...props.fieldMap,
69
+ ...optionCtrl.fieldMap,
85
70
  };
86
71
  data = fieldMapping(fieldMap, data);
87
72
  }
88
73
 
89
- data = JSON.parse(JSON.stringify(data));
90
- if (props.all) {
74
+ data = JSON.parse(JSON.stringify(data ?? []));
75
+ if (optionCtrl.all) {
91
76
  data.unshift({
92
77
  label: '全部',
93
- value: undefined,
78
+ value: optionCtrl.allValue ?? undefined,
94
79
  });
95
80
  }
96
81
 
@@ -100,48 +85,54 @@ const updateOptions = (
100
85
  /**
101
86
  * 选项重载事件处理
102
87
  * @param url 选项接口
103
- * @param props 选项外部属性值
88
+ * @param optionCtrl 选项控制器
104
89
  * @param data 提供的下拉数据
105
90
  * @param options 实际选择项
106
91
  */
107
92
  const optionEventHandler = (
108
93
  url: IUrlInfo,
109
- props: OptionProps,
94
+ optionCtrl: OptionControl,
110
95
  params_data: Record<string, AnyData> | AnyData[],
111
96
  options: Ref<OptionItemProps[]>,
112
97
  ) => {
113
98
  if (Array.isArray(params_data)) {
114
99
  // 数据组仅用于联动显示
115
- updateOptions(props, params_data, options, true);
100
+ updateOptions(optionCtrl, params_data, options, true);
116
101
  } else {
117
102
  // 其它情况使用Query参数
118
- doQueryOptions(url, props, params_data, options);
103
+ doQueryOptions(url, optionCtrl, params_data, options);
119
104
  }
120
105
  };
121
106
 
122
107
  /**
123
108
  * 卸载选择项
124
- * @param props 选项外部属性值
125
- * @param inputFactory 输入组件工厂
109
+ * @param optionCtrl 选项控制器
126
110
  */
127
- export const unloadOption = (props: OptionProps, inputFactory?: InputFactoryItems<any>) => {
128
- if (inputFactory && props.reloadEvent && inputFactory.reloadHandler)
129
- eventBus.off(props.reloadEvent, inputFactory.reloadHandler);
111
+ export const unloadOption = (optionCtrl: OptionControl, props: OptionProps) => {
112
+ if (optionCtrl.inputFactory?.value && props.reloadEvent && optionCtrl.inputFactory.value.reloadHandler)
113
+ eventBus.off(props.reloadEvent, optionCtrl.inputFactory.value.reloadHandler);
130
114
  };
131
115
 
132
116
  /**
133
- *
117
+ * 查询选项数据
134
118
  * @param url 选项接口
135
- * @param props 选项外部属性值
119
+ * @param optionCtrl 选项控制器
136
120
  * @param params 查询条件
137
121
  * @param options 实际选择项
138
122
  */
139
- const doQueryOptions = (url: IUrlInfo, props: OptionProps, params: ReqParams, options: Ref<OptionItemProps[]>) => {
140
- const newParams: ReqParams = combineParams(url.params, props.params, params);
141
- queryOptions(url, props.fieldMap, newParams).then((results) => {
123
+ const doQueryOptions = (
124
+ url: IUrlInfo,
125
+ optionCtrl: OptionControl,
126
+ params: ReqParams,
127
+ options: Ref<OptionItemProps[]>,
128
+ ) => {
129
+ const urlParams = JSON.parse(JSON.stringify(url.params ?? {}));
130
+ const ctrlParams = JSON.parse(JSON.stringify(optionCtrl.params ?? {}));
131
+ const newParams: ReqParams = combineParams(urlParams, ctrlParams, params);
132
+ queryOptions(url, optionCtrl, optionCtrl.fieldMap, newParams).then((results) => {
142
133
  // 使用url,由request负责转换,无需再次map转换
143
134
  const data = results as OptionItemProps[];
144
- updateOptions(props, data, options, false);
135
+ updateOptions(optionCtrl, data, options, false);
145
136
  });
146
137
  };
147
138
 
@@ -163,6 +154,7 @@ const doQueryOptions = (url: IUrlInfo, props: OptionProps, params: ReqParams, op
163
154
  */
164
155
  const queryOptions = <T>(
165
156
  url: IUrlInfo,
157
+ optionCtrl: OptionControl,
166
158
  fieldMap?: Record<string, string>,
167
159
  params?: ReqParams,
168
160
  ): Promise<T[] | undefined> => {
@@ -183,14 +175,19 @@ const queryOptions = <T>(
183
175
  optionUrl.loadingText = false;
184
176
  if (!params) params = {};
185
177
  if (!params.Query) params.Query = {};
186
- return httpPost<T>(optionUrl, params).then((result: ApiResponse<T> | null) => {
187
- if (result?.status === ResStatus.SUCCESS) {
188
- if (result.data) {
189
- return result.data as T[];
178
+ optionCtrl.isOptionLoading.value = true;
179
+ return httpPost<T>(optionUrl, params)
180
+ .then((result: ApiResponse<T> | null) => {
181
+ if (result?.status === ResStatus.SUCCESS) {
182
+ if (result.data) {
183
+ return result.data as T[];
184
+ }
190
185
  }
191
- }
192
- return [];
193
- });
186
+ return [];
187
+ })
188
+ .finally(() => {
189
+ optionCtrl.isOptionLoading.value = false;
190
+ });
194
191
  };
195
192
 
196
193
  /**
@@ -273,24 +270,23 @@ export const outFormDataFields = (
273
270
 
274
271
  /**
275
272
  * 选项选中事件处理函数
276
- * @param props 选项外部属性值
273
+ * @param optionCtrl 选项控制器
277
274
  * @param values 选中的项目,支持单选或多项
278
- * @param options 实际选择项
279
275
  * @param inputFactory 输入组件工厂
280
276
  */
281
277
  export const onOptionChanged = (
278
+ optionCtrl: OptionControl,
282
279
  props: OptionProps,
283
280
  values: undefined | SelectValue,
284
- options: Ref<OptionItemProps[]>,
285
- inputFactory: InputFactoryItems<any>,
286
281
  ): OptionItemProps | OptionItemProps[] | undefined => {
282
+ const inputFactory = optionCtrl.inputFactory?.value;
287
283
  // 如果存在验证错误,重新检测
288
- if (inputFactory.editorCtrl && inputFactory.errInfo?.value.errClass) {
284
+ if (inputFactory?.editorCtrl && inputFactory.errInfo?.value.errClass) {
289
285
  formValidate(inputFactory.editorCtrl);
290
286
  }
291
287
 
292
288
  // 获取选中的选项对象或对象数组
293
- const selectedValues = getSelectedValues(values, options.value);
289
+ const selectedValues = getSelectedValues(values, optionCtrl.options.value);
294
290
 
295
291
  // 如果配置了 formData 和 outFields,将选中的其它属性值映射到 formData 上
296
292
  if (props.formData && props.outFields) {
@@ -330,7 +326,7 @@ export const onOptionChanged = (
330
326
  }
331
327
  }
332
328
  // 触发 inputFactory 的 change 事件
333
- if (inputFactory.inputEmit) {
329
+ if (inputFactory?.inputEmit) {
334
330
  inputFactory.inputEmit('change', values, selectedValues);
335
331
  }
336
332
  return selectedValues;
package/src/utils/page.ts CHANGED
@@ -7,12 +7,16 @@ import { TreeControl, TreeControlOption } from '@/typings/tree.d';
7
7
  import { ref, watch, shallowRef } from 'vue';
8
8
  import { queryTree } from './tree';
9
9
  import { gridQueryFind, gridQueryList } from './table';
10
+ import { OptionControl, OptionControlOption, OptionProps } from '@/typings/option';
11
+ import { loadOption } from './options';
12
+ import { IUrlInfo } from '@skyfox2000/fapi';
10
13
 
11
14
  const defaultOptions: {
12
15
  PageOption: PageControlOption;
13
16
  GridOption: GridControlOption;
14
17
  EditorOption: EditorControlOption;
15
18
  TreeOption: TreeControlOption;
19
+ OptionOption: OptionControlOption;
16
20
  } = {
17
21
  PageOption: {
18
22
  primaryKey: 'Id',
@@ -42,6 +46,11 @@ const defaultOptions: {
42
46
  TreeOption: {
43
47
  autoload: true,
44
48
  },
49
+ OptionOption: {
50
+ all: false,
51
+ allValue: [0, 1],
52
+ autoload: true,
53
+ },
45
54
  };
46
55
 
47
56
  /**
@@ -213,6 +222,38 @@ export const useTreeFactory = <T>(urls: ApiUrls, pageCtrl: PageControl<T>) => {
213
222
  };
214
223
  };
215
224
 
225
+ export const useOptionFactory = (url?: IUrlInfo, props?: OptionProps) => {
226
+ const optionCtrl: OptionControl = {
227
+ ...defaultOptions.OptionOption,
228
+ url: url,
229
+ options: ref([]),
230
+ reload: ref(false),
231
+ data: shallowRef([]),
232
+ selected: ref([]),
233
+ selectedOptions: ref([]),
234
+ optionQuery: {},
235
+ isOptionLoading: ref(false),
236
+ };
237
+
238
+ // 监听重载状态
239
+ watch(
240
+ () => optionCtrl.reload.value,
241
+ (newVal) => {
242
+ if (newVal) {
243
+ // 使用 nextTick 或 setTimeout 延迟重置值
244
+ setTimeout(() => {
245
+ optionCtrl.reload.value = false;
246
+ }, 1);
247
+ loadOption(optionCtrl, props);
248
+ }
249
+ },
250
+ );
251
+
252
+ return {
253
+ optionCtrl,
254
+ };
255
+ };
256
+
216
257
  /**
217
258
  * 页面控制工厂处理
218
259
  *