xydata-tools 1.1.22 → 1.1.23
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.
|
@@ -6,19 +6,36 @@
|
|
|
6
6
|
<view v-if="actualButtonPosition === 'vertical'" :class="['vertical-layout']">
|
|
7
7
|
<!-- 图片区域 -->
|
|
8
8
|
<view v-if="enableImage && showFileList" class="media-section">
|
|
9
|
-
<shmily-drag-media
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
<shmily-drag-media
|
|
10
|
+
v-if="imageFileList.length > 0"
|
|
11
|
+
v-model="imageUrls"
|
|
12
|
+
:number="imageLimit"
|
|
13
|
+
:cols="cols"
|
|
14
|
+
:imageWidth="itemWidth"
|
|
15
|
+
:padding="10"
|
|
16
|
+
:borderRadius="itemBorderRadius"
|
|
17
|
+
:draggable="draggable"
|
|
18
|
+
moveType="image"
|
|
19
|
+
@input="handleImageDragChange"
|
|
20
|
+
>
|
|
12
21
|
</shmily-drag-media>
|
|
13
22
|
</view>
|
|
14
23
|
|
|
15
24
|
<!-- 视频区域 -->
|
|
16
|
-
<view v-if="enableVideo && showFileList" class="media-section"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
:
|
|
21
|
-
|
|
25
|
+
<view v-if="enableVideo && showFileList" class="media-section" :style="{ marginTop: enableImage && videoFileList.length > 0 ? '20rpx' : '0' }">
|
|
26
|
+
<shmily-drag-media
|
|
27
|
+
v-if="videoFileList.length > 0"
|
|
28
|
+
v-model="videoUrls"
|
|
29
|
+
:number="videoLimit"
|
|
30
|
+
:cols="cols"
|
|
31
|
+
:imageWidth="itemWidth"
|
|
32
|
+
:padding="10"
|
|
33
|
+
:borderRadius="itemBorderRadius"
|
|
34
|
+
:draggable="draggable"
|
|
35
|
+
moveType="video"
|
|
36
|
+
@input="handleVideoDragChange"
|
|
37
|
+
@videoClick="handleVideoItemClick"
|
|
38
|
+
>
|
|
22
39
|
</shmily-drag-media>
|
|
23
40
|
</view>
|
|
24
41
|
|
|
@@ -26,10 +43,13 @@
|
|
|
26
43
|
<view class="upload-buttons-row">
|
|
27
44
|
<!-- 图片上传按钮 -->
|
|
28
45
|
<view v-if="enableImage" class="upload-button-wrapper">
|
|
29
|
-
<slot name="image-upload-button" :select="selectAndUploadImage" :limit="imageLimit"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
<slot name="image-upload-button" :select="selectAndUploadImage" :limit="imageLimit" :count="imageFileList.length">
|
|
47
|
+
<view
|
|
48
|
+
class="upload-btn-vertical"
|
|
49
|
+
:style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
50
|
+
v-if="imageFileList.length < imageLimit"
|
|
51
|
+
@click="selectAndUploadImage"
|
|
52
|
+
>
|
|
33
53
|
<image :src="imageUploadIcon" class="upload-icon"></image>
|
|
34
54
|
<view class="upload-text">{{ imageButtonTitle }}</view>
|
|
35
55
|
</view>
|
|
@@ -38,10 +58,13 @@
|
|
|
38
58
|
|
|
39
59
|
<!-- 视频上传按钮 -->
|
|
40
60
|
<view v-if="enableVideo" class="upload-button-wrapper">
|
|
41
|
-
<slot name="video-upload-button" :select="selectAndUploadVideo" :limit="videoLimit"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
<slot name="video-upload-button" :select="selectAndUploadVideo" :limit="videoLimit" :count="videoFileList.length">
|
|
62
|
+
<view
|
|
63
|
+
class="upload-btn-vertical"
|
|
64
|
+
:style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
65
|
+
v-if="videoFileList.length < videoLimit"
|
|
66
|
+
@click="selectAndUploadVideo"
|
|
67
|
+
>
|
|
45
68
|
<image :src="videoUploadIcon" class="upload-icon"></image>
|
|
46
69
|
<view class="upload-text">{{ videoButtonTitle }}</view>
|
|
47
70
|
</view>
|
|
@@ -53,36 +76,51 @@
|
|
|
53
76
|
<!-- 水平布局:上传按钮跟随媒体(仅单一媒体类型时使用) -->
|
|
54
77
|
<view v-else class="horizontal-layout">
|
|
55
78
|
<!-- 图片水平布局 -->
|
|
56
|
-
<shmily-drag-media
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
79
|
+
<shmily-drag-media
|
|
80
|
+
v-if="enableImage && !enableVideo && showFileList"
|
|
81
|
+
v-model="imageUrls"
|
|
82
|
+
:number="imageLimit"
|
|
83
|
+
:cols="cols"
|
|
84
|
+
:imageWidth="itemWidth"
|
|
85
|
+
:padding="10"
|
|
86
|
+
:borderRadius="itemBorderRadius"
|
|
87
|
+
:align="align"
|
|
88
|
+
:draggable="draggable"
|
|
89
|
+
:enableAddButton="true"
|
|
90
|
+
moveType="image"
|
|
91
|
+
@input="handleImageDragChange"
|
|
92
|
+
>
|
|
60
93
|
<template #add-button>
|
|
61
|
-
<slot name="image-upload-button" :select="selectAndUploadImage" :limit="imageLimit"
|
|
62
|
-
:count="imageFileList.length">
|
|
94
|
+
<slot name="image-upload-button" :select="selectAndUploadImage" :limit="imageLimit" :count="imageFileList.length">
|
|
63
95
|
<view class="drag-upload-btn" @click="selectAndUploadImage">
|
|
64
|
-
<image :src="imageUploadIcon" class="upload-icon"
|
|
65
|
-
|
|
66
|
-
<view class="upload-text" :style="dragTextStyle">{{ imageButtonTitle }}
|
|
67
|
-
</view>
|
|
96
|
+
<image :src="imageUploadIcon" class="upload-icon" :style="dragIconStyle"></image>
|
|
97
|
+
<view class="upload-text" :style="dragTextStyle">{{ imageButtonTitle }} </view>
|
|
68
98
|
</view>
|
|
69
99
|
</slot>
|
|
70
100
|
</template>
|
|
71
101
|
</shmily-drag-media>
|
|
72
102
|
|
|
73
103
|
<!-- 视频水平布局 -->
|
|
74
|
-
<shmily-drag-media
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
104
|
+
<shmily-drag-media
|
|
105
|
+
v-else-if="enableVideo && !enableImage && showFileList"
|
|
106
|
+
v-model="videoUrls"
|
|
107
|
+
:number="videoLimit"
|
|
108
|
+
:cols="cols"
|
|
109
|
+
:imageWidth="itemWidth"
|
|
110
|
+
:padding="10"
|
|
111
|
+
:borderRadius="itemBorderRadius"
|
|
112
|
+
:align="align"
|
|
113
|
+
:draggable="draggable"
|
|
114
|
+
:enableAddButton="true"
|
|
115
|
+
moveType="video"
|
|
116
|
+
@input="handleVideoDragChange"
|
|
117
|
+
@videoClick="handleVideoItemClick"
|
|
118
|
+
>
|
|
78
119
|
<template #add-button>
|
|
79
|
-
<slot name="video-upload-button" :select="selectAndUploadVideo" :limit="videoLimit"
|
|
80
|
-
:count="videoFileList.length">
|
|
120
|
+
<slot name="video-upload-button" :select="selectAndUploadVideo" :limit="videoLimit" :count="videoFileList.length">
|
|
81
121
|
<view class="drag-upload-btn" @click="selectAndUploadVideo">
|
|
82
|
-
<image :src="videoUploadIcon" class="upload-icon"
|
|
83
|
-
|
|
84
|
-
<view class="upload-text" :style="dragTextStyle">{{ videoButtonTitle }}
|
|
85
|
-
</view>
|
|
122
|
+
<image :src="videoUploadIcon" class="upload-icon" :style="dragIconStyle"></image>
|
|
123
|
+
<view class="upload-text" :style="dragTextStyle">{{ videoButtonTitle }} </view>
|
|
86
124
|
</view>
|
|
87
125
|
</slot>
|
|
88
126
|
</template>
|
|
@@ -92,32 +130,43 @@
|
|
|
92
130
|
|
|
93
131
|
<!-- ==================== 只读模式(混合展示图片和视频) ==================== -->
|
|
94
132
|
<block v-else-if="allFileList.length && showFileList">
|
|
95
|
-
<view class="readonly-grid" :class="{ 'align-right': align === 'right' && itemWidth > 0 }"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
133
|
+
<view class="readonly-grid" :class="{ 'align-right': align === 'right' && itemWidth > 0 }" :style="readonlyGridStyle">
|
|
134
|
+
<view
|
|
135
|
+
v-for="(file, i) in readonlyDisplayList"
|
|
136
|
+
:key="file.id || file.url || i"
|
|
137
|
+
:style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
138
|
+
:class="['readonly-grid-item', { 'placeholder-item': file.type === 'placeholder' }, { 'filter-avatar': file.type !== 'placeholder' && isLastRealItem(i) }]"
|
|
139
|
+
:data-count="file.type !== 'placeholder' && isLastRealItem(i) ? '+' + (allFileList.length - maxShowCount) : ''"
|
|
140
|
+
@click="handleReadonlyItemClick(i, file)"
|
|
141
|
+
>
|
|
105
142
|
<!-- 占位元素(不显示任何内容) -->
|
|
106
143
|
<view v-if="file.type === 'placeholder'" class="placeholder-content"></view>
|
|
107
144
|
|
|
108
145
|
<!-- 图片 -->
|
|
109
146
|
<template v-else>
|
|
110
|
-
<image
|
|
111
|
-
|
|
112
|
-
|
|
147
|
+
<image
|
|
148
|
+
v-if="file.type === 'image'"
|
|
149
|
+
:src="lazyLoadImageSrcs[i]"
|
|
150
|
+
mode="aspectFill"
|
|
151
|
+
:style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
152
|
+
:id="componentId + '-imgview-' + i"
|
|
153
|
+
@load="onMediaLoad('readonly-' + i)"
|
|
154
|
+
@error="onMediaError('readonly-' + i)"
|
|
155
|
+
>
|
|
113
156
|
</image>
|
|
114
157
|
|
|
115
158
|
<!-- 视频 -->
|
|
116
|
-
<video
|
|
117
|
-
|
|
159
|
+
<video
|
|
160
|
+
v-else-if="file.type === 'video'"
|
|
161
|
+
:id="'readonlyVideo' + i"
|
|
162
|
+
class="readonly-video"
|
|
163
|
+
:src="file.url"
|
|
164
|
+
:controls="false"
|
|
165
|
+
:show-center-play-btn="false"
|
|
118
166
|
:style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
119
|
-
@loadedmetadata="onMediaLoad('readonly-' + i)"
|
|
120
|
-
|
|
167
|
+
@loadedmetadata="onMediaLoad('readonly-' + i)"
|
|
168
|
+
@error="onMediaError('readonly-' + i)"
|
|
169
|
+
></video>
|
|
121
170
|
|
|
122
171
|
<!-- 视频播放图标覆盖层 -->
|
|
123
172
|
<view v-if="file.type === 'video'" class="video-play-overlay">
|
|
@@ -134,8 +183,7 @@
|
|
|
134
183
|
</block>
|
|
135
184
|
|
|
136
185
|
<!-- ==================== 自定义弹窗展示所有媒体(从底部滑出) ==================== -->
|
|
137
|
-
<view v-if="popupVisible" class="popup-overlay" @click="closePopup" @touchmove.stop.prevent
|
|
138
|
-
:class="{ 'popup-overlay-show': popupAnimated }">
|
|
186
|
+
<view v-if="popupVisible" class="popup-overlay" @click="closePopup" @touchmove.stop.prevent :class="{ 'popup-overlay-show': popupAnimated }">
|
|
139
187
|
<view class="popup-content" @click.stop @touchmove.stop :class="{ 'popup-content-show': popupAnimated }">
|
|
140
188
|
<view class="popup-header">
|
|
141
189
|
<view class="popup-title">{{ popupTitle }}</view>
|
|
@@ -143,21 +191,30 @@
|
|
|
143
191
|
</view>
|
|
144
192
|
<scroll-view class="popup-scroll" scroll-y :show-scrollbar="false">
|
|
145
193
|
<view class="popup-grid" :style="popupGridStyle">
|
|
146
|
-
<view v-for="(file, i) in allFileList" :key="i" class="popup-grid-item"
|
|
147
|
-
@click="handlePopupItemClick(file, i)">
|
|
148
|
-
|
|
194
|
+
<view v-for="(file, i) in allFileList" :key="i" class="popup-grid-item" @click="handlePopupItemClick(file, i)">
|
|
149
195
|
<!-- 图片 -->
|
|
150
|
-
<image
|
|
151
|
-
|
|
152
|
-
|
|
196
|
+
<image
|
|
197
|
+
v-if="file.type === 'image'"
|
|
198
|
+
:src="popupLazyLoadImageSrcs[i]"
|
|
199
|
+
mode="aspectFill"
|
|
200
|
+
:style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
201
|
+
:id="componentId + '-popup-imgview-' + i"
|
|
202
|
+
@load="onMediaLoad('popup-' + i)"
|
|
203
|
+
@error="onMediaError('popup-' + i)"
|
|
204
|
+
>
|
|
153
205
|
</image>
|
|
154
206
|
|
|
155
207
|
<!-- 视频 -->
|
|
156
|
-
<video
|
|
157
|
-
|
|
208
|
+
<video
|
|
209
|
+
v-else-if="file.type === 'video'"
|
|
210
|
+
class="popup-video"
|
|
211
|
+
:src="file.url"
|
|
212
|
+
:controls="false"
|
|
213
|
+
:show-center-play-btn="false"
|
|
158
214
|
:style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
159
|
-
@loadedmetadata="onMediaLoad('popup-' + i)"
|
|
160
|
-
|
|
215
|
+
@loadedmetadata="onMediaLoad('popup-' + i)"
|
|
216
|
+
@error="onMediaError('popup-' + i)"
|
|
217
|
+
></video>
|
|
161
218
|
|
|
162
219
|
<!-- 视频播放图标 -->
|
|
163
220
|
<view v-if="file.type === 'video'" class="video-play-overlay">
|
|
@@ -175,10 +232,16 @@
|
|
|
175
232
|
</view>
|
|
176
233
|
|
|
177
234
|
<!-- 专门用于全屏预览的 video,隐藏在视图外 -->
|
|
178
|
-
<video
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
235
|
+
<video
|
|
236
|
+
v-if="enableVideo"
|
|
237
|
+
id="fullscreenPreviewVideo"
|
|
238
|
+
class="fullscreen-preview-video"
|
|
239
|
+
:src="fullscreenVideoSrc"
|
|
240
|
+
:controls="true"
|
|
241
|
+
:show-center-play-btn="true"
|
|
242
|
+
object-fit="contain"
|
|
243
|
+
style="position: fixed; left: -9999px; top: -9999px; width: 1px; height: 1px"
|
|
244
|
+
></video>
|
|
182
245
|
</view>
|
|
183
246
|
</template>
|
|
184
247
|
|
|
@@ -189,7 +252,7 @@ import shmilyDragMedia from './shmily-drag-media.vue';
|
|
|
189
252
|
export default {
|
|
190
253
|
name: 'MediaPicker',
|
|
191
254
|
components: {
|
|
192
|
-
shmilyDragMedia
|
|
255
|
+
shmilyDragMedia
|
|
193
256
|
},
|
|
194
257
|
props: {
|
|
195
258
|
// ==================== 通用配置 ====================
|
|
@@ -338,8 +401,8 @@ export default {
|
|
|
338
401
|
observer: null,
|
|
339
402
|
componentId: null, // 组件实例的唯一ID
|
|
340
403
|
popupLazyLoadImageSrcs: [], // 用于弹窗中图片懒加载,存储进入视图的图片src
|
|
341
|
-
popupObserver: null
|
|
342
|
-
}
|
|
404
|
+
popupObserver: null // 弹窗图片懒加载观察器
|
|
405
|
+
};
|
|
343
406
|
},
|
|
344
407
|
created() {
|
|
345
408
|
this.componentId = 'mp-' + Date.now() + Math.random().toString(36).substr(2, 9);
|
|
@@ -348,65 +411,67 @@ export default {
|
|
|
348
411
|
// ==================== 媒体类型判断 ====================
|
|
349
412
|
/** 是否启用图片上传 */
|
|
350
413
|
enableImage() {
|
|
351
|
-
return ['image', 'both'].includes(this.uploadType)
|
|
414
|
+
return ['image', 'both'].includes(this.uploadType);
|
|
352
415
|
},
|
|
353
416
|
/** 是否启用视频上传 */
|
|
354
417
|
enableVideo() {
|
|
355
|
-
return ['video', 'both'].includes(this.uploadType)
|
|
418
|
+
return ['video', 'both'].includes(this.uploadType);
|
|
356
419
|
},
|
|
357
420
|
/** 实际的布局方式(两种类型时强制为 vertical) */
|
|
358
421
|
actualButtonPosition() {
|
|
359
422
|
if (this.enableImage && this.enableVideo) {
|
|
360
|
-
return 'vertical'
|
|
423
|
+
return 'vertical';
|
|
361
424
|
}
|
|
362
|
-
return this.buttonPosition
|
|
425
|
+
return this.buttonPosition;
|
|
363
426
|
},
|
|
364
427
|
|
|
365
428
|
/** 只读模式:需要显示的文件列表(右对齐时包含占位元素) */
|
|
366
429
|
readonlyDisplayList() {
|
|
367
|
-
const displayList = this.allFileList.slice(0, this.maxShowCount)
|
|
430
|
+
const displayList = this.allFileList.slice(0, this.maxShowCount);
|
|
368
431
|
|
|
369
432
|
// 如果是右对齐,需要在最后一行前面添加占位元素
|
|
370
433
|
if (this.readonly && this.align === 'right' && displayList.length > 0) {
|
|
371
|
-
const totalCount = displayList.length
|
|
372
|
-
const lastRowCount = totalCount % this.cols
|
|
434
|
+
const totalCount = displayList.length;
|
|
435
|
+
const lastRowCount = totalCount % this.cols;
|
|
373
436
|
|
|
374
437
|
// 如果最后一行不满,需要在最后一行开始位置插入占位元素
|
|
375
438
|
if (lastRowCount !== 0) {
|
|
376
|
-
const placeholderCount = this.cols - lastRowCount
|
|
377
|
-
const rows = Math.ceil(totalCount / this.cols)
|
|
378
|
-
const lastRowStartIndex = (rows - 1) * this.cols
|
|
439
|
+
const placeholderCount = this.cols - lastRowCount;
|
|
440
|
+
const rows = Math.ceil(totalCount / this.cols);
|
|
441
|
+
const lastRowStartIndex = (rows - 1) * this.cols;
|
|
379
442
|
|
|
380
443
|
// 创建占位元素
|
|
381
|
-
const placeholders = Array(placeholderCount)
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
444
|
+
const placeholders = Array(placeholderCount)
|
|
445
|
+
.fill(null)
|
|
446
|
+
.map((_, i) => ({
|
|
447
|
+
type: 'placeholder',
|
|
448
|
+
id: `placeholder-${i}`
|
|
449
|
+
}));
|
|
385
450
|
|
|
386
451
|
// 将列表分为:前面几行(满的) + 最后一行
|
|
387
|
-
const beforeLastRow = displayList.slice(0, lastRowStartIndex)
|
|
388
|
-
const lastRow = displayList.slice(lastRowStartIndex)
|
|
452
|
+
const beforeLastRow = displayList.slice(0, lastRowStartIndex);
|
|
453
|
+
const lastRow = displayList.slice(lastRowStartIndex);
|
|
389
454
|
|
|
390
455
|
// 在最后一行前面插入占位元素
|
|
391
|
-
return [...beforeLastRow, ...placeholders, ...lastRow]
|
|
456
|
+
return [...beforeLastRow, ...placeholders, ...lastRow];
|
|
392
457
|
}
|
|
393
458
|
}
|
|
394
459
|
|
|
395
|
-
return displayList
|
|
460
|
+
return displayList;
|
|
396
461
|
},
|
|
397
462
|
|
|
398
463
|
// ==================== 图标配置 ====================
|
|
399
464
|
imageUploadIcon() {
|
|
400
|
-
return this.imageButtonIcon || this.defaultImageIcon
|
|
465
|
+
return this.imageButtonIcon || this.defaultImageIcon;
|
|
401
466
|
},
|
|
402
467
|
videoUploadIcon() {
|
|
403
|
-
return this.videoButtonIcon || this.defaultVideoIcon
|
|
468
|
+
return this.videoButtonIcon || this.defaultVideoIcon;
|
|
404
469
|
},
|
|
405
470
|
|
|
406
471
|
// ==================== URL 列表 ====================
|
|
407
472
|
imageUrls: {
|
|
408
473
|
get() {
|
|
409
|
-
return this.imageFileList.map(file => file.url)
|
|
474
|
+
return this.imageFileList.map((file) => file.url);
|
|
410
475
|
},
|
|
411
476
|
set(newUrls) {
|
|
412
477
|
// setter 用于拖拽组件更新时,由 handleImageDragChange 处理
|
|
@@ -414,7 +479,7 @@ export default {
|
|
|
414
479
|
},
|
|
415
480
|
videoUrls: {
|
|
416
481
|
get() {
|
|
417
|
-
return this.videoFileList.map(file => file.url)
|
|
482
|
+
return this.videoFileList.map((file) => file.url);
|
|
418
483
|
},
|
|
419
484
|
set(newUrls) {
|
|
420
485
|
// setter 用于拖拽组件更新时,由 handleVideoDragChange 处理
|
|
@@ -422,57 +487,57 @@ export default {
|
|
|
422
487
|
},
|
|
423
488
|
/** 合并的所有媒体列表(用于只读模式和弹窗) */
|
|
424
489
|
allFileList() {
|
|
425
|
-
const combined = []
|
|
490
|
+
const combined = [];
|
|
426
491
|
// 标记每个文件的类型
|
|
427
|
-
this.imageFileList.forEach(file => {
|
|
428
|
-
combined.push({ ...file, type: 'image' })
|
|
429
|
-
})
|
|
430
|
-
this.videoFileList.forEach(file => {
|
|
431
|
-
combined.push({ ...file, type: 'video' })
|
|
432
|
-
})
|
|
433
|
-
return combined
|
|
492
|
+
this.imageFileList.forEach((file) => {
|
|
493
|
+
combined.push({ ...file, type: 'image' });
|
|
494
|
+
});
|
|
495
|
+
this.videoFileList.forEach((file) => {
|
|
496
|
+
combined.push({ ...file, type: 'video' });
|
|
497
|
+
});
|
|
498
|
+
return combined;
|
|
434
499
|
},
|
|
435
500
|
|
|
436
501
|
// ==================== 上传地址 ====================
|
|
437
502
|
finalUploadUrl() {
|
|
438
|
-
return this.actualUploadUrl || this.uploadUrl || (getApp().globalData && getApp().globalData.uploadUrl) || ''
|
|
503
|
+
return this.actualUploadUrl || this.uploadUrl || (getApp().globalData && getApp().globalData.uploadUrl) || '';
|
|
439
504
|
},
|
|
440
505
|
|
|
441
506
|
// ==================== 动态尺寸计算 ====================
|
|
442
507
|
uploadIconSize() {
|
|
443
508
|
if (this.itemWidth > 0) {
|
|
444
|
-
return Math.floor((this.itemWidth - 20) * 0.3)
|
|
509
|
+
return Math.floor((this.itemWidth - 20) * 0.3);
|
|
445
510
|
}
|
|
446
|
-
const screenWidth = 750
|
|
447
|
-
const gap = 20
|
|
448
|
-
const containerWidth = (screenWidth - gap * (this.cols + 1)) / this.cols
|
|
449
|
-
return Math.floor(containerWidth * 0.3)
|
|
511
|
+
const screenWidth = 750;
|
|
512
|
+
const gap = 20;
|
|
513
|
+
const containerWidth = (screenWidth - gap * (this.cols + 1)) / this.cols;
|
|
514
|
+
return Math.floor(containerWidth * 0.3);
|
|
450
515
|
},
|
|
451
516
|
uploadTextSize() {
|
|
452
|
-
return Math.max(20, Math.floor(this.uploadIconSize * 0.38))
|
|
517
|
+
return Math.max(20, Math.floor(this.uploadIconSize * 0.38));
|
|
453
518
|
},
|
|
454
519
|
// 拖拽模式下的图标和文字样式(预计算好,避免模板中使用方法调用报错)
|
|
455
520
|
dragIconStyle() {
|
|
456
521
|
return {
|
|
457
522
|
width: this.uploadIconSize + 'rpx',
|
|
458
523
|
height: this.uploadIconSize + 'rpx'
|
|
459
|
-
}
|
|
524
|
+
};
|
|
460
525
|
},
|
|
461
526
|
dragTextStyle() {
|
|
462
527
|
return {
|
|
463
528
|
fontSize: this.uploadTextSize + 'rpx'
|
|
464
|
-
}
|
|
529
|
+
};
|
|
465
530
|
},
|
|
466
531
|
|
|
467
532
|
// ==================== 只读模式网格样式 ====================
|
|
468
533
|
readonlyGridStyle() {
|
|
469
534
|
// 如果指定了 itemWidth,使用固定宽度;否则使用 1fr 自动分配
|
|
470
|
-
const columnWidth = this.itemWidth ? `${this.itemWidth}rpx` : '1fr'
|
|
535
|
+
const columnWidth = this.itemWidth ? `${this.itemWidth}rpx` : '1fr';
|
|
471
536
|
|
|
472
537
|
return {
|
|
473
538
|
gridTemplateColumns: `repeat(${this.cols}, ${columnWidth})`,
|
|
474
539
|
gap: '10rpx'
|
|
475
|
-
}
|
|
540
|
+
};
|
|
476
541
|
},
|
|
477
542
|
|
|
478
543
|
// ==================== 弹窗模式网格样式 ====================
|
|
@@ -480,19 +545,19 @@ export default {
|
|
|
480
545
|
return {
|
|
481
546
|
gridTemplateColumns: `repeat(${this.cols}, 1fr)`,
|
|
482
547
|
gap: '10rpx'
|
|
483
|
-
}
|
|
548
|
+
};
|
|
484
549
|
}
|
|
485
550
|
},
|
|
486
551
|
watch: {
|
|
487
552
|
imageFiles: {
|
|
488
553
|
handler(val) {
|
|
489
|
-
this.imageFileList = val || []
|
|
554
|
+
this.imageFileList = val || [];
|
|
490
555
|
},
|
|
491
556
|
immediate: true
|
|
492
557
|
},
|
|
493
558
|
videoFiles: {
|
|
494
559
|
handler(val) {
|
|
495
|
-
this.videoFileList = val || []
|
|
560
|
+
this.videoFileList = val || [];
|
|
496
561
|
},
|
|
497
562
|
immediate: true
|
|
498
563
|
},
|
|
@@ -504,7 +569,7 @@ export default {
|
|
|
504
569
|
},
|
|
505
570
|
mounted() {
|
|
506
571
|
if (!this.uploadUrl) {
|
|
507
|
-
this.actualUploadUrl = (getApp().globalData && getApp().globalData.uploadUrl) || ''
|
|
572
|
+
this.actualUploadUrl = (getApp().globalData && getApp().globalData.uploadUrl) || '';
|
|
508
573
|
}
|
|
509
574
|
this.initLazyObserver(); // 在mounted时初始化观察器
|
|
510
575
|
},
|
|
@@ -525,7 +590,7 @@ export default {
|
|
|
525
590
|
* @returns {Boolean} - 是否被监听
|
|
526
591
|
*/
|
|
527
592
|
hasEventListener(eventName) {
|
|
528
|
-
return !!(this.$listeners && this.$listeners[eventName])
|
|
593
|
+
return !!(this.$listeners && this.$listeners[eventName]);
|
|
529
594
|
},
|
|
530
595
|
|
|
531
596
|
// ==================== 图片相关方法 ====================
|
|
@@ -536,10 +601,10 @@ export default {
|
|
|
536
601
|
*/
|
|
537
602
|
checkImageSize(size) {
|
|
538
603
|
if (this.imageMaxSize <= 0) {
|
|
539
|
-
return true
|
|
604
|
+
return true;
|
|
540
605
|
}
|
|
541
|
-
const maxSizeInBytes = this.imageMaxSize * 1024 * 1024
|
|
542
|
-
return size <= maxSizeInBytes
|
|
606
|
+
const maxSizeInBytes = this.imageMaxSize * 1024 * 1024;
|
|
607
|
+
return size <= maxSizeInBytes;
|
|
543
608
|
},
|
|
544
609
|
|
|
545
610
|
/**
|
|
@@ -549,11 +614,11 @@ export default {
|
|
|
549
614
|
*/
|
|
550
615
|
formatFileSize(size) {
|
|
551
616
|
if (size < 1024) {
|
|
552
|
-
return size + 'B'
|
|
617
|
+
return size + 'B';
|
|
553
618
|
} else if (size < 1024 * 1024) {
|
|
554
|
-
return (size / 1024).toFixed(2) + 'KB'
|
|
619
|
+
return (size / 1024).toFixed(2) + 'KB';
|
|
555
620
|
} else {
|
|
556
|
-
return (size / (1024 * 1024)).toFixed(2) + 'MB'
|
|
621
|
+
return (size / (1024 * 1024)).toFixed(2) + 'MB';
|
|
557
622
|
}
|
|
558
623
|
},
|
|
559
624
|
|
|
@@ -566,31 +631,31 @@ export default {
|
|
|
566
631
|
this.$emit('imageLimitReached', {
|
|
567
632
|
current: this.imageFileList.length,
|
|
568
633
|
limit: this.imageLimit
|
|
569
|
-
})
|
|
634
|
+
});
|
|
570
635
|
|
|
571
636
|
// 如果用户未监听事件,显示默认提示
|
|
572
637
|
if (!this.hasEventListener('imageLimitReached')) {
|
|
573
638
|
uni.showToast({
|
|
574
639
|
icon: 'none',
|
|
575
640
|
title: `上传最大限制${this.imageLimit}张`
|
|
576
|
-
})
|
|
641
|
+
});
|
|
577
642
|
}
|
|
578
|
-
return
|
|
643
|
+
return;
|
|
579
644
|
}
|
|
580
645
|
|
|
581
646
|
if (!this.finalUploadUrl) {
|
|
582
647
|
uni.showToast({
|
|
583
648
|
title: '请先配置上传地址',
|
|
584
649
|
icon: 'none'
|
|
585
|
-
})
|
|
586
|
-
return
|
|
650
|
+
});
|
|
651
|
+
return;
|
|
587
652
|
}
|
|
588
653
|
|
|
589
|
-
const remainCount = this.imageLimit - this.imageFileList.length
|
|
654
|
+
const remainCount = this.imageLimit - this.imageFileList.length;
|
|
590
655
|
|
|
591
656
|
uni.chooseImage({
|
|
592
657
|
count: remainCount,
|
|
593
|
-
sizeType: [
|
|
658
|
+
sizeType: ['original', 'compressed'],
|
|
594
659
|
sourceType: this.imageSourceType,
|
|
595
660
|
// #ifndef MP-WEIXIN
|
|
596
661
|
success: (chooseImageRes) => {
|
|
@@ -600,23 +665,23 @@ export default {
|
|
|
600
665
|
current: this.imageFileList.length,
|
|
601
666
|
limit: this.imageLimit,
|
|
602
667
|
attempted: chooseImageRes.tempFiles.length
|
|
603
|
-
})
|
|
668
|
+
});
|
|
604
669
|
|
|
605
670
|
// 如果用户未监听事件,显示默认提示
|
|
606
671
|
if (!this.hasEventListener('imageLimitReached')) {
|
|
607
672
|
uni.showToast({
|
|
608
673
|
icon: 'none',
|
|
609
674
|
title: `上传最大限制${this.imageLimit}张`
|
|
610
|
-
})
|
|
675
|
+
});
|
|
611
676
|
}
|
|
612
|
-
return
|
|
677
|
+
return;
|
|
613
678
|
}
|
|
614
679
|
|
|
615
680
|
// 检查图片大小
|
|
616
681
|
if (this.imageMaxSize > 0) {
|
|
617
|
-
const oversizedFiles = chooseImageRes.tempFiles.filter(file => !this.checkImageSize(file.size))
|
|
682
|
+
const oversizedFiles = chooseImageRes.tempFiles.filter((file) => !this.checkImageSize(file.size));
|
|
618
683
|
if (oversizedFiles.length > 0) {
|
|
619
|
-
const firstOversized = oversizedFiles[0]
|
|
684
|
+
const firstOversized = oversizedFiles[0];
|
|
620
685
|
|
|
621
686
|
// 触发图片大小超限事件
|
|
622
687
|
this.$emit('imageSizeExceed', {
|
|
@@ -624,7 +689,7 @@ export default {
|
|
|
624
689
|
maxSize: this.imageMaxSize * 1024 * 1024,
|
|
625
690
|
file: firstOversized,
|
|
626
691
|
message: `图片大小不能超过${this.imageMaxSize}MB(当前:${this.formatFileSize(firstOversized.size)})`
|
|
627
|
-
})
|
|
692
|
+
});
|
|
628
693
|
|
|
629
694
|
// 如果用户未监听事件,显示默认提示
|
|
630
695
|
if (!this.hasEventListener('imageSizeExceed')) {
|
|
@@ -632,34 +697,20 @@ export default {
|
|
|
632
697
|
icon: 'none',
|
|
633
698
|
title: `图片大小不能超过${this.imageMaxSize}MB(当前:${this.formatFileSize(firstOversized.size)})`,
|
|
634
699
|
duration: 3000
|
|
635
|
-
})
|
|
700
|
+
});
|
|
636
701
|
}
|
|
637
|
-
return
|
|
702
|
+
return;
|
|
638
703
|
}
|
|
639
704
|
}
|
|
640
705
|
|
|
641
706
|
uni.showLoading({
|
|
642
707
|
title: '上传中',
|
|
643
708
|
mask: true
|
|
644
|
-
})
|
|
709
|
+
});
|
|
645
710
|
|
|
646
|
-
chooseImageRes.
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
new Compressor(tempFile, {
|
|
650
|
-
quality: 0.8,
|
|
651
|
-
success: (compressedFile) => {
|
|
652
|
-
this.uploadImageFile(this.finalUploadUrl, compressedFile)
|
|
653
|
-
},
|
|
654
|
-
error: (err) => {
|
|
655
|
-
uni.hideLoading()
|
|
656
|
-
uni.showToast({
|
|
657
|
-
icon: 'none',
|
|
658
|
-
title: '图片压缩失败'
|
|
659
|
-
})
|
|
660
|
-
},
|
|
661
|
-
})
|
|
662
|
-
})
|
|
711
|
+
chooseImageRes.tempFiles.forEach((fileItem) => {
|
|
712
|
+
this.uploadImageFile(this.finalUploadUrl, fileItem);
|
|
713
|
+
});
|
|
663
714
|
},
|
|
664
715
|
// #endif
|
|
665
716
|
|
|
@@ -671,23 +722,23 @@ export default {
|
|
|
671
722
|
current: this.imageFileList.length,
|
|
672
723
|
limit: this.imageLimit,
|
|
673
724
|
attempted: chooseImageRes.tempFiles.length
|
|
674
|
-
})
|
|
725
|
+
});
|
|
675
726
|
|
|
676
727
|
// 如果用户未监听事件,显示默认提示
|
|
677
728
|
if (!this.hasEventListener('imageLimitReached')) {
|
|
678
729
|
uni.showToast({
|
|
679
730
|
icon: 'none',
|
|
680
731
|
title: `上传最大限制${this.imageLimit}张`
|
|
681
|
-
})
|
|
732
|
+
});
|
|
682
733
|
}
|
|
683
|
-
return
|
|
734
|
+
return;
|
|
684
735
|
}
|
|
685
736
|
|
|
686
737
|
// 检查图片大小
|
|
687
738
|
if (this.imageMaxSize > 0) {
|
|
688
|
-
const oversizedFiles = chooseImageRes.tempFiles.filter(file => !this.checkImageSize(file.size))
|
|
739
|
+
const oversizedFiles = chooseImageRes.tempFiles.filter((file) => !this.checkImageSize(file.size));
|
|
689
740
|
if (oversizedFiles.length > 0) {
|
|
690
|
-
const firstOversized = oversizedFiles[0]
|
|
741
|
+
const firstOversized = oversizedFiles[0];
|
|
691
742
|
|
|
692
743
|
// 触发图片大小超限事件
|
|
693
744
|
this.$emit('imageSizeExceed', {
|
|
@@ -695,7 +746,7 @@ export default {
|
|
|
695
746
|
maxSize: this.imageMaxSize * 1024 * 1024,
|
|
696
747
|
file: firstOversized,
|
|
697
748
|
message: `图片大小不能超过${this.imageMaxSize}MB(当前:${this.formatFileSize(firstOversized.size)})`
|
|
698
|
-
})
|
|
749
|
+
});
|
|
699
750
|
|
|
700
751
|
// 如果用户未监听事件,显示默认提示
|
|
701
752
|
if (!this.hasEventListener('imageSizeExceed')) {
|
|
@@ -703,20 +754,20 @@ export default {
|
|
|
703
754
|
icon: 'none',
|
|
704
755
|
title: `图片大小不能超过${this.imageMaxSize}MB(当前:${this.formatFileSize(firstOversized.size)})`,
|
|
705
756
|
duration: 3000
|
|
706
|
-
})
|
|
757
|
+
});
|
|
707
758
|
}
|
|
708
|
-
return
|
|
759
|
+
return;
|
|
709
760
|
}
|
|
710
761
|
}
|
|
711
762
|
|
|
712
763
|
uni.showLoading({
|
|
713
764
|
title: '上传中',
|
|
714
765
|
mask: true
|
|
715
|
-
})
|
|
766
|
+
});
|
|
716
767
|
|
|
717
768
|
chooseImageRes.tempFilePaths.forEach((tempPath, index) => {
|
|
718
|
-
const tempFile = chooseImageRes.tempFiles[index]
|
|
719
|
-
const lowerPath = tempPath.toLowerCase()
|
|
769
|
+
const tempFile = chooseImageRes.tempFiles[index];
|
|
770
|
+
const lowerPath = tempPath.toLowerCase();
|
|
720
771
|
|
|
721
772
|
// 对 jpg/jpeg 格式的图片进行压缩
|
|
722
773
|
if (lowerPath.indexOf('.jpg') !== -1 || lowerPath.indexOf('.jpeg') !== -1) {
|
|
@@ -724,16 +775,16 @@ export default {
|
|
|
724
775
|
src: tempFile.path,
|
|
725
776
|
quality: 100,
|
|
726
777
|
success: (res) => {
|
|
727
|
-
this.uploadImageFileByPath(this.finalUploadUrl, res.tempFilePath, tempPath)
|
|
778
|
+
this.uploadImageFileByPath(this.finalUploadUrl, res.tempFilePath, tempPath);
|
|
728
779
|
}
|
|
729
|
-
})
|
|
780
|
+
});
|
|
730
781
|
} else {
|
|
731
|
-
this.uploadImageFileByPath(this.finalUploadUrl, tempPath, tempPath)
|
|
782
|
+
this.uploadImageFileByPath(this.finalUploadUrl, tempPath, tempPath);
|
|
732
783
|
}
|
|
733
|
-
})
|
|
734
|
-
}
|
|
784
|
+
});
|
|
785
|
+
}
|
|
735
786
|
// #endif
|
|
736
|
-
})
|
|
787
|
+
});
|
|
737
788
|
},
|
|
738
789
|
|
|
739
790
|
/**
|
|
@@ -743,41 +794,63 @@ export default {
|
|
|
743
794
|
uni.uploadFile({
|
|
744
795
|
url,
|
|
745
796
|
file,
|
|
746
|
-
name:
|
|
797
|
+
name: 'file',
|
|
747
798
|
success: (uploadFileRes) => {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
url: result.data.pathUrl,
|
|
754
|
-
type: 'image'
|
|
799
|
+
// 1. 先检查 HTTP 状态码
|
|
800
|
+
if (uploadFileRes.statusCode !== 200) {
|
|
801
|
+
console.error('HTTP状态码错误:', uploadFileRes.statusCode);
|
|
802
|
+
uni.showToast({ title: `服务器响应异常(${uploadFileRes.statusCode})`, icon: 'none' });
|
|
803
|
+
return;
|
|
755
804
|
}
|
|
756
|
-
this.imageFileList.push(fileInfo)
|
|
757
805
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
806
|
+
try {
|
|
807
|
+
// 2. 尝试解析 JSON
|
|
808
|
+
const result = JSON.parse(uploadFileRes.data);
|
|
809
|
+
|
|
810
|
+
// 3. 检查后端定义的业务 Code (假设 200 为成功)
|
|
811
|
+
if (result.rspCode === '000000') {
|
|
812
|
+
const fileInfo = {
|
|
813
|
+
fileName: result.data.fileName,
|
|
814
|
+
name: result.data.originFileName,
|
|
815
|
+
url: result.data.pathUrl,
|
|
816
|
+
type: 'image'
|
|
817
|
+
};
|
|
818
|
+
this.imageFileList.push(fileInfo);
|
|
819
|
+
|
|
820
|
+
this.$emit('imageUploadSuccess', {
|
|
821
|
+
uploadFileRes: uploadFileRes,
|
|
822
|
+
file: fileInfo,
|
|
823
|
+
response: result
|
|
824
|
+
});
|
|
825
|
+
} else {
|
|
826
|
+
// 后端业务层报错(如:格式不支持、权限不足)
|
|
827
|
+
uni.showToast({ title: result.rspMsg || '业务处理失败', icon: 'none' });
|
|
828
|
+
this.$emit('imageUploadFail', { error: result, message: result.rspMsg });
|
|
829
|
+
}
|
|
830
|
+
} catch (error) {
|
|
831
|
+
// 解析 JSON 失败,通常是后端挂了返回了非 JSON 格式
|
|
832
|
+
console.error('返回数据解析异常:', uploadFileRes.data);
|
|
833
|
+
uni.showToast({ title: '服务器数据解析失败', icon: 'none' });
|
|
834
|
+
this.$emit('imageUploadFail', { error: error, message: '解析失败' });
|
|
835
|
+
}
|
|
763
836
|
},
|
|
764
837
|
fail: (error) => {
|
|
765
838
|
uni.showToast({
|
|
766
839
|
icon: 'none',
|
|
767
840
|
title: '上传失败'
|
|
768
|
-
})
|
|
841
|
+
});
|
|
769
842
|
|
|
770
843
|
// 触发图片上传失败事件
|
|
771
844
|
this.$emit('imageUploadFail', {
|
|
772
845
|
error: error,
|
|
773
846
|
message: '图片上传失败'
|
|
774
|
-
})
|
|
847
|
+
});
|
|
775
848
|
},
|
|
776
849
|
complete: () => {
|
|
777
|
-
uni.hideLoading()
|
|
778
|
-
this.emitImageChange()
|
|
850
|
+
uni.hideLoading();
|
|
851
|
+
this.emitImageChange();
|
|
779
852
|
}
|
|
780
|
-
})
|
|
853
|
+
});
|
|
781
854
|
},
|
|
782
855
|
|
|
783
856
|
/**
|
|
@@ -787,53 +860,55 @@ export default {
|
|
|
787
860
|
uni.uploadFile({
|
|
788
861
|
url,
|
|
789
862
|
filePath,
|
|
790
|
-
name:
|
|
863
|
+
name: 'file',
|
|
791
864
|
success: (uploadFileRes) => {
|
|
792
|
-
const result = JSON.parse(uploadFileRes.data)
|
|
865
|
+
const result = JSON.parse(uploadFileRes.data);
|
|
793
866
|
|
|
794
867
|
const fileInfo = {
|
|
795
868
|
fileName: result.data.fileName,
|
|
796
869
|
name: result.data.originFileName,
|
|
797
870
|
url: result.data.pathUrl,
|
|
798
871
|
type: 'image'
|
|
799
|
-
}
|
|
800
|
-
this.imageFileList.push(fileInfo)
|
|
872
|
+
};
|
|
873
|
+
this.imageFileList.push(fileInfo);
|
|
801
874
|
|
|
802
875
|
// 触发图片上传成功事件
|
|
803
876
|
this.$emit('imageUploadSuccess', {
|
|
804
877
|
file: fileInfo,
|
|
805
878
|
response: result
|
|
806
|
-
})
|
|
879
|
+
});
|
|
807
880
|
},
|
|
808
881
|
fail: (error) => {
|
|
809
882
|
uni.showToast({
|
|
810
883
|
icon: 'none',
|
|
811
884
|
title: '上传失败'
|
|
812
|
-
})
|
|
885
|
+
});
|
|
813
886
|
|
|
814
887
|
// 触发图片上传失败事件
|
|
815
888
|
this.$emit('imageUploadFail', {
|
|
816
889
|
error: error,
|
|
817
890
|
message: '图片上传失败'
|
|
818
|
-
})
|
|
891
|
+
});
|
|
819
892
|
},
|
|
820
893
|
complete: () => {
|
|
821
|
-
uni.hideLoading()
|
|
822
|
-
this.emitImageChange()
|
|
894
|
+
uni.hideLoading();
|
|
895
|
+
this.emitImageChange();
|
|
823
896
|
}
|
|
824
|
-
})
|
|
897
|
+
});
|
|
825
898
|
},
|
|
826
899
|
|
|
827
900
|
/**
|
|
828
901
|
* 处理图片拖拽排序变化
|
|
829
902
|
*/
|
|
830
|
-
handleImageDragChange(newUrls) {
|
|
831
|
-
const newFileList = newUrls
|
|
832
|
-
|
|
833
|
-
|
|
903
|
+
handleImageDragChange(newUrls) {
|
|
904
|
+
const newFileList = newUrls
|
|
905
|
+
.map((url) => {
|
|
906
|
+
return this.imageFileList.find((file) => file.url === url);
|
|
907
|
+
})
|
|
908
|
+
.filter(Boolean);
|
|
834
909
|
|
|
835
|
-
this.imageFileList = newFileList
|
|
836
|
-
this.emitImageChange()
|
|
910
|
+
this.imageFileList = newFileList;
|
|
911
|
+
this.emitImageChange();
|
|
837
912
|
},
|
|
838
913
|
|
|
839
914
|
/**
|
|
@@ -843,15 +918,15 @@ export default {
|
|
|
843
918
|
uni.previewImage({
|
|
844
919
|
current,
|
|
845
920
|
urls,
|
|
846
|
-
indicator:
|
|
847
|
-
})
|
|
921
|
+
indicator: 'number'
|
|
922
|
+
});
|
|
848
923
|
},
|
|
849
924
|
|
|
850
925
|
/**
|
|
851
926
|
* 触发图片变更事件
|
|
852
927
|
*/
|
|
853
928
|
emitImageChange() {
|
|
854
|
-
this.$emit('imageChange', this.imageFileList)
|
|
929
|
+
this.$emit('imageChange', this.imageFileList);
|
|
855
930
|
},
|
|
856
931
|
|
|
857
932
|
// ==================== 视频相关方法 ====================
|
|
@@ -863,8 +938,8 @@ export default {
|
|
|
863
938
|
uni.showToast({
|
|
864
939
|
title: '请先配置上传地址',
|
|
865
940
|
icon: 'none'
|
|
866
|
-
})
|
|
867
|
-
return
|
|
941
|
+
});
|
|
942
|
+
return;
|
|
868
943
|
}
|
|
869
944
|
|
|
870
945
|
if (this.videoFileList.length >= this.videoLimit) {
|
|
@@ -872,16 +947,16 @@ export default {
|
|
|
872
947
|
this.$emit('videoLimitReached', {
|
|
873
948
|
current: this.videoFileList.length,
|
|
874
949
|
limit: this.videoLimit
|
|
875
|
-
})
|
|
950
|
+
});
|
|
876
951
|
|
|
877
952
|
// 如果用户未监听事件,显示默认提示
|
|
878
953
|
if (!this.hasEventListener('videoLimitReached')) {
|
|
879
954
|
uni.showToast({
|
|
880
955
|
title: `最多上传${this.videoLimit}个视频`,
|
|
881
956
|
icon: 'none'
|
|
882
|
-
})
|
|
957
|
+
});
|
|
883
958
|
}
|
|
884
|
-
return
|
|
959
|
+
return;
|
|
885
960
|
}
|
|
886
961
|
|
|
887
962
|
uni.chooseVideo({
|
|
@@ -896,20 +971,20 @@ export default {
|
|
|
896
971
|
maxDuration: this.videoMaxDuration,
|
|
897
972
|
file: res,
|
|
898
973
|
message: `视频时长不能超过${this.videoMaxDuration}秒`
|
|
899
|
-
})
|
|
974
|
+
});
|
|
900
975
|
|
|
901
976
|
// 如果用户未监听事件,显示默认提示
|
|
902
977
|
if (!this.hasEventListener('videoDurationExceed')) {
|
|
903
978
|
uni.showToast({
|
|
904
979
|
title: `视频时长不能超过${this.videoMaxDuration}秒`,
|
|
905
980
|
icon: 'none'
|
|
906
|
-
})
|
|
981
|
+
});
|
|
907
982
|
}
|
|
908
|
-
return
|
|
983
|
+
return;
|
|
909
984
|
}
|
|
910
|
-
this.uploadVideo(res.tempFilePath)
|
|
985
|
+
this.uploadVideo(res.tempFilePath);
|
|
911
986
|
}
|
|
912
|
-
})
|
|
987
|
+
});
|
|
913
988
|
},
|
|
914
989
|
|
|
915
990
|
/**
|
|
@@ -919,57 +994,57 @@ export default {
|
|
|
919
994
|
const uploadTask = uni.uploadFile({
|
|
920
995
|
url: this.finalUploadUrl,
|
|
921
996
|
filePath,
|
|
922
|
-
name:
|
|
997
|
+
name: 'file',
|
|
923
998
|
success: (uploadFileRes) => {
|
|
924
|
-
const result = JSON.parse(uploadFileRes.data)
|
|
999
|
+
const result = JSON.parse(uploadFileRes.data);
|
|
925
1000
|
|
|
926
1001
|
const fileInfo = {
|
|
927
1002
|
fileName: result.data.fileName,
|
|
928
1003
|
name: result.data.originFileName || 'video',
|
|
929
1004
|
url: result.data.pathUrl,
|
|
930
1005
|
type: 'video'
|
|
931
|
-
}
|
|
1006
|
+
};
|
|
932
1007
|
|
|
933
|
-
this.videoFileList.push(fileInfo)
|
|
934
|
-
this.emitVideoChange()
|
|
1008
|
+
this.videoFileList.push(fileInfo);
|
|
1009
|
+
this.emitVideoChange();
|
|
935
1010
|
|
|
936
1011
|
// 触发视频上传成功事件
|
|
937
1012
|
this.$emit('videoUploadSuccess', {
|
|
938
1013
|
file: fileInfo,
|
|
939
1014
|
response: result
|
|
940
|
-
})
|
|
1015
|
+
});
|
|
941
1016
|
},
|
|
942
1017
|
fail: (err) => {
|
|
943
1018
|
uni.showToast({
|
|
944
1019
|
icon: 'none',
|
|
945
1020
|
title: '视频上传失败'
|
|
946
|
-
})
|
|
1021
|
+
});
|
|
947
1022
|
|
|
948
1023
|
// 触发视频上传失败事件
|
|
949
1024
|
this.$emit('videoUploadFail', {
|
|
950
1025
|
error: err,
|
|
951
1026
|
message: '视频上传失败'
|
|
952
|
-
})
|
|
1027
|
+
});
|
|
953
1028
|
},
|
|
954
1029
|
complete: () => {
|
|
955
|
-
uni.hideLoading()
|
|
1030
|
+
uni.hideLoading();
|
|
956
1031
|
}
|
|
957
|
-
})
|
|
1032
|
+
});
|
|
958
1033
|
|
|
959
1034
|
uploadTask.onProgressUpdate((res) => {
|
|
960
1035
|
uni.showLoading({
|
|
961
|
-
title: '已上传' + res.progress +
|
|
962
|
-
mask: true
|
|
1036
|
+
title: '已上传' + res.progress + '%',
|
|
1037
|
+
mask: true
|
|
963
1038
|
});
|
|
964
|
-
console.log(
|
|
965
|
-
console.log(
|
|
966
|
-
console.log(
|
|
1039
|
+
console.log('上传进度' + res.progress);
|
|
1040
|
+
console.log('已经上传的数据长度' + res.totalBytesSent);
|
|
1041
|
+
console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
|
|
967
1042
|
// // 测试条件,取消上传任务。
|
|
968
1043
|
if (res.progress === 100) {
|
|
969
1044
|
uni.hideLoading();
|
|
970
1045
|
uni.showLoading({
|
|
971
|
-
title:
|
|
972
|
-
mask: true
|
|
1046
|
+
title: '确认中...',
|
|
1047
|
+
mask: true
|
|
973
1048
|
});
|
|
974
1049
|
}
|
|
975
1050
|
});
|
|
@@ -979,42 +1054,44 @@ export default {
|
|
|
979
1054
|
* 处理视频拖拽排序变化
|
|
980
1055
|
*/
|
|
981
1056
|
handleVideoDragChange(newUrls) {
|
|
982
|
-
const newFileList = newUrls
|
|
983
|
-
|
|
984
|
-
|
|
1057
|
+
const newFileList = newUrls
|
|
1058
|
+
.map((url) => {
|
|
1059
|
+
return this.videoFileList.find((file) => file.url === url);
|
|
1060
|
+
})
|
|
1061
|
+
.filter(Boolean);
|
|
985
1062
|
|
|
986
|
-
this.videoFileList = newFileList
|
|
987
|
-
this.emitVideoChange()
|
|
1063
|
+
this.videoFileList = newFileList;
|
|
1064
|
+
this.emitVideoChange();
|
|
988
1065
|
},
|
|
989
1066
|
|
|
990
1067
|
/**
|
|
991
1068
|
* 触发视频变更事件
|
|
992
1069
|
*/
|
|
993
1070
|
emitVideoChange() {
|
|
994
|
-
this.$emit('videoChange', this.videoFileList)
|
|
1071
|
+
this.$emit('videoChange', this.videoFileList);
|
|
995
1072
|
},
|
|
996
1073
|
|
|
997
1074
|
/**
|
|
998
1075
|
* 处理拖拽组件中的视频点击
|
|
999
1076
|
*/
|
|
1000
1077
|
handleVideoItemClick(item) {
|
|
1001
|
-
console.log('点击视频:', item)
|
|
1078
|
+
console.log('点击视频:', item);
|
|
1002
1079
|
// shmily-drag-media 传递的是 item.src
|
|
1003
|
-
this.playVideo(item.src)
|
|
1080
|
+
this.playVideo(item.src);
|
|
1004
1081
|
},
|
|
1005
1082
|
|
|
1006
1083
|
/**
|
|
1007
|
-
* 播放视频(统一播放方法)
|
|
1084
|
+
* 播放视频(统一播放方法)
|
|
1008
1085
|
*/
|
|
1009
1086
|
playVideo(url) {
|
|
1010
1087
|
// 设置视频源
|
|
1011
|
-
this.fullscreenVideoSrc = url
|
|
1088
|
+
this.fullscreenVideoSrc = url;
|
|
1012
1089
|
// 等待视频组件更新
|
|
1013
1090
|
this.$nextTick(() => {
|
|
1014
|
-
const videoContext = uni.createVideoContext('fullscreenPreviewVideo', this)
|
|
1015
|
-
videoContext.requestFullScreen()
|
|
1016
|
-
videoContext.play()
|
|
1017
|
-
})
|
|
1091
|
+
const videoContext = uni.createVideoContext('fullscreenPreviewVideo', this);
|
|
1092
|
+
videoContext.requestFullScreen();
|
|
1093
|
+
videoContext.play();
|
|
1094
|
+
});
|
|
1018
1095
|
},
|
|
1019
1096
|
|
|
1020
1097
|
// ==================== 只读模式交互 ====================
|
|
@@ -1022,15 +1099,15 @@ export default {
|
|
|
1022
1099
|
* 判断是否是最后一个真实元素(用于显示 +N 遮罩)
|
|
1023
1100
|
*/
|
|
1024
1101
|
isLastRealItem(displayIndex) {
|
|
1025
|
-
const file = this.readonlyDisplayList[displayIndex]
|
|
1026
|
-
if (!file || file.type === 'placeholder') return false
|
|
1102
|
+
const file = this.readonlyDisplayList[displayIndex];
|
|
1103
|
+
if (!file || file.type === 'placeholder') return false;
|
|
1027
1104
|
|
|
1028
1105
|
// 计算占位元素数量
|
|
1029
|
-
const placeholderCount = this.readonlyDisplayList.filter(f => f.type === 'placeholder').length
|
|
1030
|
-
const realIndex = displayIndex - placeholderCount
|
|
1106
|
+
const placeholderCount = this.readonlyDisplayList.filter((f) => f.type === 'placeholder').length;
|
|
1107
|
+
const realIndex = displayIndex - placeholderCount;
|
|
1031
1108
|
|
|
1032
1109
|
// 判断是否是最后一个真实元素,且总数超过限制
|
|
1033
|
-
return this.allFileList.length > this.maxShowCount && realIndex === this.maxShowCount - 1
|
|
1110
|
+
return this.allFileList.length > this.maxShowCount && realIndex === this.maxShowCount - 1;
|
|
1034
1111
|
},
|
|
1035
1112
|
|
|
1036
1113
|
/**
|
|
@@ -1039,7 +1116,7 @@ export default {
|
|
|
1039
1116
|
handleReadonlyItemClick(index, file) {
|
|
1040
1117
|
// 如果点击的是占位元素,不做任何处理
|
|
1041
1118
|
if (!file || file.type === 'placeholder') {
|
|
1042
|
-
return
|
|
1119
|
+
return;
|
|
1043
1120
|
}
|
|
1044
1121
|
|
|
1045
1122
|
// 判断是否点击的是遮罩层(最后一项且超出限制)
|
|
@@ -1049,19 +1126,19 @@ export default {
|
|
|
1049
1126
|
showCount: this.maxShowCount,
|
|
1050
1127
|
hiddenCount: this.allFileList.length - this.maxShowCount,
|
|
1051
1128
|
allFiles: this.allFileList
|
|
1052
|
-
})
|
|
1129
|
+
});
|
|
1053
1130
|
|
|
1054
1131
|
if (!this.hasEventListener('moreClick')) {
|
|
1055
|
-
this.openPopup()
|
|
1132
|
+
this.openPopup();
|
|
1056
1133
|
}
|
|
1057
1134
|
} else {
|
|
1058
1135
|
if (file.type === 'image') {
|
|
1059
1136
|
// 预览图片(只提取图片列表)
|
|
1060
|
-
const imageUrls = this.allFileList.filter(f => f.type === 'image').map(f => f.url)
|
|
1061
|
-
const imageIndex = this.imageFileList.findIndex(f => f.url === file.url)
|
|
1062
|
-
this.previewImage(imageUrls, imageIndex)
|
|
1137
|
+
const imageUrls = this.allFileList.filter((f) => f.type === 'image').map((f) => f.url);
|
|
1138
|
+
const imageIndex = this.imageFileList.findIndex((f) => f.url === file.url);
|
|
1139
|
+
this.previewImage(imageUrls, imageIndex);
|
|
1063
1140
|
} else if (file.type === 'video') {
|
|
1064
|
-
this.playVideo(file.url)
|
|
1141
|
+
this.playVideo(file.url);
|
|
1065
1142
|
}
|
|
1066
1143
|
}
|
|
1067
1144
|
},
|
|
@@ -1071,43 +1148,43 @@ export default {
|
|
|
1071
1148
|
*/
|
|
1072
1149
|
handlePopupItemClick(file, index) {
|
|
1073
1150
|
if (file.type === 'image') {
|
|
1074
|
-
const imageUrls = this.allFileList.filter(f => f.type === 'image').map(f => f.url)
|
|
1075
|
-
const imageIndex = this.imageFileList.findIndex(f => f.url === file.url)
|
|
1076
|
-
this.previewImage(imageUrls, imageIndex)
|
|
1151
|
+
const imageUrls = this.allFileList.filter((f) => f.type === 'image').map((f) => f.url);
|
|
1152
|
+
const imageIndex = this.imageFileList.findIndex((f) => f.url === file.url);
|
|
1153
|
+
this.previewImage(imageUrls, imageIndex);
|
|
1077
1154
|
} else if (file.type === 'video') {
|
|
1078
|
-
this.playVideo(file.url)
|
|
1155
|
+
this.playVideo(file.url);
|
|
1079
1156
|
}
|
|
1080
1157
|
},
|
|
1081
1158
|
|
|
1082
1159
|
// ==================== 弹窗控制 ====================
|
|
1083
1160
|
openPopup() {
|
|
1084
|
-
this.popupVisible = true
|
|
1161
|
+
this.popupVisible = true;
|
|
1085
1162
|
this.$nextTick(() => {
|
|
1086
1163
|
setTimeout(() => {
|
|
1087
|
-
this.popupAnimated = true
|
|
1164
|
+
this.popupAnimated = true;
|
|
1088
1165
|
this.initPopupLazyObserver(); // 弹窗打开时初始化懒加载观察器
|
|
1089
|
-
}, 50)
|
|
1090
|
-
})
|
|
1166
|
+
}, 50);
|
|
1167
|
+
});
|
|
1091
1168
|
},
|
|
1092
1169
|
|
|
1093
1170
|
closePopup() {
|
|
1094
|
-
this.popupAnimated = false
|
|
1171
|
+
this.popupAnimated = false;
|
|
1095
1172
|
setTimeout(() => {
|
|
1096
|
-
this.popupVisible = false
|
|
1173
|
+
this.popupVisible = false;
|
|
1097
1174
|
if (this.popupObserver) {
|
|
1098
1175
|
this.popupObserver.disconnect(); // 弹窗关闭时断开观察器
|
|
1099
1176
|
this.popupObserver = null;
|
|
1100
1177
|
}
|
|
1101
|
-
}, 300)
|
|
1178
|
+
}, 300);
|
|
1102
1179
|
},
|
|
1103
1180
|
|
|
1104
1181
|
// ==================== 加载状态管理 ====================
|
|
1105
1182
|
onMediaLoad(key) {
|
|
1106
|
-
this.$set(this.mediaLoadingStatus, key, true)
|
|
1183
|
+
this.$set(this.mediaLoadingStatus, key, true);
|
|
1107
1184
|
},
|
|
1108
1185
|
|
|
1109
1186
|
onMediaError(key) {
|
|
1110
|
-
this.$set(this.mediaLoadingStatus, key, true)
|
|
1187
|
+
this.$set(this.mediaLoadingStatus, key, true);
|
|
1111
1188
|
},
|
|
1112
1189
|
|
|
1113
1190
|
// ==================== 初始化图片懒加载观察器 ====================
|
|
@@ -1122,18 +1199,18 @@ export default {
|
|
|
1122
1199
|
this.observer = null;
|
|
1123
1200
|
}
|
|
1124
1201
|
|
|
1125
|
-
this.lazyLoadImageSrcs = Array(this.allFileList.length).fill(null);
|
|
1202
|
+
this.lazyLoadImageSrcs = Array(this.allFileList.length).fill(null);
|
|
1126
1203
|
|
|
1127
1204
|
this.$nextTick(() => {
|
|
1128
1205
|
const currentObserver = uni.createIntersectionObserver(this, { observeAll: true });
|
|
1129
|
-
this.observer = currentObserver;
|
|
1206
|
+
this.observer = currentObserver;
|
|
1130
1207
|
|
|
1131
1208
|
if (!this.observer) {
|
|
1132
|
-
console.warn(
|
|
1209
|
+
console.warn('IntersectionObserver failed to create.');
|
|
1133
1210
|
return;
|
|
1134
1211
|
}
|
|
1135
1212
|
|
|
1136
|
-
this.observer.relativeToViewport({ top: 0, bottom: 50 });
|
|
1213
|
+
this.observer.relativeToViewport({ top: 0, bottom: 50 });
|
|
1137
1214
|
|
|
1138
1215
|
this.allFileList.forEach((file, index) => {
|
|
1139
1216
|
if (file.type === 'image') {
|
|
@@ -1141,7 +1218,7 @@ export default {
|
|
|
1141
1218
|
currentObserver.observe(sel, (res) => {
|
|
1142
1219
|
const isVisible = res.intersectionRatio > 0;
|
|
1143
1220
|
if (isVisible && !this.lazyLoadImageSrcs[index]) {
|
|
1144
|
-
this.$set(this.lazyLoadImageSrcs, index, file.url);
|
|
1221
|
+
this.$set(this.lazyLoadImageSrcs, index, file.url);
|
|
1145
1222
|
}
|
|
1146
1223
|
});
|
|
1147
1224
|
}
|
|
@@ -1170,7 +1247,7 @@ export default {
|
|
|
1170
1247
|
this.popupObserver = currentPopupObserver;
|
|
1171
1248
|
|
|
1172
1249
|
if (!this.popupObserver) {
|
|
1173
|
-
console.warn(
|
|
1250
|
+
console.warn('Popup IntersectionObserver failed to create.');
|
|
1174
1251
|
return;
|
|
1175
1252
|
}
|
|
1176
1253
|
|
|
@@ -1204,12 +1281,12 @@ export default {
|
|
|
1204
1281
|
if (this.uploadType === 'both') {
|
|
1205
1282
|
return {
|
|
1206
1283
|
images: this.imageFileList,
|
|
1207
|
-
videos: this.videoFileList
|
|
1208
|
-
}
|
|
1284
|
+
videos: this.videoFileList
|
|
1285
|
+
};
|
|
1209
1286
|
} else if (this.uploadType === 'image') {
|
|
1210
|
-
return this.imageFileList
|
|
1287
|
+
return this.imageFileList;
|
|
1211
1288
|
} else if (this.uploadType === 'video') {
|
|
1212
|
-
return this.videoFileList
|
|
1289
|
+
return this.videoFileList;
|
|
1213
1290
|
}
|
|
1214
1291
|
},
|
|
1215
1292
|
|
|
@@ -1217,31 +1294,31 @@ export default {
|
|
|
1217
1294
|
* 获取参数(不包含 url 字段)
|
|
1218
1295
|
*/
|
|
1219
1296
|
getParams() {
|
|
1220
|
-
const imageParams = this.imageFileList.map(file => {
|
|
1221
|
-
const { url, type, ...rest } = file
|
|
1222
|
-
return rest
|
|
1223
|
-
})
|
|
1224
|
-
const videoParams = this.videoFileList.map(file => {
|
|
1225
|
-
const { url, type, ...rest } = file
|
|
1226
|
-
return rest
|
|
1227
|
-
})
|
|
1297
|
+
const imageParams = this.imageFileList.map((file) => {
|
|
1298
|
+
const { url, type, ...rest } = file;
|
|
1299
|
+
return rest;
|
|
1300
|
+
});
|
|
1301
|
+
const videoParams = this.videoFileList.map((file) => {
|
|
1302
|
+
const { url, type, ...rest } = file;
|
|
1303
|
+
return rest;
|
|
1304
|
+
});
|
|
1228
1305
|
if (this.uploadType === 'both') {
|
|
1229
1306
|
return {
|
|
1230
1307
|
images: JSON.stringify(imageParams),
|
|
1231
1308
|
videos: JSON.stringify(videoParams)
|
|
1232
|
-
}
|
|
1309
|
+
};
|
|
1233
1310
|
} else if (this.uploadType === 'image') {
|
|
1234
1311
|
return {
|
|
1235
1312
|
images: JSON.stringify(imageParams)
|
|
1236
|
-
}
|
|
1313
|
+
};
|
|
1237
1314
|
} else if (this.uploadType === 'video') {
|
|
1238
1315
|
return {
|
|
1239
1316
|
videos: JSON.stringify(videoParams)
|
|
1240
|
-
}
|
|
1317
|
+
};
|
|
1241
1318
|
}
|
|
1242
1319
|
}
|
|
1243
1320
|
}
|
|
1244
|
-
}
|
|
1321
|
+
};
|
|
1245
1322
|
</script>
|
|
1246
1323
|
|
|
1247
1324
|
<style lang="scss">
|
package/dist/uniapp.js
CHANGED