useUpload.ts 4.3 KB

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