@skyfox2000/webui 1.3.5 → 1.3.7
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/.vscode/settings.json +1 -1
- package/lib/assets/modules/{file-upload-C0twqMV5.js → file-upload-CKliLHBF.js} +50 -50
- package/lib/assets/modules/{index-D1XAa1Uo.js → index-CTOX9glc.js} +2 -2
- package/lib/assets/modules/index-Cm_1mhHh.js +377 -0
- package/lib/assets/modules/{index-C4CryM-R.js → index-DTFrhJdN.js} +1 -1
- package/lib/assets/modules/{menuTabs-BrYQa4UO.js → menuTabs-ylnnzjNu.js} +2 -2
- package/lib/assets/modules/{toolIcon-B-g9pyE4.js → toolIcon-CNfvNkNh.js} +1 -1
- package/lib/assets/modules/{uploadList-DCWRIxPJ.js → uploadList-DroJGtBI.js} +4 -4
- package/lib/assets/modules/{uploadList-0f2FA_5s.js → uploadList-M21hxVQy.js} +129 -128
- package/lib/components/common/alert/index.vue.d.ts +13 -0
- package/lib/components/common/icon/helper.vue.d.ts +1 -0
- package/lib/components/common/index.d.ts +2 -0
- package/lib/components/content/form/formItem.vue.d.ts +1 -0
- package/lib/components/form/input/index.vue.d.ts +4 -1
- package/lib/components/form/select/index.vue.d.ts +2 -0
- package/lib/components/form/treeSelect/index.vue.d.ts +11 -2
- package/lib/components/index.d.ts +1 -1
- 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 +309 -275
- package/lib/es/UploadForm/index.js +4 -4
- package/lib/index.d.ts +1 -1
- package/lib/typings/form.d.ts +2 -2
- package/lib/utils/excel-preview.d.ts +24 -0
- package/lib/utils/form-excel.d.ts +17 -4
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +677 -662
- package/package.json +2 -2
- package/src/components/common/alert/index.vue +76 -0
- package/src/components/common/icon/helper.vue +7 -1
- package/src/components/common/index.ts +4 -1
- package/src/components/content/dialog/excelForm.vue +337 -311
- package/src/components/content/form/formItem.vue +6 -2
- package/src/components/form/input/index.vue +16 -3
- package/src/components/form/select/index.vue +5 -11
- package/src/components/form/treeSelect/index.vue +22 -17
- package/src/components/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/typings/form.d.ts +2 -2
- package/src/utils/data.ts +10 -1
- package/src/utils/excel-preview.ts +189 -0
- package/src/utils/file-upload.ts +0 -2
- package/src/utils/form-excel.ts +132 -126
- package/lib/assets/modules/index-CKJIxasX.js +0 -333
|
@@ -26,6 +26,10 @@ const props = defineProps<{
|
|
|
26
26
|
* 是否显示在独立行
|
|
27
27
|
*/
|
|
28
28
|
nextLine?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 底部间距
|
|
31
|
+
*/
|
|
32
|
+
bottomMargin?: string;
|
|
29
33
|
}>();
|
|
30
34
|
|
|
31
35
|
// 关闭自动继承属性到根元素
|
|
@@ -87,13 +91,13 @@ const required = computed(() => {
|
|
|
87
91
|
// });
|
|
88
92
|
</script>
|
|
89
93
|
<template>
|
|
90
|
-
<div :class="['relative mb-1']">
|
|
94
|
+
<div :class="['relative', bottomMargin ? bottomMargin : 'mb-1']">
|
|
91
95
|
<FormItem
|
|
92
96
|
v-if="visible"
|
|
93
97
|
:required="required"
|
|
94
98
|
class="relative"
|
|
95
|
-
v-bind="attrs"
|
|
96
99
|
:class="[nextLine ? 'mb-0' : rule ? '' : 'mb-3']"
|
|
100
|
+
v-bind="attrs"
|
|
97
101
|
>
|
|
98
102
|
<template #label>
|
|
99
103
|
<span :class="[errInfo.errClass ? 'text-[#ff4d4f]' : '', 'w-full']"> {{ label }}</span>
|
|
@@ -11,9 +11,22 @@ const onBlur = () => {
|
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
const props = defineProps<{
|
|
14
|
+
const props = withDefaults(defineProps<{
|
|
15
15
|
value?: any;
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* 清空时设置的值
|
|
18
|
+
* - false,则清空时设置为 null
|
|
19
|
+
* - true,则清空时设置为 undefined
|
|
20
|
+
*/
|
|
21
|
+
undefValue?: boolean;
|
|
22
|
+
}>(),
|
|
23
|
+
{
|
|
24
|
+
undefValue: false,
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// 如果初始value为undefined,自动设置undefValue为true
|
|
29
|
+
const undefValue = props.value === undefined ? true : props.undefValue;
|
|
17
30
|
const emit = defineEmits(['update:value']);
|
|
18
31
|
// 内部值,拦截外部传入的 value
|
|
19
32
|
const innerValue = ref(props.value);
|
|
@@ -40,7 +53,7 @@ watch(
|
|
|
40
53
|
|
|
41
54
|
const onClear = () => {
|
|
42
55
|
if (innerValue.value === '') {
|
|
43
|
-
innerValue.value = undefined;
|
|
56
|
+
innerValue.value = undefValue ? undefined : null;
|
|
44
57
|
}
|
|
45
58
|
};
|
|
46
59
|
</script>
|
|
@@ -43,7 +43,7 @@ const props = defineProps({
|
|
|
43
43
|
|
|
44
44
|
const inputFactory = useInputFactory();
|
|
45
45
|
const { editorCtrl, errInfo, labelText } = inputFactory;
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
const defaultCtrl = useOptionFactory(props.url, props);
|
|
48
48
|
const optionCtrl = props.optionCtrl ?? defaultCtrl.optionCtrl;
|
|
49
49
|
optionCtrl.inputFactory = shallowRef(inputFactory);
|
|
@@ -67,7 +67,7 @@ const placeholder = ref(attrs.placeholder);
|
|
|
67
67
|
|
|
68
68
|
/// 避免类型错误
|
|
69
69
|
const innerValue = ref<string | number | string[] | number[] | undefined>(optionCtrl?.selected.value || undefined);
|
|
70
|
-
const emit = defineEmits(['change', 'update:value', 'update:labels']);
|
|
70
|
+
const emit = defineEmits(['change', 'update:value', 'update:label', 'update:labels']);
|
|
71
71
|
inputFactory.inputEmit = emit;
|
|
72
72
|
|
|
73
73
|
/**
|
|
@@ -92,6 +92,7 @@ const onChanged = (value: any) => {
|
|
|
92
92
|
|
|
93
93
|
innerValue.value = value;
|
|
94
94
|
emit('update:labels', labels);
|
|
95
|
+
emit('update:label', labels.join(";"));
|
|
95
96
|
emit('change', value);
|
|
96
97
|
|
|
97
98
|
if (errInfo?.value.errClass && editorCtrl) {
|
|
@@ -160,15 +161,8 @@ onUnmounted(() => {
|
|
|
160
161
|
<circleLoading class="text-[#555] mx-[5px] !ml-[10px] !w-4 !h-4" />
|
|
161
162
|
<span>数据加载中...</span>
|
|
162
163
|
</div>
|
|
163
|
-
<Select
|
|
164
|
-
:
|
|
165
|
-
v-model:value="innerValue"
|
|
166
|
-
:allow-clear="true"
|
|
167
|
-
@change="onChanged"
|
|
168
|
-
:placeholder="placeholder"
|
|
169
|
-
:label-in-value="false"
|
|
170
|
-
v-bind="attrs"
|
|
171
|
-
>
|
|
164
|
+
<Select :class="[errInfo?.errClass, 'w-full']" v-model:value="innerValue" :allow-clear="true" @change="onChanged"
|
|
165
|
+
:placeholder="placeholder" :label-in-value="false" v-bind="attrs">
|
|
172
166
|
<template v-for="item in selectOptions" :key="item.value">
|
|
173
167
|
<SelectOption :value="item.value" v-if="item.visible !== false">
|
|
174
168
|
{{ item.label }}
|
|
@@ -16,10 +16,22 @@ const props = defineProps({
|
|
|
16
16
|
},
|
|
17
17
|
value: {
|
|
18
18
|
type: [String, Number, Array] as PropType<SelectValue>,
|
|
19
|
-
required:
|
|
19
|
+
required: false,
|
|
20
|
+
},
|
|
21
|
+
/**
|
|
22
|
+
* 清空时设置的值
|
|
23
|
+
* - false,则清空时设置为 null
|
|
24
|
+
* - true,则清空时设置为 undefined
|
|
25
|
+
*/
|
|
26
|
+
undefValue: {
|
|
27
|
+
type: Boolean,
|
|
28
|
+
default: false,
|
|
20
29
|
},
|
|
21
30
|
});
|
|
22
31
|
|
|
32
|
+
// 如果初始value为undefined,自动设置undefValue为true
|
|
33
|
+
const undefValue = props.value === undefined ? true : props.undefValue;
|
|
34
|
+
|
|
23
35
|
const treeCtrl = props.treeCtrl;
|
|
24
36
|
|
|
25
37
|
const inputFactory = useInputFactory();
|
|
@@ -32,13 +44,13 @@ inputFactory.inputEmit = emit;
|
|
|
32
44
|
// 树选择数据
|
|
33
45
|
const selectTreeData = ref<TreeNode[]>([]);
|
|
34
46
|
// 当前选中值
|
|
35
|
-
const currentValue = ref<SelectValue>();
|
|
47
|
+
const currentValue = ref<SelectValue | null>();
|
|
36
48
|
|
|
37
49
|
// 监听值变化
|
|
38
50
|
watch(
|
|
39
51
|
() => props.value,
|
|
40
52
|
(newVal) => {
|
|
41
|
-
currentValue.value = newVal
|
|
53
|
+
currentValue.value = newVal;
|
|
42
54
|
},
|
|
43
55
|
{ immediate: true },
|
|
44
56
|
);
|
|
@@ -59,7 +71,7 @@ const handleChange = (value: SelectValue) => {
|
|
|
59
71
|
if (props.multiple) {
|
|
60
72
|
currentValue.value = value ?? [];
|
|
61
73
|
} else {
|
|
62
|
-
currentValue.value = value ??
|
|
74
|
+
currentValue.value = value ?? undefValue ? undefined : null;
|
|
63
75
|
}
|
|
64
76
|
emit('change', currentValue.value);
|
|
65
77
|
emit('update:value', currentValue.value);
|
|
@@ -82,22 +94,15 @@ onMounted(() => {
|
|
|
82
94
|
queryTree(props.treeCtrl);
|
|
83
95
|
}
|
|
84
96
|
});
|
|
97
|
+
const onClear = () => {
|
|
98
|
+
currentValue.value = undefValue ? undefined : null;
|
|
99
|
+
};
|
|
85
100
|
</script>
|
|
86
101
|
|
|
87
102
|
<template>
|
|
88
|
-
<TreeSelect
|
|
89
|
-
:class="
|
|
90
|
-
|
|
91
|
-
:multiple="multiple"
|
|
92
|
-
:tree-default-expanded-keys="['-']"
|
|
93
|
-
v-model:value="currentValue"
|
|
94
|
-
:tree-data="selectTreeData"
|
|
95
|
-
:placeholder="'请选择' + labelText"
|
|
96
|
-
:allow-clear="true"
|
|
97
|
-
class="w-full"
|
|
98
|
-
@change="handleChange"
|
|
99
|
-
v-bind="$attrs"
|
|
100
|
-
/>
|
|
103
|
+
<TreeSelect :class="[errInfo?.errClass]" tree-line :multiple="multiple" :tree-default-expanded-keys="['-']"
|
|
104
|
+
v-model:value="currentValue" :tree-data="selectTreeData" :placeholder="'请选择' + labelText" class="w-full"
|
|
105
|
+
@change="handleChange" @clear="onClear" v-bind="$attrs" />
|
|
101
106
|
</template>
|
|
102
107
|
<style scoped>
|
|
103
108
|
.error :deep(.ant-select-selector) {
|
package/src/components/index.ts
CHANGED
package/src/index.ts
CHANGED
package/src/typings/form.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyData, IUrlInfo } from '@skyfox2000/fapi';
|
|
1
|
+
import { AnyData, IUrlInfo, ReqParams } from '@skyfox2000/fapi';
|
|
2
2
|
import { PageControl } from './page';
|
|
3
3
|
import Validator, { RuleItem, ValidateError } from 'async-validator';
|
|
4
4
|
import { Ref, DefineProps } from 'vue';
|
|
@@ -71,7 +71,7 @@ export type EditorControl<T> = EditorControlOption & {
|
|
|
71
71
|
* @param editorCtrl 表单配置数据
|
|
72
72
|
* @returns 是否保存
|
|
73
73
|
*/
|
|
74
|
-
beforeSave?: () => boolean | undefined;
|
|
74
|
+
beforeSave?: (params?: ReqParams) => boolean | undefined | void;
|
|
75
75
|
/**
|
|
76
76
|
* 表单保存后处理
|
|
77
77
|
* @param editorCtrl 表单配置数据
|
package/src/utils/data.ts
CHANGED
|
@@ -3,12 +3,21 @@ import { ApiResponse, httpPost, IUrlInfo, ResStatus } from '@skyfox2000/fapi';
|
|
|
3
3
|
import message from 'vue-m-message';
|
|
4
4
|
import { isEmpty } from './isEmpty';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* 合并URL信息
|
|
8
|
+
* - 使用控件的URL信息
|
|
9
|
+
* - 使用页面的URL信息
|
|
10
|
+
* - 单独配置项的URL信息
|
|
11
|
+
* @param control
|
|
12
|
+
* @param options
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
6
15
|
const combineUrl = (control: AnyControl, options: ExecuteOptions<any>) => {
|
|
7
16
|
const pageCtrl = control.page;
|
|
8
17
|
const url: IUrlInfo | undefined = {
|
|
9
18
|
url: '',
|
|
10
|
-
...pageCtrl.urls?.[options.urlKey],
|
|
11
19
|
...control.url,
|
|
20
|
+
...pageCtrl.urls?.[options.urlKey],
|
|
12
21
|
...options.url,
|
|
13
22
|
loadingText: options.loadingText,
|
|
14
23
|
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Excel预览相关工具方法
|
|
3
|
+
* 处理Excel和CSV文件的预览功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { csvToExcelView } from './excel-view';
|
|
7
|
+
import { AnyData, ResStatus, IUrlInfo, httpGet, ApiResponse } from '@skyfox2000/fapi';
|
|
8
|
+
import { doQuery } from '@/index';
|
|
9
|
+
import message from 'vue-m-message';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 判断是否为CSV格式的内容
|
|
13
|
+
* @param data 文件内容
|
|
14
|
+
* @returns 是否为CSV格式
|
|
15
|
+
*/
|
|
16
|
+
export const isCsvContent = (data: string): boolean => {
|
|
17
|
+
return data.includes(',') || data.includes('\n');
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 判断是否为CSV类型
|
|
22
|
+
* @param type MIME类型
|
|
23
|
+
* @param filename 文件名
|
|
24
|
+
* @returns 是否为CSV类型
|
|
25
|
+
*/
|
|
26
|
+
export const isCsvType = (type?: string, filename?: string): boolean => {
|
|
27
|
+
return type === 'text/csv' || filename?.toLowerCase().includes('.csv') || false;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 判断是否为Excel类型
|
|
32
|
+
* @param type MIME类型
|
|
33
|
+
* @param filename 文件名
|
|
34
|
+
* @returns 是否为Excel类型
|
|
35
|
+
*/
|
|
36
|
+
export const isExcelType = (type?: string, filename?: string): boolean => {
|
|
37
|
+
return (
|
|
38
|
+
type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
|
|
39
|
+
type === 'application/vnd.ms-excel' ||
|
|
40
|
+
filename?.toLowerCase().match(/\.(xlsx|xls)$/) !== null
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* CSV内容处理的公共方法
|
|
46
|
+
* @param content CSV内容
|
|
47
|
+
* @param filename 文件名
|
|
48
|
+
* @returns 处理结果
|
|
49
|
+
*/
|
|
50
|
+
export const processCsvContent = async (content: string, filename: string = 'preview.csv') => {
|
|
51
|
+
const csvResult = await csvToExcelView(content, filename);
|
|
52
|
+
if (csvResult.success) {
|
|
53
|
+
return {
|
|
54
|
+
success: true,
|
|
55
|
+
blobUrl: csvResult.blobUrl!,
|
|
56
|
+
fileName: csvResult.fileName!,
|
|
57
|
+
};
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error(csvResult.error || 'CSV格式处理失败');
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Excel内容处理的公共方法
|
|
65
|
+
* @param content Excel内容
|
|
66
|
+
* @param mimeType MIME类型
|
|
67
|
+
* @param filename 文件名
|
|
68
|
+
* @returns 处理结果
|
|
69
|
+
*/
|
|
70
|
+
export const processExcelContent = (content: string, mimeType?: string, filename: string = '预览文件.xlsx') => {
|
|
71
|
+
const type = mimeType || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
72
|
+
return {
|
|
73
|
+
success: true,
|
|
74
|
+
blobUrl: `data:${type};base64,${content}`,
|
|
75
|
+
fileName: filename,
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 处理文件数据的统一方法
|
|
81
|
+
* @param data 文件数据
|
|
82
|
+
* @param isRawMode 是否为原始模式
|
|
83
|
+
* @returns 处理结果
|
|
84
|
+
*/
|
|
85
|
+
export const handleFileData = async (data: any, isRawMode: boolean = false) => {
|
|
86
|
+
// 原始模式:直接处理文件内容
|
|
87
|
+
if (isRawMode) {
|
|
88
|
+
if (typeof data === 'string') {
|
|
89
|
+
if (isCsvContent(data)) {
|
|
90
|
+
return await processCsvContent(data);
|
|
91
|
+
} else {
|
|
92
|
+
return processExcelContent(data);
|
|
93
|
+
}
|
|
94
|
+
} else if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
|
|
95
|
+
const blob = new Blob([data], {
|
|
96
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
success: true,
|
|
100
|
+
blobUrl: URL.createObjectURL(blob),
|
|
101
|
+
fileName: '预览文件.xlsx',
|
|
102
|
+
};
|
|
103
|
+
} else {
|
|
104
|
+
throw new Error('不支持的原始文件格式');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 标准模式:处理结构化数据
|
|
109
|
+
if (data.Content && data.Type) {
|
|
110
|
+
if (isCsvType(data.Type, data.FileName)) {
|
|
111
|
+
return await processCsvContent(data.Content, data.FileName || 'preview.csv');
|
|
112
|
+
} else if (isExcelType(data.Type, data.FileName)) {
|
|
113
|
+
return processExcelContent(data.Content, data.Type, data.FileName || '预览文件.xlsx');
|
|
114
|
+
} else {
|
|
115
|
+
return processExcelContent(data.Content);
|
|
116
|
+
}
|
|
117
|
+
} else if (data.url) {
|
|
118
|
+
return {
|
|
119
|
+
success: true,
|
|
120
|
+
blobUrl: data.url,
|
|
121
|
+
fileName: data.fileName || '预览文件.xlsx',
|
|
122
|
+
};
|
|
123
|
+
} else if (typeof data === 'string') {
|
|
124
|
+
return await processCsvContent(data);
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error('不支持的文件格式');
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 加载预览文件
|
|
132
|
+
* @param previewUrl 预览URL配置
|
|
133
|
+
* @param excelCtrl Excel控制器
|
|
134
|
+
* @returns 预览文件处理结果
|
|
135
|
+
*/
|
|
136
|
+
export const loadPreviewFile = async (
|
|
137
|
+
previewUrl: IUrlInfo,
|
|
138
|
+
excelCtrl: any,
|
|
139
|
+
): Promise<{ success: boolean; blobUrl?: string; fileName?: string }> => {
|
|
140
|
+
if (!previewUrl || !excelCtrl) {
|
|
141
|
+
message.error('预览URL或Excel控制器未配置');
|
|
142
|
+
return { success: false };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
let result: ApiResponse<AnyData> | null = null;
|
|
147
|
+
|
|
148
|
+
// 根据请求方法选择不同的处理方式
|
|
149
|
+
if (previewUrl.method === 'GET') {
|
|
150
|
+
// 使用 httpGet 方法处理 GET 请求
|
|
151
|
+
const getUrl: IUrlInfo = {
|
|
152
|
+
...previewUrl,
|
|
153
|
+
method: 'GET' as const,
|
|
154
|
+
api: previewUrl.api || excelCtrl.page.api,
|
|
155
|
+
authorize: previewUrl.authorize ?? excelCtrl.page.authorize,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
result = await httpGet(getUrl);
|
|
159
|
+
} else {
|
|
160
|
+
// 使用 doQuery 处理 POST 请求
|
|
161
|
+
const queryParams = previewUrl.params;
|
|
162
|
+
result = await doQuery(excelCtrl, {
|
|
163
|
+
url: previewUrl,
|
|
164
|
+
urlKey: 'preview',
|
|
165
|
+
params: queryParams,
|
|
166
|
+
hideErrorToast: true,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 原始模式下,result 就是原始数据,不是 ApiResponse 格式
|
|
171
|
+
if (previewUrl.raw) {
|
|
172
|
+
// 原始模式:直接处理返回的数据
|
|
173
|
+
return await handleFileData(result, true);
|
|
174
|
+
} else {
|
|
175
|
+
// 标准模式:检查 ApiResponse 格式
|
|
176
|
+
if (result?.status === ResStatus.SUCCESS && result.data) {
|
|
177
|
+
const data = result.data;
|
|
178
|
+
// 处理返回的文件数据
|
|
179
|
+
return await handleFileData(data, false);
|
|
180
|
+
} else {
|
|
181
|
+
throw new Error(result?.msg || '文件加载失败');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} catch (error: any) {
|
|
185
|
+
console.error('预览文件加载错误:', error);
|
|
186
|
+
message.error('文件加载失败:' + (error?.message || '未知错误'));
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
};
|
package/src/utils/file-upload.ts
CHANGED
|
@@ -148,7 +148,6 @@ export class AsyncUploader {
|
|
|
148
148
|
// 等待所有上传任务完成
|
|
149
149
|
await Promise.all(activeUploads);
|
|
150
150
|
} catch (error) {
|
|
151
|
-
console.error('上传失败:', error);
|
|
152
151
|
fileList.forEach((file) => {
|
|
153
152
|
file.status = UploadStatus.Error;
|
|
154
153
|
file.error = error instanceof Error ? error : new Error('上传失败');
|
|
@@ -179,7 +178,6 @@ export class AsyncUploader {
|
|
|
179
178
|
});
|
|
180
179
|
} catch (error) {
|
|
181
180
|
file.error = error instanceof Error ? error : new Error('上传失败');
|
|
182
|
-
console.error(file.error);
|
|
183
181
|
} finally {
|
|
184
182
|
// 启动下一个上传任务
|
|
185
183
|
if (pendingFiles.length > 0) {
|