| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- import { isArray, isDef, isFunction } from '../common/util'
- import type { ChooseFile, ChooseFileOption, UploadFileItem, UploadMethod, UploadStatusType } from '../wd-upload/types'
- 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
- // #ifndef MP-WEIXIN
- uni.chooseImage({
- count: multiple ? maxCount : 1,
- sizeType,
- sourceType,
- // #ifdef H5
- extension,
- // #endif
- success: (res) => resolve(formatImage(res)),
- 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
- // #ifndef MP-WEIXIN
- uni.chooseVideo({
- sourceType,
- compressed,
- maxDuration,
- camera,
- // #ifdef H5
- extension,
- // #endif
- success: (res) => resolve(formatVideo(res)),
- 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
- // #ifndef MP-WEIXIN
- uni.chooseImage({
- count: multiple ? maxCount : 1,
- sizeType,
- sourceType,
- // #ifdef H5
- extension,
- // #endif
- success: (res) => resolve(formatImage(res)),
- fail: reject
- })
- // #endif
- break
- }
- })
- }
- return {
- startUpload,
- abort,
- UPLOAD_STATUS,
- chooseFile
- }
- }
|