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 v-if="imageFileList.length > 0" v-model="imageUrls" :number="imageLimit"
10
- :cols="cols" :imageWidth="itemWidth" :padding="10" :borderRadius="itemBorderRadius"
11
- :draggable="draggable" moveType="image" @input="handleImageDragChange">
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
- :style="{ marginTop: enableImage && videoFileList.length > 0 ? '20rpx' : '0' }">
18
- <shmily-drag-media v-if="videoFileList.length > 0" v-model="videoUrls" :number="videoLimit"
19
- :cols="cols" :imageWidth="itemWidth" :padding="10" :borderRadius="itemBorderRadius"
20
- :draggable="draggable" moveType="video" @input="handleVideoDragChange"
21
- @videoClick="handleVideoItemClick">
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
- :count="imageFileList.length">
31
- <view class="upload-btn-vertical" :style="{ borderRadius: itemBorderRadius + 'rpx' }"
32
- v-if="imageFileList.length < imageLimit" @click="selectAndUploadImage">
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
- :count="videoFileList.length">
43
- <view class="upload-btn-vertical" :style="{ borderRadius: itemBorderRadius + 'rpx' }"
44
- v-if="videoFileList.length < videoLimit" @click="selectAndUploadVideo">
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 v-if="enableImage && !enableVideo && showFileList" v-model="imageUrls"
57
- :number="imageLimit" :cols="cols" :imageWidth="itemWidth" :padding="10"
58
- :borderRadius="itemBorderRadius" :align="align" :draggable="draggable" :enableAddButton="true"
59
- moveType="image" @input="handleImageDragChange">
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
- :style="dragIconStyle"></image>
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 v-else-if="enableVideo && !enableImage && showFileList" v-model="videoUrls"
75
- :number="videoLimit" :cols="cols" :imageWidth="itemWidth" :padding="10"
76
- :borderRadius="itemBorderRadius" :align="align" :draggable="draggable" :enableAddButton="true"
77
- moveType="video" @input="handleVideoDragChange" @videoClick="handleVideoItemClick">
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
- :style="dragIconStyle"></image>
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
- :style="readonlyGridStyle">
97
- <view v-for="(file, i) in readonlyDisplayList" :key="file.id || file.url || i"
98
- :style="{ borderRadius: itemBorderRadius + 'rpx' }" :class="[
99
- 'readonly-grid-item',
100
- { 'placeholder-item': file.type === 'placeholder' },
101
- { 'filter-avatar': file.type !== 'placeholder' && isLastRealItem(i) }
102
- ]" :data-count="file.type !== 'placeholder' && isLastRealItem(i) ? '+' + (allFileList.length - maxShowCount) : ''"
103
- @click="handleReadonlyItemClick(i, file)">
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 v-if="file.type === 'image'" :src="lazyLoadImageSrcs[i]" mode="aspectFill"
111
- :style="{ borderRadius: itemBorderRadius + 'rpx' }" :id="componentId + '-imgview-' + i"
112
- @load="onMediaLoad('readonly-' + i)" @error="onMediaError('readonly-' + i)">
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 v-else-if="file.type === 'video'" :id="'readonlyVideo' + i" class="readonly-video"
117
- :src="file.url" :controls="false" :show-center-play-btn="false"
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)" @error="onMediaError('readonly-' + i)">
120
- </video>
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 v-if="file.type === 'image'" :src="popupLazyLoadImageSrcs[i]" mode="aspectFill"
151
- :style="{ borderRadius: itemBorderRadius + 'rpx' }" :id="componentId + '-popup-imgview-' + i"
152
- @load="onMediaLoad('popup-' + i)" @error="onMediaError('popup-' + i)">
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 v-else-if="file.type === 'video'" class="popup-video" :src="file.url"
157
- :controls="false" :show-center-play-btn="false"
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)" @error="onMediaError('popup-' + i)">
160
- </video>
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 v-if="enableVideo" id="fullscreenPreviewVideo" class="fullscreen-preview-video" :src="fullscreenVideoSrc"
179
- :controls="true" :show-center-play-btn="true" object-fit="contain"
180
- style="position: fixed; left: -9999px; top: -9999px; width: 1px; height: 1px;">
181
- </video>
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).fill(null).map((_, i) => ({
382
- type: 'placeholder',
383
- id: `placeholder-${i}`
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: ["original", "compressed"],
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.tempFilePaths.forEach((tempPath, index) => {
647
- const tempFile = chooseImageRes.tempFiles[index]
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: "file",
797
+ name: 'file',
747
798
  success: (uploadFileRes) => {
748
- const result = JSON.parse(uploadFileRes.data)
749
-
750
- const fileInfo = {
751
- fileName: result.data.fileName,
752
- name: result.data.originFileName,
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
- this.$emit('imageUploadSuccess', {
760
- file: fileInfo,
761
- response: result
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: "file",
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.map(url => {
832
- return this.imageFileList.find(file => file.url === url)
833
- }).filter(Boolean)
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: "number"
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: "file",
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("上传进度" + res.progress);
965
- console.log("已经上传的数据长度" + res.totalBytesSent);
966
- console.log("预期需要上传的数据总长度" + res.totalBytesExpectedToSend);
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.map(url => {
983
- return this.videoFileList.find(file => file.url === url)
984
- }).filter(Boolean)
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("IntersectionObserver failed to create.");
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("Popup IntersectionObserver failed to create.");
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
@@ -1,10 +1,3 @@
1
- /**
2
- * uni-app 专用组件导出
3
- * 使用方式: import { PicPicker, VideoPicker } from 'xydata-tools/dist/uniapp'
4
- *
5
- * @module uniapp
6
- */
7
-
8
1
  /**
9
2
  * PicPicker - uni-app 图片选择上传组件
10
3
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xydata-tools",
3
- "version": "1.1.22",
3
+ "version": "1.1.23",
4
4
  "description": "xydata tools",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",