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

chore: 优化上传

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