399 lines
10 KiB
Vue

<template>
<div>
<el-dialog :visible.sync="visible" class="details-content" :custom-class="officePreview ? 'dialog-office':''">
<div v-if="officePreview" class="office-preview">
<vue-office-docx
v-if="file.suffix === 'docx' && visible"
:src="fleUrl"
@rendered="rendered"
/>
<vue-office-excel
v-if="file.suffix === 'xlsx' && visible"
:options="excelOptions"
:src="fleUrl"
@rendered="rendered"
/>
</div>
<div v-else class="drawer-icon">
<el-image v-if="file && file.showCover" fit="contain" :src="imageUrl + file.id + '&showCover=true'" class="cover">
<div slot="error" class="image-slot-error">
<svg-icon icon-class="image"/>
</div>
</el-image>
<icon-file
v-else
class="drawer-icon-font"
:grid="true"
:details="true"
:item="file"
:image-url="imageUrl"
:audio-cover-url="audioCoverUrl"
></icon-file>
</div>
<el-form class="details-form">
<el-form-item v-if="!isOSSFile(file)" label="重建索引:" class="details-scan">
<el-popover
placement="bottom"
trigger="click">
<p class="el-popconfirm__main">
<i class="el-popconfirm__icon el-icon-question" style="color: rgb(255, 153, 0);"></i>
是否开始扫描?
</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="cancelScan()">取消</el-button>
<el-button type="primary" size="mini" @click="scanDirectory(file)">确定</el-button>
</div>
<el-button slot="reference" id="scanDirectoryBtn-file" type="primary" size="small" :loading="syncLoading"><i class="el-icon-refresh"></i></el-button>
</el-popover>
<span v-show="syncPercent < 100">正在同步文件基本信息: {{ syncPercent }}%</span>
<span v-show="indexingPercent > 0 && indexingPercent < 100">正在为文件内容创建索引: </span><span v-show="indexingPercent > 0 && indexingPercent < 100">{{ indexingPercent }}%</span>
</el-form-item>
<el-scrollbar wrap-class="scrollbar-wrapper" class="details-form-list">
<el-form-item label="名称:">
<span>{{ file.name }}</span>
</el-form-item>
<el-form-item label="类型:">
<span>{{
file.isFolder ? '文件夹' : file.contentType
}}</span>
</el-form-item>
<div v-if="file.music">
<el-form-item label="🎵 歌手:">
<span>{{ file.music.singer }}</span>
</el-form-item>
<el-form-item label="🎵 专辑:">
<span>{{ '《' + file.music.album + '》' }}</span>
</el-form-item>
<el-form-item label="🎵 歌名:">
<span>{{ '《' + file.music.songName + '》' }}</span>
</el-form-item>
</div>
<el-form-item
v-show="file.w && file.h"
label="尺寸:"
class="details-resolution"
>
<span>{{ file.w + ' x ' + file.h }}</span>
</el-form-item>
<el-form-item label="大小:">
<span> {{ formatSize(file.size) }}</span>
</el-form-item>
<el-form-item label="位置:" class="details-position">
<a :href="'/?path=' + file.path + '&highlight=' + file.name">{{ file.path }}</a>
</el-form-item>
<el-form-item label="上传时间:">
<span>{{ file.uploadDate }}</span>
</el-form-item>
<el-form-item label="修改时间:">
<span>{{ file.updateDate }}</span>
</el-form-item>
<el-form-item v-if="file.exif" label="">
<span style="white-space: break-spaces;">{{ formatExif(file.exif) }}</span>
</el-form-item>
<el-form-item v-if="file.video" label="">
<span style="white-space: break-spaces;">{{ formatVideo(file.video) }}</span>
</el-form-item>
</el-scrollbar>
<el-button v-if="allowOpenFile" type="primary" size="small" @click="openFile" class="open-file">打开文件</el-button>
<el-button v-if="onlyOfficeSupportedFormats(file)" type="primary" size="small" @click="openOnlyOffice" class="open-file">使用OnlyOffice打开</el-button>
</el-form>
</el-dialog>
</div>
</template>
<script>
import { onlyOfficeSupportedFormats } from '@/utils/file-type'
// 引入VueOfficeDocx 组件
import VueOfficeDocx from '@vue-office/docx'
// 引入VueOfficeDocx 相关样式
import '@vue-office/docx/lib/index.css'
// 引入VueOfficeExcel 组件
import VueOfficeExcel from '@vue-office/excel'
// 引入VueOfficeExcel 相关样式
import '@vue-office/excel/lib/index.css'
import fileConfig from '@/utils/file-config'
import { formatSize } from '@/utils/number'
import IconFile from '@/components/Icon/IconFile'
import {mapState} from "vuex";
import {formatExif,formatVideo} from "@/utils/media";
import settingApi from "@/api/setting-api";
export default {
name: 'FileDetails',
components: {
IconFile,
VueOfficeDocx,
VueOfficeExcel
},
props: {
visible: {
type: Boolean,
required: true,
},
file: {
type: Object,
required: true,
},
imageUrl: {
type: String,
required: true,
},
audioCoverUrl: {
type: String,
required: true,
},
},
data() {
return {
syncLoading: false,
clickSync: false,
indexingPercent: 100,
syncPercent: 100,
excelOptions: {
minColLength: 10,
minRowLength: 10,
widthOffset: 10,
heightOffset: 10,
excel: window.location.origin + fileConfig.previewUrl(this.$store.state.user.name, this.file, this.$store.getters.token)
}
}
},
mounted() {
},
computed: {
...mapState(['message']),
fleUrl() {
return window.location.origin + fileConfig.previewUrl(this.$store.state.user.name, this.file, this.$store.getters.token)
},
officePreview() {
return ['docx', 'xlsx'].includes(this.file.suffix) && this.file.size > 0 && this.file.size < 1024 * 1024 * 5
},
allowOpenFile() {
if (!this.file.contentType) {
return false
}
return (this.file.contentType.indexOf('office') > -1 || ['pdf', 'epub'].includes(this.file.suffix))
},
},
watch: {
message(msg) {
if (msg.event === 'msg/synced') {
this.updateSyncStatus(msg.data.body)
}
},
visible(val) {
this.$emit('update:visible', val)
if (val) {
this.getIsSync()
}
}
},
methods: {
isOSSFile(file) {
if (!file || !file.id) {
return false
}
// 判断id字符串里是否有斜杠,如果则返回false
return this.file.id.indexOf('/') > -1 || this.file.ossFolder
},
openFile() {
this.$emit('openFile', this.file)
},
openOnlyOffice() {
this.$emit('openOnlyOffice', this.file)
},
rendered() {
console.log('rendered')
},
formatSize(size) {
return formatSize(size)
},
formatExif(exifInfo) {
return formatExif(exifInfo)
},
formatVideo(videoInfo) {
return formatVideo(videoInfo)
},
getIsSync() {
settingApi.isSync({username: this.$store.state.user.name}).then((res) => {
this.updateSyncStatus(res.data)
})
},
onlyOfficeSupportedFormats(file) {
if (!file || !file.suffix) {
return false
}
return onlyOfficeSupportedFormats.includes(file.suffix.toLowerCase())
},
updateSyncStatus(dataPercent) {
if (this.clickSync) {
return
}
const {syncPercent, indexingPercent} = dataPercent
if (syncPercent) {
this.syncPercent = syncPercent
} else {
this.syncPercent = 0
}
if (indexingPercent) {
this.indexingPercent = indexingPercent
} else {
this.indexingPercent = 0
}
this.syncLoading = !((this.syncPercent === 100 && this.indexingPercent === 100) || (this.syncPercent === 0 && this.indexingPercent === 0));
},
cancelScan() {
document.getElementById('scanDirectoryBtn-file').click()
},
scanDirectory(file) {
this.cancelScan()
this.syncLoading = true
this.syncPercent = 0
this.clickSync = true
settingApi.syncUser({username: this.$store.state.user.name, path: decodeURIComponent(file.path + file.name)}).then(() => {
this.clickSync = false
}).catch(() => {
this.clickSync = false
})
},
}
}
</script>
<style scoped lang="scss">
>>> .el-drawer__header {
color: #000000;
span {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.details-form {
padding-bottom: 20px;
width: 280px;
>>> .el-scrollbar__view {
max-height: 50vh;
}
>>> .el-form-item__content {
white-space: normal;
word-break: break-all;
word-wrap: break-word;
line-height: 25px;
}
>>> .el-form-item__label {
line-height: 25px;
}
>>> .el-form-item {
margin-bottom: 0;
}
>>> .details-scan {
.el-form-item__label {
line-height: 32.5px;
}
margin-bottom: 10px;
.el-button--mini, .el-button--mini.is-round {
padding: 5px 15px;
}
}
>>> .details-position {
margin: 10px 0;
.el-form-item__content {
line-height: 20px;
color: #84a0c3;
}
.el-form-item__label {
line-height: 20px;
}
}
a:hover {
color: #409eff;
}
}
.drawer-icon {
margin-right: 20px;
text-align: center;
position: relative;
flex: 1;
display: flex;
align-content: center;
flex-wrap: wrap;
justify-content: center;
>>> .icon-favorite {
display: none;
}
>>> .icon-share {
display: none;
}
>>> .icon-tag {
display: none;
}
}
.drawer-icon-font {
margin-bottom: 40px;
>>> .svg-icon {
font-size: 8rem;
}
}
.details-content {
display: flex;
align-items: center;
justify-content: center;
>>> .el-dialog__body {
display: flex;
}
}
>>> .el-image {
height: 200px !important;
}
>>> .el-image.cover {
height: unset !important;
margin-bottom: 20px;
}
>>> .el-dialog {
margin-top: 0 !important;
width: fit-content;
min-width: 500px;
max-width: 800px;
}
>>> .dialog-office {
max-width: 1400px;
min-width: 1225px;
height: 90vh;
}
.office-preview {
flex: 20;
height: 80vh;
max-width: 885px;
margin-right: 20px;
>>> .docx-wrapper {
padding: 10px;
}
}
.open-file {
margin-top: 10px;
}
</style>