详细组件内容如下面的折叠的代码

点击查看代码
<template>
    <div class="upload-container1">
        <!-- 如果isDisabled为false且multipleFlag为true或者multipleFlag为false且fileList的长度为0,则显示el-upload组件 -->
        <el-upload v-if="!isDisabled && (multipleFlag || !multipleFlag && fileList.length == 0)" :disabled="isDisabled"
            class="avatar1-uploader1" :limit="limit" :multiple="multipleFlag"
            :accept="'.png,.jpg,.jpeg,.doc,.docx,.txt,.xls,.xlsx,.pdf'" element-loading-text="正在上传"
            :show-file-list="false" ref="imageUp" :http-request="doUpload" :before-upload="beforeUpload">
            <!-- 显示上传图标 -->
            <el-icon class="avatar1-uploader1-icon">
                <Plus />
            </el-icon>
        </el-upload>
        <!-- 修改预览区域 -->
        <div v-if="fileList.length" class="previews-container">
            <!-- 单/多文件预览模式 -->
            <div v-for="(file, index) in fileList" :key="index" class="multi-preview-item">
                <div @click="previewImage(file)">
                    <img v-if="isImage(file)" :src="file.url" class="avatar1" />
                    <!-- 如果是图片,则显示图片 -->
                    <div v-else class="file-preview">
                        <!-- 否则显示文件预览 -->
                        <el-icon class="document-icon">
                            <component :is="file.icon" />
                        </el-icon>
                        <!-- 显示文件图标 -->
                        <span class="filename">{{ file.name }}</span>
                        <!-- 显示文件名 -->
                    </div>
                </div>
                <div class="down-file">
                    <el-button type="primary" @click="handleDownload(file)">下载</el-button>
                    <!-- 点击下载文件 -->
                </div>
                <el-icon v-if="!isDisabled" class="close-icon" @click.stop="removeFile(index)">
                    <Close />
                </el-icon>
                <!-- 如果不是禁用状态,则显示关闭按钮 -->
            </div>
        </div>
        <!-- 预览对话框 -->
        <el-dialog v-model="previewVisible" width="60%" title="预览">
            <!-- 预览图片 -->
            <div class="preview-image">
                <!-- 如果是图片,则显示图片 -->
                <img v-if="isImage" :src="previewImageUrl" />
            </div>
        </el-dialog>
    </div>
</template>

<script setup>
import api from '@/utils/interface'
// 导入Element Plus图标库中的Document、Plus、Close图标
import {
    Document,
    Plus,
    Close
} from '@element-plus/icons-vue'
import { ref, computed, markRaw } from 'vue';
import { storeToRefs } from 'pinia' // 注意先安装哦
import { useStorageStore } from "@/stores/storage";
import axios from 'axios'
const store = useStorageStore();
const { user } = storeToRefs(store);
const props = defineProps({
    // 图片上传的url
    url: {
        type: String,
        default: ''
    },
    // 是否禁用
    isDisabled: {
        type: Boolean,
        default: false
    },
    // 是否支持多选
    multipleFlag: {
        type: Boolean,
        default: false
    },
    // 限制上传数量
    limit: {
        type: Number,
        default: 1
    },
    // 媒体名称
    mediaName: {
        type: String,
        default: ''
    }
})
// 判断props.url是否为空,如果为空,则kongflag为true,否则为false
let kongflag = props.url == '' ? true : false
// 定义一个空数组
let defaultArray = []
// 如果kongflag为false,则执行以下代码
if (!kongflag) {
    // 判断props.url的后缀是否为.doc,.docx,.txt,.xls,.xlsx,.pdf中的一个,如果是,则extFlag为true,否则为false
    let extFlag = '.doc,.docx,.txt,.xls,.xlsx,.pdf'.includes(props.url.split('.').pop()) ? true : false
    // 将props.url按逗号分隔,得到一个数组
    let urlArrary = props.url.split(',')
    // 遍历urlArrary数组
    urlArrary.forEach((item, index) => {
        // 将数组中的每个元素添加到defaultArray数组中
        defaultArray.push({
            name: props.mediaName,
            type: props.url.split('.').pop(),
            url: item,
            icon: extFlag ? markRaw(Document) : ''
        })
    })
}
// 修改为数组存储多个文件
const fileList = ref(Array.isArray(props.url) ? props.url : kongflag ? [] : defaultArray)
let multipleFlag = ref(props.multipleFlag)
let loading = ref(false)
const imageUp = ref();
const emit = defineEmits(["closeInvoice"]);
// 新增响应式数据和计算属性
const isImage = (file) => ['png', 'jpg', 'jpeg'].includes(file.type)
const previewVisible = ref(false)
const previewImageUrl = ref('')

// 预览图片
const previewImage = (file) => {
    // 判断文件是否为图片
    if (!isImage(file)) {
        return
    }
    // 设置预览图片的url
    previewImageUrl.value = file.url
    // 设置预览图片的可见性为true
    previewVisible.value = true
}
// 新增删除文件方法
const removeFile = (index) => {
    fileList.value.splice(index, 1)
    emit("closeInvoice", fileList.value)
}
const handleDownload = (item) => {
    // 图片文件直接下载
    const link = document.createElement('a')
    link.href = item.url;
    link.setAttribute('download', item.name)
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
}
async function doUpload(option) {
    loading.value = true
    const file = option.file;
    let userinfo = user.value
    let ext = file.name.split(".").pop();
    try {
        const formData = new FormData();
        formData.append('file', file);
        const response = await axios.post(
            '/base/webback/uploadTos',
            formData,
            {
                headers: {
                    "Authorization": userinfo.token,
                },
            }
        );
        if (response.data.code) {
            let extFlag = '.doc,.docx,.txt,.xls,.xlsx,.pdf'.includes(ext) ? true : false
            const newFile = {
                name: file.name,
                type: ext,
                url: response.data.data.url,
                icon: extFlag ? markRaw(Document) : ''
            }
            fileList.value.push(newFile)
            imageUp.value.clearFiles();
            emit("emitUrl", fileList.value)  // 返回整个文件列表
            loading.value = false
        } else {
            ElMessage({ type: 'error', message: response.data.message })
        }

    } catch (error) {
        ElMessage({ type: 'error', message: error })
    }

}
function beforeUpload(file) {
    const allowedTypes = ['png', 'jpg', 'jpeg', 'doc', 'docx', 'txt', 'xls', 'xlsx', 'pdf']
    const fileType = file.name.split('.').pop().toLowerCase()
    const isValidType = allowedTypes.includes(fileType)

    if (!isValidType) {
        ElMessage.error('仅支持上传:' + allowedTypes.join(', '))
        return false
    }
    const isLt2M = file.size / 1024 / 1024 < 20;
    if (!isLt2M) {
        ElMessage.error('上传图片大小不能超过 20MB!');
    }
    return isLt2M;
}

</script>

<style scoped>
.down-file {
    display: flex;
    justify-content: center;
    margin-top: 5px;
}

.preview-image {
    width: 100%;
    height: 70vh;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: auto;
}

.preview-image img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: 4px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.upload-container1 {
    margin-left: 35px;
    width: 170px;
    min-height: 170px;
}

.avatar1 {
    width: 100%;
    height: 155px;
    display: block;
    object-fit: contain;
}

:deep(.avatar1-uploader1 .el-upload) {
    border: 1px dashed var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
}

:deep(.el-icon.avatar1-uploader1-icon) {
    font-size: 28px;
    color: #8c939d;
    width: 150px;
    height: 150px;
    text-align: center;
}

.file-preview {
    display: flex;
    margin-top: 10px;
    height: 125px;
    flex-direction: column;
    align-items: center;
    padding: 10px;
}

.document-icon {
    font-size: 60px;
    color: #409eff;
    margin-bottom: 8px;
}

.filename {
    font-size: 12px;
    color: #666;
    word-break: break-all;
    text-align: center;
    max-width: 140px;
}

/* 新增多文件预览样式 */
.previews-container {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    width: 586px;
    background: #f5f7fa;
    padding: 10px;
    margin-top: 10px;
}

.multi-preview-item {
    position: relative;
    width: 180px;
    border: 1px solid #eee;
    border-radius: 4px;
    padding: 6px 0;
    background: #e1e1e1;

    &:hover .close-icon {
        display: block;
    }
}

.thumb-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.file-thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
}

.close-icon {
    position: absolute;
    width: 25px;
    height: 25px;
    line-height: 25px;
    text-align: center;
    right: 4px;
    top: 4px;
    color: red;
    font-size: 24px;
    background: white;
    border-radius: 50%;
    display: none;
    cursor: pointer;
}

.document-icon-small {
    font-size: 32px;
}
</style>
posted on 2025-03-24 17:52  好久不见-库克  阅读(106)  评论(0)    收藏  举报