@skyfox2000/webui 1.3.1 → 1.3.3
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/lib/assets/modules/{file-upload-Ce5MFm6o.js → file-upload-D4Pqs8h3.js} +1 -1
- package/lib/assets/modules/{form-excel-Bq-9rkHa.js → form-excel-D1vXB4c4.js} +1 -1
- package/lib/assets/modules/{index-B8uZAVPS.js → index-CSnwbbQT.js} +2 -2
- package/lib/assets/modules/{index-CrAJ72MK.js → index-V1j9haWy.js} +1 -1
- package/lib/assets/modules/{menuTabs-DEq88ENK.js → menuTabs-e8XoJN7m.js} +2 -2
- package/lib/assets/modules/{toolIcon-OGhmNg0x.js → toolIcon-BSF7eiPf.js} +1 -1
- package/lib/assets/modules/uploadList-Bcf7g1bf.js +382 -0
- package/lib/assets/modules/{uploadList-BzBJXttS.js → uploadList-DA4TRDWR.js} +686 -712
- package/lib/components/form/autoComplete/index.vue.d.ts +10 -48
- package/lib/components/form/upload/uploadList.vue.d.ts +1 -0
- package/lib/es/AceEditor/index.js +3 -3
- package/lib/es/BasicLayout/index.js +3 -3
- package/lib/es/Error403/index.js +1 -1
- package/lib/es/Error404/index.js +1 -1
- package/lib/es/ExcelForm/index.js +4 -4
- package/lib/es/UploadForm/index.js +4 -4
- package/lib/index.d.ts +1 -1
- package/lib/typings/option.d.ts +3 -2
- package/lib/utils/download.d.ts +2 -0
- package/lib/utils/options.d.ts +1 -1
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +275 -273
- package/package.json +1 -1
- package/src/components/content/table/index.vue +22 -10
- package/src/components/form/autoComplete/index.vue +29 -60
- package/src/components/form/cascader/index.vue +1 -1
- package/src/components/form/checkbox/index.vue +1 -1
- package/src/components/form/radio/index.vue +1 -1
- package/src/components/form/select/index.vue +1 -9
- package/src/components/form/switch/index.vue +1 -1
- package/src/components/form/upload/uploadList.vue +50 -11
- package/src/index.ts +1 -1
- package/src/typings/option.d.ts +3 -2
- package/src/utils/download.ts +31 -0
- package/src/utils/options.ts +15 -26
- package/src/utils/page.ts +39 -4
- package/lib/assets/modules/uploadList-DzK2YNwb.js +0 -327
package/package.json
CHANGED
|
@@ -67,7 +67,7 @@ const curPageSize = ref(gridCtrl.pageSize.value);
|
|
|
67
67
|
const curPageNo = ref(gridCtrl.pageNo.value);
|
|
68
68
|
|
|
69
69
|
const dataList = ref<Record<string, AnyData>[]>([]);
|
|
70
|
-
const pagination: Ref<TablePaginationConfig> = ref<TablePaginationConfig>({
|
|
70
|
+
const pagination: Ref<false | TablePaginationConfig> = ref<false | TablePaginationConfig>({
|
|
71
71
|
...{
|
|
72
72
|
total: 0,
|
|
73
73
|
current: 1,
|
|
@@ -76,8 +76,10 @@ const pagination: Ref<TablePaginationConfig> = ref<TablePaginationConfig>({
|
|
|
76
76
|
return `共 ${total} 条记录`;
|
|
77
77
|
},
|
|
78
78
|
onChange: (page: number, pageSize: number) => {
|
|
79
|
-
pagination.value
|
|
80
|
-
|
|
79
|
+
if (pagination.value !== false) {
|
|
80
|
+
pagination.value.current = page;
|
|
81
|
+
pagination.value.pageSize = pageSize;
|
|
82
|
+
}
|
|
81
83
|
curPageSize.value = pageSize;
|
|
82
84
|
curPageNo.value = page;
|
|
83
85
|
if (gridCtrl) {
|
|
@@ -90,14 +92,20 @@ const pagination: Ref<TablePaginationConfig> = ref<TablePaginationConfig>({
|
|
|
90
92
|
...props.pagination,
|
|
91
93
|
});
|
|
92
94
|
|
|
95
|
+
if (props.pagination === false) {
|
|
96
|
+
pagination.value = false;
|
|
97
|
+
}
|
|
98
|
+
|
|
93
99
|
watch(
|
|
94
100
|
() => gridCtrl.tableData.value,
|
|
95
101
|
(newVal) => {
|
|
96
102
|
if (newVal) {
|
|
97
103
|
dataList.value = newVal;
|
|
98
|
-
pagination.value
|
|
99
|
-
|
|
100
|
-
|
|
104
|
+
if (pagination.value !== false) {
|
|
105
|
+
pagination.value.total = gridCtrl.total.value ?? 0;
|
|
106
|
+
pagination.value.current = gridCtrl.pageNo.value ?? 1;
|
|
107
|
+
pagination.value.pageSize = gridCtrl.pageSize.value ?? 10;
|
|
108
|
+
}
|
|
101
109
|
}
|
|
102
110
|
},
|
|
103
111
|
{ immediate: true },
|
|
@@ -108,9 +116,11 @@ watch(
|
|
|
108
116
|
(newVal) => {
|
|
109
117
|
if (newVal) {
|
|
110
118
|
dataList.value = newVal;
|
|
111
|
-
pagination.value
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
if (pagination.value !== false) {
|
|
120
|
+
pagination.value.total = newVal.length;
|
|
121
|
+
pagination.value.current = gridCtrl.pageNo.value ?? 1;
|
|
122
|
+
pagination.value.pageSize = gridCtrl.pageSize.value ?? 10;
|
|
123
|
+
}
|
|
114
124
|
}
|
|
115
125
|
},
|
|
116
126
|
{ immediate: true },
|
|
@@ -162,7 +172,9 @@ onMounted(async () => {
|
|
|
162
172
|
if (gridCtrl.tableData.value) {
|
|
163
173
|
dataList.value = gridCtrl.tableData.value;
|
|
164
174
|
gridCtrl.total.value = dataList.value.length;
|
|
165
|
-
pagination.value
|
|
175
|
+
if (pagination.value !== false) {
|
|
176
|
+
pagination.value.total = gridCtrl.total.value ?? 0;
|
|
177
|
+
}
|
|
166
178
|
} else if (gridCtrl.autoload !== false) {
|
|
167
179
|
if (gridCtrl.remotePage) {
|
|
168
180
|
dataList.value = (await gridQueryFind(gridCtrl)).rows;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref,
|
|
2
|
+
import { ref, onUnmounted, useAttrs, watch, shallowRef, PropType } from 'vue';
|
|
3
3
|
import { AutoComplete } from 'ant-design-vue';
|
|
4
4
|
import {
|
|
5
5
|
useInputFactory,
|
|
@@ -13,35 +13,23 @@ import {
|
|
|
13
13
|
formValidate,
|
|
14
14
|
outFormDataFields,
|
|
15
15
|
} from '@/index';
|
|
16
|
-
import { ReqParams
|
|
16
|
+
import { ReqParams } from '@skyfox2000/fapi';
|
|
17
17
|
import { useOptionFactory } from '@/utils/page';
|
|
18
|
+
import { combineParams } from '@skyfox2000/microbase';
|
|
18
19
|
|
|
19
20
|
const props = defineProps({
|
|
20
21
|
...OptionCommProps,
|
|
21
22
|
value: {
|
|
22
|
-
type: [String, Number,
|
|
23
|
+
type: [String, Number, Array, null] as PropType<string | number | string[] | null>,
|
|
23
24
|
default: undefined,
|
|
24
25
|
},
|
|
25
|
-
/**
|
|
26
|
-
* 查询字段
|
|
27
|
-
* - 模糊查询
|
|
28
|
-
*/
|
|
29
|
-
searchField: {
|
|
30
|
-
type: [String, Array<string>],
|
|
31
|
-
},
|
|
32
|
-
/**
|
|
33
|
-
* 自定义查询参数
|
|
34
|
-
* - 查询参数
|
|
35
|
-
* - query参数
|
|
36
|
-
*/
|
|
37
|
-
onsearch: {
|
|
38
|
-
type: Function,
|
|
39
|
-
},
|
|
40
26
|
/**
|
|
41
27
|
* 修改输入数据则自动清空关联数据
|
|
28
|
+
* - FormData: 表单数据
|
|
29
|
+
* - outFields: 输出字段
|
|
42
30
|
*/
|
|
43
31
|
autoClean: {
|
|
44
|
-
type: Boolean
|
|
32
|
+
type: Boolean as PropType<boolean>,
|
|
45
33
|
default: true,
|
|
46
34
|
},
|
|
47
35
|
});
|
|
@@ -56,14 +44,18 @@ const inputFactory = useInputFactory();
|
|
|
56
44
|
const defaultCtrl = useOptionFactory(props.url, props);
|
|
57
45
|
const optionCtrl = props.optionCtrl ?? defaultCtrl.optionCtrl;
|
|
58
46
|
optionCtrl.inputFactory = shallowRef(inputFactory);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
47
|
+
/***
|
|
48
|
+
* 默认字段映射
|
|
49
|
+
* - label: 显示字段 支持模板 ${}
|
|
50
|
+
* - value: 值字段
|
|
51
|
+
*/
|
|
52
|
+
optionCtrl.fieldMap = {
|
|
53
|
+
...{
|
|
54
|
+
label: 'Name',
|
|
55
|
+
value: 'Id',
|
|
56
|
+
},
|
|
57
|
+
...optionCtrl?.fieldMap,
|
|
58
|
+
};
|
|
67
59
|
|
|
68
60
|
/// 避免类型错误
|
|
69
61
|
const innerValue = ref<SelectValue | undefined>(optionCtrl?.selected.value || undefined);
|
|
@@ -103,7 +95,7 @@ if (optionCtrl) {
|
|
|
103
95
|
(newOptions) => {
|
|
104
96
|
selectOptions.value = newOptions || [];
|
|
105
97
|
},
|
|
106
|
-
{ immediate: true, deep: true }
|
|
98
|
+
{ immediate: true, deep: true },
|
|
107
99
|
);
|
|
108
100
|
}
|
|
109
101
|
|
|
@@ -112,29 +104,14 @@ const onSearch = (value: string) => {
|
|
|
112
104
|
if (value === '') return;
|
|
113
105
|
let search_value = value.trim();
|
|
114
106
|
let query: ReqParams = {
|
|
115
|
-
...url.value.params,
|
|
116
107
|
Query: {
|
|
117
|
-
|
|
108
|
+
SearchField: '%' + search_value + '%',
|
|
118
109
|
},
|
|
119
110
|
};
|
|
120
|
-
if (props.searchField) {
|
|
121
|
-
if (Array.isArray(props.searchField)) {
|
|
122
|
-
props.searchField.forEach((field) => {
|
|
123
|
-
query.Query![field] = {
|
|
124
|
-
$like: '%' + search_value + '%',
|
|
125
|
-
};
|
|
126
|
-
});
|
|
127
|
-
} else {
|
|
128
|
-
query.Query![props.searchField] = {
|
|
129
|
-
$like: '%' + search_value + '%',
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
if (props.onsearch) {
|
|
134
|
-
props.onsearch(search_value, query);
|
|
135
|
-
}
|
|
136
111
|
|
|
137
|
-
|
|
112
|
+
optionCtrl.params = combineParams(optionCtrl.params, query);
|
|
113
|
+
|
|
114
|
+
if (optionCtrl) loadOption(true, optionCtrl, props);
|
|
138
115
|
};
|
|
139
116
|
|
|
140
117
|
const onSelected = (value: any) => {
|
|
@@ -153,17 +130,6 @@ const onSelected = (value: any) => {
|
|
|
153
130
|
}
|
|
154
131
|
};
|
|
155
132
|
|
|
156
|
-
onMounted(() => {
|
|
157
|
-
if (url.value && !url.value.fieldMap) {
|
|
158
|
-
url.value.fieldMap = {
|
|
159
|
-
title: 'Name',
|
|
160
|
-
label: 'Name',
|
|
161
|
-
value: 'Name',
|
|
162
|
-
key: 'Id',
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
|
|
167
133
|
onUnmounted(() => {
|
|
168
134
|
if (optionCtrl) unloadOption(optionCtrl, props);
|
|
169
135
|
});
|
|
@@ -173,13 +139,16 @@ onUnmounted(() => {
|
|
|
173
139
|
<div>
|
|
174
140
|
<AutoComplete
|
|
175
141
|
v-model:value="innerValue"
|
|
176
|
-
:class="[
|
|
142
|
+
:class="['w-full', errInfo?.errClass]"
|
|
177
143
|
:options="selectOptions"
|
|
178
144
|
@search="onSearch"
|
|
179
145
|
@select="onSelected"
|
|
180
|
-
:placeholder="
|
|
146
|
+
:placeholder="'请输入并选择' + labelText"
|
|
181
147
|
v-bind="attrs"
|
|
182
148
|
>
|
|
149
|
+
<template #option="{ label }">
|
|
150
|
+
{{ label }}
|
|
151
|
+
</template>
|
|
183
152
|
</AutoComplete>
|
|
184
153
|
</div>
|
|
185
154
|
</template>
|
|
@@ -102,7 +102,7 @@ onMounted(() => {
|
|
|
102
102
|
key: 'Id',
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
if (optionCtrl) loadOption(optionCtrl, props);
|
|
105
|
+
if (optionCtrl) loadOption(optionCtrl.autoload, optionCtrl, props);
|
|
106
106
|
});
|
|
107
107
|
onUnmounted(() => {
|
|
108
108
|
if (optionCtrl) unloadOption(optionCtrl, props);
|
|
@@ -135,14 +135,6 @@ watch(
|
|
|
135
135
|
},
|
|
136
136
|
);
|
|
137
137
|
|
|
138
|
-
// watch(
|
|
139
|
-
// () => props.params,
|
|
140
|
-
// (newVal) => {
|
|
141
|
-
// loadOption(true, props, selectOptions, inputFactory, url.value, newVal);
|
|
142
|
-
// },
|
|
143
|
-
// { deep: true },
|
|
144
|
-
// );
|
|
145
|
-
|
|
146
138
|
onMounted(() => {
|
|
147
139
|
if (url.value && !url.value.fieldMap) {
|
|
148
140
|
url.value.fieldMap = {
|
|
@@ -154,7 +146,7 @@ onMounted(() => {
|
|
|
154
146
|
if (props.dataKey) {
|
|
155
147
|
const options = JSON.parse(JSON.stringify(OPTIONS.getOptions(props.dataKey)));
|
|
156
148
|
selectOptions.value = options;
|
|
157
|
-
} else if (optionCtrl) loadOption(optionCtrl, props);
|
|
149
|
+
} else if (optionCtrl) loadOption(optionCtrl.autoload, optionCtrl, props);
|
|
158
150
|
});
|
|
159
151
|
|
|
160
152
|
onUnmounted(() => {
|
|
@@ -4,7 +4,7 @@ import { computed, ref, watch } from 'vue';
|
|
|
4
4
|
import message from 'vue-m-message';
|
|
5
5
|
import type { UploadProps } from 'ant-design-vue';
|
|
6
6
|
import { Upload, Progress, Tag, Popconfirm } from 'ant-design-vue';
|
|
7
|
-
import { UploadFile, UploadStatus, donwloadFromMinio, path, Switch } from '@/index';
|
|
7
|
+
import { UploadFile, UploadStatus, donwloadFromMinio, path, Switch, previewFromMinio } from '@/index';
|
|
8
8
|
import { useInputFactory } from '@/utils/form-validate';
|
|
9
9
|
import { IUrlInfo } from '@skyfox2000/fapi';
|
|
10
10
|
|
|
@@ -22,6 +22,10 @@ export interface UploadListProps {
|
|
|
22
22
|
* 下载Url
|
|
23
23
|
*/
|
|
24
24
|
downloadUrl?: IUrlInfo;
|
|
25
|
+
/**
|
|
26
|
+
* 预览Url
|
|
27
|
+
*/
|
|
28
|
+
previewUrl?: IUrlInfo;
|
|
25
29
|
/**
|
|
26
30
|
* 文件列表
|
|
27
31
|
*/
|
|
@@ -168,12 +172,11 @@ watch(
|
|
|
168
172
|
);
|
|
169
173
|
|
|
170
174
|
const downloadFile = (index: number) => {
|
|
171
|
-
if (!props.downloadUrl) return;
|
|
172
175
|
const minioFile = fileList.value[index].minioFile!;
|
|
173
176
|
const url: IUrlInfo = {
|
|
174
|
-
api: props.downloadUrl
|
|
175
|
-
authorize: props.downloadUrl
|
|
176
|
-
url: props.downloadUrl
|
|
177
|
+
api: props.downloadUrl!.api,
|
|
178
|
+
authorize: props.downloadUrl!.authorize,
|
|
179
|
+
url: props.downloadUrl!.url,
|
|
177
180
|
params: {
|
|
178
181
|
Query: {
|
|
179
182
|
FileKey: minioFile.Key,
|
|
@@ -190,10 +193,21 @@ const onlineOrOffline = (file: UploadFile) => {
|
|
|
190
193
|
}
|
|
191
194
|
};
|
|
192
195
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
const previewFile = (index: number) => {
|
|
197
|
+
const minioFile = fileList.value[index].minioFile!;
|
|
198
|
+
const url: IUrlInfo = {
|
|
199
|
+
api: props.previewUrl!.api,
|
|
200
|
+
authorize: props.previewUrl!.authorize,
|
|
201
|
+
url: props.previewUrl!.url,
|
|
202
|
+
params: {
|
|
203
|
+
Query: {
|
|
204
|
+
FileKey: minioFile.Key,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
previewFromMinio(url, minioFile.FileName!);
|
|
210
|
+
};
|
|
197
211
|
|
|
198
212
|
const removeFile = (index: number) => {
|
|
199
213
|
fileList.value.splice(index, 1);
|
|
@@ -322,7 +336,26 @@ const getStatus = (status?: UploadStatus) => {
|
|
|
322
336
|
>
|
|
323
337
|
</Tooltip>
|
|
324
338
|
</div>
|
|
325
|
-
|
|
339
|
+
<div
|
|
340
|
+
class="flex items-center text-blue-500 hover:text-blue-700 mr-1 cursor-pointer"
|
|
341
|
+
v-if="previewUrl && (file.status == UploadStatus.Online || file.status == UploadStatus.Offline)"
|
|
342
|
+
>
|
|
343
|
+
<Tooltip title="预览">
|
|
344
|
+
<ToolIcon
|
|
345
|
+
icon="icon-eye"
|
|
346
|
+
v-auth="{ role: ['Super', 'Admin'], permit: ':uploadlist:preview' }"
|
|
347
|
+
clickable
|
|
348
|
+
@click="previewFile(index)"
|
|
349
|
+
/>
|
|
350
|
+
<span
|
|
351
|
+
v-if="showActionText"
|
|
352
|
+
class="mr-2 text-sm text-nowrap"
|
|
353
|
+
v-auth="{ role: ['Super', 'Admin'], permit: ':uploadlist:preview' }"
|
|
354
|
+
@click="previewFile(index)"
|
|
355
|
+
>预览</span
|
|
356
|
+
>
|
|
357
|
+
</Tooltip>
|
|
358
|
+
</div>
|
|
326
359
|
<div class="flex items-center text-red-500 hover:text-red-700 cursor-pointer">
|
|
327
360
|
<Popconfirm
|
|
328
361
|
v-model:open="confirmOpen"
|
|
@@ -356,7 +389,13 @@ const getStatus = (status?: UploadStatus) => {
|
|
|
356
389
|
</div>
|
|
357
390
|
|
|
358
391
|
<!-- 上传进度条 -->
|
|
359
|
-
<div
|
|
392
|
+
<div
|
|
393
|
+
v-if="
|
|
394
|
+
file.status !== UploadStatus.Online &&
|
|
395
|
+
file.status !== UploadStatus.Offline &&
|
|
396
|
+
file.status !== UploadStatus.Success
|
|
397
|
+
"
|
|
398
|
+
>
|
|
360
399
|
<Progress :percent="file.percent" :stroke-width="2" :show-info="false" style="height: 2px"></Progress>
|
|
361
400
|
</div>
|
|
362
401
|
</div>
|
package/src/index.ts
CHANGED
|
@@ -129,7 +129,7 @@ export {
|
|
|
129
129
|
} from '@/utils/options';
|
|
130
130
|
|
|
131
131
|
// download 工具
|
|
132
|
-
export { downloadBlob, donwloadFromMinio } from '@/utils/download';
|
|
132
|
+
export { downloadBlob, donwloadFromMinio, previewFromMinio, CanPreviewFileExt } from '@/utils/download';
|
|
133
133
|
|
|
134
134
|
// icon-loader 工具
|
|
135
135
|
export {
|
package/src/typings/option.d.ts
CHANGED
|
@@ -179,11 +179,12 @@ export type OptionControl = OptionControlOption & {
|
|
|
179
179
|
*/
|
|
180
180
|
optionQuery?: ReqParams;
|
|
181
181
|
/**
|
|
182
|
-
*
|
|
182
|
+
* 当前传入数据
|
|
183
183
|
*/
|
|
184
184
|
data: ShallowRef<OptionItemProps[] | undefined>;
|
|
185
185
|
/**
|
|
186
|
-
*
|
|
186
|
+
* 实际选项数据
|
|
187
|
+
* - 已转换fieldMap
|
|
187
188
|
*/
|
|
188
189
|
options: Ref<OptionItemProps[]>;
|
|
189
190
|
/**
|
package/src/utils/download.ts
CHANGED
|
@@ -78,3 +78,34 @@ export const donwloadFromMinio = <T>(url: IUrlInfo, params?: ReqParams, pageCtrl
|
|
|
78
78
|
message.error('文件下载失败,请稍后重试');
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
|
+
|
|
82
|
+
export const CanPreviewFileExt = ['xlsx', 'xls', 'csv', 'txt'];
|
|
83
|
+
|
|
84
|
+
export const previewFromMinio = (url: IUrlInfo, fileName: string, params?: ReqParams) => {
|
|
85
|
+
const fileExt = fileName.split('.').pop();
|
|
86
|
+
if (CanPreviewFileExt.includes(fileExt!)) {
|
|
87
|
+
console.log(url);
|
|
88
|
+
} else {
|
|
89
|
+
message.error('文件类型不支持预览');
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const newParams = combineParams(url.params, params);
|
|
94
|
+
return httpPost(url, newParams).then((result: ApiResponse<any> | null) => {
|
|
95
|
+
if (result?.status === ResStatus.SUCCESS && result.data) {
|
|
96
|
+
const minioFile: MinioFile = result.data as unknown as MinioFile;
|
|
97
|
+
// 提取内容和文件名
|
|
98
|
+
const base64String = minioFile.Content!;
|
|
99
|
+
|
|
100
|
+
// 解码 Base64 字符串
|
|
101
|
+
const byteCharacters = atob(base64String);
|
|
102
|
+
const byteArrays = [];
|
|
103
|
+
for (let b = 0; b < byteCharacters.length; b++) {
|
|
104
|
+
byteArrays.push(byteCharacters.charCodeAt(b));
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
message.error('文件预览失败!');
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
});
|
|
111
|
+
};
|
package/src/utils/options.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ReqParams,
|
|
9
9
|
ResStatus,
|
|
10
10
|
} from '@skyfox2000/fapi';
|
|
11
|
-
import { inject, ref,
|
|
11
|
+
import { inject, ref, watch } from 'vue';
|
|
12
12
|
import { OptionItemProps, SelectValue, OptionControl, OptionProps } from '@/typings/option.d';
|
|
13
13
|
import { ProviderKeys } from '@/typings/page.d';
|
|
14
14
|
import message from 'vue-m-message';
|
|
@@ -20,12 +20,12 @@ import { combineParams } from '@skyfox2000/microbase';
|
|
|
20
20
|
* 自动初始化选择项
|
|
21
21
|
* @param optionCtrl 选项控制器
|
|
22
22
|
*/
|
|
23
|
-
export const loadOption = (optionCtrl: OptionControl, props?: OptionProps) => {
|
|
23
|
+
export const loadOption = (load: boolean, optionCtrl: OptionControl, props?: OptionProps) => {
|
|
24
24
|
if (optionCtrl.inputFactory && props?.reloadEvent) {
|
|
25
25
|
const inputFactory = optionCtrl.inputFactory.value;
|
|
26
26
|
/// 接收事件,联动显示或者重新加载数据
|
|
27
27
|
inputFactory.reloadHandler = (_event: string, params: Record<string, AnyData> | AnyData[]) => {
|
|
28
|
-
optionEventHandler(optionCtrl.url!, optionCtrl, params
|
|
28
|
+
optionEventHandler(optionCtrl.url!, optionCtrl, params);
|
|
29
29
|
};
|
|
30
30
|
eventBus.on(props.reloadEvent, inputFactory.reloadHandler);
|
|
31
31
|
}
|
|
@@ -35,13 +35,12 @@ export const loadOption = (optionCtrl: OptionControl, props?: OptionProps) => {
|
|
|
35
35
|
watch(
|
|
36
36
|
() => props.data,
|
|
37
37
|
() => {
|
|
38
|
-
updateOptions(optionCtrl, props.data!,
|
|
38
|
+
updateOptions(optionCtrl, props.data!, true);
|
|
39
39
|
},
|
|
40
40
|
{ deep: true, immediate: true },
|
|
41
41
|
);
|
|
42
42
|
} else if (optionCtrl.url && optionCtrl.url.url) {
|
|
43
|
-
if (optionCtrl.
|
|
44
|
-
doQueryOptions(optionCtrl.url, optionCtrl, optionCtrl.params ?? {}, optionCtrl.options);
|
|
43
|
+
if (load) doQueryOptions(optionCtrl.url, optionCtrl, optionCtrl.params ?? {});
|
|
45
44
|
} else {
|
|
46
45
|
const labelText = ref<string>(inject(ProviderKeys.LabelText, ''));
|
|
47
46
|
message.error('`' + labelText.value + '` 未配置选项数据!', {
|
|
@@ -54,15 +53,9 @@ export const loadOption = (optionCtrl: OptionControl, props?: OptionProps) => {
|
|
|
54
53
|
* 组件选项数据更新
|
|
55
54
|
* @param optionCtrl 选项控制器
|
|
56
55
|
* @param data 提供的下拉数据
|
|
57
|
-
* @param options 实际选择项
|
|
58
56
|
* @param mapping 是否需要转换字段
|
|
59
57
|
*/
|
|
60
|
-
const updateOptions = (
|
|
61
|
-
optionCtrl: OptionControl,
|
|
62
|
-
data: Record<string, AnyData>[],
|
|
63
|
-
options: Ref<OptionItemProps[]>,
|
|
64
|
-
mapping: boolean,
|
|
65
|
-
) => {
|
|
58
|
+
const updateOptions = (optionCtrl: OptionControl, data: Record<string, AnyData>[], mapping: boolean) => {
|
|
66
59
|
if (mapping) {
|
|
67
60
|
// 转换字段
|
|
68
61
|
const fieldMap = {
|
|
@@ -79,7 +72,7 @@ const updateOptions = (
|
|
|
79
72
|
});
|
|
80
73
|
}
|
|
81
74
|
|
|
82
|
-
options.value = data as OptionItemProps[];
|
|
75
|
+
optionCtrl.options.value = data as OptionItemProps[];
|
|
83
76
|
};
|
|
84
77
|
|
|
85
78
|
/**
|
|
@@ -93,14 +86,13 @@ const optionEventHandler = (
|
|
|
93
86
|
url: IUrlInfo,
|
|
94
87
|
optionCtrl: OptionControl,
|
|
95
88
|
params_data: Record<string, AnyData> | AnyData[],
|
|
96
|
-
options: Ref<OptionItemProps[]>,
|
|
97
89
|
) => {
|
|
98
90
|
if (Array.isArray(params_data)) {
|
|
99
91
|
// 数据组仅用于联动显示
|
|
100
|
-
updateOptions(optionCtrl, params_data,
|
|
92
|
+
updateOptions(optionCtrl, params_data, true);
|
|
101
93
|
} else {
|
|
102
94
|
// 其它情况使用Query参数
|
|
103
|
-
doQueryOptions(url, optionCtrl, params_data
|
|
95
|
+
doQueryOptions(url, optionCtrl, params_data);
|
|
104
96
|
}
|
|
105
97
|
};
|
|
106
98
|
|
|
@@ -118,21 +110,15 @@ export const unloadOption = (optionCtrl: OptionControl, props: OptionProps) => {
|
|
|
118
110
|
* @param url 选项接口
|
|
119
111
|
* @param optionCtrl 选项控制器
|
|
120
112
|
* @param params 查询条件
|
|
121
|
-
* @param options 实际选择项
|
|
122
113
|
*/
|
|
123
|
-
const doQueryOptions = (
|
|
124
|
-
url: IUrlInfo,
|
|
125
|
-
optionCtrl: OptionControl,
|
|
126
|
-
params: ReqParams,
|
|
127
|
-
options: Ref<OptionItemProps[]>,
|
|
128
|
-
) => {
|
|
114
|
+
const doQueryOptions = (url: IUrlInfo, optionCtrl: OptionControl, params: ReqParams) => {
|
|
129
115
|
const urlParams = JSON.parse(JSON.stringify(url.params ?? {}));
|
|
130
116
|
const ctrlParams = JSON.parse(JSON.stringify(optionCtrl.params ?? {}));
|
|
131
117
|
const newParams: ReqParams = combineParams(urlParams, ctrlParams, params);
|
|
132
118
|
queryOptions(url, optionCtrl, optionCtrl.fieldMap, newParams).then((results) => {
|
|
133
119
|
// 使用url,由request负责转换,无需再次map转换
|
|
134
120
|
const data = results as OptionItemProps[];
|
|
135
|
-
updateOptions(optionCtrl, data,
|
|
121
|
+
updateOptions(optionCtrl, data, false);
|
|
136
122
|
});
|
|
137
123
|
};
|
|
138
124
|
|
|
@@ -164,8 +150,8 @@ const queryOptions = <T>(
|
|
|
164
150
|
url: '',
|
|
165
151
|
cacheTime: 60000,
|
|
166
152
|
fieldMap: {
|
|
167
|
-
...fieldMap,
|
|
168
153
|
...url.fieldMap,
|
|
154
|
+
...fieldMap,
|
|
169
155
|
},
|
|
170
156
|
};
|
|
171
157
|
const optionUrl = {
|
|
@@ -175,6 +161,7 @@ const queryOptions = <T>(
|
|
|
175
161
|
optionUrl.loadingText = false;
|
|
176
162
|
if (!params) params = {};
|
|
177
163
|
if (!params.Query) params.Query = {};
|
|
164
|
+
optionCtrl.optionQuery = params;
|
|
178
165
|
optionCtrl.isOptionLoading.value = true;
|
|
179
166
|
return httpPost<T>(optionUrl, params)
|
|
180
167
|
.then((result: ApiResponse<T> | null) => {
|
|
@@ -284,9 +271,11 @@ export const onOptionChanged = (
|
|
|
284
271
|
if (inputFactory?.editorCtrl && inputFactory.errInfo?.value.errClass) {
|
|
285
272
|
formValidate(inputFactory.editorCtrl);
|
|
286
273
|
}
|
|
274
|
+
optionCtrl.selected.value = values as undefined | string | number | string[] | number[];
|
|
287
275
|
|
|
288
276
|
// 获取选中的选项对象或对象数组
|
|
289
277
|
const selectedValues = getSelectedValues(values, optionCtrl.options.value);
|
|
278
|
+
optionCtrl.selectedOptions.value = selectedValues as OptionItemProps[];
|
|
290
279
|
|
|
291
280
|
// 如果配置了 formData 和 outFields,将选中的其它属性值映射到 formData 上
|
|
292
281
|
if (props.formData && props.outFields) {
|
package/src/utils/page.ts
CHANGED
|
@@ -230,12 +230,12 @@ export const useOptionFactory = (url?: IUrlInfo, props?: OptionProps) => {
|
|
|
230
230
|
const optionCtrl: OptionControl = {
|
|
231
231
|
...defaultOptions.OptionOption,
|
|
232
232
|
url: url,
|
|
233
|
-
options: ref([]),
|
|
234
233
|
reload: ref(false),
|
|
234
|
+
optionQuery: {},
|
|
235
235
|
data: shallowRef([]),
|
|
236
236
|
selected: ref([]),
|
|
237
237
|
selectedOptions: ref([]),
|
|
238
|
-
|
|
238
|
+
options: ref([]),
|
|
239
239
|
isOptionLoading: ref(false),
|
|
240
240
|
};
|
|
241
241
|
|
|
@@ -244,15 +244,50 @@ export const useOptionFactory = (url?: IUrlInfo, props?: OptionProps) => {
|
|
|
244
244
|
() => optionCtrl.reload.value,
|
|
245
245
|
(newVal) => {
|
|
246
246
|
if (newVal) {
|
|
247
|
-
// 使用 nextTick 或 setTimeout 延迟重置值
|
|
248
247
|
setTimeout(() => {
|
|
249
248
|
optionCtrl.reload.value = false;
|
|
250
249
|
}, 1);
|
|
251
|
-
loadOption(optionCtrl, props);
|
|
250
|
+
loadOption(true, optionCtrl, props);
|
|
252
251
|
}
|
|
253
252
|
},
|
|
254
253
|
);
|
|
255
254
|
|
|
255
|
+
// // 为 optionCtrl 创建响应式的 params 监听
|
|
256
|
+
// // 使用 Proxy 来拦截 params 的设置,确保能够触发响应式更新
|
|
257
|
+
// const originalParams = optionCtrl.params;
|
|
258
|
+
// const paramsRef = ref(originalParams);
|
|
259
|
+
|
|
260
|
+
// // 使用 Object.defineProperty 来拦截 params 的赋值
|
|
261
|
+
// Object.defineProperty(optionCtrl, 'params', {
|
|
262
|
+
// get() {
|
|
263
|
+
// return paramsRef.value;
|
|
264
|
+
// },
|
|
265
|
+
// set(newParams) {
|
|
266
|
+
// paramsRef.value = newParams;
|
|
267
|
+
// },
|
|
268
|
+
// enumerable: true,
|
|
269
|
+
// configurable: true,
|
|
270
|
+
// });
|
|
271
|
+
|
|
272
|
+
// let isInitialized = false;
|
|
273
|
+
|
|
274
|
+
// // 监听params变化,自动重新加载数据
|
|
275
|
+
// watch(
|
|
276
|
+
// () => paramsRef.value,
|
|
277
|
+
// () => {
|
|
278
|
+
// if (!isInitialized) {
|
|
279
|
+
// isInitialized = true;
|
|
280
|
+
// return;
|
|
281
|
+
// }
|
|
282
|
+
// // 确保有URL且params存在时才自动重新加载
|
|
283
|
+
// // 避免重复加载,通过reload状态控制
|
|
284
|
+
// if (!optionCtrl.reload.value) {
|
|
285
|
+
// optionCtrl.reload.value = true;
|
|
286
|
+
// }
|
|
287
|
+
// },
|
|
288
|
+
// { deep: true },
|
|
289
|
+
// );
|
|
290
|
+
|
|
256
291
|
return {
|
|
257
292
|
optionCtrl,
|
|
258
293
|
};
|