zgg-ui
Version:
2.0.1 正式版本 基于 Vue 3、UniApp 和 TypeScript 开发的多端适配移动端 UI 组件库,旨在提供丰富的组件集合,帮助开发者快速构建多端响应式的移动应用界面
302 lines (278 loc) • 9.7 kB
text/typescript
import { PropsTypeHook } from '../../libs/zHooks'
import zType from '../../libs/zType'
import zTest from '../../libs/zTest'
import z from '../../libs/z'
import { watch, ref } from 'vue'
import zImageUpload from './z-image-upload.vue'
export type ImageUploadSizeTypes = 'original' | 'compressed'
export type ImageUploadSources = 'album' | 'camera'
export type ImageExtensions = 'jpg' | 'jpeg' | 'png' | 'gif' | 'webp' | 'ico'
export type ImageUploadFile = UniApp.ChooseImageSuccessCallbackResultFile | File
export type ImageUploadList = Array<ImageUploadListItem>
export type ImageUploadInstance = InstanceType<typeof zImageUpload>
export interface ImageUploadListItem {
url: string
status: 'ready' | 'uploading' | 'done' | 'failed'
progress: number
uploadTask?: UniApp.UploadTask
file?: ImageUploadFile
}
export type ImageUploadCustomFunction = (
file: ImageUploadFile
) => Promise<string> | string
export type ImageUploadCustomCallbackFunction = (
data: UniApp.UploadFileSuccessCallbackResult
) => Promise<string> | string
export type ImageBeforeUploadFunction = (
file: ImageUploadFile
) => boolean | Promise<boolean>
export type ImageBeforeRemoveFunction = (
file: ImageUploadListItem
) => boolean | Promise<boolean>
export interface ImageUploadListItem {
url: string
status: 'ready' | 'uploading' | 'done' | 'failed'
progress: number
uploadTask?: UniApp.UploadTask
file?: ImageUploadFile
}
interface PropsType extends PropsTypeHook {
modelValue?: Array<string>
disabled?: boolean
action?: string
name?: string
header?: object
formData?: object
limit?: number
autoUpload?: boolean
showRemove?: boolean
showErrorTips?: boolean
showUploadProgress?: boolean
sizeType?: Array<ImageUploadSizeTypes>
sourceType?: Array<ImageUploadSources>
multiple?: boolean
maxSize: number
extensions?: Array<string>
autoRemoveFaildFile?: boolean
customUploadHandler?: ImageUploadCustomFunction
customUploadCallback?: ImageUploadCustomCallbackFunction
beforeUpload?: ImageBeforeUploadFunction
beforeRemove?: ImageBeforeRemoveFunction
validateEvent?: boolean
}
/**
*
* @param props 上传触发方法
* @returns
*/
export function useUploadHandleFunction(props: PropsType) {
// 选择系统图片
const chooseImage = (count: number) => {
return new Promise<Array<ImageUploadFile>>((resolve, reject) => {
uni.chooseImage({
count,
sizeType: props.sizeType,
// extension: props.extensions,
sourceType: props.sourceType,
success: (res) => {
resolve(
zType.isArray(res.tempFiles) ? res.tempFiles : [res.tempFiles]
)
},
fail: (err) => {
reject(err)
},
})
})
}
// 上传图片事件,调用接口
// 正在上传标识
const uploading = ref(false)
watch(
() => uploading.value,
(val) => {
if (props.showErrorTips) {
if (val) uni.showLoading({ title: '上传中' })
else uni.hideLoading()
}
}
)
const uploadProcess = (item: ImageUploadListItem): Promise<boolean> => {
const { customUploadHandler, customUploadCallback } = props
if (uploading.value) return Promise.reject('有文件正在上传')
return new Promise((resolve, reject) => {
// 如果有自定义上传处理函数,则调用自定义上传处理函数
if (customUploadHandler) {
const uploadHandlerResult = customUploadHandler(item.file!)
const isUploadHandlePromiseOrString = [
zType.isPromise(uploadHandlerResult),
zType.isString(uploadHandlerResult),
].includes(true)
if (!isUploadHandlePromiseOrString) {
console.error(
'zImageUpload 自定义上传处理函数必须返回Promise和String'
)
reject('自定义上传处理函数必须返回Promise和String')
return
}
uploading.value = true
item.status = 'uploading'
if (zType.isPromise(uploadHandlerResult)) {
uploadHandlerResult
.then((res) => {
if (res) {
item.url = res
resolve(true)
} else {
resolve(false)
}
})
.catch((err) => {
console.error('zImageUpload 上传文件发生错误', err)
reject(err?.errMsg || '上传文件发生错误')
})
.finally(() => {
uploading.value = false
})
} else {
if (uploadHandlerResult) {
item.url = uploadHandlerResult
resolve(true)
} else {
resolve(false)
}
uploading.value = false
}
} else {
// 内部集成图片上传
uploading.value = true
item.status = 'uploading'
// 创建上传对象
const task = uni.uploadFile({
url: props.action!,
filePath: item.url,
name: props.name,
formData: props.formData,
header: props.header,
success: (res: UniApp.UploadFileSuccessCallbackResult) => {
// 判断用户是否自己处理上传后服务器回传的结果
if (customUploadCallback) {
const customUploadCallbackResult = customUploadCallback(res)
const isCustomUploadCallbackPromiseOrString = [
zType.isPromise(customUploadCallbackResult),
zType.isString(customUploadCallbackResult),
].includes(true)
if (!isCustomUploadCallbackPromiseOrString) {
console.error(
'zImageUpload 自定义上传回调函数必须返回Promise和String'
)
reject('自定义上传回调函数必须返回Promise和String')
return
}
if (zType.isPromise(customUploadCallbackResult)) {
customUploadCallbackResult
.then((res) => {
if (res) {
item.url = res
resolve(true)
} else {
resolve(false)
}
})
.catch((err) => {
console.error('zImageUpload 上传文件发生错误', err)
reject(err?.errMsg || '上传文件发生错误')
})
} else {
if (customUploadCallbackResult) {
item.url = customUploadCallbackResult
resolve(true)
} else {
resolve(false)
}
}
} else {
// 使用集成的上传回调函数
const { statusCode, data: resData } = res
if (![200, 201, 204].includes(statusCode)) {
console.error('zImageUpload 上传文件发生错误', res)
reject(res?.errMsg || '上传文件发生错误')
return
} else {
const data = zTest.jsonString(resData)
? JSON.parse(resData)
: resData
// 默认返回的格式为 { code: 200, data: { errorCode: 0, url: '' } }
if (data.code === 200 && data.data.errCode === 0) {
item.url = data.data.url
resolve(true)
} else {
console.error('zImageUpload 上传文件发生错误', res)
reject(
z.isEmptyVariableInDefault(
data?.message,
data?.msg || '上传文件发生错误'
)
)
}
}
}
},
fail: (err) => {
console.error('zImageUpload 上传文件发生错误', err)
reject(err?.errMsg || '上传文件发生错误')
},
complete: () => {
uploading.value = false
resolve(true)
},
})
item.uploadTask = task
// 监听上传进度
task.onProgressUpdate((res) => {
if (res.progress > 0) {
item.progress = res.progress
}
})
}
})
}
// 检查文件是否超过最大文件尺寸或者不符合上传文件类型
const checkFileSizeAndExtension = (files: Array<ImageUploadFile>) => {
const { extensions, maxSize } = props
// #ifdef MP-ALIPAY
extensions?.push('image')
// #endif
const extReg = /.+\./
return files.filter((item) => {
// 获取文件后缀名
let fileExt = ''
// #ifdef H5
fileExt = (item as File).name.replace(extReg, '').toLowerCase()
// #endif
// #ifndef H5
fileExt = (item as UniApp.ChooseImageSuccessCallbackResultFile).path
.replace(extReg, '')
.toLowerCase()
// #endif
return (
!extensions?.some((ext) => ext.toLowerCase() === fileExt) ||
item.size > maxSize
)
})
}
// 是否显示错误提示
const showErrorTips = (msg: string) => {
if (!props.showErrorTips) return
uni.showToast({
icon: 'none',
title: msg,
})
}
return {
chooseImage,
uploadProcess,
checkFileSizeAndExtension,
showErrorTips,
}
}