云文件系统初始化
This commit is contained in:
@@ -175,7 +175,7 @@ const formatDate = (date) => {
|
|||||||
const canPreview = (file) => {
|
const canPreview = (file) => {
|
||||||
if (file.type === 'folder') return false
|
if (file.type === 'folder') return false
|
||||||
const ext = file.name.split('.').pop()?.toLowerCase()
|
const ext = file.name.split('.').pop()?.toLowerCase()
|
||||||
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf', 'txt', 'md', 'json', 'xml', 'log', 'js', 'ts', 'vue', 'java', 'py', 'css', 'html'].includes(ext)
|
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf', 'txt', 'md', 'json', 'xml', 'log', 'js', 'ts', 'vue', 'java', 'py', 'css', 'html', 'docx', 'xlsx', 'pptx', 'doc', 'xls', 'ppt', 'ofd'].includes(ext)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,18 @@
|
|||||||
:title="previewFile?.name || '预览'"
|
:title="previewFile?.name || '预览'"
|
||||||
width="80%"
|
width="80%"
|
||||||
top="5vh"
|
top="5vh"
|
||||||
class="custom-dialog"
|
class="custom-dialog preview-dialog"
|
||||||
>
|
>
|
||||||
<div class="preview-content">
|
<div class="preview-content">
|
||||||
<img v-if="isImage" :src="previewUrl" class="preview-image" />
|
<img v-if="isImage" :src="previewUrl" class="preview-image" />
|
||||||
<iframe v-else-if="isPdf" :src="previewUrl" class="preview-iframe" />
|
<iframe v-else-if="isPdf" :src="previewUrl" class="preview-iframe" />
|
||||||
<pre v-else-if="isText" class="preview-text">{{ previewContent }}</pre>
|
<pre v-else-if="isText" class="preview-text">{{ previewContent }}</pre>
|
||||||
|
<div v-else-if="isOffice" ref="officeViewer" class="preview-office">
|
||||||
|
<div v-if="!jitViewerLoaded" class="preview-loading">
|
||||||
|
<el-icon class="is-loading" :size="32"><Loading /></el-icon>
|
||||||
|
<p>正在加载预览组件...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-else class="preview-unsupported">
|
<div v-else class="preview-unsupported">
|
||||||
<el-icon :size="64"><Document /></el-icon>
|
<el-icon :size="64"><Document /></el-icon>
|
||||||
<p>此文件类型暂不支持预览</p>
|
<p>此文件类型暂不支持预览</p>
|
||||||
@@ -23,8 +29,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed, ref, watch, nextTick } from 'vue'
|
||||||
import { Document, Download } from '@element-plus/icons-vue'
|
import { Document, Download, Loading } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: Boolean,
|
modelValue: Boolean,
|
||||||
@@ -40,6 +46,9 @@ const visible = computed({
|
|||||||
set: (v) => emit('update:modelValue', v)
|
set: (v) => emit('update:modelValue', v)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const officeViewer = ref(null)
|
||||||
|
const jitViewerLoaded = ref(false)
|
||||||
|
|
||||||
const isImage = computed(() => {
|
const isImage = computed(() => {
|
||||||
if (!props.previewFile) return false
|
if (!props.previewFile) return false
|
||||||
const ext = props.previewFile.name.split('.').pop()?.toLowerCase()
|
const ext = props.previewFile.name.split('.').pop()?.toLowerCase()
|
||||||
@@ -56,6 +65,70 @@ const isText = computed(() => {
|
|||||||
const ext = props.previewFile.name.split('.').pop()?.toLowerCase()
|
const ext = props.previewFile.name.split('.').pop()?.toLowerCase()
|
||||||
return ['txt', 'md', 'json', 'xml', 'log', 'js', 'ts', 'vue', 'java', 'py', 'css', 'html'].includes(ext)
|
return ['txt', 'md', 'json', 'xml', 'log', 'js', 'ts', 'vue', 'java', 'py', 'css', 'html'].includes(ext)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isOffice = computed(() => {
|
||||||
|
if (!props.previewFile) return false
|
||||||
|
const ext = props.previewFile.name.split('.').pop()?.toLowerCase()
|
||||||
|
return ['docx', 'xlsx', 'pptx', 'doc', 'xls', 'ppt', 'ofd'].includes(ext)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 加载 jit-viewer 脚本
|
||||||
|
const loadJitViewer = () => {
|
||||||
|
if (window.jitView) {
|
||||||
|
jitViewerLoaded.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src = 'https://cdn.jsdelivr.net/npm/jit-viewer@latest/dist/jit-viewer.min.js'
|
||||||
|
script.onload = () => {
|
||||||
|
jitViewerLoaded.value = true
|
||||||
|
initOfficeViewer()
|
||||||
|
}
|
||||||
|
script.onerror = () => {
|
||||||
|
jitViewerLoaded.value = false
|
||||||
|
}
|
||||||
|
document.head.appendChild(script)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化 Office 预览
|
||||||
|
const initOfficeViewer = async () => {
|
||||||
|
if (!officeViewer.value || !props.previewUrl) return
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
// 使用 jit-viewer 预览
|
||||||
|
if (window.jitView) {
|
||||||
|
officeViewer.value.innerHTML = ''
|
||||||
|
const viewer = document.createElement('div')
|
||||||
|
viewer.style.width = '100%'
|
||||||
|
viewer.style.height = '70vh'
|
||||||
|
officeViewer.value.appendChild(viewer)
|
||||||
|
|
||||||
|
try {
|
||||||
|
window.jitView(viewer, {
|
||||||
|
url: props.previewUrl,
|
||||||
|
fileType: props.previewFile?.name.split('.').pop()?.toLowerCase()
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
officeViewer.value.innerHTML = '<div class="preview-error">预览加载失败,请下载后查看</div>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听弹窗显示和文件变化
|
||||||
|
watch(() => props.modelValue, (val) => {
|
||||||
|
if (val && isOffice.value) {
|
||||||
|
jitViewerLoaded.value = false
|
||||||
|
loadJitViewer()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.previewUrl, (val) => {
|
||||||
|
if (val && isOffice.value && props.modelValue) {
|
||||||
|
initOfficeViewer()
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -93,6 +166,35 @@ const isText = computed(() => {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preview-office {
|
||||||
|
width: 100%;
|
||||||
|
height: 70vh;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-loading {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-loading p {
|
||||||
|
margin-top: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-error {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
color: #f56c6c;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.preview-unsupported {
|
.preview-unsupported {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
@@ -102,4 +204,13 @@ const isText = computed(() => {
|
|||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.is-loading {
|
||||||
|
animation: rotating 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotating {
|
||||||
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ const formatDate = (date) => {
|
|||||||
const canPreview = (file) => {
|
const canPreview = (file) => {
|
||||||
if (file.type === 'folder') return false
|
if (file.type === 'folder') return false
|
||||||
const ext = file.name.split('.').pop()?.toLowerCase()
|
const ext = file.name.split('.').pop()?.toLowerCase()
|
||||||
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf', 'txt', 'md'].includes(ext)
|
return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf', 'txt', 'md', 'docx', 'xlsx', 'pptx', 'doc', 'xls', 'ppt', 'ofd'].includes(ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页
|
// 分页
|
||||||
|
|||||||
Reference in New Issue
Block a user