287 lines
7.9 KiB
Vue
287 lines
7.9 KiB
Vue
<!-- FileOrImageDisplay.vue -->
|
|
<template>
|
|
<div class="detail-item">
|
|
<div class="item-label">{{ label }}</div>
|
|
<div class="item-value">
|
|
<!-- 文件类型 -->
|
|
<div v-if="isFile" class="file-display" @click="handleFileClick">
|
|
<i class="el-icon-document file-icon"></i>
|
|
<span class="file-name">{{ fileName }}</span>
|
|
</div>
|
|
|
|
<!-- 图片类型 -->
|
|
<div v-else-if="imageUrl" class="image-display" @click="handleImageClick">
|
|
<el-image
|
|
:src="imageUrl"
|
|
:preview-src-list="finalPreviewList"
|
|
class="license-image"
|
|
fit="fill"
|
|
hide-on-click-modal
|
|
:style="imageStyle"
|
|
>
|
|
<div slot="error" class="image-error">
|
|
<i class="el-icon-picture"></i>
|
|
<span>图片加载失败</span>
|
|
</div>
|
|
<div slot="placeholder" class="image-loading">
|
|
<i class="el-icon-loading"></i>
|
|
<span>图片加载中...</span>
|
|
</div>
|
|
</el-image>
|
|
</div>
|
|
|
|
<!-- 空状态 -->
|
|
<span v-else class="empty-text">--</span>
|
|
<!-- <el-dialog v-if="dialogVisible" :visible.sync="dialogVisible" width="50%" class="preview-dialog" title="文件预览">
|
|
<OnlyOfficeViewer :document-url="documentUrl" :document-title="documentTitle"
|
|
:document-key="documentKey" :mode="mode" :type="type" @document-ready="handleDocumentReady"
|
|
@app-ready="handleAppReady" @error="handleError" @initialized="handleInitialized" :force-save="true"
|
|
:save-timeout="15000" />
|
|
</el-dialog> -->
|
|
<ViewFile v-if="dialogVisible" :file="fileData" @closeDialog="handleCloseDialog" :without-modal="withoutModal" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import ViewFile from './ViewFile';
|
|
export default {
|
|
name: 'FileOrImageDisplay',
|
|
components: {
|
|
ViewFile
|
|
},
|
|
data() {
|
|
return {
|
|
dialogVisible: false,
|
|
fileData: {},
|
|
}
|
|
},
|
|
props: {
|
|
// 标签名称
|
|
label: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
// 文件对象
|
|
file: {
|
|
type: Object,
|
|
default: () => null
|
|
},
|
|
// 图片URL
|
|
imageUrl: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
// 预览图片列表
|
|
previewSrcList: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
// 文件类型字段名
|
|
fileTypeKey: {
|
|
type: String,
|
|
default: 'fileType'
|
|
},
|
|
// 文件名字段名
|
|
fileNameKey: {
|
|
type: String,
|
|
default: 'name'
|
|
},
|
|
// 文件路径字段名
|
|
filePathKey: {
|
|
type: String,
|
|
default: 'lsFilePath'
|
|
},
|
|
// 判断为文件的类型值
|
|
fileTypeValue: {
|
|
type: [Number, String],
|
|
default: '2'
|
|
},
|
|
// 固定图片宽度
|
|
imageWidth: {
|
|
type: [Number, String],
|
|
default: 600
|
|
},
|
|
// 固定图片高度
|
|
imageHeight: {
|
|
type: [Number, String],
|
|
default: 400
|
|
},
|
|
withoutModal: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
// 是否为文件类型
|
|
isFile() {
|
|
return this.file && this.file[this.fileTypeKey] === this.fileTypeValue
|
|
},
|
|
// 文件名
|
|
fileName() {
|
|
return this.file?.[this.fileNameKey] || '未命名文件'
|
|
},
|
|
// 文件路径
|
|
filePath() {
|
|
return this.file?.[this.filePathKey]
|
|
},
|
|
// 最终预览列表
|
|
finalPreviewList() {
|
|
return this.previewSrcList.length > 0 ? this.previewSrcList : [this.imageUrl]
|
|
},
|
|
imageStyle() {
|
|
const width = typeof this.imageWidth === 'number' ? `${this.imageWidth}px` : this.imageWidth
|
|
const height = typeof this.imageHeight === 'number' ? `${this.imageHeight}px` : this.imageHeight
|
|
return {
|
|
width,
|
|
height
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
// 文件点击事件
|
|
handleFileClick() {
|
|
console.log(this.file);
|
|
|
|
this.fileData = this.file
|
|
this.dialogVisible = true
|
|
},
|
|
// 图片点击事件
|
|
handleImageClick() {
|
|
this.$emit('image-click', this.imageUrl)
|
|
},
|
|
handleDocumentReady() {
|
|
console.log('文档已准备就绪')
|
|
},
|
|
handleAppReady() {
|
|
console.log('应用已准备就绪')
|
|
},
|
|
handleError(error) {
|
|
console.log('错误:', error)
|
|
},
|
|
handleInitialized() {
|
|
console.log('初始化完成')
|
|
},
|
|
handleCloseDialog() {
|
|
this.dialogVisible = false
|
|
this.fileData = {}
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.detail-item {
|
|
margin-bottom: 16px;
|
|
|
|
.item-label {
|
|
color: #424242;
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.item-value {
|
|
color: #424242;
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
|
|
.file-display {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
padding: 40px;
|
|
border: 2px dashed #d9d9d9;
|
|
border-radius: 8px;
|
|
background: #ffffff;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
min-height: 240px;
|
|
width: 100%;
|
|
margin: 0 auto;
|
|
|
|
&:hover {
|
|
border-color: #409EFF;
|
|
background: #f8f9ff;
|
|
}
|
|
|
|
.file-icon {
|
|
font-size: 48px;
|
|
color: #409EFF;
|
|
}
|
|
|
|
.file-name {
|
|
font-size: 14px;
|
|
color: #333333;
|
|
text-align: center;
|
|
word-break: break-all;
|
|
line-height: 1.4;
|
|
}
|
|
}
|
|
|
|
.image-display {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0;
|
|
border: 2px dashed #d9d9d9;
|
|
border-radius: 8px;
|
|
background: #ffffff;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
min-height: 120px;
|
|
width: 100%;
|
|
margin: 0 auto;
|
|
overflow: hidden;
|
|
|
|
&:hover {
|
|
border-color: #409EFF;
|
|
background: #f8f9ff;
|
|
}
|
|
|
|
.license-image {
|
|
width: auto;
|
|
height: auto;
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
display: block;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
object-fit: contain;
|
|
cursor: pointer;
|
|
transition: transform 0.3s ease;
|
|
|
|
&:hover {
|
|
transform: scale(1.02);
|
|
}
|
|
}
|
|
}
|
|
|
|
.empty-text {
|
|
color: #909399;
|
|
font-style: italic;
|
|
}
|
|
|
|
.image-error,
|
|
.image-loading {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 200px;
|
|
color: #909399;
|
|
gap: 8px;
|
|
border: 1px dashed #e0e0e0;
|
|
border-radius: 8px;
|
|
width: 100%;
|
|
max-width: 400px;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
</style>
|