提交 f02f1b17 authored 作者: 王鹏飞's avatar 王鹏飞

chore: 优化上传

上级 f3175e50
<script lang="ts" setup>
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import type { UploadProps, UploadUserFile } from 'element-plus'
import type { UploadProps, UploadUserFile, UploadFile, UploadFiles, UploadInstance } from 'element-plus'
import md5 from 'blueimp-md5'
import axios from 'axios'
import { getSignature } from '@/api/base'
interface Props {
modelValue: string | { name: string; url: string }[]
prefix?: string
size?: number
beforeUpload?: (file: any) => boolean | void
onChange?: (file: any, files: any) => void
beforeUpload?: UploadProps['beforeUpload']
onChange?: (uploadFile: UploadFile, uploadFiles: UploadFiles, uploadRef?: UploadInstance) => void
}
const props = withDefaults(defineProps<Props>(), {
......@@ -19,7 +20,7 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits(['update:modelValue', 'success'])
const uploadData = ref()
const uploadRef = ref<UploadInstance>()
const fileList = ref<UploadUserFile[]>([])
......@@ -34,84 +35,92 @@ const showFileList = computed(() => {
return Array.isArray(props.modelValue)
})
// 自定义上传
const handleHttpRequest: UploadProps['httpRequest'] = async xhr => {
const name = xhr.file.name
const key = `${props.prefix}${md5(name + Date.now())}.${name.split('.').pop()}`
const signature: Record<string, any> = await getSignature()
const params = {
key,
OSSAccessKeyId: signature.accessid,
policy: signature.policy,
signature: signature.signature,
success_action_status: '200',
url: `${signature.host}/${key}`,
file: xhr.file
}
return axios
.post('https://webapp-pub.oss-cn-beijing.aliyuncs.com', Object.assign(params, xhr.data), {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress(progress: any) {
progress.percent = progress.total > 0 ? (progress.loaded / progress.total) * 100 : 0
xhr.onProgress(progress)
}
})
.then(() => {
return params
})
}
// 文件改变
const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
props.onChange && props.onChange(uploadFile, uploadFiles, uploadRef.value)
}
// 上传之前
const handleBeforeUpload = async (file: any) => {
const handleBeforeUpload: UploadProps['beforeUpload'] = file => {
if (props.size && file.size > props.size) {
ElMessage.error(`文件大小不能超过${props.size / 1024 / 1024}M`)
return false
}
const fileName = file.name
const key = props.prefix + md5(fileName + new Date().getTime()) + fileName.substr(fileName.lastIndexOf('.'))
const response: Record<string, any> = await getSignature()
uploadData.value = {
key,
OSSAccessKeyId: response.accessid,
policy: response.policy,
signature: response.signature,
success_action_status: '200',
url: `${response.host}/${key}`
}
file.url = `${response.host}/${key}`
if (props.beforeUpload) {
return props.beforeUpload(file)
}
}
// 上传限制
const handleExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('文件超出个数限制')
}
// 上传成功
const handleSuccess: UploadProps['onSuccess'] = (response, file: any, files: any) => {
if (!files.every((item: any) => item.status === 'success')) return
if (showFileList.value) {
emit(
'update:modelValue',
files.map((item: any) => {
const handleSuccess: UploadProps['onSuccess'] = (response, uploadFile: any, uploadFiles) => {
uploadFile.type = uploadFile.raw?.type
uploadFile.url = response.url
const value = showFileList.value
? uploadFiles.map((item: any) => {
return {
name: item.name,
url: item.url || item.raw?.url,
url: item.url,
size: item.size || item.raw?.size,
type: item.type || item.raw?.type
}
})
)
} else {
emit('update:modelValue', file.raw.url)
}
emit('success', file, files)
}
// 上传限制
const handleExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('文件超出个数限制')
: response.url
emit('update:modelValue', value)
emit('success', uploadFile, uploadFiles)
}
// 删除
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
if (showFileList.value) {
emit(
'update:modelValue',
uploadFiles.map((item: any) => {
return { name: item.name, url: item.url || item.raw.url }
})
)
} else {
emit('update:modelValue', '')
}
if (uploadFile.status === 'ready') return
const value = showFileList.value
? uploadFiles.map((item: any) => ({ name: item.name, url: item.url, size: item.size, type: item.type }))
: ''
emit('update:modelValue', value)
}
// 预览
const handlePreview: UploadProps['onPreview'] = uploadFile => {
window.open(uploadFile.url)
}
const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
console.log(uploadFile, uploadFiles)
}
</script>
<template>
<el-upload
action="https://webapp-pub.oss-cn-beijing.aliyuncs.com"
:data="uploadData"
:show-file-list="showFileList"
:http-request="handleHttpRequest"
:before-upload="handleBeforeUpload"
:on-change="handleChange"
:on-exceed="handleExceed"
......@@ -119,7 +128,8 @@ const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
:on-preview="handlePreview"
:on-success="handleSuccess"
:file-list="fileList"
class="uploader">
class="uploader"
ref="uploadRef">
<slot>
<template v-if="showFileList">
<template v-if="$attrs['list-type'] === 'picture-card'">
......@@ -143,6 +153,7 @@ const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
<style lang="scss">
.uploader {
flex: 1;
overflow: hidden;
}
.avatar-uploader {
width: 178px;
......
......@@ -39,20 +39,18 @@ const create = () => {
})
}
const images = $computed(() => {
return form.files.filter((item: any) => !isVideo(item.url))
})
const videos = $computed(() => {
return form.files.filter((item: any) => isVideo(item.url))
})
function beforeUpload(file: any) {
if (images.length >= 10 && !isVideo(file.url)) {
function onChange(file: any, files: any, uploadRef: any) {
if (file.status !== 'ready') return
const images = files.filter((item: any) => !isVideo(item.name))
const videos = files.filter((item: any) => isVideo(item.name))
if (images.length > 10 && !isVideo(file.name)) {
ElMessage.error('最多上传10张图片')
uploadRef?.handleRemove(file)
return false
}
if (videos.length >= 1 && isVideo(file.url)) {
if (videos.length > 1 && isVideo(file.name)) {
ElMessage.error('最多上传1个视频')
uploadRef?.handleRemove(file)
return false
}
}
......@@ -76,7 +74,7 @@ function beforeUpload(file: any) {
v-model="form.content"></el-input>
</el-form-item>
<el-form-item prop="files">
<AppUpload v-model="form.files" accept="image/*,video/*" :beforeUpload="beforeUpload">
<AppUpload v-model="form.files" accept="image/*,video/*" :onChange="onChange">
<el-button size="default">上传图片/视频附件</el-button>
<template #tip
>支持最多上传10张图片,格式支持jpg,jpeg,png,2MB以内<br />视频最多上传1个,100Mb以内
......
......@@ -58,20 +58,19 @@ const create = () => {
emit('update:modelValue', false)
})
}
const images = $computed(() => {
return form.files.filter((item: any) => !isVideo(item.url))
})
const videos = $computed(() => {
return form.files.filter((item: any) => isVideo(item.url))
})
function beforeUpload(file: any) {
if (images.length >= 10 && !isVideo(file.url)) {
function onChange(file: any, files: any, uploadRef: any) {
if (file.status !== 'ready') return
const images = files.filter((item: any) => !isVideo(item.name))
const videos = files.filter((item: any) => isVideo(item.name))
if (images.length > 10 && !isVideo(file.name)) {
ElMessage.error('最多上传10张图片')
uploadRef?.handleRemove(file)
return false
}
if (videos.length >= 1 && isVideo(file.url)) {
if (videos.length > 1 && isVideo(file.name)) {
ElMessage.error('最多上传1个视频')
uploadRef?.handleRemove(file)
return false
}
}
......@@ -115,7 +114,7 @@ function beforeUpload(file: any) {
v-model="form.content"></el-input>
</el-form-item>
<el-form-item prop="files">
<AppUpload v-model="form.files" accept="image/*,video/*" :beforeUpload="beforeUpload">
<AppUpload v-model="form.files" accept="image/*,video/*" :onChange="onChange">
<el-button size="default">上传图片/视频附件</el-button>
<template #tip
>支持最多上传10张图片,格式支持jpg,jpeg,png,2MB以内<br />视频最多上传1个,100Mb以内
......
......@@ -19,9 +19,9 @@ export function formatQuestionType(type: QuestionType) {
// 是否是视频
export function isVideo(url: string) {
return url.includes('.mp4')
return url?.includes('.mp4')
}
export function content2Html(content: string) {
return content.replaceAll('\n', '<br>')
return content?.replaceAll('\n', '<br>')
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论