You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

537 lines
14 KiB

<template>
<div class="erf-attachment-manager">
<!-- 操作按钮 -->
<div style="margin-bottom: 10px">
<el-button
type="primary"
size="small"
v-if="!disabled"
@click="handleUpload">
上传附件
</el-button>
<el-button
type="primary"
size="small"
@click="handleDownload">
下载
</el-button>
</div>
<!-- 附件列表表格 -->
<el-table
:height="height"
:data="dataList"
ref="table"
v-loading="queryLoading"
border
@selection-change="handleSelectionChange"
style="width: 100%;">
<el-table-column type="selection" width="55" align="center"/>
<el-table-column
prop="fileName"
label="文件名"
min-width="200"
align="left"
header-align="center"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="fileType"
label="文件类型"
min-width="100"
align="center"
header-align="center">
</el-table-column>
<el-table-column
prop="createdBy"
label="上传人"
min-width="100"
align="center"
header-align="center">
</el-table-column>
<el-table-column
prop="createDate"
label="上传时间"
min-width="160"
align="center"
header-align="center">
</el-table-column>
<el-table-column
prop="orderRef5"
label="备注"
min-width="160"
align="center"
header-align="center">
</el-table-column>
<el-table-column
label="操作"
width="150"
align="center"
header-align="center"
fixed="right">
<template slot-scope="{row}">
<el-link
style="cursor:pointer; margin-right: 10px;"
@click="previewFile(row)">
预览
</el-link>
<el-link
style="cursor:pointer; color: #F56C6C;"
v-if="!disabled"
@click="handleRemove(row)">
删除
</el-link>
</template>
</el-table-column>
</el-table>
<!-- 上传对话框 -->
<el-dialog
title="上传附件"
:visible.sync="ossVisible"
width="380px"
append-to-body
:close-on-click-modal="false">
<el-form :inline="true" label-position="top" label-width="80px">
<el-row>
<el-form-item label="申请单号">
<el-input v-model="ossForm.orderRef2" readonly style="width: 310px"></el-input>
</el-form-item>
</el-row>
</el-form>
<!-- 文件上传区域 -->
<div style="margin: 15px 0;">
<div style="margin-bottom: 10px;">
选择文件:
<span style="color: #67C23A; font-size: 12px; margin-left: 10px;">
<i class="el-icon-picture-outline"></i> 可支持直接 Ctrl+V 粘贴图片,不需要点击上传按钮
</span>
</div>
<el-upload
drag
action="#"
ref="upload"
:file-list="fileList"
:on-remove="onRemoveFile"
:on-change="onChangeFile"
multiple
:auto-upload="false"
style="text-align: left;">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em>,或<em style="color: #67C23A;">Ctrl+V 粘贴图片</em></div>
<div class="el-upload__tip" slot="tip">
支持pdf、dwg、dxf、doc、docx、xls、xlsx、jpg、png格式
</div>
</el-upload>
</div>
<!-- 备注区域 -->
<div style="margin: 15px 0;">
<div style="margin-bottom: 10px;">备注:</div>
<el-input
type="textarea"
v-model="ossForm.remark"
resize="none"
:autosize="{minRows: 2, maxRows: 2}">
</el-input>
</div>
<span slot="footer" class="dialog-footer">
<el-button type="primary" :loading="uploadLoading" @click="handleUploadFiles">保存</el-button>
<el-button @click="ossVisible = false">关闭</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { ossUpload, queryOss, removeOss, previewOssFileById, previewOssFileById2 } from '@/api/oss/oss'
export default {
name: 'ErfAttachmentManager',
props: {
// 申请单号
applyNo: {
type: String,
required: true
},
// 是否禁用编辑
disabled: {
type: Boolean,
default: false
},
// 表格高度
height: {
type: [String, Number],
default: '30vh'
}
},
data() {
return {
dataList: [],
queryLoading: false,
uploadLoading: false,
selectionDataList: [],
ossVisible: false,
ossForm: {
orderRef1: 'ERF', // 模块标识
orderRef2: '', // 申请单号
orderRef6: 'EXP_APPLY', // 业务类型标识
remark: ''
},
fileList: [],
pasteImageCounter: 0 // 粘贴图片计数器,用于生成文件名
}
},
mounted() {
this.handleQuery()
},
watch: {
applyNo(newVal) {
if (newVal) {
this.handleQuery()
}
},
// 监听对话框关闭,移除粘贴事件监听器
ossVisible(newVal) {
if (!newVal) {
document.removeEventListener('paste', this.handlePaste)
}
}
},
beforeDestroy() {
// 组件销毁时移除监听器
document.removeEventListener('paste', this.handlePaste)
},
methods: {
/**
* 查询附件列表
*/
handleQuery() {
if (!this.applyNo) {
return
}
let params = {
orderRef1: 'ERF',
orderRef2: this.applyNo,
orderRef6: 'EXP_APPLY'
}
this.queryLoading = true
queryOss(params).then(({data}) => {
this.queryLoading = false
if (data && data.code === 0) {
this.dataList = data.rows || []
} else {
this.dataList = []
this.$message.warning(data.msg || '查询失败')
}
}).catch(error => {
this.queryLoading = false
this.$message.error('查询异常')
})
},
/**
* 打开上传对话框
*/
handleUpload() {
this.$nextTick(() => {
if (this.$refs.upload) {
this.$refs.upload.clearFiles()
}
})
this.fileList = []
this.ossForm.orderRef2 = this.applyNo
this.ossForm.remark = ''
this.ossVisible = true
this.pasteImageCounter = 0
// 添加粘贴事件监听器
this.$nextTick(() => {
document.addEventListener('paste', this.handlePaste)
})
},
/**
* 文件选择变化
*/
onRemoveFile(file, fileList) {
this.fileList = fileList
},
onChangeFile(file, fileList) {
this.fileList = fileList
},
/**
* 处理粘贴事件(支持直接粘贴图片)
*/
handlePaste(event) {
// 只在对话框打开时处理粘贴
if (!this.ossVisible) {
return
}
const items = (event.clipboardData || event.originalEvent.clipboardData).items
for (let i = 0; i < items.length; i++) {
const item = items[i]
// 检查是否为图片类型
if (item.type.indexOf('image') !== -1) {
event.preventDefault() // 阻止默认粘贴行为
const blob = item.getAsFile()
if (!blob) continue
// 获取文件扩展名
const extension = blob.type.split('/')[1] || 'png'
// 尝试使用原始文件名,如果没有则使用简洁的默认名称
let fileName = blob.name
if (!fileName || fileName === 'image.png' || fileName === 'blob') {
// 截图或无名称的情况,使用简洁的默认名称
this.pasteImageCounter++
fileName = `粘贴图片${this.pasteImageCounter}.${extension}`
}
// 创建 File 对象(保留原始文件名)
const file = new File([blob], fileName, { type: blob.type })
// 创建一个符合 el-upload 格式的文件对象
const uploadFile = {
name: fileName,
size: file.size,
type: file.type,
raw: file,
uid: Date.now() + this.pasteImageCounter,
status: 'ready'
}
// 添加到文件列表
this.fileList.push(uploadFile)
// 手动触发 el-upload 的文件列表更新
if (this.$refs.upload) {
this.$refs.upload.uploadFiles.push(uploadFile)
}
this.$message.success(`已粘贴图片: ${fileName}`)
break // 只处理第一张图片
}
}
},
/**
* 执行上传
*/
handleUploadFiles() {
if (this.fileList.length === 0) {
this.$message.error('请选择文件')
return
}
let formData = new FormData()
for (let i = 0; i < this.fileList.length; i++) {
formData.append('file', this.fileList[i].raw)
}
formData.append('orderRef1', 'ERF')
formData.append('orderRef2', this.ossForm.orderRef2)
formData.append('orderRef6', 'EXP_APPLY')
formData.append('createdBy', this.$store.state.user.name)
formData.append('orderRef5', this.ossForm.remark)
this.uploadLoading = true
ossUpload(formData).then(({data}) => {
this.uploadLoading = false
if (data && data.code === 0) {
this.$message.success('上传成功')
this.handleQuery()
this.ossVisible = false
} else {
this.$message.warning(data.msg || '上传失败')
}
}).catch(error => {
this.uploadLoading = false
this.$message.error('上传异常')
})
},
/**
* 删除附件
*/
handleRemove(row) {
this.$confirm('确认删除该附件吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let ids = [row.id]
removeOss(ids).then(({data}) => {
if (data && data.code === 0) {
this.$message.success('删除成功')
this.handleQuery()
} else {
this.$message.warning(data.msg || '删除失败')
}
}).catch(error => {
this.$message.error('删除异常')
})
}).catch(() => {})
},
/**
* 预览文件
*/
previewFile(row) {
let type = ''
let fileType = row.fileType.toLowerCase()
// 图片类型
let image = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
if (image.includes(fileType)) {
type = 'image/' + fileType
}
// 视频类型
let video = ['mp4', 'avi', 'mov', 'wmv', 'flv']
if (video.includes(fileType)) {
type = 'video/' + fileType
}
// 文本类型
if (fileType === 'txt') {
type = 'text/plain;charset=utf-8'
}
// Excel类型
if (fileType === 'xlsx' || fileType === 'xls') {
type = 'excel'
}
// Word类型
if (fileType === 'docx') {
type = 'word'
}
// PDF类型
if (fileType === 'pdf') {
type = 'application/pdf;charset-UTF-8'
}
// Office文件不支持预览
if (fileType === 'doc' || fileType === 'ppt' || fileType === 'pptx') {
this.$message.warning('该文件格式暂不支持预览,请下载后查看')
return
}
// CAD文件不支持预览
if (fileType === 'dwg' || fileType === 'dxf') {
this.$message.warning('CAD文件暂不支持预览,请下载后使用CAD软件查看')
return
}
if (type === '') {
this.$message.warning('该文件格式暂不支持预览')
return
}
let params = {
id: row.id,
fileType: type
}
previewOssFileById2(params).then(({data}) => {
if (type === 'excel' || type === 'word') {
type = 'application/pdf;charset=UTF-8'
}
const blob = new Blob([data], { type: type })
const fileURL = URL.createObjectURL(blob)
if (type === 'xls' || type === 'docx' || type === 'xlsx') {
const { href } = this.$router.resolve({
name: 'pre',
query: {
src: fileURL,
type: 'pdf'
}
})
window.open(href, '_blank')
} else {
// 在新标签页中打开文件预览
window.open(fileURL, '_blank')
}
})
},
/**
* 选择变化
*/
handleSelectionChange(val) {
this.selectionDataList = val
},
/**
* 下载选中的附件
*/
handleDownload() {
if (this.selectionDataList.length === 0) {
this.$message.warning('请选择要下载的附件')
return
}
let selectList = this.selectionDataList.map(item => ({ ...item }))
for (let i = 0; i < selectList.length; i++) {
let params = {
id: selectList[i].id
}
previewOssFileById(params).then((response) => {
const blob = new Blob([response.data], { type: response.headers['content-type'] })
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.setAttribute('download', selectList[i].fileName)
link.target = '_blank'
link.click()
URL.revokeObjectURL(link.href)
})
}
this.$refs.table.clearSelection()
}
}
}
</script>
<style scoped>
.erf-attachment-manager {
}
/* 表格样式优化 */
.el-table >>> .el-table__header th {
background-color: #F5F7FA;
color: #606266;
font-weight: bold;
}
.el-table >>> .el-table__row td {
padding: 8px 0;
}
</style>