diff --git a/src/hooks/useUpload.ts b/src/hooks/useUpload.ts index adc083d..3bb06a4 100644 --- a/src/hooks/useUpload.ts +++ b/src/hooks/useUpload.ts @@ -1,69 +1,144 @@ -// TODO: 别忘加更改环境变量的 VITE_UPLOAD_BASEURL 地址。 +import { ref, Ref } from 'vue' import { getEnvBaseUploadUrl } from '@/utils' const VITE_UPLOAD_BASEURL = `${getEnvBaseUploadUrl()}` -/** - * useUpload 是一个定制化的请求钩子,用于处理上传图片。 - * @param formData 额外传递给后台的数据,如{name: '菲鸽'}。 - * @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。 - */ -export default function useUpload(formData: Record = {}) { +type TfileType = 'image' | 'file' +type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*' +type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage + +type TOptions = { + formData?: Record + maxSize?: number + accept?: T extends 'image' ? TImage[] : TFile[] + fileType?: T + success?: (params: any) => void + error?: (err: any) => void +} + +export default function useUpload(options: TOptions = {} as TOptions) { + const { + formData = {}, + maxSize = 5 * 1024 * 1024, + accept = ['*'], + fileType = 'image', + success, + error: onError, + } = options + const loading = ref(false) - const error = ref(false) - const data = ref() + const error = ref(null) + const data = ref(null) + const run = () => { // #ifdef MP-WEIXIN // 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。 // 微信小程序在2023年10月17日之后,使用本API需要配置隐私协议 - uni.chooseMedia({ + const chooseFileOptions = { count: 1, - mediaType: ['image'], - success: (res) => { - loading.value = true - const tempFilePath = res.tempFiles[0].tempFilePath - uploadFile({ tempFilePath, formData, data, error, loading }) + success: (res: any) => { + handleFileChoose({ tempFilePath: res.tempFilePaths[0], tempFiles: res.tempFiles[0] }) }, - fail: (err) => { - console.error('uni.chooseMedia err->', err) - error.value = true + fail: (err: any) => { + console.error('File selection failed:', err) + error.value = err + onError?.(err) + }, + } + + if (fileType === 'image') { + // #ifdef MP-WEIXIN + uni.chooseMedia({ + ...chooseFileOptions, + mediaType: ['image'], + }) + // #endif + + // #ifndef MP-WEIXIN + uni.chooseImage(chooseFileOptions) + // #endif + } else { + uni.chooseFile({ + ...chooseFileOptions, + type: 'all', + }) + } + } + + const handleFileChoose = (file: { + tempFilePath: string + tempFiles?: { size?: number; name?: string } + }) => { + if (file?.tempFiles?.size && file.tempFiles.size > maxSize) { + uni.showToast({ + title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`, + icon: 'none', + }) + return + } + + const fileExtension = file?.tempFiles?.name?.split('.').pop()?.toLowerCase() + const isTypeValid = accept.some((type) => type === '*' || type.toLowerCase() === fileExtension) + + if (!isTypeValid) { + uni.showToast({ + title: `仅支持 ${accept.join(', ')} 格式的文件`, + icon: 'none', + }) + return + } + + loading.value = true + uploadFile({ + tempFilePath: file.tempFilePath, + formData, + onSuccess: (res) => { + data.value = res + success?.(res) + }, + onError: (err) => { + error.value = err + onError?.(err) + }, + onComplete: () => { + loading.value = false }, }) - // #endif - // #ifndef MP-WEIXIN - uni.chooseImage({ - count: 1, - success: (res) => { - loading.value = true - const tempFilePath = res.tempFilePaths[0] - uploadFile({ tempFilePath, formData, data, error, loading }) - }, - fail: (err) => { - console.error('uni.chooseImage err->', err) - error.value = true - }, - }) - // #endif } return { loading, error, data, run } } -function uploadFile({ tempFilePath, formData, data, error, loading }) { +async function uploadFile({ + tempFilePath, + formData, + onSuccess, + onError, + onComplete, +}: { + tempFilePath: string + formData: Record + onSuccess: (data: any) => void + onError: (err: any) => void + onComplete: () => void +}) { uni.uploadFile({ url: VITE_UPLOAD_BASEURL, filePath: tempFilePath, name: 'file', formData, success: (uploadFileRes) => { - data.value = uploadFileRes.data as T + try { + const data = JSON.parse(uploadFileRes.data) + onSuccess(data) + } catch (err) { + onError(err) + } }, fail: (err) => { - console.error('uni.uploadFile err->', err) - error.value = true - }, - complete: () => { - loading.value = false + console.error('Upload failed:', err) + onError(err) }, + complete: onComplete, }) }