@10yun/cv-mobile-ui 0.5.57 → 0.5.59

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.
@@ -0,0 +1,854 @@
1
+ <template>
2
+ <view class="u-upload" :style="[addStyle(customStyle)]">
3
+ <view class="u-upload__wrap">
4
+ <template v-if="previewImage">
5
+ <view class="u-upload__wrap__preview" v-for="(item, index) in lists" :key="index">
6
+ <image
7
+ v-if="item.isImage || (item.type && item.type === 'image')"
8
+ :src="item.thumb || item.url"
9
+ :mode="imageMode"
10
+ class="u-upload__wrap__preview__image"
11
+ @tap="onClickPreview(item, index)"
12
+ :style="[
13
+ {
14
+ width: addUnit(width),
15
+ height: addUnit(height)
16
+ }
17
+ ]"
18
+ />
19
+ <view
20
+ class="u-upload__wrap__preview__video"
21
+ :style="{
22
+ width: addUnit(width),
23
+ height: addUnit(height)
24
+ }"
25
+ v-else-if="(item.isVideo || (item.type && item.type === 'video')) && getVideoThumb"
26
+ >
27
+ <image
28
+ v-if="item.thumb"
29
+ :src="item.thumb"
30
+ :mode="imageMode"
31
+ class="u-upload__wrap__preview__image"
32
+ @tap="onClickPreview(item, index)"
33
+ :style="[
34
+ {
35
+ width: addUnit(width),
36
+ height: addUnit(height)
37
+ }
38
+ ]"
39
+ />
40
+ <up-icon
41
+ v-else
42
+ color="#80CBF9"
43
+ size="26"
44
+ :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'file-text'"
45
+ ></up-icon>
46
+ <view v-if="item.status === 'success'" class="u-upload__wrap__play" @tap="onClickPreview(item, index)">
47
+ <slot name="playIcon"></slot>
48
+ <up-icon v-if="!$slots['playIcon']" class="u-upload__wrap__play__icon" name="play-right" size="22px"></up-icon>
49
+ </view>
50
+ </view>
51
+ <view
52
+ v-else
53
+ class="u-upload__wrap__preview__other"
54
+ @tap="onClickPreview(item, index)"
55
+ :style="[
56
+ {
57
+ width: addUnit(width),
58
+ height: addUnit(height)
59
+ }
60
+ ]"
61
+ >
62
+ <up-icon
63
+ color="#80CBF9"
64
+ size="26"
65
+ :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'folder'"
66
+ ></up-icon>
67
+ <text class="u-upload__wrap__preview__other__text">
68
+ {{
69
+ item.isVideo || (item.type && item.type === 'video')
70
+ ? item.name || t('up.common.video')
71
+ : item.name || t('up.common.file')
72
+ }}
73
+ </text>
74
+ </view>
75
+ <view class="u-upload__status" v-if="item.status === 'uploading' || item.status === 'failed'">
76
+ <view class="u-upload__status__icon">
77
+ <up-icon v-if="item.status === 'failed'" name="close-circle" color="#ffffff" size="25" />
78
+ <up-loading-icon size="22" mode="circle" v-else />
79
+ </view>
80
+ <text v-if="item.message" class="u-upload__status__message">{{ item.message }}</text>
81
+ <up-gap class="u-upload__progress" height="3px" :style="{ width: item.progress + '%' }"></up-gap>
82
+ </view>
83
+ <view
84
+ class="u-upload__deletable"
85
+ v-if="item.status !== 'uploading' && (deletable || item.deletable)"
86
+ @tap.stop="deleteItem(index)"
87
+ >
88
+ <view class="u-upload__deletable__icon">
89
+ <up-icon name="close" color="#ffffff" size="10"></up-icon>
90
+ </view>
91
+ </view>
92
+ <slot name="success">
93
+ <view class="u-upload__success" v-if="item.status === 'success'">
94
+ <!-- #ifdef APP-NVUE -->
95
+ <image :src="successIcon" class="u-upload__success__icon"></image>
96
+ <!-- #endif -->
97
+ <!-- #ifndef APP-NVUE -->
98
+ <view class="u-upload__success__icon">
99
+ <up-icon name="checkmark" color="#ffffff" size="12"></up-icon>
100
+ </view>
101
+ <!-- #endif -->
102
+ </view>
103
+ </slot>
104
+ </view>
105
+ </template>
106
+ <canvas id="myCanvas" type="2d" style="width: 100px; height: 150px; display: none"></canvas>
107
+ <template v-if="isInCount">
108
+ <view v-if="$slots.trigger" @tap="chooseFile">
109
+ <slot name="trigger" />
110
+ </view>
111
+ <view v-else-if="!$slots.trigger && ($slots.default || $slots.$default)" @tap="chooseFile">
112
+ <slot />
113
+ </view>
114
+ <view
115
+ v-else
116
+ class="u-upload__button"
117
+ :hover-class="!disabled ? 'u-upload__button--hover' : ''"
118
+ hover-stay-time="150"
119
+ @tap="chooseFile"
120
+ :class="[disabled && 'u-upload__button--disabled']"
121
+ :style="[
122
+ {
123
+ width: addUnit(width),
124
+ height: addUnit(height)
125
+ }
126
+ ]"
127
+ >
128
+ <up-icon :name="uploadIcon" size="26" :color="uploadIconColor"></up-icon>
129
+ <text v-if="uploadText" class="u-upload__button__text">{{ uploadText }}</text>
130
+ </view>
131
+ </template>
132
+ </view>
133
+ <up-popup mode="center" v-model:show="popupShow">
134
+ <video
135
+ id="myVideo"
136
+ v-if="popupShow"
137
+ :src="currentItemIndex >= 0 ? lists[currentItemIndex].url : ''"
138
+ @error="videoErrorCallback"
139
+ show-center-play-btn
140
+ :object-fit="videoPreviewObjectFit"
141
+ show-fullscreen-btn="true"
142
+ enable-play-gesture
143
+ controls
144
+ :autoplay="true"
145
+ auto-pause-if-open-native
146
+ @loadedmetadata="loadedVideoMetadata"
147
+ :initial-time="0.1"
148
+ ></video>
149
+ </up-popup>
150
+ </view>
151
+ </template>
152
+ <script>
153
+ import { chooseFile } from './utils';
154
+ import { mixinUpload } from './mixin';
155
+ import { props } from './props';
156
+ import { mpMixin } from '../../libs/mixin/mpMixin';
157
+ import { mixin } from '../../libs/mixin/mixin';
158
+ import { addStyle, addUnit, toast } from '../../libs/function/index';
159
+ import test from '../../libs/function/test';
160
+ import { t } from '../../libs/i18n';
161
+ /**
162
+ * upload 上传
163
+ * @description 该组件用于上传图片场景
164
+ * @tutorial https://uview-plus.jiangruyi.com/components/upload.html
165
+ * @property {String} accept 接受的文件类型, 可选值为all media image file video (默认 'image' )
166
+ * @property {String | Array} capture 图片或视频拾取模式,当accept为image类型时设置capture可选额外camera可以直接调起摄像头(默认 ['album', 'camera'] )
167
+ * @property {Array} extension 选择文件的后缀名,暂只支持.zip、.png等,不支持application/msword等值
168
+ * @property {Boolean} compressed 当accept为video时生效,是否压缩视频,默认为true(默认 true )
169
+ * @property {String} camera 当accept为video时生效,可选值为back或front(默认 'back' )
170
+ * @property {Number} maxDuration 当accept为video时生效,拍摄视频最长拍摄时间,单位秒(默认 60 )
171
+ * @property {String} uploadIcon 上传区域的图标,只能内置图标(默认 'camera-fill' )
172
+ * @property {String} uploadIconColor 上传区域的图标的字体颜色,只能内置图标(默认 #D3D4D6 )
173
+ * @property {Boolean} useBeforeRead 是否开启文件读取前事件(默认 false )
174
+ * @property {Boolean} previewFullImage 是否显示组件自带的图片预览功能(默认 true )
175
+ * @property {String | Number} maxCount 最大上传数量(默认 52 )
176
+ * @property {Boolean} disabled 是否启用(默认 false )
177
+ * @property {String} imageMode 预览上传的图片时的裁剪模式,和image组件mode属性一致(默认 'aspectFill' )
178
+ * @property {String} name 标识符,可以在回调函数的第二项参数中获取
179
+ * @property {Array} sizeType 所选的图片的尺寸, 可选值为original compressed(默认 ['original', 'compressed'] )
180
+ * @property {Boolean} multiple 是否开启图片多选,部分安卓机型不支持 (默认 false )
181
+ * @property {Boolean} deletable 是否展示删除按钮(默认 true )
182
+ * @property {String | Number} maxSize 文件大小限制,单位为byte (默认 Number.MAX_VALUE )
183
+ * @property {Array} fileList 显示已上传的文件列表
184
+ * @property {String} uploadText 上传区域的提示文字
185
+ * @property {String | Number} width 内部预览图片区域和选择图片按钮的区域宽度(默认 80 )
186
+ * @property {String | Number} height 内部预览图片区域和选择图片按钮的区域高度(默认 80 )
187
+ * @property {Object} customStyle 组件的样式,对象形式
188
+ * @event {Function} afterRead 读取后的处理函数
189
+ * @event {Function} beforeRead 读取前的处理函数
190
+ * @event {Function} oversize 文件超出大小限制
191
+ * @event {Function} clickPreview 点击预览图片
192
+ * @event {Function} delete 删除图片
193
+ * @example <up-upload :action="action" :fileList="fileList" ></up-upload>
194
+ */
195
+ export default {
196
+ name: 'u-upload',
197
+ mixins: [mpMixin, mixin, mixinUpload, props],
198
+ data() {
199
+ return {
200
+ // #ifdef APP-NVUE
201
+ successIcon:
202
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAKKADAAQAAAABAAAAKAAAAAB65masAAACP0lEQVRYCc3YXygsURwH8K/dpcWyG3LF5u/6/+dKVylSypuUl6uUPMifKMWL8oKEB1EUT1KeUPdR3uTNUsSLxb2udG/cbvInNuvf2rVnazZ/ZndmZ87snjM1Z+Z3zpzfp9+Z5mEAhlvjRtZgCKs+gnPAOcAkkMOR4jEHfItjDvgRxxSQD8cM0BuOCaAvXNCBQrigAsXgggYUiwsK0B9cwIH+4gIKlIILGFAqLiBAOTjFgXJxigJp4BQD0sIpAqSJow6kjSNAFTnRaHJwLenD6Mud52VQAcrBfTd2oyq+HtGaGGWAcnAVcXWoM3bCZrdi+ncPfaAcXE5UKVpdW/vitGPqqAtn98d0gXJwX7Qp6MmegUYVhvmTIezdmHlxJCjpHRTCFerLkRRu4k0aqdajN3sWOo0BK//msHa+xDuPC/oNFMKRhTtM4xjIX0SCNpXL4+7VIaHuyiWEp2L7ahWLf8fejfPdqPmC3mJicORZUp1CQzm+GiphvljGk+PBvWRbxii+xVTj5M6CiZ/tsDufvaXyxEUDxeLIyvu3m0iOyEFWVAkydcVYdyFrE9tQk9iMq6f/GNlvwt3LjQfh60LUrw9/cFyyMJUW/XkLSNMV4Mi6C5ML+ui4x5ClAX9sB9w0wV6wglJwJCv5fOxcr6EstgbGiEw4XcfUry4cWrcEUW8n+ARKxXEJHhw2WG43UKSvwI/TSZgvl7kh0b3XLZaLEy0QmMgLZAVH7J+ALOE+AVnDvQOyiPMAWcW5gSzjCPAV+78S5WE0GrQAAAAASUVORK5CYII=',
203
+ // #endif
204
+ lists: [],
205
+ isInCount: true,
206
+ popupShow: false,
207
+ currentItemIndex: -1
208
+ };
209
+ },
210
+ watch: {
211
+ // 监听文件列表的变化,重新整理内部数据
212
+ fileList: {
213
+ handler() {
214
+ this.formatFileList();
215
+ },
216
+ immediate: true,
217
+ deep: true
218
+ },
219
+ deletable(newVal) {
220
+ this.formatFileList();
221
+ },
222
+ maxCount(newVal) {
223
+ this.formatFileList();
224
+ },
225
+ accept(newVal) {
226
+ this.formatFileList();
227
+ },
228
+ popupShow(newVal) {
229
+ if (!newVal) {
230
+ this.currentItemIndex = -1;
231
+ }
232
+ }
233
+ },
234
+ // #ifdef VUE3
235
+ emits: ['error', 'beforeRead', 'oversize', 'afterRead', 'delete', 'clickPreview', 'update:fileList', 'afterAutoUpload'],
236
+ // #endif
237
+ methods: {
238
+ t,
239
+ addUnit,
240
+ addStyle,
241
+ videoErrorCallback() {},
242
+ loadedVideoMetadata(e) {
243
+ if (this.currentItemIndex < 0) {
244
+ return;
245
+ }
246
+ if (this.autoUploadDriver != 'local') {
247
+ return;
248
+ }
249
+ if (!this.getVideoThumb) {
250
+ return;
251
+ }
252
+ // 截取第一帧作为封面,oss等云存储场景直接使用拼接参数。
253
+ let w = this.lists[this.currentItemIndex].width;
254
+ let h = this.lists[this.currentItemIndex].height;
255
+ const dpr = uni.getSystemInfoSync().pixelRatio;
256
+ uni
257
+ .createSelectorQuery()
258
+ .select('#myVideo')
259
+ .context((res) => {
260
+ console.log('select video', res);
261
+ const myVideo = res.context;
262
+ uni
263
+ .createSelectorQuery()
264
+ .select('#myCanvas')
265
+ .fields({ node: true, size: true })
266
+ .exec(([res]) => {
267
+ console.log('select canvas', res);
268
+ const ctx1 = res[0].node.getContext('2d');
269
+ res[0].node.width = w * dpr;
270
+ res[0].node.height = h * dpr;
271
+ // Draw the first frame and export it as an image
272
+ // myVideo.onPlay(() => {
273
+ setTimeout(() => {
274
+ captureFirstFrame();
275
+ }, 500);
276
+ // })
277
+ const captureFirstFrame = () => {
278
+ ctx1.drawImage(myVideo, 0, 0, w * dpr, h * dpr);
279
+ wx.canvasToTempFilePath({
280
+ canvas: res[0].node,
281
+ success: (result) => {
282
+ console.log('First frame image path:', result.tempFilePath);
283
+ // Now you can use the image path (result.tempFilePath)
284
+ this.fileList['currentItemIndex'].thumb = result.tempFilePath;
285
+ },
286
+ fail: (err) => {
287
+ console.error('Failed to export image:', err);
288
+ }
289
+ });
290
+ };
291
+ // Capture the first frame
292
+ setInterval(() => {
293
+ ctx1.drawImage(myVideo, 0, 0, w * dpr, h * dpr);
294
+ }, 1000 / 24);
295
+ })
296
+ .exec();
297
+ })
298
+ .exec();
299
+ },
300
+ formatFileList() {
301
+ const { fileList = [], maxCount } = this;
302
+ const lists = fileList.map((item) => {
303
+ const name = item.name || item.url || item.thumb;
304
+ return Object.assign(Object.assign({}, item), {
305
+ // 如果item.url为本地选择的blob文件的话,无法判断其为video还是image,此处优先通过accept做判断处理
306
+ isImage: item.name ? test.image(item.name) : this.accept === 'image' || test.image(name),
307
+ isVideo: item.name ? test.video(item.name) : this.accept === 'video' || test.video(name),
308
+ deletable: typeof item.deletable === 'boolean' ? item.deletable : this.deletable
309
+ });
310
+ });
311
+ this.lists = lists;
312
+ this.isInCount = lists.length < maxCount;
313
+ },
314
+ chooseFile(params) {
315
+ const { maxCount, multiple, lists, disabled } = this;
316
+ if (disabled) return Promise.reject();
317
+ const chooseParams = Object.assign(
318
+ {
319
+ accept: this.accept,
320
+ extension: this.extension,
321
+ multiple: this.multiple,
322
+ capture: this.capture,
323
+ compressed: this.compressed,
324
+ maxDuration: this.maxDuration,
325
+ sizeType: this.sizeType,
326
+ camera: this.camera
327
+ },
328
+ {
329
+ maxCount: maxCount - lists.length,
330
+ ...params
331
+ }
332
+ );
333
+ return chooseFile(chooseParams)
334
+ .then((res) => {
335
+ const result = chooseParams.multiple ? res : res[0];
336
+ this.onBeforeRead(result);
337
+ return result;
338
+ })
339
+ .catch((error) => {
340
+ this.$emit('error', error);
341
+ });
342
+ },
343
+ // 文件读取之前
344
+ onBeforeRead(file) {
345
+ const { beforeRead, useBeforeRead } = this;
346
+ let res = file;
347
+ // beforeRead是否为一个方法
348
+ if (test.func(beforeRead)) {
349
+ // 如果用户定义了此方法,则去执行此方法,并传入读取的文件回调
350
+ res = beforeRead(file, this.getDetail());
351
+ }
352
+ if (useBeforeRead) {
353
+ res = new Promise((resolve, reject) => {
354
+ this.$emit(
355
+ 'beforeRead',
356
+ Object.assign(
357
+ Object.assign(
358
+ {
359
+ file
360
+ },
361
+ this.getDetail()
362
+ ),
363
+ {
364
+ callback: (ok) => {
365
+ ok ? resolve() : reject();
366
+ }
367
+ }
368
+ )
369
+ );
370
+ });
371
+ }
372
+ if (test.promise(res)) {
373
+ res.then((data) => this.onAfterRead(data || file));
374
+ } else {
375
+ this.onAfterRead(res || file);
376
+ }
377
+ },
378
+ getDetail(index) {
379
+ return {
380
+ name: this.name,
381
+ index: index == null ? this.fileList.length : index
382
+ };
383
+ },
384
+ async onAfterRead(file) {
385
+ const { maxSize, afterRead } = this;
386
+ const oversize = Array.isArray(file) ? file.some((item) => item.size > maxSize) : file.size > maxSize;
387
+ if (oversize) {
388
+ uni.showToast({
389
+ title: t('up.upload.sizeExceed')
390
+ });
391
+ this.$emit(
392
+ 'oversize',
393
+ Object.assign(
394
+ {
395
+ file
396
+ },
397
+ this.getDetail()
398
+ )
399
+ );
400
+ return;
401
+ }
402
+ let len = this.fileList.length;
403
+ if (this.autoUpload) {
404
+ // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
405
+ let lists = [].concat(file);
406
+ let fileListLen = this.fileList.length;
407
+ lists.map((item) => {
408
+ this.fileList.push({
409
+ ...item,
410
+ status: 'uploading',
411
+ message: t('up.upload.uploading'),
412
+ progress: 0
413
+ });
414
+ });
415
+ let that = this;
416
+ this.$emit('update:fileList', this.fileList);
417
+ for (let i = 0; i < lists.length; i++) {
418
+ let j = i;
419
+ let result = '';
420
+ switch (this.autoUploadDriver) {
421
+ case 'cos': // 腾讯云
422
+ break;
423
+ case 'kodo': // 七牛云
424
+ break;
425
+ case 'oss':
426
+ case 'upload_oss':
427
+ // 阿里云前端直传
428
+ // 获取签名
429
+ console.log();
430
+ let formData = {};
431
+ let ret = await uni.request({
432
+ url: this.autoUploadAuthUrl,
433
+ method: 'get',
434
+ header: this.autoUploadHeader,
435
+ data: {
436
+ filename: lists[j].name
437
+ }
438
+ });
439
+ // console.log(ret);
440
+ let res0 = ret.data;
441
+ if (res0.code == 200) {
442
+ // 路径 + 文件名 + 扩展名
443
+ // 不传递filename就要拼接key
444
+ // res0.data.params.key = res0.data.params.dir + res0.data.params.uniqidName + fileExt;
445
+ formData = res0.data.params;
446
+ } else {
447
+ uni.showToast({
448
+ title: res0.msg,
449
+ duration: 1500
450
+ });
451
+ return;
452
+ }
453
+ var uploadTask = uni.uploadFile({
454
+ url: res0.data.params.host,
455
+ filePath: lists[j].url,
456
+ name: 'file',
457
+ // fileType: 'video', // 仅支付宝小程序,且必填。
458
+ // header: header,
459
+ formData: formData,
460
+ success: (uploadFileRes) => {
461
+ let thumb = '';
462
+ let afterPromise = '';
463
+ if (that.customAfterAutoUpload) {
464
+ afterPromise = new Promise((resolve, reject) => {
465
+ that.$emit(
466
+ 'afterAutoUpload',
467
+ Object.assign(res0, {
468
+ callback: (r) => {
469
+ r.url ? resolve(r) : reject();
470
+ }
471
+ })
472
+ );
473
+ });
474
+ }
475
+ if (test.promise(afterPromise)) {
476
+ afterPromise.then((data) => that.succcessUpload(len + j, data.url, data.thumb));
477
+ } else {
478
+ result = res0.data.params.host + '/' + res0.data.params.key;
479
+ if (that.accept === 'video' || test.video(result)) {
480
+ thumb = result + '?x-oss-process=video/snapshot,t_10000,m_fast';
481
+ }
482
+ that.succcessUpload(len + j, result, thumb);
483
+ }
484
+ }
485
+ });
486
+ uploadTask.onProgressUpdate((res) => {
487
+ that.updateUpload(len + j, {
488
+ progress: res.progress
489
+ });
490
+ // console.log('上传进度' + res.progress);
491
+ // console.log('已经上传的数据长度' + res.totalBytesSent);
492
+ // console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
493
+ });
494
+ break;
495
+ case 'local':
496
+ default:
497
+ // 服务器本机上传
498
+ var uploadTask = uni.uploadFile({
499
+ url: this.autoUploadApi,
500
+ filePath: lists[j].url,
501
+ name: 'file',
502
+ // fileType: 'video', // 仅支付宝小程序,且必填。
503
+ header: this.autoUploadHeader,
504
+ success: (uploadFileRes) => {
505
+ let res0 = uploadFileRes.data;
506
+ let afterPromise = '';
507
+ if (that.customAfterAutoUpload) {
508
+ afterPromise = new Promise((resolve, reject) => {
509
+ that.$emit(
510
+ 'afterAutoUpload',
511
+ Object.assign(res0, {
512
+ callback: (r) => {
513
+ r.url ? resolve(r) : reject();
514
+ }
515
+ })
516
+ );
517
+ });
518
+ }
519
+ if (test.promise(afterPromise)) {
520
+ afterPromise.then((data) => that.succcessUpload(len + j, data.url));
521
+ } else {
522
+ if (res0.code != 200) {
523
+ uni.showToast({
524
+ title: res0.msg
525
+ });
526
+ } else {
527
+ result = res0.data.url;
528
+ that.succcessUpload(len + j, result);
529
+ }
530
+ }
531
+ }
532
+ });
533
+ uploadTask.onProgressUpdate((res) => {
534
+ that.updateUpload(len + j, {
535
+ progress: res.progress
536
+ });
537
+ // console.log('上传进度' + res.progress);
538
+ // console.log('已经上传的数据长度' + res.totalBytesSent);
539
+ // console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
540
+ });
541
+ break;
542
+ }
543
+ }
544
+ } else {
545
+ if (typeof afterRead === 'function') {
546
+ afterRead(file, this.getDetail());
547
+ }
548
+ this.$emit(
549
+ 'afterRead',
550
+ Object.assign(
551
+ {
552
+ file
553
+ },
554
+ this.getDetail()
555
+ )
556
+ );
557
+ }
558
+ },
559
+ updateUpload(index, param) {
560
+ let item = this.fileList[index];
561
+ this.fileList.splice(index, 1, {
562
+ ...item,
563
+ // 注意这里不判断会出现succcessUpload先执行又被覆盖的问题
564
+ status: param.progress == 100 ? 'success' : 'uploading',
565
+ message: '',
566
+ progress: param.progress
567
+ });
568
+ this.$emit('update:fileList', this.fileList);
569
+ },
570
+ succcessUpload(index, url, thumb = '') {
571
+ let item = this.fileList[index];
572
+ this.fileList.splice(index, 1, {
573
+ ...item,
574
+ status: 'success',
575
+ message: '',
576
+ url: url,
577
+ progress: 100,
578
+ thumb: thumb
579
+ });
580
+ this.$emit('update:fileList', this.fileList);
581
+ },
582
+ deleteItem(index) {
583
+ if (this.autoDelete) {
584
+ this.fileList.splice(index, 1);
585
+ this.$emit('update:fileList', this.fileList);
586
+ } else {
587
+ this.$emit(
588
+ 'delete',
589
+ Object.assign(Object.assign({}, this.getDetail(index)), {
590
+ file: this.fileList[index]
591
+ })
592
+ );
593
+ }
594
+ },
595
+ // 预览图片
596
+ onPreviewImage(previewItem, index) {
597
+ if (!previewItem.isImage || !this.previewFullImage) return;
598
+ let current = 0;
599
+ const urls = [];
600
+ let imageIndex = 0;
601
+ for (var i = 0; i < this.lists.length; i++) {
602
+ const item = this.lists[i];
603
+ if (item.isImage || (item.type && item.type === 'image')) {
604
+ urls.push(item.url || item.thumb);
605
+ if (i === index) {
606
+ current = imageIndex;
607
+ }
608
+ imageIndex += 1;
609
+ }
610
+ }
611
+ if (urls.length < 1) {
612
+ return;
613
+ }
614
+ uni.previewImage({
615
+ urls: urls,
616
+ current: current,
617
+ fail() {
618
+ toast(t('up.upload.previewImageFail'));
619
+ }
620
+ });
621
+ },
622
+ onPreviewVideo(previewItem, index) {
623
+ if (!this.previewFullImage) return;
624
+ let current = 0;
625
+ const sources = [];
626
+ let videoIndex = 0;
627
+ for (var i = 0; i < this.lists.length; i++) {
628
+ const item = this.lists[i];
629
+ if (item.isVideo || (item.type && item.type === 'video')) {
630
+ sources.push(
631
+ Object.assign(Object.assign({}, item), {
632
+ type: 'video'
633
+ })
634
+ );
635
+ if (i === index) {
636
+ current = videoIndex;
637
+ }
638
+ videoIndex += 1;
639
+ }
640
+ }
641
+ if (sources.length < 1) {
642
+ return;
643
+ }
644
+ // #ifndef MP-WEIXIN
645
+ this.popupShow = true;
646
+ this.currentItemIndex = index;
647
+ console.log(this.lists[this.currentItemIndex]);
648
+ // #endif
649
+ // #ifdef MP-WEIXIN
650
+ wx.previewMedia({
651
+ sources: sources,
652
+ current: current,
653
+ fail() {
654
+ toast(t('up.upload.previewVideoFail'));
655
+ }
656
+ });
657
+ // #endif
658
+ },
659
+ onClickPreview(item, index) {
660
+ if (this.previewFullImage) {
661
+ switch (item.type) {
662
+ case 'image':
663
+ this.onPreviewImage(item, index);
664
+ break;
665
+ case 'video':
666
+ this.onPreviewVideo(item, index);
667
+ break;
668
+ default:
669
+ break;
670
+ }
671
+ }
672
+ this.$emit('clickPreview', Object.assign(Object.assign({}, item), this.getDetail(index)));
673
+ }
674
+ }
675
+ };
676
+ </script>
677
+ <style scoped>
678
+ .u-upload {
679
+ /* #ifndef APP-NVUE */
680
+ display: flex;
681
+ /* #endif */
682
+ flex-direction: column;
683
+ flex: 1;
684
+ }
685
+ .u-upload__wrap {
686
+ /* #ifndef APP-NVUE */
687
+ display: flex;
688
+ /* #endif */
689
+ flex-direction: row;
690
+ flex-wrap: wrap;
691
+ flex: 1;
692
+ }
693
+ .u-upload__wrap__preview {
694
+ border-radius: 2px;
695
+ margin: 0 8px 8px 0;
696
+ position: relative;
697
+ overflow: hidden;
698
+ /* #ifndef APP-NVUE */
699
+ display: flex;
700
+ /* #endif */
701
+ flex-direction: row;
702
+ }
703
+ .u-upload__wrap__preview__image {
704
+ width: 80px;
705
+ height: 80px;
706
+ }
707
+ .u-upload__wrap__preview__video,
708
+ .u-upload__wrap__preview__other {
709
+ width: 80px;
710
+ height: 80px;
711
+ background-color: rgb(242, 242, 242);
712
+ flex: 1;
713
+ /* #ifndef APP-NVUE */
714
+ display: flex;
715
+ /* #endif */
716
+ flex-direction: column;
717
+ justify-content: center;
718
+ align-items: center;
719
+ }
720
+ .u-upload__wrap__preview__video__text,
721
+ .u-upload__wrap__preview__other__text {
722
+ font-size: 11px;
723
+ color: var(--u-tips-color);
724
+ margin-top: 2px;
725
+ }
726
+ .u-upload__wrap__play {
727
+ position: absolute;
728
+ top: 0px;
729
+ left: 0px;
730
+ bottom: 0px;
731
+ right: 0px;
732
+ display: flex;
733
+ justify-content: center;
734
+ align-items: center;
735
+ }
736
+ .u-upload__wrap__play__icon {
737
+ background: #fff;
738
+ border-radius: 100px;
739
+ opacity: 0.8;
740
+ }
741
+ .u-upload__deletable {
742
+ position: absolute;
743
+ top: 0;
744
+ right: 0;
745
+ background-color: rgb(55, 55, 55);
746
+ height: 14px;
747
+ width: 14px;
748
+ /* #ifndef APP-NVUE */
749
+ display: flex;
750
+ /* #endif */
751
+ flex-direction: row;
752
+ border-bottom-left-radius: 100px;
753
+ align-items: center;
754
+ justify-content: center;
755
+ z-index: 3;
756
+ }
757
+ .u-upload__deletable__icon {
758
+ position: absolute;
759
+ transform: scale(0.7);
760
+ top: 0px;
761
+ right: 0px;
762
+ /* #ifdef H5 */
763
+ top: 1px;
764
+ right: 0;
765
+ /* #endif */
766
+ }
767
+ .u-upload__success {
768
+ position: absolute;
769
+ bottom: 0;
770
+ right: 0;
771
+ /* #ifndef APP-NVUE */
772
+ display: flex;
773
+ /* #endif */
774
+ flex-direction: row;
775
+ /* #ifndef APP-NVUE */
776
+ border-style: solid;
777
+ border-top-color: transparent;
778
+ border-left-color: transparent;
779
+ border-bottom-color: var(--u-success);
780
+ border-right-color: var(--u-success);
781
+ border-width: 9px;
782
+ align-items: center;
783
+ justify-content: center;
784
+ /* #endif */
785
+ }
786
+ .u-upload__success__icon {
787
+ /* #ifndef APP-NVUE */
788
+ position: absolute;
789
+ transform: scale(0.7);
790
+ bottom: -10px;
791
+ right: -10px;
792
+ /* #endif */
793
+ /* #ifdef APP-NVUE */
794
+ width: 16px;
795
+ height: 16px;
796
+ /* #endif */
797
+ }
798
+ .u-upload__progress {
799
+ background-color: var(--u-primary) !important;
800
+ position: absolute;
801
+ bottom: 0;
802
+ left: 0;
803
+ }
804
+ .u-upload__status {
805
+ position: absolute;
806
+ top: 0;
807
+ bottom: 0;
808
+ left: 0;
809
+ right: 0;
810
+ background-color: rgba(0, 0, 0, 0.5);
811
+ /* #ifndef APP-NVUE */
812
+ display: flex;
813
+ /* #endif */
814
+ flex-direction: column;
815
+ align-items: center;
816
+ justify-content: center;
817
+ }
818
+ .u-upload__status__icon {
819
+ position: relative;
820
+ z-index: 1;
821
+ }
822
+ .u-upload__status__message {
823
+ font-size: 12px;
824
+ color: #ffffff;
825
+ margin-top: 5px;
826
+ }
827
+ .u-upload__button {
828
+ /* #ifndef APP-NVUE */
829
+ display: flex;
830
+ /* #endif */
831
+ flex-direction: column;
832
+ align-items: center;
833
+ justify-content: center;
834
+ width: 80px;
835
+ height: 80px;
836
+ background-color: rgb(244, 245, 247);
837
+ border-radius: 2px;
838
+ margin: 0 8px 8px 0;
839
+ /* #ifndef APP-NVUE */
840
+ box-sizing: border-box;
841
+ /* #endif */
842
+ }
843
+ .u-upload__button__text {
844
+ font-size: 11px;
845
+ color: var(--u-tips-color);
846
+ margin-top: 2px;
847
+ }
848
+ .u-upload__button--hover {
849
+ background-color: rgb(230, 231, 233);
850
+ }
851
+ .u-upload__button--disabled {
852
+ opacity: 0.5;
853
+ }
854
+ </style>