useUpload.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import { ref, Ref } from 'vue'
  2. import { getEnvBaseUploadUrl } from '@/utils'
  3. const VITE_UPLOAD_BASEURL = `${getEnvBaseUploadUrl()}`
  4. type TfileType = 'image' | 'file'
  5. type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*'
  6. type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage
  7. type TOptions<T extends TfileType> = {
  8. formData?: Record<string, any>
  9. maxSize?: number
  10. accept?: T extends 'image' ? TImage[] : TFile[]
  11. fileType?: T
  12. success?: (params: any) => void
  13. error?: (err: any) => void
  14. }
  15. export default function useUpload<T extends TfileType>(options: TOptions<T> = {} as TOptions<T>) {
  16. const {
  17. formData = {},
  18. maxSize = 5 * 1024 * 1024,
  19. accept = ['*'],
  20. fileType = 'image',
  21. success,
  22. error: onError,
  23. } = options
  24. const loading = ref(false)
  25. const error = ref<Error | null>(null)
  26. const data = ref<any>(null)
  27. const run = () => {
  28. // 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。
  29. // 微信小程序在2023年10月17日之后,使用本API需要配置隐私协议
  30. const chooseFileOptions = {
  31. count: 1,
  32. success: (res: any) => {
  33. console.log('File selected successfully:', res)
  34. // h5中res:{errMsg: "chooseImage:ok", tempFilePaths: "blob:http://localhost:9000/f74ab6b8-a14d-4cb6-a10d-fcf4511a0de5", tempFiles: [File]}
  35. // h5的File有一下字段:{name: "girl.jpeg", size: 48976, type: "image/jpeg"}
  36. // 小程序中res:{errMsg: "chooseImage:ok", tempFiles: [{fileType: "image", size: 48976, tempFilePath: "http://tmp/5iG1WpIxTaJf3ece38692a337dc06df7eb69ecb49c6b.jpeg"}]}
  37. let tempFilePath = ''
  38. let size = 0
  39. // #ifdef H5
  40. tempFilePath = res.tempFilePaths[0]
  41. size = res.tempFiles[0].size
  42. // #endif
  43. // #ifdef MP-WEIXIN
  44. tempFilePath = res.tempFiles[0].tempFilePath
  45. size = res.tempFiles[0].size
  46. // #endif
  47. handleFileChoose({ tempFilePath, size })
  48. },
  49. fail: (err: any) => {
  50. console.error('File selection failed:', err)
  51. error.value = err
  52. onError?.(err)
  53. },
  54. }
  55. if (fileType === 'image') {
  56. // #ifdef MP-WEIXIN
  57. uni.chooseMedia({
  58. ...chooseFileOptions,
  59. mediaType: ['image'],
  60. })
  61. // #endif
  62. // #ifndef MP-WEIXIN
  63. uni.chooseImage(chooseFileOptions)
  64. // #endif
  65. } else {
  66. uni.chooseFile({
  67. ...chooseFileOptions,
  68. type: 'all',
  69. })
  70. }
  71. }
  72. const handleFileChoose = ({ tempFilePath, size }: { tempFilePath: string; size: number }) => {
  73. if (size > maxSize) {
  74. uni.showToast({
  75. title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`,
  76. icon: 'none',
  77. })
  78. return
  79. }
  80. // const fileExtension = file?.tempFiles?.name?.split('.').pop()?.toLowerCase()
  81. // const isTypeValid = accept.some((type) => type === '*' || type.toLowerCase() === fileExtension)
  82. // if (!isTypeValid) {
  83. // uni.showToast({
  84. // title: `仅支持 ${accept.join(', ')} 格式的文件`,
  85. // icon: 'none',
  86. // })
  87. // return
  88. // }
  89. loading.value = true
  90. uploadFile({
  91. tempFilePath: tempFilePath,
  92. formData,
  93. onSuccess: (res) => {
  94. data.value = res
  95. // https://oss.laf.run/ukw0y1-unibest/unibest.f5308ecd-06c3-463b-b3e0-5df08154c7f3.svg
  96. // console.log('上传成功', res)
  97. success?.(res)
  98. },
  99. onError: (err) => {
  100. error.value = err
  101. onError?.(err)
  102. },
  103. onComplete: () => {
  104. loading.value = false
  105. },
  106. })
  107. }
  108. return { loading, error, data, run }
  109. }
  110. async function uploadFile({
  111. tempFilePath,
  112. formData,
  113. onSuccess,
  114. onError,
  115. onComplete,
  116. }: {
  117. tempFilePath: string
  118. formData: Record<string, any>
  119. onSuccess: (data: any) => void
  120. onError: (err: any) => void
  121. onComplete: () => void
  122. }) {
  123. uni.uploadFile({
  124. url: VITE_UPLOAD_BASEURL,
  125. filePath: tempFilePath,
  126. name: 'file',
  127. formData,
  128. success: (uploadFileRes) => {
  129. try {
  130. const data = uploadFileRes.data
  131. onSuccess(data)
  132. } catch (err) {
  133. onError(err)
  134. }
  135. },
  136. fail: (err) => {
  137. console.error('Upload failed:', err)
  138. onError(err)
  139. },
  140. complete: onComplete,
  141. })
  142. }