云文件系统初始化

This commit is contained in:
2026-04-01 23:56:09 +08:00
parent 3107b11bc4
commit 61a675b4de
3 changed files with 116 additions and 5 deletions

View File

@@ -175,7 +175,7 @@ const formatDate = (date) => {
const canPreview = (file) => {
if (file.type === 'folder') return false
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>

View File

@@ -4,12 +4,18 @@
:title="previewFile?.name || '预览'"
width="80%"
top="5vh"
class="custom-dialog"
class="custom-dialog preview-dialog"
>
<div class="preview-content">
<img v-if="isImage" :src="previewUrl" class="preview-image" />
<iframe v-else-if="isPdf" :src="previewUrl" class="preview-iframe" />
<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">
<el-icon :size="64"><Document /></el-icon>
<p>此文件类型暂不支持预览</p>
@@ -23,8 +29,8 @@
</template>
<script setup>
import { computed } from 'vue'
import { Document, Download } from '@element-plus/icons-vue'
import { computed, ref, watch, nextTick } from 'vue'
import { Document, Download, Loading } from '@element-plus/icons-vue'
const props = defineProps({
modelValue: Boolean,
@@ -40,6 +46,9 @@ const visible = computed({
set: (v) => emit('update:modelValue', v)
})
const officeViewer = ref(null)
const jitViewerLoaded = ref(false)
const isImage = computed(() => {
if (!props.previewFile) return false
const ext = props.previewFile.name.split('.').pop()?.toLowerCase()
@@ -56,6 +65,70 @@ const isText = computed(() => {
const ext = props.previewFile.name.split('.').pop()?.toLowerCase()
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>
<style scoped>
@@ -93,6 +166,35 @@ const isText = computed(() => {
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 {
text-align: center;
color: #909399;
@@ -102,4 +204,13 @@ const isText = computed(() => {
margin: 16px 0;
font-size: 14px;
}
.is-loading {
animation: rotating 2s linear infinite;
}
@keyframes rotating {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>

View File

@@ -269,7 +269,7 @@ const formatDate = (date) => {
const canPreview = (file) => {
if (file.type === 'folder') return false
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)
}
// 分页