@skyfox2000/webui 1.3.2 → 1.3.4
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-BVB9c-eZ.js → file-upload-BBlFaIXB.js} +1 -1
- package/lib/assets/modules/index-4kDAt8nS.js +333 -0
- package/lib/assets/modules/{index-CaaMz5sz.js → index-BG1SqSVl.js} +1 -1
- package/lib/assets/modules/{index-k_AnrbPY.js → index-m5rogIyM.js} +2 -2
- package/lib/assets/modules/{menuTabs-_Ph7P8ES.js → menuTabs-tPIz4a89.js} +2 -2
- package/lib/assets/modules/{toolIcon-QMXCkImG.js → toolIcon-DwWoD9TN.js} +1 -1
- package/lib/assets/modules/{uploadList-D-FOtndj.js → uploadList-D_Z-Y2tw.js} +482 -508
- package/lib/assets/modules/uploadList-Da7mQUNK.js +382 -0
- 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 +332 -202
- package/lib/es/UploadForm/index.js +4 -4
- package/lib/index.d.ts +4 -3
- package/lib/utils/download.d.ts +2 -0
- package/lib/utils/excel-view.d.ts +25 -0
- package/lib/utils/form-csv.d.ts +18 -0
- package/lib/utils/form-excel.d.ts +2 -13
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +773 -742
- package/package.json +2 -2
- package/src/components/common/loading/index.vue +1 -1
- package/src/components/content/dialog/excelForm.vue +384 -106
- package/src/components/content/table/index.vue +22 -10
- package/src/components/form/autoComplete/index.vue +29 -60
- package/src/components/form/upload/uploadList.vue +50 -11
- package/src/index.ts +26 -3
- package/src/utils/download.ts +31 -0
- package/src/utils/excel-view.ts +340 -0
- package/src/utils/form-csv.ts +55 -0
- package/src/utils/form-excel.ts +59 -192
- package/src/utils/options.ts +0 -1
- package/vite.config.ts +0 -1
- package/lib/assets/modules/form-excel-CsQBtfkA.js +0 -235
- package/lib/assets/modules/uploadList-CXa3siDj.js +0 -327
|
@@ -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"
|
|
144
|
+
:placeholder="'请输入并选择' + labelText"
|
|
178
145
|
@search="onSearch"
|
|
179
146
|
@select="onSelected"
|
|
180
|
-
:placeholder="optionCtrl?.url?.loading ? '请输入并选择' + 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>
|
|
@@ -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 {
|
|
@@ -162,8 +162,31 @@ export {
|
|
|
162
162
|
} from '@/utils/form-validate';
|
|
163
163
|
|
|
164
164
|
// form-excel 工具
|
|
165
|
-
export {
|
|
166
|
-
|
|
165
|
+
export {
|
|
166
|
+
validateExcel,
|
|
167
|
+
checkExcelDuplicates,
|
|
168
|
+
processExcelFile,
|
|
169
|
+
appendExcelData,
|
|
170
|
+
createMarkedExcelView,
|
|
171
|
+
} from '@/utils/form-excel';
|
|
172
|
+
// ExcelMarkCell, ExcelMarkInfo 已移至 excel-view 统一管理
|
|
173
|
+
|
|
174
|
+
// form-csv 工具
|
|
175
|
+
export { csvToExcelBlob, processCsvFile } from '@/utils/form-csv';
|
|
176
|
+
|
|
177
|
+
// excel-view 工具
|
|
178
|
+
export {
|
|
179
|
+
csvToNormalized,
|
|
180
|
+
excelToNormalized,
|
|
181
|
+
toExcel,
|
|
182
|
+
csvToExcelView,
|
|
183
|
+
excelToExcelView,
|
|
184
|
+
normalizedToExcelView,
|
|
185
|
+
type NormalizedData,
|
|
186
|
+
type ExcelViewResult,
|
|
187
|
+
type ExcelMarkCell,
|
|
188
|
+
type ExcelMarkInfo,
|
|
189
|
+
} from '@/utils/excel-view';
|
|
167
190
|
|
|
168
191
|
// table 工具
|
|
169
192
|
export {
|
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
|
+
};
|