el-upload上传图片和视频,支持预览和删除

news2024/11/16 7:30:41

话不多说, 直接上代码:

视图层:

        <div class="contentDetail">
          <div class="contentItem">
            <div style="margin-top:5px;" class="label csAttachment">客服上传图片:</div>
            <el-upload
              :auto-upload="false"
              :limit="10"
              :on-change="fileChange"
              :on-remove="handleRemoveImg"
              :file-list="csImages"
              action="#"
              accept=".jpg,.jpeg,.png"
              list-type="picture-card"
            >
              <i slot="default" class="el-icon-plus"></i>
              <div slot="file" slot-scope="{ file }">
                <img :src="file.url" class="el-upload-list__item-thumbnail" alt="" />
                <div class="el-upload-list__item-actions">
                  <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
                    <i class="el-icon-zoom-in"></i>
                  </span>
                  <span class="el-upload-list__item-delete" @click="handleRemoveImg(file)">
                    <i class="el-icon-delete"></i>
                  </span>
                </div>
              </div>
            </el-upload>
          </div>
        </div>
        <div class="contentDetail">
          <div class="contentItem">
            <div class="label csAttachment">客服上传视频:</div>
            <el-upload
              :auto-upload="false"
              :limit="3"
              :on-change="changeUploadVideo"
              :file-list="csVideos"
              class="avatar-uploader"
              action="#"
              list-type="picture-card"
            >
              <i slot="default" class="el-icon-plus"></i>
              <div slot="file" slot-scope="{ file }">
                <video
                  :src="file.url"
                  :style="{
                    width: csVideos.length > 0 ? '200px' : 0,
                    height: csVideos.length > 0 ? '120px' : 0
                  }"
                  class="video-avatar"
                  controls="controls"
                >
                  <span>您的浏览器不支持视频播放</span>
                </video>
                <div class="el-upload-list__item-actions" style="z-index:101;height:50px;">
                  <span class="el-upload-list__item-delete" @click="handleRemoveVideo(file)">
                    <i class="el-icon-delete"></i>
                  </span>
                </div>
              </div>
            </el-upload>
          </div>
        </div>

逻辑层:

// 监听附件相关数据 
watch: {
    // 新增图片
    fileList: {
      async handler(newList) {
        this.fileData.imgFiles = []
        if (newList.length) {
          let fileObj = {}
          await newList.map(file => {
            // 上传的文件流转为base64格式
            if (file.raw) {
              getBase64File(file.raw).then(res => {
                fileObj = {
                  fileName: file.name,
                  fileBase64: res
                }
                this.fileData.imgFiles.push(fileObj)
              })
            } else {
              fileObj = {
                fileBase64: file.fileBase64,
                fileName: file.name,
                type: file.type
              }
              this.fileData.imgFiles.push(fileObj)
            }
          })
        }
      }
    },
    // 删除已上传图片时
    newImgList: {
      handler: function(list) {
        let obj = {
          fileBase64: '',
          fileName: '',
          type: ''
        }
        list.map(file => {
          obj = {
            fileBase64: file.fileBase64,
            fileName: file.name,
            type: file.type
          }
        })
        this.fileData.imgFiles.push(obj)
      }
    },
    
   //添加视频
    videoList: {
      async handler(newList) {
        this.fileData.videoFiles = []
        if (newList.length) {
          let fileObj = {}
          await newList.map(file => {
            // 上传的文件流转为base64格式
            if (file.raw) {
              getBase64File(file.raw).then(res => {
                fileObj = {
                  fileName: file.name,
                  fileBase64: res
                }
                this.fileData.videoFiles.push(fileObj)
              })
            } else {
              fileObj = {
                fileBase64: file.fileBase64,
                fileName: file.name,
                type: file.type
              }
              this.fileData.videoFiles.push(fileObj)
            }
          })
        }
      }
    },
    // 删除已上传视频时
    newVideoList: {
      handler: function(list) {
        let obj = {
          fileBase64: '',
          fileName: '',
          type: ''
        }
        list.map(file => {
          obj = {
            fileBase64: file.fileBase64,
            fileName: file.name,
            type: file.type
          }
        })
        this.fileData.videoFiles.push(obj)
      }
    }
  },  

 
// 添加图片文件
    fileChange(file, fileList) {
      this.fileList = fileList
      this.fileList.map((item, index) => {
        const fileSize = item.size / 1024 / 1024
        if (fileSize > 20) {
          this.$message.error('单个附件大小不能超过20M')
          this.fileList.splice(index, 1)
        }
      })

      setTimeout(() => {
        this.editFile('image')
      }, 1000)
    },

 // 添加视频文件
    changeUploadVideo(file, fileList) {
      const fileSize = file.size / 1024 / 1024 <= 50
      if (
        ['video/mp4', 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb', 'video/mov'].indexOf(
          file.raw.type
        ) == -1 // 控制格式
      ) {
        this.$message.error('请上传正确的视频格式')
        return false
      }
      if (!fileSize) {
        this.$message.error('视频大小不能超过50MB')
        return false
      }
      this.videoList = fileList

      setTimeout(() => {
        this.editFile('video')
      }, 1000)
    },

    // 移除图片文件
    handleRemoveImg(file) {
      this.fileList.map((item, index) => {
        if (item.name === file.name) {
          // 回显图片时
          if (item.type === 2) {
            item.type = 1 // 2 保留 1 删除
            this.newImgList = this.fileList.splice(index, 1)
            setTimeout(() => {
              this.editFile('image')
            }, 500)
          } else {
            // 新增图片时
            this.fileList.splice(index, 1)
          }
        }
      })
    },

    // 移除视频文件
    handleRemoveVideo(file) {
      this.videoList.map((item, index) => {
        if (item.name === file.name) {
          // 回显视频时
          if (item.type === 2) {
            item.type = 1 // 2 保留 1 删除
            this.newVideoList = this.videoList.splice(index, 1)
            setTimeout(() => {
              this.editFile('video')
            }, 500)
          } else {
            // 新增视频时
            this.videoList.splice(index, 1)
          }
        }
      })
    },

    // 预览图片
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url
      this.$alert(`<img src="${this.dialogImageUrl}" width="100%">`, {
        dangerouslyUseHTMLString: true,
        callback: () => {}
      })
    },


    // 编辑附件
    editFile(type) {
      const params = {
        imgFiles: this.fileData.imgFiles,
        videoFiles: this.fileData.videoFiles,
        csClass: this.summaryDetail.csClassIds[this.summaryDetail.csClassIds.length - 1],
        csFeedbackDescribe: this.summaryDetail.csFeedbackDescribe,
        id: this.summaryDetail.id,
        role: 1,
        appPhone: this.summaryDetail.appPhone,
        sn: this.summaryDetail.sn,
        qrCode: this.summaryDetail.qrCode,
        iscallBack: 1 // 是否编辑回电  1否 2是
      }
      this.$confirm('确认修改?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          this.loading = true
          addSummary(params) // 后端接口
            .then(res => {
              if (res.code === 0) {
                this.getSummaryList(this.activeName)
                this.$message.success(res.msg)
              }
            })
            .catch(() => {
              this.loading = false
              // 添加修改失败,恢复原有数据
              if (type === 'image') {
                this.csImages = handleFileFormat(this.summaryDetail.csImgFiles)
              } else {
                this.csVideos = handleFileFormat(this.summaryDetail.csVideoFiles)
              }
            })
        })
        .catch(() => {
          // 取消添加修改,恢复原有数据
          if (type === 'image') {
            this.csImages = handleFileFormat(this.summaryDetail.csImgFiles)
          } else {
            this.csVideos = handleFileFormat(this.summaryDetail.csVideoFiles)
          }
        })
    }

上传附件没有使用单独的上传接口,是调用添加记录接口时,统一传参保存。添加接口请求成功后再回显。

因为我们的需求是在详情页面也能编辑图片和视频,所以加了`type`字段,1代表删除,2代表保留,添加的话就不传。如果你们的需求没有在详情编辑的功能,相关的逻辑可以不用管。

添加失败或取消添加时,恢复原有数据。

视频的时候需要注意:video标签的层级比较高,鼠标hover时上面的删除图标显示不出来,手动修改它们的`z-index`,比如:

 

 删除图标的容器宽度也修改下,否则会覆盖视频播放按钮。

样式设置:

/deep/ .el-upload--picture-card {
    width: 80px;
    height: 80px;
  }
  /deep/ .el-upload-list__item {
    width: 80px;
    height: 80px;
  }
  .avatar-uploader {
    /deep/ .el-upload--picture-card {
      display: inline-block;
      width: 200px;
      height: 120px;
    }
    /deep/ .el-upload-list__item {
      display: inline-block;
      width: 200px;
      height: 120px;
    }
  }
  video {
    display: inline-block;
    position: relative;
    z-index: 100;
  }

  /deep/ .el-icon-plus {
    position: relative;
    top: -35%;
  }
  .avatar-uploader {
    /deep/ .el-icon-plus {
      position: relative;
      top: -6%;
    }
  }

上传前: 

 上传后:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/798188.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【spring】spring bean的生命周期

spring bean的生命周期 文章目录 spring bean的生命周期简介一、bean的创建阶段二、bean的初始化阶段三、bean的销毁阶段四、spring bean的生命周期总述 简介 本文测试并且介绍了spring中bean的生命周期&#xff0c;如果只想知道结果可以跳到最后一部分直接查看。 一、bean的…

创建维基WIKI百科和建立百度百科有何不同?

很多企业有出口业务&#xff0c;想在互联网上开展全球性网络营销&#xff0c;维基百科往往被认为是开展海外营销的第一站。其作用相当于开展国内网络营销的百度百科&#xff0c;经常有些企业给小马识途营销顾问提供的词条内容就是百度百科的内容&#xff0c;可事实上两个平台的…

无人机影像配准并发布(共线方程)

无人机影像 DEM 计算四个角点坐标&#xff08;刚性变换&#xff09; 像空间坐标&#xff08;x,y,-f&#xff09; 像空间坐标畸变纠正 deltax,deltay 已知(x,y)&#xff0c;求解(X,Y, Z)或者(Lat,Lon) 这里的Z是DEM上获取的坐标和Zs为相机坐标的高程&#xff0c;如果均为已…

水文章——推荐一个视频播放器和一个图片查看器

视频播放器——PotPlayer http://www.potplayercn.com/ 图片查看器——JPEGVIEW https://www.bilibili.com/video/BV1ZY411P7fX/?spm_id_from333.337.search-card.all.click&vd_sourceab35b4ab4f3968642ce6c3f773f85138

PHP数组转对象和对象转数组

PHP数组转对象和对象转数组 <?php function array_to_object($arr){$obj new stdClass();foreach ($arr as $key > $val) {if (is_array($val) || is_object($val)) {$obj->$key array_to_object($val);} else {$obj->$key $val;}}return $obj; } function o…

pdf怎么转换成word 文档?这几种方法收藏一下

pdf怎么转换成word 文档&#xff1f;PDF和Word是我们平时工作和学习中最常用的两种文档格式。PDF文档格式通常用于电子书籍、合同、申请表等需要保持原样式的文档。而Word文档则通常用于编辑和修改。但是&#xff0c;有时我们需要将PDF文档转换为可编辑的Word文档&#xff0c;以…

【Docker】在Docker大火的背后,究竟隐藏着未来科技发展的哪些大趋势

这里写目录标题 在docker大火的背后是什么新科技的发展呢&#xff1f;1.容器化技术的普及2.云原生应用的兴起3.边缘计算的发展4.容器编排和管理平台的演进5.混合云和多云架构的普及 docker三大特性轻量化可移植性可扩展性 docker被谁抢了风头呢1.风头被Kubernetes (K8S)抢了2.缺…

日撸代码300行:第54天(基于 M-distance 的推荐)

代码来自闵老师”日撸 Java 三百行&#xff08;51-60天&#xff09;“&#xff0c;链接&#xff1a;日撸 Java 三百行&#xff08;51-60天&#xff0c;kNN 与 NB&#xff09;_闵帆的博客-CSDN博客 算法是基于M-distance的推荐&#xff0c;通过用户评分矩阵对用户进行电影推荐。…

如果你在选型低代码平台,可以从这5个角度去分析抉择

研究低代码平台已有3年&#xff0c;也算是个低代码资深用户了&#xff0c;很多企业面临低代码选型上的困难&#xff0c;选平台容易&#xff0c;换平台难。下面基于个人理解给大家做一份千字的注意事项&#xff01;希望对大家在选型低代码方面有一定帮助。最终&#xff0c;正确且…

[AWD靶场搭建]

文章目录 [AWD靶场搭建]前言AWD平台搭建靶机搭建Cadinal添加靶机 连接Asteroid大屏默认ssh账号密码参考 [AWD靶场搭建] 前言 觉得好玩搭建了一下AWD靶场&#xff0c;使用了vidar-team编写的 Cardinal AWD平台搭建 这里我是在kali搭建的&#xff0c;所以我下载了这个压缩包&…

centos7搭建k8s环境并部署springboot项目

之前看了很多文章&#xff0c;都是部署后一直报错&#xff0c;百度解决后下次又忘了&#xff0c;这次决定把从头到尾的过程记录下来方便下次再看&#xff0c;部署参考文章尚硅谷Kubernetes&#xff08;k8s&#xff09;视频学习笔记_尚硅谷k8s笔记_溯光旅者的博客-CSDN博客 1、…

13年测试老鸟,接口性能测试总结整理,据说这是全网最全的...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试按照不同…

支持多种通信方式和协议方便接入第三方服务器或云平台

2路RS485串口是一种常用的通信接口&#xff0c;可以支持Modbus Slave协议&#xff0c;并可接入SCADA、HMI、DSC、PLC等上位机。它还支持Modbus RTU Master协议&#xff0c;可用于扩展多达48个Modbus Slave设备&#xff0c;如Modbus RTU远程数据采集模块、电表、水表、柴油发电机…

GAN论文精读

标题:Generative Adversarial Nets 摘要: 简写:作者提出了一个framework通过一个对抗的过程&#xff0c;在这里面会同时训练两个模型。 第一个模型为生成模型G&#xff0c;是用来抓住整个数据的分布 第二个模型为辨别模型D&#xff0c;是用来估计一个样本是否从G中产生。 …

BD Biosciences通过使用Liquid UI优化SAP QM,节省了80%的处理时间,提高了 95% 的数据准确性

背景 BD 生物科学公司成立于 1897 年&#xff0c;致力于改善患者的治疗效果&#xff0c;并在一个多世纪的时间里始终坚持这一理念&#xff0c;现已涉足诊断、生物科学以及各种医疗设备和仪器系统。 挑战 手动验证数据 原因&#xff1a;使用非自动程序演示和验证数据&#xff0c…

FRR+VPP

安装 三者的结合&#xff0c;实际上编译安装好就行了&#xff0c;不需要做任何代码上的修改&#xff0c;只需要安装和配置&#xff0c;然后你就有了一台路由器。 FRRouting使用frr-8.5.2版本&#xff0c;VPP使用23.06版本&#xff0c;DPDK和lcpng是VPP的插件&#xff0c;安装…

【CAS6.6源码解析】源码构建时-默认service配置不生效解决方案

CAS6的源码提供了默认的HTTPSandIMAPS-10000001.json配置用于授权所有的https和imaps服务&#xff0c;但是当添加JsonServiceRegistry模块启动后&#xff0c;会发现service是没有被注册的&#xff0c;是由于json路径引起的错误&#xff0c;可以把路径修改为绝对路径以解决此问题…

在idea中添加try/catch的快捷键

在idea中添加try/catch的快捷键 在idea中添加try/catch的快捷键 ctrlaltt 选中想被try/catch包围的语句&#xff0c;同时按下ctrlaltt&#xff0c; 出现下图 选择try/catch即可。

QTDAY3

闹钟 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> //定时器事件处理函数 #include <QTime> //时间类 #include <QString> #include <QPushButton> #include <QTextToSpeech> #include …

spring中存储和获取bean对象

文章目录 1. 存储bean对象1.1 使用配置文件存储bean对象1.2 使用五大类注解存储bean对象1.2.1 类注解1.2.2 五大类注解的作用1.2.3 方法注解 2.获取bean对象2.1 属性注入2.2 构造器注入2.3 getter注入2.4 注入对象的时候有spring中有多个bean对象怎么办2.4.1 将类中属性的名字&…