393 lines
10 KiB
TypeScript
393 lines
10 KiB
TypeScript
import { isArray, isDef, isFunction } from '../common/util'
|
|
import type { ChooseFile, ChooseFileOption, UploadFileItem, UploadMethod, UploadStatusType } from '../wd-upload/types'
|
|
import { chooseSystemMedia } from "@/uni_modules/uni-chooseSystemImage"
|
|
|
|
export const UPLOAD_STATUS: Record<string, UploadStatusType> = {
|
|
PENDING: 'pending',
|
|
LOADING: 'loading',
|
|
SUCCESS: 'success',
|
|
FAIL: 'fail'
|
|
}
|
|
|
|
export interface UseUploadReturn {
|
|
// 开始上传文件
|
|
startUpload: (file: UploadFileItem, options: UseUploadOptions) => UniApp.UploadTask | void | Promise<void>
|
|
// 中断上传
|
|
abort: (task?: UniApp.UploadTask) => void
|
|
// 上传状态常量
|
|
UPLOAD_STATUS: Record<string, UploadStatusType>
|
|
// 选择文件
|
|
chooseFile: (options: ChooseFileOption) => Promise<ChooseFile[]>
|
|
}
|
|
|
|
export interface UseUploadOptions {
|
|
// 上传地址
|
|
action: string
|
|
// 请求头
|
|
header?: Record<string, any>
|
|
// 文件对应的 key
|
|
name?: string
|
|
// 其它表单数据
|
|
formData?: Record<string, any>
|
|
// 文件类型 仅支付宝支持且在支付宝平台必填
|
|
fileType?: 'image' | 'video' | 'audio'
|
|
// 成功状态码
|
|
statusCode?: number
|
|
// 文件状态的key
|
|
statusKey?: string
|
|
// 自定义上传方法
|
|
uploadMethod?: UploadMethod
|
|
// 上传成功回调
|
|
onSuccess?: (res: UniApp.UploadFileSuccessCallbackResult, file: UploadFileItem, formData: Record<string, any>) => void
|
|
// 上传失败回调
|
|
onError?: (res: UniApp.GeneralCallbackResult, file: UploadFileItem, formData: Record<string, any>) => void
|
|
// 上传进度回调
|
|
onProgress?: (res: UniApp.OnProgressUpdateResult, file: UploadFileItem) => void
|
|
// 是否自动中断之前的上传任务
|
|
abortPrevious?: boolean
|
|
// 根据文件拓展名过滤(H5支持全部类型过滤,微信小程序支持all和file时过滤,其余平台不支持)
|
|
extension?: string[]
|
|
}
|
|
|
|
export function useUpload(): UseUploadReturn {
|
|
let currentTask: UniApp.UploadTask | null = null
|
|
|
|
// 中断上传
|
|
const abort = (task?: UniApp.UploadTask) => {
|
|
if (task) {
|
|
task.abort()
|
|
} else if (currentTask) {
|
|
currentTask.abort()
|
|
currentTask = null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 默认上传方法
|
|
*/
|
|
const defaultUpload: UploadMethod = (file, formData, options) => {
|
|
// 如果配置了自动中断,则中断之前的上传任务
|
|
if (options.abortPrevious) {
|
|
abort()
|
|
}
|
|
|
|
const uploadTask = uni.uploadFile({
|
|
url: options.action,
|
|
header: options.header,
|
|
name: options.name,
|
|
fileName: options.name,
|
|
fileType: options.fileType,
|
|
formData,
|
|
filePath: file.url,
|
|
success(res) {
|
|
if (res.statusCode === options.statusCode) {
|
|
// 上传成功
|
|
options.onSuccess(res, file, formData)
|
|
} else {
|
|
// 上传失败
|
|
options.onError({ ...res, errMsg: res.errMsg || '' }, file, formData)
|
|
}
|
|
},
|
|
fail(err) {
|
|
// 上传失败
|
|
options.onError(err, file, formData)
|
|
}
|
|
})
|
|
|
|
currentTask = uploadTask
|
|
|
|
// 获取当前文件加载的百分比
|
|
uploadTask.onProgressUpdate((res) => {
|
|
options.onProgress(res, file)
|
|
})
|
|
|
|
// 返回上传任务实例,让外部可以控制上传过程
|
|
return uploadTask
|
|
}
|
|
|
|
/**
|
|
* 开始上传文件
|
|
*/
|
|
const startUpload = (file: UploadFileItem, options: UseUploadOptions) => {
|
|
const {
|
|
uploadMethod,
|
|
formData = {},
|
|
action,
|
|
name = 'file',
|
|
header = {},
|
|
fileType = 'image',
|
|
statusCode = 200,
|
|
statusKey = 'status',
|
|
abortPrevious = false
|
|
} = options
|
|
|
|
// 设置上传中状态
|
|
file[statusKey] = UPLOAD_STATUS.LOADING
|
|
|
|
const uploadOptions = {
|
|
action,
|
|
header,
|
|
name,
|
|
fileName: name,
|
|
fileType,
|
|
statusCode,
|
|
abortPrevious,
|
|
onSuccess: (res: UniApp.UploadFileSuccessCallbackResult, file: UploadFileItem, formData: Record<string, any>) => {
|
|
// 更新文件状态
|
|
file[statusKey] = UPLOAD_STATUS.SUCCESS
|
|
currentTask = null
|
|
options.onSuccess?.(res, file, formData)
|
|
},
|
|
onError: (error: UniApp.GeneralCallbackResult, file: UploadFileItem, formData: Record<string, any>) => {
|
|
// 更新文件状态和错误信息
|
|
file[statusKey] = UPLOAD_STATUS.FAIL
|
|
file.error = error.errMsg
|
|
currentTask = null
|
|
options.onError?.(error, file, formData)
|
|
},
|
|
onProgress: (res: UniApp.OnProgressUpdateResult, file: UploadFileItem) => {
|
|
// 更新上传进度
|
|
file.percent = res.progress
|
|
options.onProgress?.(res, file)
|
|
}
|
|
}
|
|
|
|
// 返回上传任务实例,支持外部获取uploadTask进行操作
|
|
if (isFunction(uploadMethod)) {
|
|
return uploadMethod(file, formData, uploadOptions)
|
|
} else {
|
|
return defaultUpload(file, formData, uploadOptions)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 格式化图片信息
|
|
*/
|
|
function formatImage(res: UniApp.ChooseImageSuccessCallbackResult): ChooseFile[] {
|
|
// #ifdef MP-DINGTALK
|
|
// 钉钉文件在files中
|
|
res.tempFiles = isDef((res as any).files) ? (res as any).files : res.tempFiles
|
|
// #endif
|
|
if (isArray(res.tempFiles)) {
|
|
return res.tempFiles.map((item: any) => ({
|
|
path: item.path || '',
|
|
name: item.name || '',
|
|
size: item.size,
|
|
type: 'image',
|
|
thumb: item.path || ''
|
|
}))
|
|
}
|
|
return [
|
|
{
|
|
path: (res.tempFiles as any).path || '',
|
|
name: (res.tempFiles as any).name || '',
|
|
size: (res.tempFiles as any).size,
|
|
type: 'image',
|
|
thumb: (res.tempFiles as any).path || ''
|
|
}
|
|
]
|
|
}
|
|
|
|
/**
|
|
* 格式化视频信息
|
|
*/
|
|
function formatVideo(res: UniApp.ChooseVideoSuccess): ChooseFile[] {
|
|
return [
|
|
{
|
|
path: res.tempFilePath || (res as any).filePath || '',
|
|
name: res.name || '',
|
|
size: res.size,
|
|
type: 'video',
|
|
thumb: (res as any).thumbTempFilePath || '',
|
|
duration: res.duration
|
|
}
|
|
]
|
|
}
|
|
|
|
/**
|
|
* 格式化媒体信息
|
|
*/
|
|
function formatMedia(res: UniApp.ChooseMediaSuccessCallbackResult): ChooseFile[] {
|
|
return res.tempFiles.map((item) => ({
|
|
type: item.fileType,
|
|
path: item.tempFilePath,
|
|
thumb: item.fileType === 'video' ? item.thumbTempFilePath : item.tempFilePath,
|
|
size: item.size,
|
|
duration: item.duration
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* 选择文件
|
|
*/
|
|
function chooseFile({
|
|
multiple,
|
|
sizeType,
|
|
sourceType,
|
|
maxCount,
|
|
accept,
|
|
compressed,
|
|
maxDuration,
|
|
camera,
|
|
extension
|
|
}: ChooseFileOption): Promise<ChooseFile[]> {
|
|
return new Promise((resolve, reject) => {
|
|
switch (accept) {
|
|
case 'image':
|
|
// #ifdef MP-WEIXIN
|
|
uni.chooseMedia({
|
|
count: multiple ? maxCount : 1,
|
|
mediaType: ['image'],
|
|
sourceType,
|
|
sizeType,
|
|
camera,
|
|
success: (res) => resolve(formatMedia(res)),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
// #ifdef H5
|
|
uni.chooseImage({
|
|
count: multiple ? maxCount : 1,
|
|
sizeType,
|
|
sourceType,
|
|
extension,
|
|
success: (res) => resolve(formatImage(res)),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
// #ifdef APP-PLUS
|
|
chooseSystemMedia({
|
|
count: multiple ? maxCount : 1,
|
|
mediaType: ['image'],
|
|
success: (res) => {
|
|
const tempFiles = res.filePaths.map((item: any) => ({
|
|
path: item
|
|
}))
|
|
resolve(formatImage({ tempFiles }))
|
|
},
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
break
|
|
case 'video':
|
|
// #ifdef MP-WEIXIN
|
|
uni.chooseMedia({
|
|
count: multiple ? maxCount : 1,
|
|
mediaType: ['video'],
|
|
sourceType,
|
|
camera,
|
|
maxDuration,
|
|
success: (res) => resolve(formatMedia(res)),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
// #ifdef H5
|
|
uni.chooseVideo({
|
|
sourceType,
|
|
compressed,
|
|
maxDuration,
|
|
camera,
|
|
extension,
|
|
success: (res) => resolve(formatVideo(res)),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
// #ifdef APP-PLUS
|
|
chooseSystemMedia({
|
|
count: multiple ? maxCount : 1,
|
|
mediaType: ['video'],
|
|
success: (res) => {
|
|
const tempFiles = res.filePaths.map((item: any) => ({
|
|
path: item
|
|
}))
|
|
resolve(formatImage({ tempFiles }))
|
|
},
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
break
|
|
// #ifdef MP-WEIXIN
|
|
case 'media':
|
|
uni.chooseMedia({
|
|
count: multiple ? maxCount : 1,
|
|
sourceType,
|
|
sizeType,
|
|
camera,
|
|
maxDuration,
|
|
success: (res) => resolve(formatMedia(res)),
|
|
fail: reject
|
|
})
|
|
break
|
|
case 'file':
|
|
uni.chooseMessageFile({
|
|
count: multiple ? (isDef(maxCount) ? maxCount : 100) : 1,
|
|
type: accept,
|
|
extension,
|
|
success: (res) => resolve(res.tempFiles),
|
|
fail: reject
|
|
})
|
|
break
|
|
// #endif
|
|
case 'all':
|
|
// #ifdef H5
|
|
uni.chooseFile({
|
|
count: multiple ? maxCount : 1,
|
|
type: accept,
|
|
extension,
|
|
success: (res) => resolve(res.tempFiles as ChooseFile[]),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
// #ifdef MP-WEIXIN
|
|
uni.chooseMessageFile({
|
|
count: multiple ? Number(maxCount) : 1,
|
|
type: accept,
|
|
extension,
|
|
success: (res) => resolve(res.tempFiles),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
break
|
|
default:
|
|
// #ifdef MP-WEIXIN
|
|
uni.chooseMedia({
|
|
count: multiple ? maxCount : 1,
|
|
mediaType: ['image'],
|
|
sourceType,
|
|
sizeType,
|
|
camera,
|
|
success: (res) => resolve(formatMedia(res)),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
// #ifdef H5
|
|
uni.chooseImage({
|
|
count: multiple ? maxCount : 1,
|
|
sizeType,
|
|
sourceType,
|
|
extension,
|
|
success: (res) => resolve(formatImage(res)),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
// #ifdef APP-PLUS
|
|
chooseSystemMedia({
|
|
count: multiple ? maxCount : 1,
|
|
mediaType: ['image'],
|
|
success: (res) => resolve(formatImage(res)),
|
|
fail: reject
|
|
})
|
|
// #endif
|
|
break
|
|
}
|
|
})
|
|
}
|
|
|
|
return {
|
|
startUpload,
|
|
abort,
|
|
UPLOAD_STATUS,
|
|
chooseFile
|
|
}
|
|
}
|