话不多说, 直接上代码:
视图层:
<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 = fileListthis.fileList.map((item, index) => {const fileSize = item.size / 1024 / 1024if (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 <= 50if (['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 = fileListsetTimeout(() => {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.urlthis.$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 = trueaddSummary(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%;}}
上传前:
上传后: