im-ui-mobile 0.1.16 → 0.1.17

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.
@@ -11,7 +11,7 @@
11
11
  </template>
12
12
 
13
13
  <script setup lang="ts">
14
- import { ref, computed, watch, nextTick, useSlots, inject } from 'vue'
14
+ import { computed, inject } from 'vue'
15
15
 
16
16
  // 定义 Props
17
17
  interface Props {
@@ -10,10 +10,10 @@
10
10
  <!-- 按钮类型 -->
11
11
  <template v-if="type === 'button'">
12
12
  <im-button :type="buttonType" :size="buttonSize" :disabled="disabled" :loading="uploading">
13
- <view class="im-upload__button-content">
14
- <text v-if="!uploading" class="im-upload__icon">+</text>
15
- <text class="im-upload__text">{{ uploading ? '上传中...' : buttonText }}</text>
16
- </view>
13
+ <!-- <view> -->
14
+ <text v-if="!uploading" class="im-upload__icon">+</text>
15
+ <text class="im-upload__text">{{ uploading ? '上传中...' : buttonText }}</text>
16
+ <!-- </view> -->
17
17
  </im-button>
18
18
  </template>
19
19
 
@@ -29,9 +29,9 @@
29
29
  <!-- 头像类型 -->
30
30
  <template v-else-if="type === 'avatar'">
31
31
  <view class="im-upload__avatar">
32
- <im-avatar :src="fileList[0]?.url" :size="avatarSize" :radius="avatarRadius">
32
+ <im-avatar :url="fileList[0]?.url" :size="avatarSize" :radius="avatarRadius">
33
33
  <template v-if="!fileList[0]?.url">
34
- <text class="im-upload__avatar-icon">+</text>
34
+ <im-icon name="plus" size="40" color="#8c939d" />
35
35
  </template>
36
36
  </im-avatar>
37
37
  <text class="im-upload__avatar-text">{{ avatarText }}</text>
@@ -57,7 +57,7 @@
57
57
  <!-- 图片列表 -->
58
58
  <template v-if="listType === 'picture'">
59
59
  <view class="im-upload__item-preview">
60
- <image v-if="file.type?.startsWith('image/')" class="im-upload__item-image" :src="file.url || file.thumbUrl"
60
+ <image v-if="file.type?.startsWith('image')" class="im-upload__item-image" :src="file.url || file.thumbUrl"
61
61
  mode="aspectFill" @tap="handlePreview(file)" />
62
62
  <view v-else class="im-upload__item-file">
63
63
  <text class="im-upload__item-file-icon">📄</text>
@@ -83,10 +83,6 @@
83
83
 
84
84
  <!-- 操作按钮 -->
85
85
  <view class="im-upload__item-actions">
86
- <text v-if="file.status === 'done' && previewable" class="im-upload__item-action"
87
- @tap="handlePreview(file)">
88
- 👁️
89
- </text>
90
86
  <text v-if="!readonly && removable" class="im-upload__item-action" @tap="handleRemove(file, index)">
91
87
 
92
88
  </text>
@@ -176,7 +172,7 @@ interface UploadFile {
176
172
  // 定义 Props
177
173
  interface Props {
178
174
  // 值
179
- modelValue?: UploadFile[]
175
+ modelValue?: string | UploadFile[]
180
176
 
181
177
  // 上传类型
182
178
  type?: 'button' | 'card' | 'avatar' | 'drag' | undefined
@@ -241,18 +237,17 @@ interface Props {
241
237
 
242
238
  // 定义 Emits
243
239
  interface Emits {
244
- (e: 'update:modelValue', files: UploadFile[]): void
245
- (e: 'change', files: UploadFile[]): void
240
+ (e: 'update:modelValue', files: string | UploadFile[]): void
241
+ (e: 'change', files: string | UploadFile[]): void
246
242
  (e: 'select', file: Object): void
247
- (e: 'upload', file: UploadFile): void
248
- (e: 'success', response: any, file: UploadFile): void
243
+ (e: 'success', file: UploadFile): void
249
244
  (e: 'error', error: Error, file: UploadFile): void
250
245
  (e: 'progress', percent: number, file: UploadFile): void
251
246
  (e: 'remove', file: UploadFile, index: number): void
252
247
  (e: 'preview', file: UploadFile): void
253
248
  (e: 'exceed', files: Object[]): void
254
- (e: 'before-upload', file: UploadFile): void
255
- (e: 'after-upload', file: UploadFile): void
249
+ (e: 'uploading', file: UploadFile): void
250
+ (e: 'uploaded', file: UploadFile): void
256
251
  }
257
252
 
258
253
  // 定义 Props 默认值
@@ -294,6 +289,7 @@ const props = withDefaults(defineProps<Props>(), {
294
289
  autoUpload: true,
295
290
 
296
291
  responseFormatter: (response: any) => {
292
+ console.log('responseFormatter', response)
297
293
  return {
298
294
  url: response?.data?.url || response?.result?.url || response?.url || response?.fileUrl,
299
295
  name: response?.data?.fileName || response?.result?.fileName || response?.data?.name || response?.result?.name || response?.name,
@@ -313,7 +309,7 @@ const props = withDefaults(defineProps<Props>(), {
313
309
  const emit = defineEmits<Emits>()
314
310
 
315
311
  // 响应式状态
316
- const fileList = ref<UploadFile[]>(props.modelValue || [])
312
+ const fileList = ref<UploadFile[]>([]) //props.modelValue || []
317
313
  const dragOver = ref(false)
318
314
  const uploadingAll = ref(false)
319
315
 
@@ -322,8 +318,19 @@ const uploadTasks = new Map<string, UniApp.UploadTask>()
322
318
 
323
319
  // 监听 modelValue 变化
324
320
  watch(() => props.modelValue, (val) => {
325
- if (val) {
326
- fileList.value = val
321
+ if (!val) return
322
+
323
+ if (isSingleFile()) {
324
+ fileList.value = [{
325
+ url: String(props.modelValue),
326
+ uid: '',
327
+ name: 'single file',
328
+ size: 0,
329
+ status: 'uploading'
330
+ }]
331
+ }
332
+ else {
333
+ fileList.value = val as UploadFile[]
327
334
  }
328
335
  }, { deep: true })
329
336
 
@@ -334,7 +341,7 @@ const uploading = computed(() => {
334
341
 
335
342
  // 生成唯一ID
336
343
  const generateUid = () => {
337
- return Date.now() + '-' + Math.random().toString(36).substr(2, 9)
344
+ return Date.now() + '-' + Math.random().toString(36).substring(2, 9)
338
345
  }
339
346
 
340
347
  // 格式化文件大小
@@ -370,8 +377,13 @@ const handleUploadTap = async () => {
370
377
  return
371
378
  }
372
379
 
373
- const maxSelectable = props.multiple ?
374
- Math.max(0, props.maxCount! - fileList.value.length) : 1
380
+ let accept = getFileType(props.accept) // image, video, all
381
+ let maxSelectable = props.multiple ? Math.max(0, props.maxCount! - fileList.value.length) : 1
382
+
383
+ if (props.type === 'avatar') {
384
+ accept = 'image'
385
+ maxSelectable = 1
386
+ }
375
387
 
376
388
  if (maxSelectable <= 0) {
377
389
  emit('exceed', [])
@@ -384,9 +396,10 @@ const handleUploadTap = async () => {
384
396
 
385
397
  try {
386
398
  const res = await chooseFile({
387
- count: 9,
388
- type: getFileType(props.accept) //'image' // image, video, all
399
+ count: maxSelectable,
400
+ type: accept
389
401
  })
402
+
390
403
  for (const tempFile of res.tempFiles as Array<any>) {
391
404
  await processFile(tempFile)
392
405
  }
@@ -397,25 +410,6 @@ const handleUploadTap = async () => {
397
410
  icon: 'none'
398
411
  })
399
412
  }
400
-
401
-
402
- // uni.chooseFile({
403
- // count: maxSelectable,
404
- // type: getFileType(props.accept),
405
- // extension: getFileExtensions(props.accept),
406
- // success: async (res) => {
407
- // for (const tempFile of res.tempFiles as Array<any>) {
408
- // await processFile(tempFile)
409
- // }
410
- // },
411
- // fail: (err) => {
412
- // console.error('选择文件失败:', err)
413
- // uni.showToast({
414
- // title: '选择文件失败',
415
- // icon: 'none'
416
- // })
417
- // }
418
- // })
419
413
  }
420
414
 
421
415
  // 获取文件类型
@@ -425,19 +419,9 @@ const getFileType = (accept: string): 'image' | 'video' | 'all' => {
425
419
  return 'all'
426
420
  }
427
421
 
428
- // 获取文件扩展名
429
- const getFileExtensions = (accept: string): string[] | undefined => {
430
- if (accept === '*' || accept.includes('all')) {
431
- return undefined
432
- }
433
-
434
- const extensions = accept
435
- .split(',')
436
- .map(ext => ext.trim())
437
- .filter(ext => ext.startsWith('.'))
438
- .map(ext => ext.substring(1))
439
-
440
- return extensions.length > 0 ? extensions : undefined
422
+ // 是否仅上传单个文件
423
+ const isSingleFile = () => {
424
+ return typeof props.modelValue === 'string' || props.type === 'avatar' || !props.multiple
441
425
  }
442
426
 
443
427
  // 处理文件
@@ -485,7 +469,7 @@ const processFile = async (uniFile: any) => {
485
469
  status: 'pending',
486
470
  progress: 0,
487
471
  url: uniFile.path,
488
- thumbUrl: uniFile.type?.startsWith('image/') ? uniFile.path : undefined,
472
+ thumbUrl: uniFile.type?.startsWith('image') ? uniFile.path : undefined,
489
473
  rawFile: uniFile,
490
474
  file
491
475
  }
@@ -493,6 +477,7 @@ const processFile = async (uniFile: any) => {
493
477
  // 添加到文件列表
494
478
  if (!props.multiple) {
495
479
  fileList.value = [uploadFile]
480
+
496
481
  } else {
497
482
  fileList.value.push(uploadFile)
498
483
  }
@@ -506,69 +491,13 @@ const processFile = async (uniFile: any) => {
506
491
  }
507
492
  }
508
493
 
509
- // // 检查文件类型是否被接受
510
- // const isFileTypeAccepted = (uniFile: any): boolean => {
511
- // if (props.accept === '*') return true
512
-
513
- // const acceptTypes = props.accept.split(',').map(type => type.trim())
514
-
515
- // for (const acceptType of acceptTypes) {
516
- // if (acceptType === '*') return true
517
-
518
- // // 检查 MIME 类型
519
- // if (acceptType.endsWith('/*')) {
520
- // const category = acceptType.split('/')[0]
521
- // if (uniFile.type?.startsWith(category + '/')) {
522
- // return true
523
- // }
524
- // }
525
-
526
- // // 检查扩展名
527
- // if (acceptType.startsWith('.')) {
528
- // const ext = acceptType.substring(1).toLowerCase()
529
- // const fileName = uniFile.name.toLowerCase()
530
- // if (fileName.endsWith('.' + ext)) {
531
- // return true
532
- // }
533
- // }
534
-
535
- // // 检查完整 MIME 类型
536
- // if (uniFile.type === acceptType) {
537
- // return true
538
- // }
539
- // }
540
-
541
- // return false
542
- // }
543
-
544
- // 从 uniapp 文件创建 File 对象
545
- // const createFileFromUniFile = (uniFile: any): File => {
546
- // const file = new File([], uniFile.name, {
547
- // type: uniFile.type || 'application/octet-stream',
548
- // lastModified: uniFile.lastModified || Date.now()
549
- // })
550
-
551
- // Object.defineProperties(file, {
552
- // size: {
553
- // value: uniFile.size,
554
- // writable: false
555
- // },
556
- // path: {
557
- // value: uniFile.path,
558
- // writable: false
559
- // }
560
- // })
561
-
562
- // return file
563
- // }
564
-
565
494
  // 开始上传
566
495
  const startUpload = async (uploadFile: UploadFile) => {
567
496
  uploadFile.status = 'uploading'
568
497
  uploadFile.progress = 0
569
- emit('upload', uploadFile)
570
- emit('before-upload', uploadFile)
571
- updateFileList()
498
+ emit('uploading', uploadFile)
499
+
500
+ // updateFileList()
572
501
 
573
502
  try {
574
503
  let response: any
@@ -580,7 +509,7 @@ const startUpload = async (uploadFile: UploadFile) => {
580
509
  (percent) => {
581
510
  uploadFile.progress = percent
582
511
  emit('progress', percent, uploadFile)
583
- updateFileList()
512
+ updateFileList(uploadFile)
584
513
  }
585
514
  )
586
515
  } else if (props.action) {
@@ -598,7 +527,7 @@ const startUpload = async (uploadFile: UploadFile) => {
598
527
  uploadFile.response = formattedResponse
599
528
  uploadFile.url = formattedResponse.url || uploadFile.url
600
529
 
601
- emit('success', formattedResponse, uploadFile)
530
+ emit('success', uploadFile)
602
531
  } catch (error) {
603
532
  uploadFile.status = 'error'
604
533
  uploadFile.error = error as Error
@@ -609,17 +538,21 @@ const startUpload = async (uploadFile: UploadFile) => {
609
538
  icon: 'none'
610
539
  })
611
540
  } finally {
612
- emit('after-upload', uploadFile)
613
- updateFileList()
541
+ emit('uploaded', uploadFile)
542
+ updateFileList(uploadFile)
614
543
  }
615
544
  }
616
545
 
617
546
  // 默认上传实现
618
547
  const defaultUpload = (uploadFile: UploadFile): Promise<any> => {
619
- const headers = {
620
- ...props.headers,
621
- 'Authorization': `Bearer ${props.accessToken}`,
622
- 'AccessToken': props.accessToken,
548
+ let headers = props.headers
549
+
550
+ if (props.accessToken) {
551
+ headers = {
552
+ ...headers,
553
+ 'Authorization': `Bearer ${props.accessToken}`,
554
+ 'AccessToken': props.accessToken,
555
+ }
623
556
  }
624
557
 
625
558
  return universalUploadFile({
@@ -636,43 +569,17 @@ const defaultUpload = (uploadFile: UploadFile): Promise<any> => {
636
569
  timeout: props.timeout,
637
570
  withCredentials: props.withCredentials
638
571
  })
639
-
640
- // return new Promise((resolve, reject) => {
641
- // uni.uploadFile({
642
- // url: props.action!,
643
- // filePath: uploadFile.rawFile.path,
644
- // name: props.name,
645
- // formData: {
646
- // ...props.data,
647
- // filename: uploadFile.name,
648
- // size: uploadFile.size,
649
- // type: uploadFile.type
650
- // },
651
- // header: headers,
652
- // timeout: props.timeout,
653
- // withCredentials: props.withCredentials,
654
- // success: (res: any) => {
655
- // try {
656
- // const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
657
- // resolve(data)
658
- // } catch (e: any) {
659
- // reject(e)
660
- // }
661
- // },
662
- // complete: () => {
663
- // // 上传完成
664
- // },
665
- // fail: (e: any) => {
666
- // reject(e)
667
- // }
668
- // })
669
- // })
670
572
  }
671
573
 
672
574
  // 更新文件列表
673
- const updateFileList = () => {
575
+ const updateFileList = (uploadFile?: UploadFile) => {
674
576
  emit('change', [...fileList.value])
675
- emit('update:modelValue', [...fileList.value])
577
+
578
+ if (isSingleFile()) {
579
+ emit('update:modelValue', String(uploadFile?.url))
580
+ } else {
581
+ emit('update:modelValue', [...fileList.value])
582
+ }
676
583
  }
677
584
 
678
585
  // 处理删除
@@ -713,7 +620,7 @@ const handlePreview = (file: UploadFile) => {
713
620
  emit('preview', file)
714
621
 
715
622
  // 如果是图片,使用 uni.previewImage
716
- if (file.url && file.type?.startsWith('image/')) {
623
+ if (file.url && file.type?.startsWith('image')) {
717
624
  uni.previewImage({
718
625
  urls: [file.url],
719
626
  current: file.url
@@ -778,30 +685,6 @@ const handleClearAll = () => {
778
685
  })
779
686
  }
780
687
 
781
- // 手动上传文件
782
- const upload = async (file: File) => {
783
- const uploadFile: UploadFile = {
784
- uid: generateUid(),
785
- name: file.name,
786
- size: file.size,
787
- type: file.type,
788
- status: 'pending',
789
- progress: 0,
790
- file: file
791
- }
792
-
793
- if (!props.multiple) {
794
- fileList.value = [uploadFile]
795
- } else {
796
- fileList.value.push(uploadFile)
797
- }
798
-
799
- emit('select', file)
800
- updateFileList()
801
-
802
- await startUpload(uploadFile)
803
- }
804
-
805
688
  // 清空文件列表
806
689
  const clearFiles = () => {
807
690
  handleClearAll()
@@ -825,7 +708,6 @@ const abortUpload = (uid: string) => {
825
708
 
826
709
  // 暴露方法给父组件
827
710
  defineExpose({
828
- upload,
829
711
  clearFiles,
830
712
  abortUpload,
831
713
  uploadAll: handleUploadAll,
@@ -905,11 +787,6 @@ defineExpose({
905
787
  gap: 20rpx;
906
788
  }
907
789
 
908
- .im-upload__avatar-icon {
909
- font-size: 40rpx;
910
- color: #8c939d;
911
- }
912
-
913
790
  .im-upload__avatar-text {
914
791
  font-size: 26rpx;
915
792
  color: #606266;
@@ -949,12 +826,15 @@ defineExpose({
949
826
  }
950
827
 
951
828
  .im-upload__list {
952
- margin-top: 32rpx;
829
+ // margin-top: 20rpx;
830
+ display: flex;
831
+ flex-wrap: wrap;
953
832
  }
954
833
 
955
834
  .im-upload__item {
956
835
  &--picture {
957
- margin-bottom: 24rpx;
836
+ margin-top: 20rpx;
837
+ margin-right: 20rpx;
958
838
  }
959
839
 
960
840
  &--text {
@@ -1066,12 +946,6 @@ defineExpose({
1066
946
  right: 8rpx;
1067
947
  display: flex;
1068
948
  gap: 8rpx;
1069
- opacity: 0;
1070
- transition: opacity 0.3s;
1071
- }
1072
-
1073
- .im-upload__item-preview:hover .im-upload__item-actions {
1074
- opacity: 1;
1075
949
  }
1076
950
 
1077
951
  .im-upload__item-action {
@@ -0,0 +1,214 @@
1
+ // utils/file-adapter.ts
2
+
3
+ /**
4
+ * 创建统一的文件对象(多平台兼容)
5
+ * @param {Object} rawFile - 原始文件数据
6
+ * @returns {Object} 统一格式的文件对象
7
+ */
8
+ export const createFileFromUniFile = (rawFile: any): any => {
9
+ // 检查环境
10
+ // #ifdef H5
11
+ if (rawFile instanceof File) {
12
+ return rawFile
13
+ }
14
+ // #endif
15
+
16
+ const path = rawFile.path || rawFile.tempFilePath || rawFile.apFilePaths?.[0]
17
+ const name = rawFile.name || getFileNameFromPath(path)
18
+ const size = rawFile.size || 0
19
+ const type = rawFile.type || getFileTypeFromPath(name)
20
+
21
+ // 创建统一的文件对象
22
+ const unifiedFile = {
23
+ // 基础属性
24
+ path,
25
+ name,
26
+ size,
27
+ type,
28
+ lastModified: rawFile.lastModified || Date.now(),
29
+
30
+ // 原始数据
31
+ raw: rawFile,
32
+
33
+ // 方法(模拟 File 对象的部分行为)
34
+ slice(start: any, end: any) {
35
+ // 小程序环境不支持实际切片,返回一个标记对象
36
+ return {
37
+ path: this.path,
38
+ name: this.name,
39
+ size: end - start,
40
+ type: this.type,
41
+ slice: () => { }
42
+ }
43
+ },
44
+
45
+ // 转换为 base64(异步)
46
+ toBase64() {
47
+ return new Promise((resolve: any, reject: any) => {
48
+ // #ifdef MP-WEIXIN
49
+ wx.getFileSystemManager().readFile({
50
+ filePath: this.path,
51
+ encoding: 'base64',
52
+ success: (res: any) => resolve(res.data),
53
+ fail: reject
54
+ })
55
+ // #endif
56
+
57
+ // #ifdef H5
58
+ const reader = new FileReader()
59
+ reader.onload = () => resolve(reader.result.split(',')[1])
60
+ reader.onerror = reject
61
+ reader.readAsDataURL(this)
62
+ // #endif
63
+
64
+ // #ifdef APP-PLUS
65
+ plus.io.resolveLocalFileSystemURL(this.path, (entry: any) => {
66
+ entry.file((file: any) => {
67
+ const reader = new plus.io.FileReader()
68
+ reader.onload = (e: any) => resolve(e.target.result.split(',')[1])
69
+ reader.onerror = reject
70
+ reader.readAsDataURL(file)
71
+ })
72
+ })
73
+ // #endif
74
+ })
75
+ },
76
+
77
+ // 转换为 ArrayBuffer(异步)
78
+ toArrayBuffer() {
79
+ return new Promise((resolve: any, reject: any) => {
80
+ // #ifdef MP-WEIXIN
81
+ wx.getFileSystemManager().readFile({
82
+ filePath: this.path,
83
+ success: (res: any) => resolve(res.data),
84
+ fail: reject
85
+ })
86
+ // #endif
87
+
88
+ // #ifdef H5
89
+ const reader = new FileReader()
90
+ reader.onload = () => resolve(reader.result)
91
+ reader.onerror = reject
92
+ reader.readAsArrayBuffer(this)
93
+ // #endif
94
+ })
95
+ },
96
+
97
+ // 获取文件 URL(用于预览等)
98
+ getURL() {
99
+ // #ifdef H5
100
+ if (this.raw instanceof File) {
101
+ return URL.createObjectURL(this.raw)
102
+ }
103
+ // #endif
104
+ return this.path
105
+ },
106
+
107
+ // 释放资源
108
+ revoke() {
109
+ // #ifdef H5
110
+ if (this.raw instanceof File && this._objectURL) {
111
+ URL.revokeObjectURL(this._objectURL)
112
+ }
113
+ // #endif
114
+ }
115
+ }
116
+
117
+ // 如果是 H5 环境,尝试包装成 File 对象
118
+ // #ifdef H5
119
+ if (typeof File !== 'undefined' && !(rawFile instanceof File)) {
120
+ try {
121
+ // 尝试创建 File 对象(需要 fetch 支持)
122
+ return Object.assign(new Blob(), unifiedFile)
123
+ } catch (e) {
124
+ console.warn('无法创建 File 对象,使用统一格式:', e)
125
+ }
126
+ }
127
+ // #endif
128
+
129
+ return unifiedFile
130
+ }
131
+
132
+ /**
133
+ * 从文件路径提取文件名
134
+ */
135
+ const getFileNameFromPath = (path: any): any => {
136
+ if (!path) return 'unnamed'
137
+ return path.split('/').pop().split('?')[0]
138
+ }
139
+
140
+ /**
141
+ * 从文件名获取文件类型
142
+ */
143
+ const getFileTypeFromPath = (filename: any): any => {
144
+ if (!filename) return 'application/octet-stream'
145
+
146
+ const extension = filename.split('.').pop().toLowerCase()
147
+ const typeMap: any = {
148
+ // 图片
149
+ 'jpg': 'image/jpeg',
150
+ 'jpeg': 'image/jpeg',
151
+ 'png': 'image/png',
152
+ 'gif': 'image/gif',
153
+ 'bmp': 'image/bmp',
154
+ 'webp': 'image/webp',
155
+ 'svg': 'image/svg+xml',
156
+
157
+ // 视频
158
+ 'mp4': 'video/mp4',
159
+ 'avi': 'video/x-msvideo',
160
+ 'mov': 'video/quicktime',
161
+ 'wmv': 'video/x-ms-wmv',
162
+ 'flv': 'video/x-flv',
163
+ 'mkv': 'video/x-matroska',
164
+
165
+ // 音频
166
+ 'mp3': 'audio/mpeg',
167
+ 'wav': 'audio/wav',
168
+ 'aac': 'audio/aac',
169
+ 'ogg': 'audio/ogg',
170
+ 'flac': 'audio/flac',
171
+
172
+ // 文档
173
+ 'pdf': 'application/pdf',
174
+ 'doc': 'application/msword',
175
+ 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
176
+ 'xls': 'application/vnd.ms-excel',
177
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
178
+ 'ppt': 'application/vnd.ms-powerpoint',
179
+ 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
180
+ 'txt': 'text/plain'
181
+ }
182
+
183
+ return typeMap[extension] || 'application/octet-stream'
184
+ }
185
+
186
+ /**
187
+ * 批量转换文件对象
188
+ */
189
+ export const createFilesFromUniFiles = (rawFiles: any): any => {
190
+ if (!Array.isArray(rawFiles)) {
191
+ rawFiles = [rawFiles]
192
+ }
193
+
194
+ return rawFiles.map((file: any) => createFileFromUniFile(file))
195
+ }
196
+
197
+ /**
198
+ * 环境检测
199
+ */
200
+ export const isBrowserEnv = (): any => {
201
+ // #ifdef H5
202
+ return typeof File !== 'undefined'
203
+ // #endif
204
+
205
+ return false
206
+ }
207
+
208
+ export const isWeChatEnv = (): any => {
209
+ // #ifdef MP-WEIXIN
210
+ return true
211
+ // #endif
212
+
213
+ return false
214
+ }