elementui表格嵌套上传文件直传到oss服务器(表单上传)

提示:记录项目中遇到的问题,仅供参考

文章目录


前言

项目需求是在表格中嵌套一个上传图片的功能,并且回显选择的图片和已上传的图片,再通过点击操作列中上传按钮才开始上传,使用的方法是实际是通过表单上传实现的


一、vue代码

这里就只展示主要代码,对elementui的函数方法不熟系的,可以对照elementui文档来理解

提示:下面的 scope.row.status 是指状态,为 9 时才可以上传图片,为 0 时图片已经上传

js 复制代码
<template>
	<el-table v-loading="loading" :data="formRefundRecordList" v-if="showTable">
		<div slot="empty" style="text-align: left;">暂无数据</div>
		<el-table-column label="退充截图" align="center" prop="screenshot" :key="Math.random()" width="150px">
		     <template slot-scope="scope">
		         <el-upload :class="{hideUpload:dialogImageUrls[`i${scope.row.id}`] != null}"
		             :action="upData.host" :ref="`reScreenshot${scope.row.id}`" :limit="1"
		             :accept="accept.join(',')" :auto-upload="false" list-type="picture-card"
		             :on-preview="(file)=>{return handlePreview(file, scope.row.id)}"
		             :on-remove="(file,fileList)=>{return handleRemove(file, fileList, scope.row.id)}"
		             :on-change="(file,fileList)=>{return handleChange(file, fileList, scope.row.id)}"
		             v-if="scope.row.status == 9">
		             <i class="el-icon-plus"></i>
		         </el-upload>
		
		         <!-- 上传成功后图片预览 -->
		         <!-- src 为图片预览前显示的内容 -->
		         <!-- preview-src-list 为图片预览时显示的内容 -->
		         <el-image v-if="dialogImageUrls[`i${scope.row.id}`] != null && scope.row.status != 9"
		             class="hideUpload" :src="dialogImageUrls[`i${scope.row.id}`]"
		             :preview-src-list="[dialogImageUrls[`i${scope.row.id}`]]">
		         </el-image>
		     </template>
	     </el-table-column>
		<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right"
		width="200px">
			<template slot-scope="scope">
				<el-button size="mini" type="text" @click="UpdateStatus(scope.row, 0)" :disabled="scope.row.status != 9">通过</el-button>
			</template>
		</el-table-column>
	</el-table>
	
	<!-- 上传前图片预览 -->
	<el-image-viewer v-if="showViewer" :on-close="closeViewer" :url-list="srcList" />
<template>
<script>
	import { updateFormRefundRecord, getOssPolicy, uploadOss } from "@/api/bol/refundInternalMedia";
	import SparkMD5 from "spark-md5";
	import ElImageViewer from 'element-ui/packages/image/src/image-viewer';
	export default {
        name: "refundInternalMedia",
        components: { ElImageViewer },
        data() {
            return {
            	// 图片详情放大列表(上传前)
                srcList: [],
                // 图片详情放大是否显示
                showViewer: false,
                // 上传前文件列表
                fileList: {},
                // 上传成功后回显时文件的域名(例:https://xxxxxx.xxxx.com)
                fileDominName: process.env.VUE_APP_File_SHOW_DOMAIN_NAME,
                // 上传截图携带的参数(实际上不需要这个,但没有又会报错)
                upData: {
                    host: ''
                },
                // 允许上传截图的格式
                accept: ['.png', '.jpg', '.jpeg'],
                // 截图弹窗显示与隐藏
                dialogVisibles: {},
                // 截图文件路径(表格所有的)
                dialogImageUrls: {},
                // 表格显示
                showTable: true,
                // 遮罩层
                loading: true,
                // 表格数据
                formRefundRecordList: [],
			}
		},
		methods: {
            // 关闭图片放大(上传前的)
            closeViewer() {
                this.srcList = [];
                this.showViewer = false;
            },
            // 删除截图的事件
            handleRemove(file, fileList, id) {
                this.$set(this.dialogImageUrls, `i${id}`, null)
                this.$delete(this.fileList, `f${id}`)
                // 刷新表格
                this.showTable = false
                this.showTable = true
            },
            // 点击已上传的截图时的事件
            handlePreview(file, id) {
                this.srcList = [file.url];
                this.showViewer = true;
            },
            // 截图状态改变时的钩子,添加文件、上传成功和上传失败时的事件
            handleChange(file, fileList, id) {
                this.$set(this.dialogImageUrls, `i${id}`, file.url)
                this.$set(this.fileList, `f${id}`, file.raw)
                // 刷新表格
                this.showTable = false
                this.showTable = true
            },
            // 上传截图
            async uploadFile(file, id) {
                // 文件md5值
                let md5
                await this.fileMd5(file).then((res) => {
                    md5 = res
                })

                // 文件后缀名
                var suffix = file.name.substring(file.name.lastIndexOf(".")); //.xxx
                // 上传oss的文件名
                let fileName = md5 + suffix
                // 生成一个以年月作为文件夹名(例:'20230703/')
                let fileDirName = this.getDirName()
                // 存放文件的路径(放到bol项目文件夹下的 refundScreenshot 退款截图文件夹下)
                let filePath = 'bol/refundScreenshot/' + fileDirName + '/'

                // 限制允许上传文件类型
                if (!this.accept.includes(suffix)) {
                    this.$message.warning('上传文件格式有误,请检查后重新上传。')
                    return false
                }

                getOssPolicy({}).then((res) => {
                    // 拿到签名信息后,组装表单数据,作参考,具体的字段找后台要
                    let config = res.data

                    let fd = new FormData()
                    fd.append('key', filePath + fileName)
                    fd.append('success_action_status', '200')
                    fd.append('x-oss-object-acl', 'public-read')
                    fd.append('x-oss-meta-fullname', fileName)
                    fd.append('OSSAccessKeyId', config.accessid)
                    fd.append('policy', config.policy)
                    fd.append('signature', config.signature)
                    fd.append('file', file)
                    if (config.host.indexOf('http:') > -1) {
                        var protocol = window.location.protocol || 'http:'
                        var subUrl = config.host.substring(5, config.host.length)
                        config.host = protocol + subUrl
                    }
                    // 组装请求参数
                    let pre = {
                        url: config.host,
                        data: fd
                    }
                    uploadOss(pre).then(() => {
                        // 组装数据
                        let data = {
                            id: id,
                            screenshot: filePath + fileName,
                            status: 0
                        }
                        // 执行通过
                        updateFormRefundRecord(data).then((res) => {
                            this.getList();
                            this.$modal.msgSuccess("成功通过");
                        }).catch(() => {
                            this.$message.error(res.msg);
                        })
                    }).catch(err => {
                        this.$message.warning('图片上传失败')
                    })

                }).catch((err) => {
                    this.$message.warning('验签获取失败')
                })
            },

            // 生成一个以年月为文件名的字符
            getDirName() {
                var date = new Date();
                var year = date.getFullYear();
                var month = date.getMonth() + 1;

                if (month >= 1 && month <= 9) {
                    month = "0" + month;
                }
                var DirName = year + '' + month;
                return DirName;
            },
            // 返回文件md5值
            async fileMd5(file) {
                var fileReader = new FileReader();
                var spark = new SparkMD5.ArrayBuffer();
                // 获取文件二进制数据
                // fileReader.readAsArrayBuffer(event.target.files[0]);
                fileReader.readAsArrayBuffer(file);
                return new Promise((resolve, reject) => {
                    fileReader.onload = function (e) {
                        spark.append(e.target.result);
                        var md5 = spark.end();
                        resolve(md5)
                    };
                })
            },
            /** 通过操作 */
            UpdateStatus(row, status) {
                // 组装数据
                const data = {
                    id: row.id,
                    status
                }
                let that = this
                this.$modal.confirm(`是否确认 通过 xxxx单编号为 "${row.id}" 的数据项?`).then(() => {
                    // 判断点击的是通过按钮,点击通过按钮要先上传图片
                    if (status == 0) {
                        // 判断是否上传了图片
                        if (this.dialogImageUrls[`i${row.id}`]) {
                            this.uploadFile(this.fileList[`f${row.id}`], row.id);
                        } else {
                            this.$message('请先上传图片');
                        }
                    } else {
                        ........;
                    }
                }).catch(() => { });
            },
		},
	}
</script>
<style lang="scss" scoped>
    ::v-deep .el-upload--picture-card {
        margin: 5px 0;
        width: 120px;
        height: 80px;
        line-height: 80px;
    }

    ::v-deep .el-upload-list--picture-card .el-upload-list__item {
        width: 120px;
        height: 80px;
        margin-top: 0;
    }

    .hideUpload {
        margin: 5px 0;
        width: 120px;
        height: 80px;
    }

    .hideUpload ::v-deep .el-upload {
        display: none;
        /* 上传按钮隐藏 */
    }
</style>

二、js接口请求代码

提示:下面的请求接口是进行封装过的,就不进行具体展示了

js 复制代码
import request from '@/utils/request'

// 更新退款媒介内部单数据
export function updateFormRefundRecord(data) {
    return request({
        url: 'xxxxxxxxxx',
        method: 'put',
        data: data
    })
}

// 获取阿里OSS签名
export function getOssPolicy(data) {
    return request({
        url: 'xxxxxxx',
        method: 'get',
        params: data
    })
}

// 上传到阿里OSS
export function uploadOss(pre) {
    return request({
        url: pre.url,
        method: 'post',
        data: pre.data
    })
}

相关推荐
崔庆才丨静觅9 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606110 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了10 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅10 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅11 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅11 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment11 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅11 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊12 小时前
jwt介绍
前端
爱敲代码的小鱼12 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax