Files
pgserver3.0/pgweb/src/components/upload/file-upload.vue
2026-04-20 14:32:29 +08:00

537 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<div v-if="uploadType === 'btnUpload'" class="zc-flex" style="justify-content: space-between;">
<template v-if="isImg===false"><!--表示其他非图片文件-->
<div class="div-left-flex">
<span v-for="(item,index) in uploadList" class="file" :key="index">
{{item.name}}
<Icon class="pl-10" type="ios-eye-outline" @click.native="handleView(item,index)"></Icon>
<Icon class="pl-10" type="ios-trash-outline" @click.native="handleRemove(item,index)"></Icon>
</span>
</div>
</template>
<template v-else>
<div class="attach-container">
<div class="upload-container">
<div class="upload-list" v-for="(item,index) in uploadList" :key="index">
<template v-if="(item.status === 'finished') || !item.status">
<!-- <img :src="item.url ? item.url : item.response.data.url" /> -->
<!-- thum1 详情返回缩略图字段thumb_url 上传时返回缩略图字段 -->
<div v-if="item.response">
<img :src="item.thum1?item.thum1:item.response.data.thumb_url" v-if="item.response.data.ext == 'jpg' || item.response.data.ext == 'jpeg' || item.response.data.ext == 'png'"/>
<img src="@/assets/images/zip.png" v-else-if="item.response.data.ext == 'zip'"/>
<img src="@/assets/images/pptx.png" v-else-if="item.response.data.ext == 'pptx' || item.response.data.ext == 'ppt'"/>
<img src="@/assets/images/xlsx.png" v-else-if="item.response.data.ext == 'xlsx' || item.response.data.ext == 'xls' || item.response.data.ext == 'csv'"/>
<img src="@/assets/images/pdf.png" v-else-if="item.response.data.ext == 'pdf'"/>
<img src="@/assets/images/docx.png" v-else-if="item.response.data.ext == 'doc' || item.response.data.ext == 'docx'"/>
<img src="@/assets/images/file.png" v-else />
<!--显示文件名称-->
<div class="file-name">{{item.name}}</div>
</div>
<div v-else>
<img :src="item.thum1?item.thum1:item.thumb_url" v-if="item.ext == 'jpg' || item.ext == 'jpeg' || item.ext == 'png'"/>
<img src="@/assets/images/zip.png" v-else-if="item.ext == 'zip'"/>
<img src="@/assets/images/pptx.png" v-else-if="item.ext == 'pptx' || item.ext == 'ppt'"/>
<img src="@/assets/images/xlsx.png" v-else-if="item.ext == 'xlsx' || item.ext == 'xls' || item.ext == 'csv'"/>
<img src="@/assets/images/pdf.png" v-else-if="item.ext == 'pdf'"/>
<img src="@/assets/images/docx.png" v-else-if="item.ext == 'doc' || item.ext == 'docx'"/>
<img src="@/assets/images/file.png" v-else />
<!--显示文件名称-->
<div class="file-name">{{item.name}}</div>
</div>
<div class="upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(item,index)"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove(item,index)"></Icon>
</div>
</template>
<template v-else>
<Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>
</template>
</div>
</div>
</div>
</template>
<div class="mt-10">
<Upload
ref="upload"
:show-upload-list="false"
:default-file-list="defaultList"
:on-success="handleSuccess"
:format="format || defaultFormat"
:max-size="maxSize?maxSize:$config.maxSize"
:on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize"
:before-upload="handleUpload"
:on-progress="handleProgress"
multiple
type="drag"
name="pic"
:headers="uploadHeader"
:action="isUploadUrl == 'fbb'?$config.appUploadUrl:$config.uploadUrl"
>
<Button>上传附件</Button>
</Upload>
</div>
</div>
<div v-if="!uploadType">
<div class="attach-container">
<div class="upload-container">
<div class="upload-list" v-for="(item,index) in uploadList" :key="index">
<template v-if="(item.status === 'finished') || !item.status">
<img :src="item.url ? item.url : item.response.data.url" />
<div class="upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(item,index)"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
</div>
</template>
<template v-else>
<Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>
</template>
</div>
</div>
</div>
<div class="zc-left mr-10">
<Upload
ref="upload"
:show-upload-list="false"
:default-file-list="defaultList"
:on-success="handleSuccess"
:format="format || defaultFormat"
:max-size="maxSize?maxSize:$config.maxSize"
:on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize"
:before-upload="handleUpload"
:on-progress="handleProgress"
multiple
type="drag"
name="pic"
:headers="uploadHeader"
:action="isUploadUrl == 'fbb'?$config.appUploadUrl:$config.uploadUrl"
>
<div class="add-upload">
<Icon type="ios-add" size="20"></Icon>
</div>
</Upload>
</div>
</div>
<div v-if="uploadType === 'showImg'" class="attach-container">
<div class="upload-container">
<div class="upload-list" v-for="(item,index) in haveUpload" :key="index">
<template>
<img :src="item.url ? item.url : item.response.data.url" />
<div class="upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(item,index)"></Icon>
</div>
</template>
</div>
</div>
</div>
<div v-if="uploadType === 'showDraggable'">
<draggable v-model="uploadList" @update="datadragEnd">
<div class="upload-list" v-for="(item,index) in uploadList" :key="index">
<template v-if="(item.status === 'finished') || !item.status">
<!-- <img :src="item.url ? item.url : item.response.data.url" /> -->
<!-- thum1 详情返回缩略图字段thumb_url 上传时返回缩略图字段 -->
<img :src="item.thum1?item.thum1:item.response.data.thumb_url" />
<div class="upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(item,index)"></Icon>
</div>
</template>
<template v-else>
<Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>
</template>
</div>
</draggable>
</div>
<div v-if="uploadType === 'showImgName'" class="attach-container">
<span class="file_Img" v-for="(item,index) in haveUpload" :key="index">
{{item.name}}
<Icon style="padding-left: 5px;cursor: pointer;" type="ios-eye-outline" @click.native="handleView(item,index)"></Icon>
</span>
</div>
<div class="images" v-show="visible" v-viewer="{navbar: false,}">
<viewer :images="imagesList" ref='viewer' @inited='inited'>
<img v-for="(src,i) in imagesList" :src="src" :key="`${i}src`" />
</viewer>
</div>
<!-- 弹框查看图片/支持拖拉拽 -->
<Modal v-model="modal" width="850" :mask-closable="false" draggable>
<div class="header-title" slot="header"></div>
<img ref='modalImg' :src="url" style="width:825px; height:720px;transition:all .3s" />
<div slot="footer" class="text-center">
<Button type="primary" shape="circle" class="mr-10" @click="imgRotate(-90)"><Icon style='font-size: 20px;' type="ios-undo" /></Button>
<Button type="primary" shape="circle" class="mr-10" @click="imgRotate(90)"><Icon style='font-size: 20px;' type="ios-redo" /></Button>
</div>
</Modal>
<Modal v-model="validateModal" class-name="zc-modal" width="400" :mask-closable="false" >
<div class="header-title" slot="header">删除</div>
<div style="color:red;margin:20px 0;" class="text-center">是否确定删除</div>
<div slot="footer" class="text-center">
<Button type="default" shape="circle" class="mr-10" @click="validateModal=false">取消</Button>
<Button type="primary" shape="circle" @click="submitRemove(index)">确定</Button>
</div>
</Modal>
</div>
</template>
<script>
import draggable from 'vuedraggable'
import store from 'store'
export default {
components: { draggable },
props: [
'uploadType', // uploadType=上传文件按钮类型
'haveUpload', // 编辑时接收后端传回的数据
'isCanUploadVideo',
'getFlieList', // 编辑时的附件文件
'isUploadUrl', // fbb=app上传地址zc=pc上传地址
'maxLength', // 文件上传件数
'format', // 上传文件的格式
'width', // 上传附件按钮的宽度
'btnName', // 上传按钮的名字
'isImg', // 是否是图片
'isModal', // 是否采用弹框显示(拖拉拽)
'deleteValidate', // 是否删除 boolean
'maxSize'
],
data () {
return {
modal: false, // 弹框
validateModal: false, // 确认删除弹框提醒
msgFlag: false, // 多选时,标识文件超出数据是否已发出提示 methodshandleUpload
uploadSum: 0, // 多选时,记录一次上传多少个文件
url: '',
visible: false,
uploadList: [], // 上传成功之后后端返回的图片数组
defaultList: [], // 默认已上传的文件列表
uploadHeader: {},
defaultFormat: ['jpg', 'png', 'jpeg', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'zip'],
imagesList: [], // 图片预览
defaultImagesList: [], // 图片预览
fileObj: {},
index: '',
isVisible:false,
activaIndex:0,
curDegree: 0
}
},
created () {
this.init()
if (this.isCanUploadVideo) {
this.defaultFormat = [
'jpg',
'png',
'jpeg',
'doc',
'docx',
'xls',
'xlsx',
'pdf',
'mp4',
'mpeg',
'.mpg',
'avi',
'mov',
'wmv',
'mkv',
'flv',
'zip'
]
}
if (this.getFlieList) {
this.uploadList = this.getFlieList
}
},
methods: {
init () {
this.uploadHeader = { ApiAuth: store.get('apiAuth') }
},
inited(viewer) {
this.$viewer = viewer;
},
handleFormatError (file) {
if (this.format !== undefined) {
this.$Notice.warning({
title: '文件类型不合法',
desc:
file.name +
'的文件类型不正确,请上传后缀为' + this.format + '的文件。'
})
} else {
this.$Notice.warning({
title: '文件类型不合法',
desc:
file.name +
'的文件类型不正确请上传后缀为jpg、png、doc、docx、xls、xlsx、pdf、zip的文件。'
})
}
},
clearUpload () { // 清除图片列表
this.uploadList = []
this.$refs.upload.clearFiles()
},
handleSuccess (response, file, fileList) {
// this.$emit('getFilelist', { response, fileList })
// if (response && response.code === 1) {
// this.uploadList = fileList
// // this.uploadList.push(file)
// // 上传成功之后后端返回的图片数组 清空数据
// // 多选时,标识文件超出数据是否已发出提示 清空数据
// }
console.log('uploadList', this.uploadList)
this.$emit('getFilelist', { response, fileList: this.uploadList })
},
handleProgress (event, file, fileList) {
// console.log('上传中', event) // 继承了原生函数的 event 事件
// console.log('上传中 file', file) // 上传的文件
// console.log('上传中 fileList', fileList) // 上传文件列表包含file
// uploadList 就是 原文档中的那个渲染的 uplist 是个数组所以要把filelist 赋值给他
this.uploadList = fileList
// 调用监听 上传进度 的事件
event.target.onprogress = (event) => {
let uploadPercent = parseFloat(((event.loaded / event.total) * 100).toFixed(2)) // 保留两位小数,具体根据自己需求做更改
// 手动设置显示上传进度条 以及上传百分比
file.showProgress = true
file.percentage = uploadPercent
}
},
handleUpload (file, fileList) {
// console.log('handleUpload')
if (this.maxLength) {
const check = (this.uploadList.length) < this.maxLength
if (!check) {
// 多选时,标识文件超出数据是否已发出提示(否则会出现多个提示)
this.$Notice.warning({
title: `最多上传${this.maxLength}份文件`
})
} else {
// this.uploadList.push(file)
}
return check
}
},
handleMaxSize (file) {
this.$Notice.warning({
title: '文件大小不合法',
desc: file.name + `太大啦请上传小于${this.maxSize ==undefined?2:(this.maxSize/1024)}M的文件。`
})
},
// 删除图片
handleRemove (file, index) {
if (this.deleteValidate) {
this.validateModal = true
this.fileObj = file
this.index = index
} else {
this.uploadList.splice(this.uploadList.indexOf(file), 1)
this.$emit('getFilelist', { response: {}, fileList: this.uploadList, type: 'handleRemove', file: file, index, fileId: file.id ? file.id : file.response.data.id })
}
},
// 确定删除图片
submitRemove (index) {
this.uploadList.splice(this.uploadList.indexOf(this.fileObj), 1)
this.$emit('getFilelist', { response: {}, fileList: this.uploadList, type: 'handleRemove', file: this.fileObj, index, fileId: this.fileObj.id ? this.fileObj.id : this.fileObj.response.data.id })
this.validateModal = false
},
// 移动图片顺序
async datadragEnd (evt) {
evt.preventDefault()
// console.log('拖动前的索引 :' + evt.oldIndex)
// console.log('拖动后的索引 :' + evt.newIndex)
// 遍历数组,将索引值赋值到对应的sort_order上面,完成排序
// console.log(evt)
// let uploadList = JSON.parse(JSON.stringify(this.uploadList))
// if (evt.oldIndex > evt.newIndex) {
// uploadList.splice(evt.newIndex, 0, uploadList[evt.oldIndex])
// uploadList.splice(evt.oldIndex + 1, 1)
// } else {
// uploadList.splice(evt.newIndex + 1, 0, uploadList[evt.oldIndex])
// uploadList.splice(evt.oldIndex, 1)
// }
this.$emit('datadragEnd', { fileList: this.uploadList })
},
handleView (item, index) {
let type = ''
this.activaIndex = index
if (item.ext) {
type = item.ext.toLowerCase()
} else if (item.response) {
type = (item.response.data.ext || '').toLowerCase()
}
if (type === 'jpg' || type === 'png' || type === 'jpeg') {
this.url = item.url ? item.url : item.response.data.url
if (this.isModal) { // 使用弹框查看图片
this.modal = true
return false
}
this.isVisible=true
this.visible = false
if (this.isImg === false) {
this.getImagesUrl([this.uploadList[index]])
} else {
this.getImagesUrl(this.uploadList)
}
// 调用图片查看器
this.$viewer.view(index);
} else {
// window.open(item.response.data.url)
this.url = item.url ? item.url : item.response.data.url
window.open(this.url, item.name)
}
},
// 图片预览重组
group (index) {
if (index != 0) {
let newArray = this.defaultImagesList.slice(index, this.defaultImagesList.length)
let footArray = this.defaultImagesList.slice(0, index)
this.imagesList = newArray.concat(footArray)
} else {
this.imagesList = this.defaultImagesList
}
},
// 获取图片地址
getImagesUrl (list) {
this.imagesList = []
if (list.length != 0) {
console.log('list', list)
list.map(item => {
this.imagesList.push(item.url ? item.url : item.response.data.url)
this.defaultImagesList.push(item.url ? item.url : item.response.data.url)
})
}
},
// 图片旋转
imgRotate (degree) {
this.curDegree += degree
this.$refs.modalImg.style.transform = `rotate(${this.curDegree}deg)`
}
},
computed: {},
mounted () {
if (this.$refs.upload) {
this.uploadList = this.$refs.upload.fileList
this.getImagesUrl(this.$refs.upload.fileList)
}
},
watch: {
haveUpload: {
handler (newV, oldV) {
if (newV) {
this.defaultList = newV
this.uploadList = newV
this.getImagesUrl(newV)
}
},
immediate: true,
deep: true
},
getFlieList: {
handler (val) {
this.uploadList = val
this.getImagesUrl(val)
}
}
}
}
</script>
<style lang="less" scoped>
// .com_upload {
// float: right;
// // height: 72px;
// // line-height: 70px;
// background: #f1f5ff;
// color: #4e97d9;
// cursor: pointer;
// border-left: 1px solid #e6e6e6;
// }
.add-upload {
width: 100px;
height: 100px;
line-height: 100px;
border: 1px dashed #e6e6e6;
cursor: pointer;
}
.upload-list {
float: left;
width: 100px;
/*height: 100px;
line-height: 100px;*/
border: 1px solid transparent;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
margin-right: 4px;
text-align: center;
justify-content: center;
align-items: center;
}
.upload-list img {
width: 80px;
height: 80px;
}
.upload-list-cover {
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
}
.upload-list:hover .upload-list-cover {
display: block;
}
.upload-list-cover i {
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 8px;
}
.upload-list .file-name {
font-size: 12px;
color: #666;
/*一行显示,超出部分省略号*/
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file_Img {
display: inline-block;
border: 1px solid #ccc;
border-radius: 3px;
padding: 0 5px;
}
.div-left-flex{
flex: 1;
text-align: left;
padding-top: 8px;
}
.file {
border: 1px solid #e6e6e6;
border-radius: 8px;
display: inline-block;
margin: 0 5px 5px 0;
padding: 5px 10px;
cursor: pointer;
vertical-align: text-bottom;
}
</style>