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

话不多说, 直接上代码:

视图层:

        <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%;
    }
  }

上传前: 

 上传后:

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

教育新花样?看智慧教育如何出“花样”

智慧教育是物联化、智能化、感知化、泛在化的新型教育形态和教育模式。数字孪生可视化作为智慧教育的应用之一&#xff0c;优化了教育发展形态。本文以智慧教育浙江大学项目为例&#xff0c;介绍智慧教育的具体应用场景。 一、项目背景 &#xff08;一&#xff09;政策背景 …

springboot自动装配

SPI spi &#xff1a; service provider interface &#xff1a; 是java的一种服务提供机制&#xff0c;spi 允许开发者在不修改代码的情况下&#xff0c;为某个接口提供实现类&#xff0c;来扩展应用程序 将实现类独立到配置文件中&#xff0c;通过配置文件控制导入&#xff…

基于Ko-time的Springboot单体化调用链追踪实践

目录 前言 一、关于Ko-Time 1、是什么&#xff1f; 2、ko-time更新时间线 二、Ko-time怎么用&#xff1f; 1、依赖引入 2、配置集成 3、权限放行 三、链路追踪 1、系统运行 2、链路追踪 3、长时间调用模拟 总结 前言 熟悉微服务的老司机一定了解&#xff0c;在微服务模…

【C++】特殊类的设计 | 类型转换

文章目录 1. 特殊类的设计单例模式饿汉模式具体代码 懒汉模式具体代码 懒汉模式和饿汉模式的优缺点 2. C的类型转换C语言的类型转换C的类型转换static_castreinterpret_castconst_castdynamic_cast 1. 特殊类的设计 单例模式 设计模式是 被反复使用 多数人知晓 经过分类的、代…

React之生命周期

React之生命周期 旧版本&#xff0c;函数组件是没有生命周期的。新版本中通过useEffect触发函数的生命周期 一、基于类组件的生命周期 React的组件生命周期分为挂载阶段、更新阶段和销毁阶段。因为React的state不具有Vue的响应式&#xff0c;所以并没有create阶段 1、挂载阶段&…

第八章:list类

系列文章目录 文章目录 系列文章目录前言list的介绍及使用list的介绍list的使用list的构造函数list的迭代器list的容量list的成员访问list的增删改查 list与vector的对比总结 前言 list是STL的一种链表类&#xff0c;可以在常数范围内在任意位置进行插入和删除的序列式容器。 …

专访伊士曼中国区高管赵志伟:以创新应对新能源汽车后市场变化

受访人&#xff1a;伊士曼高性能膜事业部中国区商务总监赵志伟 新能源汽车发展至规模化阶段&#xff0c;以贴膜、保养维修为主的后市场产业迎来快速崛起&#xff0c;新能源消费者在汽车贴膜、改装和养护领域也表现出比燃油车更高频的需求度。 作为一家全球特种材料公司&#x…

MySQL~DQL查询语句

一、DQL:查询语句 1、排序查询 语法&#xff1a; order by 子句 ​ order by 排序字段1 排序方式1 &#xff0c;排序字段2 排序方2... 排序方式&#xff1a; ASC&#xff1a;升序[默认] DESC&#xff1a;降序 在SQL语句中永远排序最后 注&#xff1a; 如果有多个排序条…

立创EDA学习

学习树莓派3B的板子发现有个扩展板比较好&#xff0c;自己最好画一个&#xff0c;反正免费。 学习视频&#xff1a;立创EDA&#xff08;专业版&#xff09;电路设计与制作快速入门。 下载专业版&#xff0c;并激活。【分专业版和标准版&#xff0c;专业版也是免费的】 手机…

学习自动化测试该怎么学?6个步骤轻松拿捏

自动化测试作为脱离手工测试的基本核心内容&#xff0c;其重要性不言而喻了&#xff0c;而且我们来看近期大厂的一些招聘信息显示&#xff0c;基本上自动化测试是必备前提&#xff0c;没有这个基本就不用谈后面的问题了&#xff0c;下面我们通过联想集团的一个软件测试工程师的…

购物车功能实现(小兔鲜儿)【Vue3】

购物车 流程梳理和本地加入购物车实现 购物车业务逻辑梳理拆解 整个购物车的实现分为两个大分支, 本地购物车操作和接口购物车操作由于购物车数据的特殊性,采取Pinia管理购物车列表数据并添加持久化缓存 本地购物车 - 加入购物车实现 添加购物车 基础思想&#xff1a;如果…

Ceph社区上游正式合入openEuler原生支持,并通过CI持续验证

作为覆盖全场景应用、支持多样性算力的面向数字基础设施的开源操作系统&#xff0c;openEuler始终遵循“上游优先”的策略&#xff0c;帮助上游开源软件原生支持openEuler&#xff0c;让openEuler系操作系统的用户可以在开发、集成、使用这些开源软件或基于这些开源软件的产品和…

市面上的ipad国产触控笔怎么样?精选的性价比电容笔

要知道&#xff0c;真正的苹果品牌的那款原装电容笔&#xff0c;光是一支电容笔就价格近千元。实际上&#xff0c;平替电容笔对没有太多预算的用户是个不错的选择。一支苹果品牌的电容笔&#xff0c;价格是平替品牌的四倍&#xff0c;但电容笔的书写效果&#xff0c;却丝毫不逊…

idea如何解决导入的项目不是Maven工程(文件下面没有蓝色的方格)二

简介&#xff1a; Maven项目导入&#xff0c;idea不识别项目 解决方法&#xff1a; 选中pom.xml -- 右键 -- Add as Maven Project

技术实力加速企业上云,联想混合云获评专有云优秀案例入选混合云全景图四大方向

7月25-26日&#xff0c;由中国信息通信研究院、中国通信标准化协会联合主办的第十届可信云大会在京顺利召开。大会重磅发布了云计算白皮书&#xff08;2023年&#xff09;、《混合云产业全景图&#xff08;2023&#xff09;》、中国算力服务研究报告、中国云计算发展指数报告等…

Golang速成

目录 Golang 语言特性Golang的优势Golang 的应用场景Golang 的不足 基础语法变量的声明常量与 iotastring字符串遍历strings 包bytes 包strconv 包unicode 包 循环语句range 函数多返回值init 函数闭包import 导包匿名函数 指针defer切片 slice数组sliceslice 操作… mapmap 的…

MySQL InnoDB死锁原因及改善建议(InnoDB Deadlocks)

死锁是事务型数据库中一种现象&#xff0c;为了在高并发环境下不出错&#xff0c;数据库引入了"锁"这一数据结构来控制资源的并发访问&#xff0c;但也会导致死锁。 目录 一、死锁概念 1.1 死锁的原因 1.2 死锁监测 二、死锁演示 2.1 死锁生成过程 2.2 死锁信息查看 …

EtherNet/IP转Modbus网关以连接AB PLC

本案例为西门子S7-1200 PLC通过捷米特Modbus转EtherNet/IP网关捷米特JM-EIP-RTU连接AB PLC的配置案例。 网关分别从ETHERNET/IP一侧和MODBUS一侧读写数据&#xff0c;存入各自的缓冲区&#xff0c;网关内部将缓冲区的数据进行交换&#xff0c;从而实现两边数据的传输。 网关做为…

vue 实现拖拽效果

实现方式&#xff1a;使用自定义指令可以实现多个面板拖拽互不影响 1.自定义指令 js directives: {// 拖拽drag(el) {el.onmousedown function (e) {let x e.pageX - el.offsetLeftlet y e.pageY - el.offsetTopdocument.onmousemove function (e) {el.style.left e.pag…

【C++】C++ STL标准模板库知识点总结(秋招篇)

文章目录 前言STL的六大组件是&#xff1f;容器(container) 算法(algorithm) 迭代器(iterator) 三者的关系&#xff1f;容器分为几种&#xff1f;分别有哪些&#xff1f;关联性容器和非关联性容器有什么区别&#xff1f;Vector容器是怎么调整大小的&#xff1f;&#xff08;内存…