hookehuyr

feat(router): 新增PDF预览独立页面并优化预览体验

将PDF预览从弹窗改为独立页面,提升大文件加载体验
添加返回课程详情页功能并保持学习资料弹窗状态
优化PDF组件关闭逻辑和错误处理
<!--
* @Date: 2025-01-21
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-10-22 09:57:57
* @LastEditTime: 2025-10-22 10:49:55
* @FilePath: /mlaj/src/components/ui/PdfViewer.vue
* @Description: PDF预览组件 - 使用pdf-vue3库
-->
......@@ -345,7 +345,7 @@ const handleClose = () => {
// 使用nextTick确保在DOM更新前完成清理
nextTick(() => {
emit('update:show', false);
emit('onClose', true);
});
};
......
......@@ -226,6 +226,14 @@ export const routes = [
}
},
{
path: '/pdfPreview',
name: 'PdfPreview',
component: () => import('@/views/study/PdfPreviewPage.vue'),
meta: {
title: 'PDF预览',
}
},
{
path: '/profile/studyCourse/:id',
component: () => import('@/views/profile/StudyCoursePage.vue'),
meta: {
......
<!--
* @Date: 2025-10-22 10:45:51
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-10-22 10:54:10
* @FilePath: /mlaj/src/views/study/PdfPreviewPage.vue
* @Description: 文件描述
-->
<template>
<div class="pdf-preview-page">
<PdfViewer :show="true" :url="pdfUrl" :title="pdfTitle" @onClose="handleClose" />
</div>
</template>
<script setup>
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import PdfViewer from '@/components/ui/PdfViewer.vue'
const route = useRoute()
const router = useRouter()
// 从路由查询参数获取PDF的URL和标题
const pdfUrl = computed(() => {
const url = route.query.url || ''
// 兼容可能存在的编码
return typeof url === 'string' ? decodeURIComponent(url) : ''
})
const pdfTitle = computed(() => {
const title = route.query.title || ''
return typeof title === 'string' ? decodeURIComponent(title) : ''
})
const handleClose = () => {
const returnId = route.query.returnId
const openMaterials = route.query.openMaterials
if (returnId) {
// 使用 replace 跳回学习详情页并打开学习资料弹框,避免历史中保留PDF预览
router.replace({ path: `/studyDetail/${returnId}`, query: { openMaterials: openMaterials || '1' } })
} else {
// 无返回ID时,使用 replace 导航到学习页,避免返回进入PDF预览
router.replace({ path: '/study' })
}
}
</script>
<style scoped>
.pdf-preview-page {
height: 100vh;
width: 100vw;
background: #fff;
display: flex;
flex-direction: column;
}
</style>
......@@ -260,8 +260,7 @@
</div>
</van-popup>
<!-- PDF预览 -->
<PdfViewer v-model:show="pdfShow" :url="pdfUrl" :title="pdfTitle" @onLoad="onPdfLoad" @onProgress="onPdfProgress" @onComplete="onPdfComplete" />
<!-- PDF预览改为独立页面,点击资源时跳转到 /pdfPreview -->
<!-- Office 文档预览弹窗 -->
<van-popup
......@@ -877,7 +876,10 @@ const popupVideoPlayerRef = ref(null); // 弹窗视频播放器引用
const showPdf = ({ title, url, meta_id }) => {
pdfTitle.value = title;
pdfUrl.value = url;
pdfShow.value = true;
// 跳转到PDF预览页面,并带上返回的课程ID和打开资料弹框的标记
const encodedUrl = encodeURIComponent(url);
const encodedTitle = encodeURIComponent(title);
router.replace({ name: 'PdfPreview', query: { url: encodedUrl, title: encodedTitle, returnId: courseId.value, openMaterials: '1' } });
// 新增记录
let paramsObj = {
schedule_id: courseId.value,
......@@ -1270,6 +1272,22 @@ const downloadFailInfo = ref({
// 学习资料弹窗状态
const showMaterialsPopup = ref(false);
// 路由参数监听:如果openMaterials=1,则打开学习资料弹框
watch(() => route.query.openMaterials, (val) => {
if (val === '1' || val === 1 || val === true) {
showMaterialsPopup.value = true;
}
}, { immediate: true });
// 监听弹框关闭:关闭时移除URL中的openMaterials参数,防止刷新再次打开
watch(showMaterialsPopup, (val, oldVal) => {
if (oldVal && !val) {
const newQuery = { ...route.query };
delete newQuery.openMaterials;
router.replace({ path: route.path, query: newQuery });
}
});
/**
* 复制文件地址到剪贴板
* @param {string} url - 要复制的文件地址
......