@ebiz/designer-components 0.0.56 → 0.0.57
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/dist/index.mjs +6311 -6365
- package/package.json +1 -1
- package/src/components/TdesignUpload.vue +86 -454
package/package.json
CHANGED
@@ -1,48 +1,52 @@
|
|
1
1
|
<template>
|
2
|
-
<
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
<
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
<
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
<
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
<
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
<
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
<
|
44
|
-
|
45
|
-
|
2
|
+
<div>
|
3
|
+
<t-upload v-model="computedModelValue" :accept="accept" :action="internalAction"
|
4
|
+
:allowUploadDuplicateFile="allowUploadDuplicateFile" :autoUpload="autoUpload"
|
5
|
+
:beforeUpload="handleBeforeUpload" :files="computedModelValue" :data="data" :disabled="disabled"
|
6
|
+
:draggable="draggable" :fileListDisplay="fileListDisplay" :format="format" :formatRequest="formatRequest"
|
7
|
+
:headers="headers" :isBatchUpload="isBatchUpload" :max="max" :method="method" :multiple="multiple"
|
8
|
+
:name="name" :placeholder="placeholder" :showUploadProgress="showUploadProgress" :sizeLimit="sizeLimit"
|
9
|
+
:status="status" :theme="theme" :tips="tips" :uploadAllFilesInOneRequest="uploadAllFilesInOneRequest"
|
10
|
+
:uploadButton="uploadButton" :useMockProgress="useMockProgress" :withCredentials="withCredentials"
|
11
|
+
@change="handleChange" @click="handleClick" @drag="handleDrag" @drop="handleDrop" @fail="handleFail"
|
12
|
+
@preview="handlePreview" @progress="handleProgress" @remove="handleRemove"
|
13
|
+
@select-change="handleSelectChange" @success="handleSuccess" @validate="handleValidate">
|
14
|
+
<!-- 默认插槽 -->
|
15
|
+
<slot></slot>
|
16
|
+
|
17
|
+
<!-- 文件列表项插槽 -->
|
18
|
+
<template v-if="$slots.fileListDisplay" #fileListDisplay="slotProps">
|
19
|
+
<slot name="fileListDisplay" v-bind="slotProps"></slot>
|
20
|
+
</template>
|
21
|
+
|
22
|
+
<!-- 替换上传按钮插槽 -->
|
23
|
+
<template v-if="$slots.default" #default>
|
24
|
+
<slot name="default"></slot>
|
25
|
+
</template>
|
26
|
+
|
27
|
+
<!-- 单文件已上传内容插槽 -->
|
28
|
+
<template v-if="$slots.content" #content="slotProps">
|
29
|
+
<slot name="content" v-bind="slotProps"></slot>
|
30
|
+
</template>
|
31
|
+
|
32
|
+
<!-- 文件拖拽区域内容插槽 -->
|
33
|
+
<template v-if="$slots.dragContent" #dragContent>
|
34
|
+
<slot name="dragContent"></slot>
|
35
|
+
</template>
|
36
|
+
|
37
|
+
<!-- 上传按钮内容插槽 -->
|
38
|
+
<template v-if="$slots.trigger" #trigger>
|
39
|
+
<slot name="trigger"></slot>
|
40
|
+
</template>
|
41
|
+
|
42
|
+
<!-- 上传提示文本插槽 -->
|
43
|
+
<template v-if="$slots.tips" #tips>
|
44
|
+
<slot name="tips"></slot>
|
45
|
+
</template>
|
46
|
+
</t-upload>
|
47
|
+
|
48
|
+
</div>
|
49
|
+
|
46
50
|
</template>
|
47
51
|
|
48
52
|
<script>
|
@@ -54,72 +58,14 @@ export default {
|
|
54
58
|
<script setup>
|
55
59
|
import { computed, defineProps, defineEmits, ref, onMounted, watch } from 'vue';
|
56
60
|
import { Upload as TUpload } from 'tdesign-vue-next';
|
57
|
-
import dataService from '../apiService/simpleDataService';
|
58
61
|
|
59
62
|
// 内部上传地址常量
|
60
63
|
const INTERNAL_UPLOAD_URL = '/api/file/app/td-upload';
|
61
64
|
|
62
|
-
// 内部维护的文件列表,代替直接使用props.files
|
63
|
-
const internalFiles = ref([]);
|
64
|
-
|
65
|
-
// 初始化内部文件列表
|
66
|
-
const initializeFiles = () => {
|
67
|
-
// 如果提供了files,使用它初始化
|
68
|
-
if (props.files && Array.isArray(props.files)) {
|
69
|
-
internalFiles.value = [...props.files];
|
70
|
-
}
|
71
|
-
};
|
72
|
-
|
73
|
-
// 默认的格式化响应函数
|
74
|
-
const defaultFormatResponse = (res) => {
|
75
|
-
console.log('Default formatResponse handling:', res);
|
76
|
-
|
77
|
-
// 处理不同的响应格式
|
78
|
-
if (res === null || res === undefined) {
|
79
|
-
return { url: '', error: '上传失败:未收到服务器响应' };
|
80
|
-
}
|
81
|
-
|
82
|
-
// 如果res已经是字符串(文件路径),直接使用
|
83
|
-
if (typeof res === 'string') {
|
84
|
-
return { url: res };
|
85
|
-
}
|
86
|
-
|
87
|
-
// 如果返回的就是服务器的原始响应 { code: 0, msg: '上传成功', data: '文件路径' }
|
88
|
-
// axios拦截器应该已经提取了data部分,但我们做个双重检查
|
89
|
-
if (res.code === 0 && res.data) {
|
90
|
-
return { url: typeof res.data === 'string' ? res.data : '' };
|
91
|
-
}
|
92
|
-
|
93
|
-
// 如果是自定义对象,可能已经处理过
|
94
|
-
if (res.url) {
|
95
|
-
return { url: res.url };
|
96
|
-
}
|
97
|
-
|
98
|
-
// 直接处理服务器响应的标准格式
|
99
|
-
if (typeof res === 'string') {
|
100
|
-
// 直接是文件路径字符串
|
101
|
-
return { url: res };
|
102
|
-
}
|
103
|
-
|
104
|
-
// 如果服务器直接响应了数据,没有包装
|
105
|
-
if (res && !res.code && !res.data && typeof res === 'object') {
|
106
|
-
// 尝试找到可能的URL字段
|
107
|
-
if (res.url || res.path || res.filePath || res.fileUrl) {
|
108
|
-
return { url: res.url || res.path || res.filePath || res.fileUrl };
|
109
|
-
}
|
110
|
-
}
|
111
|
-
|
112
|
-
// 处理其他可能的情况
|
113
|
-
console.warn('Unknown response format:', res);
|
114
|
-
|
115
|
-
// 无法识别的格式,返回空URL
|
116
|
-
return { url: '' };
|
117
|
-
};
|
118
|
-
|
119
65
|
const props = defineProps({
|
120
66
|
// v-model值,已上传和待上传的文件列表
|
121
67
|
modelValue: {
|
122
|
-
type: Array,
|
68
|
+
type: [Array, String],
|
123
69
|
default: () => []
|
124
70
|
},
|
125
71
|
// 接受上传的文件类型,同input标签的accept属性
|
@@ -294,399 +240,112 @@ const emit = defineEmits([
|
|
294
240
|
]);
|
295
241
|
|
296
242
|
// 当前上传进度
|
297
|
-
const
|
298
|
-
|
299
|
-
// 上传列表双向绑定
|
300
|
-
const modelValue = computed({
|
243
|
+
const computedModelValue = computed({
|
301
244
|
get() {
|
302
|
-
|
303
|
-
|
304
|
-
|
245
|
+
if (props.modelValue instanceof Array) {
|
246
|
+
return props.modelValue.map(file => {
|
247
|
+
return {
|
248
|
+
url: file
|
249
|
+
}
|
250
|
+
});
|
251
|
+
}
|
252
|
+
if (props.modelValue && props.modelValue.length > 0) {
|
253
|
+
return [
|
254
|
+
{
|
255
|
+
url: props.modelValue
|
256
|
+
}
|
257
|
+
]
|
258
|
+
} else {
|
259
|
+
return []
|
305
260
|
}
|
306
|
-
return props.modelValue;
|
307
261
|
},
|
308
262
|
set(value) {
|
309
|
-
|
310
|
-
|
311
|
-
|
263
|
+
console.log('set value:', value);
|
264
|
+
const urls = value.map(file => file.url).filter(Boolean);
|
265
|
+
if (props.multiple) {
|
266
|
+
emit('update:modelValue', urls);
|
267
|
+
} else {
|
268
|
+
emit('update:modelValue', urls[0]);
|
269
|
+
}
|
312
270
|
}
|
313
271
|
});
|
314
272
|
|
315
|
-
// 监听props.modelValue的变化,同步到internalFiles
|
316
|
-
watch(
|
317
|
-
() => props.modelValue,
|
318
|
-
(newValue) => {
|
319
|
-
if (newValue && Array.isArray(newValue) && newValue.length > 0) {
|
320
|
-
console.log('External modelValue changed, updating internal files:', newValue);
|
321
|
-
// 过滤掉可能的空值
|
322
|
-
const validFiles = newValue.filter(file => file && file.name);
|
323
|
-
if (validFiles.length > 0) {
|
324
|
-
internalFiles.value = validFiles;
|
325
|
-
}
|
326
|
-
}
|
327
|
-
},
|
328
|
-
{ deep: true }
|
329
|
-
);
|
330
273
|
|
331
274
|
// 内部上传地址,如果提供了action且未启用内部上传则使用action,否则使用内部默认地址
|
332
275
|
const internalAction = computed(() => {
|
333
276
|
return (props.action && !props.useInternalUpload) ? props.action : INTERNAL_UPLOAD_URL;
|
334
277
|
});
|
335
278
|
|
336
|
-
// 自定义上传方法,使用dataService进行上传
|
337
|
-
const customRequestMethod = (options) => {
|
338
|
-
console.log('Upload options:', options);
|
339
|
-
|
340
|
-
try {
|
341
|
-
// 解构选项,获取需要的属性
|
342
|
-
const { raw, onProgress, onSuccess, onError, data, method, name } = options || {};
|
343
|
-
|
344
|
-
// 创建FormData
|
345
|
-
const formData = new FormData();
|
346
|
-
|
347
|
-
// 创建一个执行上传的函数
|
348
|
-
const executeUpload = (fileToUpload) => {
|
349
|
-
console.log('Uploading file:', fileToUpload.name, fileToUpload.size);
|
350
|
-
formData.append('file', fileToUpload);
|
351
|
-
|
352
|
-
// 添加额外数据
|
353
|
-
if (data) {
|
354
|
-
Object.keys(data).forEach(key => {
|
355
|
-
formData.append(key, data[key]);
|
356
|
-
});
|
357
|
-
}
|
358
|
-
|
359
|
-
// 定义安全的进度回调
|
360
|
-
const safeProgressCallback = (progress) => {
|
361
|
-
uploadProgress.value = progress;
|
362
|
-
if (typeof onProgress === 'function') {
|
363
|
-
onProgress({ percent: progress });
|
364
|
-
}
|
365
|
-
};
|
366
|
-
|
367
|
-
// 使用dataService上传文件
|
368
|
-
return dataService
|
369
|
-
.upload(INTERNAL_UPLOAD_URL, formData, safeProgressCallback)
|
370
|
-
.then(response => {
|
371
|
-
console.log('Upload response:', response);
|
372
|
-
|
373
|
-
// 在组件内部处理响应数据
|
374
|
-
let formattedResponse;
|
375
|
-
|
376
|
-
try {
|
377
|
-
// 使用内部处理逻辑,不依赖props.formatResponse
|
378
|
-
formattedResponse = defaultFormatResponse(response);
|
379
|
-
} catch (error) {
|
380
|
-
console.error('Error formatting response:', error);
|
381
|
-
formattedResponse = { url: '', error: error.message };
|
382
|
-
}
|
383
|
-
|
384
|
-
// 确保格式化后的响应包含文件基本信息
|
385
|
-
const fileObject = {
|
386
|
-
...formattedResponse,
|
387
|
-
name: fileToUpload.name,
|
388
|
-
size: fileToUpload.size,
|
389
|
-
type: fileToUpload.type,
|
390
|
-
status: 'success',
|
391
|
-
raw: fileToUpload, // 保存原始文件对象
|
392
|
-
lastModified: fileToUpload.lastModified
|
393
|
-
};
|
394
|
-
|
395
|
-
// 构建TDesign期望的成功响应对象
|
396
|
-
const successResponse = {
|
397
|
-
file: fileObject, // 文件对象
|
398
|
-
fileList: [fileObject], // 文件列表(可能包含多个文件)
|
399
|
-
response: {
|
400
|
-
url: fileObject.url, // 必需的URL字段
|
401
|
-
files: [fileObject], // 必需的files字段
|
402
|
-
data: response // 保留原始响应
|
403
|
-
},
|
404
|
-
e: { status: 'success' }, // 事件对象
|
405
|
-
status: 'success' // 必须的状态字段,只能是success或fail
|
406
|
-
};
|
407
|
-
|
408
|
-
console.log('Final formatted response:', successResponse);
|
409
|
-
|
410
|
-
// 安全地调用成功回调
|
411
|
-
if (typeof onSuccess === 'function') {
|
412
|
-
onSuccess(successResponse);
|
413
|
-
}
|
414
|
-
return successResponse;
|
415
|
-
})
|
416
|
-
.catch(error => {
|
417
|
-
console.error('Upload failed:', error);
|
418
|
-
|
419
|
-
// 构建错误响应对象
|
420
|
-
const failResponse = {
|
421
|
-
error: error,
|
422
|
-
status: 'fail', // 必须的状态字段,值为fail
|
423
|
-
e: { status: 'fail' }
|
424
|
-
};
|
425
|
-
|
426
|
-
// 安全地调用错误回调
|
427
|
-
if (typeof onError === 'function') {
|
428
|
-
onError(failResponse);
|
429
|
-
}
|
430
|
-
return Promise.reject(failResponse);
|
431
|
-
});
|
432
|
-
};
|
433
|
-
|
434
|
-
// 尝试获取真实的文件对象
|
435
|
-
// 1. 首先检查raw是否直接是File对象
|
436
|
-
if (raw instanceof File) {
|
437
|
-
console.log('Using raw as File directly');
|
438
|
-
return executeUpload(raw);
|
439
|
-
}
|
440
|
-
|
441
|
-
// 2. 直接从options本身获取信息创建文件
|
442
|
-
if (options && options.name && options.type && options.size) {
|
443
|
-
// 我们找到了文件信息,但没有实际内容
|
444
|
-
// 我们需要使用FileReader获取实际文件或创建一个伪文件
|
445
|
-
console.log('Creating file from options properties');
|
446
|
-
|
447
|
-
// 由于我们无法获取真实文件内容,创建一个伪文件
|
448
|
-
// 注意:这在实际上传时可能会失败,因为没有真实内容
|
449
|
-
const pseudoFileContent = new Blob([`Pseudo file content for ${options.name}`], { type: options.type });
|
450
|
-
const pseudoFile = new File([pseudoFileContent], options.name, {
|
451
|
-
type: options.type,
|
452
|
-
lastModified: options.lastModified || Date.now()
|
453
|
-
});
|
454
|
-
|
455
|
-
// 创建一个隐藏的文件输入,让用户重新选择文件
|
456
|
-
// 这是一个备选方案
|
457
|
-
const fileInput = document.createElement('input');
|
458
|
-
fileInput.type = 'file';
|
459
|
-
fileInput.style.display = 'none';
|
460
|
-
fileInput.accept = options.type;
|
461
|
-
document.body.appendChild(fileInput);
|
462
|
-
|
463
|
-
// 提示用户选择同一个文件
|
464
|
-
console.log('Please select the same file again');
|
465
|
-
alert(`上传出错:TDesign上传组件无法获取文件内容。请在出现的文件选择框中重新选择"${options.name}"文件。`);
|
466
|
-
|
467
|
-
return new Promise((resolve, reject) => {
|
468
|
-
fileInput.onchange = (e) => {
|
469
|
-
const selectedFile = e.target.files[0];
|
470
|
-
if (selectedFile) {
|
471
|
-
console.log('User selected file:', selectedFile.name);
|
472
|
-
document.body.removeChild(fileInput);
|
473
|
-
resolve(executeUpload(selectedFile));
|
474
|
-
} else {
|
475
|
-
document.body.removeChild(fileInput);
|
476
|
-
const failResponse = {
|
477
|
-
error: new Error('No file selected'),
|
478
|
-
status: 'fail',
|
479
|
-
e: { status: 'fail' }
|
480
|
-
};
|
481
|
-
reject(failResponse);
|
482
|
-
}
|
483
|
-
};
|
484
|
-
|
485
|
-
fileInput.onerror = (error) => {
|
486
|
-
document.body.removeChild(fileInput);
|
487
|
-
const failResponse = {
|
488
|
-
error: error,
|
489
|
-
status: 'fail',
|
490
|
-
e: { status: 'fail' }
|
491
|
-
};
|
492
|
-
reject(failResponse);
|
493
|
-
};
|
494
|
-
|
495
|
-
// 触发文件选择
|
496
|
-
fileInput.click();
|
497
|
-
});
|
498
|
-
}
|
499
|
-
|
500
|
-
console.error('Cannot find valid file information', options);
|
501
|
-
if (typeof onError === 'function') {
|
502
|
-
const failResponse = {
|
503
|
-
error: new Error('No valid file information found'),
|
504
|
-
status: 'fail',
|
505
|
-
e: { status: 'fail' }
|
506
|
-
};
|
507
|
-
onError(failResponse);
|
508
|
-
}
|
509
|
-
return Promise.reject({
|
510
|
-
error: new Error('No valid file information found'),
|
511
|
-
status: 'fail',
|
512
|
-
e: { status: 'fail' }
|
513
|
-
});
|
514
|
-
} catch (err) {
|
515
|
-
console.error('Upload error in customRequestMethod:', err);
|
516
|
-
return Promise.reject({
|
517
|
-
error: err,
|
518
|
-
status: 'fail',
|
519
|
-
e: { status: 'fail' }
|
520
|
-
});
|
521
|
-
}
|
522
|
-
};
|
523
|
-
|
524
279
|
// 上传前钩子,如果设置了beforeUpload则先执行
|
525
280
|
const handleBeforeUpload = (file, options) => {
|
526
|
-
|
527
|
-
|
528
|
-
}
|
529
|
-
return true;
|
281
|
+
console.log('handleBeforeUpload:', file, options);
|
282
|
+
emit('beforeUpload', file, options);
|
530
283
|
};
|
531
284
|
|
532
|
-
// 监听internalFiles的变化,记录调试信息
|
533
|
-
watch(
|
534
|
-
internalFiles,
|
535
|
-
(newFiles) => {
|
536
|
-
console.log('Internal files changed:', newFiles);
|
537
|
-
},
|
538
|
-
{ deep: true }
|
539
|
-
);
|
540
|
-
|
541
285
|
// 文件状态变化事件
|
542
286
|
const handleChange = (value, context) => {
|
543
|
-
console.log('
|
544
|
-
|
545
|
-
// 如果是上传成功,确保文件被添加到内部列表
|
546
|
-
if (context && context.file && context.file.status === 'success') {
|
547
|
-
const successFile = context.file;
|
548
|
-
|
549
|
-
// 检查是否已存在于内部文件列表
|
550
|
-
const fileExists = internalFiles.value.some(
|
551
|
-
file => file.name === successFile.name && file.size === successFile.size
|
552
|
-
);
|
553
|
-
|
554
|
-
if (!fileExists) {
|
555
|
-
console.log('Adding successful file from change event:', successFile);
|
556
|
-
internalFiles.value = [...internalFiles.value, successFile];
|
557
|
-
|
558
|
-
// 更新v-model和files属性
|
559
|
-
emit('update:modelValue', internalFiles.value);
|
560
|
-
emit('update:files', internalFiles.value);
|
561
|
-
}
|
562
|
-
}
|
563
|
-
|
287
|
+
console.log('handleChange:', value, context);
|
564
288
|
emit('change', value, context);
|
565
289
|
};
|
566
290
|
|
567
291
|
// 点击事件
|
568
292
|
const handleClick = (context) => {
|
293
|
+
console.log('handleClick:', context);
|
569
294
|
emit('click', context);
|
570
295
|
};
|
571
296
|
|
572
297
|
// 拖拽事件
|
573
298
|
const handleDrag = (context) => {
|
299
|
+
console.log('handleDrag:', context);
|
574
300
|
emit('drag', context);
|
575
301
|
};
|
576
302
|
|
577
303
|
// 文件拖放事件
|
578
304
|
const handleDrop = (context) => {
|
305
|
+
console.log('handleDrop:', context);
|
579
306
|
emit('drop', context);
|
580
307
|
};
|
581
308
|
|
582
309
|
// 上传失败事件
|
583
310
|
const handleFail = (options) => {
|
311
|
+
console.log('handleFail:', options);
|
584
312
|
emit('fail', options);
|
585
313
|
};
|
586
314
|
|
587
315
|
// 点击预览事件
|
588
316
|
const handlePreview = (options) => {
|
317
|
+
console.log('handlePreview:', options);
|
589
318
|
emit('preview', options);
|
590
319
|
};
|
591
320
|
|
592
321
|
// 上传进度事件
|
593
322
|
const handleProgress = (options) => {
|
323
|
+
console.log('handleProgress:', options);
|
594
324
|
emit('progress', options);
|
595
325
|
};
|
596
326
|
|
597
327
|
// 移除文件事件
|
598
328
|
const handleRemove = (context) => {
|
599
|
-
|
600
|
-
// 从内部文件列表中移除文件
|
601
|
-
const removedFile = context.file;
|
602
|
-
|
603
|
-
// 根据name和size过滤掉要删除的文件
|
604
|
-
internalFiles.value = internalFiles.value.filter(
|
605
|
-
file => !(file.name === removedFile.name && file.size === removedFile.size)
|
606
|
-
);
|
607
|
-
|
608
|
-
// 同时更新v-model绑定的值,保持一致性
|
609
|
-
emit('update:modelValue', internalFiles.value);
|
610
|
-
|
611
|
-
// 更新files属性,支持v-model:files双向绑定
|
612
|
-
emit('update:files', internalFiles.value);
|
613
|
-
}
|
614
|
-
|
615
|
-
// 发出原始移除事件
|
329
|
+
console.log('handleRemove:', context);
|
616
330
|
emit('remove', context);
|
617
331
|
};
|
618
332
|
|
619
333
|
// 选择文件变化事件
|
620
334
|
const handleSelectChange = (files, context) => {
|
335
|
+
console.log('handleSelectChange:', files, context);
|
621
336
|
emit('select-change', files, context);
|
622
337
|
};
|
623
338
|
|
624
339
|
// 上传成功事件
|
625
340
|
const handleSuccess = (context) => {
|
626
|
-
console.log('
|
627
|
-
|
628
|
-
// 将上传成功的文件添加到文件列表中
|
629
|
-
// 首先检查文件是否已经在列表中
|
630
|
-
if (context && context.file) {
|
631
|
-
// 获取有效的URL
|
632
|
-
let fileUrl = '';
|
633
|
-
if (context.file.url) {
|
634
|
-
fileUrl = context.file.url;
|
635
|
-
} else if (context.response && context.response.url) {
|
636
|
-
fileUrl = context.response.url;
|
637
|
-
} else if (context.response && context.response.data && typeof context.response.data === 'string') {
|
638
|
-
fileUrl = context.response.data;
|
639
|
-
}
|
640
|
-
|
641
|
-
const newFile = {
|
642
|
-
...context.file,
|
643
|
-
url: fileUrl, // 确保有URL
|
644
|
-
status: 'success', // 设置状态为成功
|
645
|
-
response: context.response // 保留响应
|
646
|
-
};
|
647
|
-
|
648
|
-
console.log('Adding file to internal files:', newFile);
|
649
|
-
|
650
|
-
// 创建新的文件列表副本,以便进行修改
|
651
|
-
const currentFiles = [...internalFiles.value];
|
652
|
-
|
653
|
-
// 检查文件是否已存在(基于name和size)
|
654
|
-
const fileExists = currentFiles.some(
|
655
|
-
file => file.name === newFile.name && file.size === newFile.size
|
656
|
-
);
|
657
|
-
|
658
|
-
// 如果文件不存在于列表中,则添加它
|
659
|
-
if (!fileExists) {
|
660
|
-
currentFiles.push(newFile);
|
661
|
-
// 更新内部文件列表
|
662
|
-
internalFiles.value = currentFiles;
|
663
|
-
} else {
|
664
|
-
// 如果文件已存在,更新其状态和URL
|
665
|
-
internalFiles.value = currentFiles.map(file => {
|
666
|
-
if (file.name === newFile.name && file.size === newFile.size) {
|
667
|
-
return { ...file, ...newFile };
|
668
|
-
}
|
669
|
-
return file;
|
670
|
-
});
|
671
|
-
}
|
672
|
-
|
673
|
-
console.log('Updated internal files:', internalFiles.value);
|
674
|
-
|
675
|
-
// 同时更新v-model绑定的值,保持一致性
|
676
|
-
emit('update:modelValue', internalFiles.value);
|
677
|
-
|
678
|
-
// 更新files属性,支持v-model:files双向绑定
|
679
|
-
emit('update:files', internalFiles.value);
|
680
|
-
} else {
|
681
|
-
console.warn('Missing file in success context:', context);
|
682
|
-
}
|
683
|
-
|
341
|
+
console.log('handleSuccess:', context);
|
684
342
|
// 发出原始成功事件
|
685
343
|
emit('success', context);
|
686
344
|
};
|
687
345
|
|
688
346
|
// 校验事件
|
689
347
|
const handleValidate = (context) => {
|
348
|
+
console.log('handleValidate:', context);
|
690
349
|
emit('validate', context);
|
691
350
|
};
|
692
351
|
|
@@ -709,23 +368,7 @@ const addUploadedFile = (file) => {
|
|
709
368
|
lastModified: file.lastModified || new Date().getTime(),
|
710
369
|
...file
|
711
370
|
};
|
712
|
-
|
713
|
-
// 检查文件是否已存在
|
714
|
-
const fileExists = internalFiles.value.some(
|
715
|
-
f => f.name === fileObject.name && f.url === fileObject.url
|
716
|
-
);
|
717
|
-
|
718
|
-
if (!fileExists) {
|
719
|
-
// 更新内部文件列表
|
720
|
-
internalFiles.value = [...internalFiles.value, fileObject];
|
721
|
-
|
722
|
-
// 同时更新v-model绑定的值,保持一致性
|
723
|
-
emit('update:modelValue', internalFiles.value);
|
724
|
-
|
725
|
-
// 更新files属性,支持v-model:files双向绑定
|
726
|
-
emit('update:files', internalFiles.value);
|
727
|
-
return true;
|
728
|
-
}
|
371
|
+
computedModelValue.value = [...computedModelValue.value, fileObject];
|
729
372
|
|
730
373
|
return false;
|
731
374
|
};
|
@@ -733,23 +376,12 @@ const addUploadedFile = (file) => {
|
|
733
376
|
// 导出组件方法供外部使用
|
734
377
|
defineExpose({
|
735
378
|
addUploadedFile,
|
736
|
-
// 导出内部文件列表,允许外部读取
|
737
|
-
getFiles: () => internalFiles.value
|
738
379
|
});
|
739
380
|
|
740
381
|
// 组件挂载时初始化文件列表
|
741
382
|
onMounted(() => {
|
742
|
-
initializeFiles();
|
743
383
|
});
|
744
384
|
|
745
|
-
// 监听files的变化,更新内部文件列表
|
746
|
-
watch(
|
747
|
-
() => props.files,
|
748
|
-
() => {
|
749
|
-
initializeFiles();
|
750
|
-
},
|
751
|
-
{ deep: true }
|
752
|
-
);
|
753
385
|
</script>
|
754
386
|
|
755
387
|
<style lang="less" scoped>
|