feat(hook): 上传文件

This commit is contained in:
吴宇杰 2025-06-04 16:21:35 +08:00
parent b8c6beabb5
commit da5a2b1afe

View File

@ -1,69 +1,144 @@
// TODO: 别忘加更改环境变量的 VITE_UPLOAD_BASEURL 地址。 import { ref, Ref } from 'vue'
import { getEnvBaseUploadUrl } from '@/utils' import { getEnvBaseUploadUrl } from '@/utils'
const VITE_UPLOAD_BASEURL = `${getEnvBaseUploadUrl()}` const VITE_UPLOAD_BASEURL = `${getEnvBaseUploadUrl()}`
/** type TfileType = 'image' | 'file'
* useUpload type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*'
* @param formData {name: '菲鸽'} type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage
* @returns {loading, error, data, run}
*/ type TOptions<T extends TfileType> = {
export default function useUpload<T = string>(formData: Record<string, any> = {}) { formData?: Record<string, any>
maxSize?: number
accept?: T extends 'image' ? TImage[] : TFile[]
fileType?: T
success?: (params: any) => void
error?: (err: any) => void
}
export default function useUpload<T extends TfileType>(options: TOptions<T> = {} as TOptions<T>) {
const {
formData = {},
maxSize = 5 * 1024 * 1024,
accept = ['*'],
fileType = 'image',
success,
error: onError,
} = options
const loading = ref(false) const loading = ref(false)
const error = ref(false) const error = ref<Error | null>(null)
const data = ref<T>() const data = ref<any>(null)
const run = () => { const run = () => {
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
// 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。 // 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。
// 微信小程序在2023年10月17日之后使用本API需要配置隐私协议 // 微信小程序在2023年10月17日之后使用本API需要配置隐私协议
const chooseFileOptions = {
count: 1,
success: (res: any) => {
handleFileChoose({ tempFilePath: res.tempFilePaths[0], tempFiles: res.tempFiles[0] })
},
fail: (err: any) => {
console.error('File selection failed:', err)
error.value = err
onError?.(err)
},
}
if (fileType === 'image') {
// #ifdef MP-WEIXIN
uni.chooseMedia({ uni.chooseMedia({
count: 1, ...chooseFileOptions,
mediaType: ['image'], mediaType: ['image'],
success: (res) => {
loading.value = true
const tempFilePath = res.tempFiles[0].tempFilePath
uploadFile<T>({ tempFilePath, formData, data, error, loading })
},
fail: (err) => {
console.error('uni.chooseMedia err->', err)
error.value = true
},
}) })
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
uni.chooseImage({ uni.chooseImage(chooseFileOptions)
count: 1, // #endif
success: (res) => { } 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 loading.value = true
const tempFilePath = res.tempFilePaths[0] uploadFile({
uploadFile<T>({ tempFilePath, formData, data, error, loading }) tempFilePath: file.tempFilePath,
formData,
onSuccess: (res) => {
data.value = res
success?.(res)
}, },
fail: (err) => { onError: (err) => {
console.error('uni.chooseImage err->', err) error.value = err
error.value = true onError?.(err)
},
onComplete: () => {
loading.value = false
}, },
}) })
// #endif
} }
return { loading, error, data, run } return { loading, error, data, run }
} }
function uploadFile<T>({ tempFilePath, formData, data, error, loading }) { async function uploadFile({
tempFilePath,
formData,
onSuccess,
onError,
onComplete,
}: {
tempFilePath: string
formData: Record<string, any>
onSuccess: (data: any) => void
onError: (err: any) => void
onComplete: () => void
}) {
uni.uploadFile({ uni.uploadFile({
url: VITE_UPLOAD_BASEURL, url: VITE_UPLOAD_BASEURL,
filePath: tempFilePath, filePath: tempFilePath,
name: 'file', name: 'file',
formData, formData,
success: (uploadFileRes) => { success: (uploadFileRes) => {
data.value = uploadFileRes.data as T try {
const data = JSON.parse(uploadFileRes.data)
onSuccess(data)
} catch (err) {
onError(err)
}
}, },
fail: (err) => { fail: (err) => {
console.error('uni.uploadFile err->', err) console.error('Upload failed:', err)
error.value = true onError(err)
},
complete: () => {
loading.value = false
}, },
complete: onComplete,
}) })
} }