使用ele-plus的图片上传组件实现图片和cad文件的分开上传和显示 在上传时判断文件类型 如果是cad则显示在图片控件的下方 显示名称 如果是图片则直接回显在图片上传组件上<template>
<div class="upload-box">
<el-upload
v-model:file-list="fileList"
accept="*/*"
:action="uploadUrl"
:before-upload="beforeUpload"
:class="['upload', drag ? 'no-border' : '']"
:disabled="disabled"
:drag="drag"
:data="uploadData"
:headers="headers"
:limit="limit"
:multiple="true"
:on-error="uploadError"
:on-exceed="handleExceed"
:on-success="uploadSuccess"
list-type="picture-card"
:show-file-list="true"
>
<div class="upload-empty">
<slot name="empty">
<Icon icon="ep:plus" />
</slot>
</div>
<template #file="{ file }">
<img :src="file.url" class="upload-image" />
<div class="upload-handle" @click.stop>
<div class="handle-icon" @click="handlePictureCardPreview(file)">
<Icon icon="ep:zoom-in" />
<span>查看</span>
</div>
<div v-if="!disabled" class="handle-icon" @click="handleRemove(file)">
<Icon icon="ep:delete" />
<span>删除</span>
</div>
</div>
</template>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
<!-- <template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template> -->
<template v-if="fileType">
只能上传 <b style="color: #f56c6c">{{ showFileType.join('/') }}</b>
</template>
的文件
</div>
<div class="el-upload__tip">
<slot name="tip"></slot>
</div>
<el-image-viewer
v-if="imgViewVisible"
:url-list="viewImageUrlList"
:initial-index="currentImageIndex"
@close="imgViewVisible = false"
/>
</div>
</template>
<script lang="ts" setup>
import type { UploadFile, UploadProps, UploadUserFile } from 'element-plus'
import { ElNotification } from 'element-plus'
import { getAccessToken } from '@/utils/auth'
import { propTypes } from '@/utils/propTypes'
// import { useUpload } from '@/components/UploadFile/src/useUpload'
defineOptions({ name: 'UploadImgs' })
const message = useMessage() // 消息弹窗
type FileTypes =
| 'image/apng'
| 'image/bmp'
| 'image/gif'
| 'image/jpeg'
| 'image/pjpeg'
| 'image/png'
| 'image/svg+xml'
| 'image/tiff'
| 'image/webp'
| 'image/x-icon'
| 'application/dwg'
const props = defineProps({
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
drag: propTypes.bool.def(true), // 是否支持拖拽上传 ==> 非必传(默认为 true)
disabled: propTypes.bool.def(false), // 是否禁用上传组件 ==> 非必传(默认为 false)
limit: propTypes.number.def(20), // 最大图片上传数 ==> 非必传(默认为 20张)
//fileSize: propTypes.number.def(5), // 图片大小限制 ==> 非必传(默认为 5M)
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif', 'image/jpg','application/dwg']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
borderradius: propTypes.string.def('8px'), // 组件边框圆角 ==> 非必传(默认为 8px)
data: propTypes.object.def({}), // 添加 data 属性
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
showFileType: propTypes.array.def(['.jpeg', '.png', '.svg','.dwg'])
})
const uploadData = computed(() => {
return {
tableName: props.data?.tableName || '' // 确保 tableName 被正确传递
}
})
// const baseUrl = import.meta.env.VITE_API_URL // 请求路径
const uploadUrl = import.meta.env.VITE_UPLOAD_URL // 上传路径
const headers = {
Authorization: 'Bearer ' + getAccessToken()
}
// const { uploadUrl, httpRequest } = useUpload()
const fileList = ref<UploadUserFile[]>([])
// const uploadList = ref([])
const uploadNumber = ref<number>(0)
const uploadList = ref<UploadUserFile[]>([])
// 是否显示提示
const showTip = computed(() => {
//return props.isShowTip && (props.fileType || props.fileSize)
return props.isShowTip && props.fileType
})
/**
* @description 文件上传之前判断
* @param rawFile 上传的文件
* */
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
// const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
// if (!imgSize)
// ElNotification({
// title: '温馨提示',
// message: `上传图片大小不能超过 ${props.fileSize}M!`,
// type: 'warning'
// })
// const imgType = props.fileType
// if (!imgType.includes(rawFile.type as FileTypes))
// ElNotification({
// title: '温馨提示',
// message: '上传图片不符合所需的格式!',
// type: 'warning'
// })
uploadNumber.value++
return true
//return imgType.includes(rawFile.type as FileTypes) && imgSize
//return imgType.includes(rawFile.type as FileTypes)
}
// 图片上传成功
interface UploadEmits {
(e: 'update:modelValue', value: string[]): void
}
const emit = defineEmits<UploadEmits>()
// const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
// console.log('res.data:', res.data);
// message.success('上传成功')
// // 确保res.data是字符串类型
// if (typeof res.data === 'string') {
// console.log('res.data:', res.data);
// // 删除自身
// const index = fileList.value.findIndex((item) => item.response?.data === res.data)
// fileList.value.splice(index, 1)
// uploadList.value.push({ name: res.data, url: res.data })
// if (uploadList.value.length == uploadNumber.value) {
// fileList.value.push(...uploadList.value)
// uploadList.value = []
// uploadNumber.value = 0
// emitUpdateModelValue()
// }
// } else {
// console.log('Invalid response data:', res.data)
// }
// }
// const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
// message.success('上传成功')
// // 确保响应数据有效
// if (res && typeof res.data === 'string') {
// // 删除临时上传记录
// const index = fileList.value.findIndex((item) => item.response?.data === res.data)
// if (index !== -1) {
// fileList.value.splice(index, 1)
// }
// // 添加到已上传列表
// uploadList.value.push({
// name: res.data.substring(res.data.lastIndexOf('/') + 1),
// url: `${res.data}?token=${token}`
// // url: `${res.data}`
// })
// // 检查是否所有文件都已上传完成
// if (uploadList.value.length === uploadNumber.value) {
// fileList.value.push(...uploadList.value)
// uploadList.value = []
// uploadNumber.value = 0
// emitUpdateModelValue()
// }
// } else {
// console.error('Invalid response data:', res.data)
// message.error('上传响应数据格式错误')
// }
// }
// 在 uploadSuccess 函数中修改 URL 构造方式
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
console.log('fileList',fileList.value);
message.success('上传成功')
if (res && typeof res.data === 'string') {
const index = fileList.value.findIndex((item) => item.response?.data === res.data)
if (index !== -1) {
fileList.value.splice(index, 1)
}
// 使用 getAccessToken() 获取 token
const token = getAccessToken()
uploadList.value.push({
name: res.data.substring(res.data.lastIndexOf('/') + 1),
// url: token ? `${res.data}?token=${token}` : res.data
url: token ? `${res.data}` : res.data
// url: res.data.url
})
if (uploadList.value.length === uploadNumber.value) {
fileList.value.push(...uploadList.value)
uploadList.value = []
uploadNumber.value = 0
emitUpdateModelValue()
}
} else {
console.error('Invalid response data:', res.data)
message.error('上传响应数据格式错误')
}
}
// 监听模型绑定值变动
watch(
() => props.modelValue,
(val: string | string[]) => {
if (!val) {
fileList.value = [] // fix:处理掉缓存,表单重置后上传组件的内容并没有重置
return
}
fileList.value = [] // 保障数据为空
// fileList.value.push(
// ...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
// )
fileList.value.push(
...(val as string[]).map((url) => {
if (typeof url === 'string') {
return { name: url.substring(url.lastIndexOf('/') + 1), url }
} else {
// 处理非字符串的 url,可能是抛出错误或返回一个默认值
console.error('Invalid url:', url)
return { name: '', url: '' } // 或者其他合适的默认值
}
})
)
},
{ immediate: true, deep: true }
)
// 发送图片链接列表更新
const emitUpdateModelValue = () => {
let result: string[] = fileList.value.map((file) => file.url!)
emit('update:modelValue', result)
}
// 删除图片
const handleRemove = (uploadFile: UploadFile) => {
fileList.value = fileList.value.filter(
(item) => item.url !== uploadFile.url || item.name !== uploadFile.name
)
emit(
'update:modelValue',
fileList.value.map((file) => file.url!)
)
}
// 图片上传错误提示
const uploadError = () => {
ElNotification({
title: '温馨提示',
message: '图片上传失败,请您重新上传!',
type: 'error'
})
}
// 文件数超出提示
const handleExceed = () => {
ElNotification({
title: '温馨提示',
message: `当前最多只能上传 ${props.limit} 张图片,请移除后上传!`,
type: 'warning'
})
}
// 图片预览
const viewImageUrlList = ref<string[]>([])
const imgViewVisible = ref(false)
const currentImageIndex = ref(0) // 新增:当前点击的图片索引
const handlePictureCardPreview = (uploadFile: UploadFile) => {
viewImageUrlList.value = fileList.value.map(file => file.url!) // 将所有图片的 URL 存储在数组中
currentImageIndex.value = fileList.value.findIndex(file => file.url === uploadFile.url) // 获取当前点击的图片索引
console.log('currentImageIndex.value',currentImageIndex.value);
imgViewVisible.value = true
}
//获取cookie
const getCookie = (name) => {
const value = `; ${document.cookie}`
const parts = value.split(`; ${name}=`)
if (parts.length === 2) {
// 如果找到了对应的cookie,返回其值(去除后面的分号和其他可能的属性)
return parts.pop().split(';').shift()
}
// 如果没有找到对应的cookie,返回null或undefined
return null
}
// 获取 accessToken
const token = getCookie('accessToken')
</script>
<style lang="scss" scoped>
.is-error {
.upload {
:deep(.el-upload--picture-card),
:deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important;
&:hover {
border-color: var(--el-color-primary) !important;
}
}
}
}
:deep(.disabled) {
.el-upload--picture-card,
.el-upload-dragger {
cursor: not-allowed;
background: var(--el-disabled-bg-color) !important;
border: 1px dashed var(--el-border-color-darker);
&:hover {
border-color: var(--el-border-color-darker) !important;
}
}
}
.upload-box {
.no-border {
:deep(.el-upload--picture-card) {
border: none !important;
}
}
:deep(.upload) {
.el-upload-dragger {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 0;
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
&:hover {
border: 1px dashed var(--el-color-primary);
}
}
.el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important;
}
.el-upload-list__item,
.el-upload--picture-card {
width: v-bind(width);
height: v-bind(height);
background-color: transparent;
border-radius: v-bind(borderradius);
}
.upload-image {
width: 100%;
height: 100%;
object-fit: contain;
}
.upload-handle {
position: absolute;
top: 0;
right: 0;
display: flex;
width: 100%;
height: 100%;
cursor: pointer;
background: rgb(0 0 0 / 60%);
opacity: 0;
box-sizing: border-box;
transition: var(--el-transition-duration-fast);
align-items: center;
justify-content: center;
.handle-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 6%;
color: aliceblue;
.el-icon {
margin-bottom: 15%;
font-size: 140%;
}
span {
font-size: 100%;
}
}
}
.el-upload-list__item {
&:hover {
.upload-handle {
opacity: 1;
}
}
}
.upload-empty {
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
line-height: 30px;
color: var(--el-color-info);
.el-icon {
font-size: 28px;
color: var(--el-text-color-secondary);<template>
<el-dialog
title="新增图纸"
v-model="dialogVisible"
:close-on-click-modal="false"
@close="handleCancel"
width="500px"
>
<!-- <div class="upload-container">
<div class="file-upload-row">
<div class="file-label">
<span class="required">*</span>图纸
</div>
<div class="upload-area-container">
<div class="upload-text">
<UploadImgs
v-model="imageDataList"
:file-type="['image/png', 'image/jpg','image/svg+xml']"
:file-size="20"
:width="'100px'"
:height="'100px'"
:show-delete="true"
:show-btn-text="false"
/>
</div>
<span v-if="fileErrors" class="error-message">{{ fileErrors }}</span>
</div>
</div>
</div> -->
<el-form ref="formRef" :model="formData" label-width="80px" :rules="formRules" v-loading="formLoading">
<el-row>
<el-col :span="24">
<el-form-item label="图纸" prop = 'file'>
<UploadImgs
v-model="formData.file"
:width="'120px'"
:height="'120px'"
:show-delete="true"
:show-btn-text="false"
:data = data
@change="handleFileChange"
/>
<!-- 非图片文件列表展示区域 -->
<div v-if="nonImageFiles.length > 0" class="non-image-files">
<div class="file-list-title">已上传文件:</div>
<div
v-for="(file, index) in nonImageFiles"
:key="index"
class="file-item"
>
<span class="file-name">{{ file.name }}</span>
<el-button
type="text"
class="delete-btn"
@click="handleDeleteFile(index)"
>
删除
</el-button>
</div>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="handleCancel" class="dialog-btn">取消</el-button>
<el-button type="primary" @click="handleConfirm" class="dialog-btn" :disabled="formLoading">确定</el-button>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage,FormRules } from 'element-plus'
import * as api from '@/api/miningAreaDrawing/index'
import UploadImgs from '@/components/UploadFile/src/UploadImgs.vue'
const data = ref({tableName : 'drawing'})
// 定义props
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
currentParentNode: {
type: Object,
default: null
}
})
const departmentId = ref('')
// 定义emits
const emit = defineEmits(['update:modelValue', 'success', 'cancel'])
const formData = ref({
parentId:'',
file: [],
departmentId:'',
name:''
})
const formRules = reactive<FormRules>({
file: [
{ required: true, message: '请上传图片', trigger: ['change','blur'] }
]
})
const formRef = ref()
const formLoading = ref(false)
// 用于区分图片和非图片文件
const nonImageFiles = ref([])
const imageFiles = ref([])
// 组件内部状态
const dialogVisible = ref(props.modelValue)
const fileErrors = ref('')
// 监听modelValue变化
watch(() => props.modelValue, (newVal) => {
console.log(newVal)
dialogVisible.value = newVal
})
// 监听dialogVisible变化,同步到父组件
watch(dialogVisible, (newVal) => {
emit('update:modelValue', newVal)
})
// 判断是否为图片文件
const isImageFile = (file) => {
const imageTypes = ['image/png', 'image/jpg', 'image/jpeg', 'image/gif', 'image/svg+xml']
return imageTypes.includes(file.raw?.type) ||
imageTypes.includes(file.type) ||
(file.name && file.name.match(/\.(png|jpg|jpeg|gif|svg)$/i));
}
// 处理上传组件的文件变化
const handleFileChange = (files) => {
// 分离图片文件和非图片文件
const images = []
const nonImages = []
files.forEach(file => {
if (isImageFile(file)) {
images.push(file)
} else {
nonImages.push(file)
}
})
imageFiles.value = images
nonImageFiles.value = nonImages
updateFormData()
}
// 更新表单数据
const updateFormData = () => {
// 合并图片文件和非图片文件
formData.value.file = [...imageFiles.value, ...nonImageFiles.value]
}
// 删除非图片文件
const handleDeleteFile = (index) => {
nonImageFiles.value.splice(index, 1)
updateFormData()
}
// 确认上传
const handleConfirm = async() => {
// 校验表单
if(!formRef.value) return
const valid = await formRef.value.validate()
if(!valid) return
// 提交请求
formLoading.value = true
try {
console.log("123")
const response = await api.addDrawing({
file: formData.value.file,
parentId: props.currentParentNode?.id,
departmentId: departmentId.value
})
if (response) {
ElMessage.success('文件上传成功')
dialogVisible.value = false
// 通知父组件刷新列表
emit('success')
} else {
ElMessage.error('文件上传失败: ' + (response?.msg || '未知错误'))
}
} finally {
formLoading.value = false
}
}
// 取消上传
const handleCancel = () => {
dialogVisible.value = false
formData.value = {
parentId:'',
file:[],
departmentId:'',
}
formRef.value?.resetFields()
fileErrors.value = ''
emit('cancel')
}
</script>
<style scoped>
.upload-container {
margin-bottom: 20px;
display: flex;
flex-direction: column;
}
.file-upload-row {
display: flex;
align-items: flex-start;
gap: 10px;
margin-bottom: 10px;
}
.upload-area-container {
display: flex;
flex-direction: column;
flex: 1;
}
.upload-area {
border: 2px dashed #dcdfe6;
border-radius: 6px;
padding: 40px 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
position: relative;
width: 100%;
}
.upload-area.dragover {
border-color: #409eff;
background-color: #f5f7fa;
}
.upload-text {
font-size: 16px;
color: #606266;
}
.click-upload {
color: #409eff;
margin-left: 5px;
}
.file-types {
margin-top: 5px;
text-align: center;
font-size: 14px;
color: #909399;
}
.file-list {
margin-top: 20px;
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 10px;
}
.file-item {
display: flex;
align-items: center;
padding: 8px;
background: #f5f7fa;
border-radius: 4px;
margin-bottom: 5px;
}
.file-name {
flex: 1;
margin-left: 10px;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.delete-icon {
cursor: pointer;
color: #f56c6c;
}
.dialog-btn {
width: 80px;
}
.file-label {
display: flex;
min-width: 100px;
font-size: 14px;
color: #606266;
padding-top: 5px;
}
.required {
color: #ff4d4f;
margin-right: 4px;
}
.error-message {
color: #ff4d4f;
font-size: 12px;
margin-top: 4px;
display: block;
height: 16px;
line-height: 16px;
}
.file-input {
displa
}
}
}
.el-upload__tip {
line-height: 15px;
text-align: center;
}
}
</style>
怎末修改上述代码 实现功能