feat(router): 新增PDF预览独立页面并优化预览体验
将PDF预览从弹窗改为独立页面,提升大文件加载体验 添加返回课程详情页功能并保持学习资料弹窗状态 优化PDF组件关闭逻辑和错误处理
Showing
4 changed files
with
86 additions
and
5 deletions
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-01-21 | 2 | * @Date: 2025-01-21 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-10-22 09:57:57 | 4 | + * @LastEditTime: 2025-10-22 10:49:55 |
| 5 | * @FilePath: /mlaj/src/components/ui/PdfViewer.vue | 5 | * @FilePath: /mlaj/src/components/ui/PdfViewer.vue |
| 6 | * @Description: PDF预览组件 - 使用pdf-vue3库 | 6 | * @Description: PDF预览组件 - 使用pdf-vue3库 |
| 7 | --> | 7 | --> |
| ... | @@ -345,7 +345,7 @@ const handleClose = () => { | ... | @@ -345,7 +345,7 @@ const handleClose = () => { |
| 345 | 345 | ||
| 346 | // 使用nextTick确保在DOM更新前完成清理 | 346 | // 使用nextTick确保在DOM更新前完成清理 |
| 347 | nextTick(() => { | 347 | nextTick(() => { |
| 348 | - emit('update:show', false); | 348 | + emit('onClose', true); |
| 349 | }); | 349 | }); |
| 350 | }; | 350 | }; |
| 351 | 351 | ... | ... |
| ... | @@ -226,6 +226,14 @@ export const routes = [ | ... | @@ -226,6 +226,14 @@ export const routes = [ |
| 226 | } | 226 | } |
| 227 | }, | 227 | }, |
| 228 | { | 228 | { |
| 229 | + path: '/pdfPreview', | ||
| 230 | + name: 'PdfPreview', | ||
| 231 | + component: () => import('@/views/study/PdfPreviewPage.vue'), | ||
| 232 | + meta: { | ||
| 233 | + title: 'PDF预览', | ||
| 234 | + } | ||
| 235 | + }, | ||
| 236 | + { | ||
| 229 | path: '/profile/studyCourse/:id', | 237 | path: '/profile/studyCourse/:id', |
| 230 | component: () => import('@/views/profile/StudyCoursePage.vue'), | 238 | component: () => import('@/views/profile/StudyCoursePage.vue'), |
| 231 | meta: { | 239 | meta: { | ... | ... |
src/views/study/PdfPreviewPage.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-10-22 10:45:51 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-10-22 10:54:10 | ||
| 5 | + * @FilePath: /mlaj/src/views/study/PdfPreviewPage.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="pdf-preview-page"> | ||
| 10 | + <PdfViewer :show="true" :url="pdfUrl" :title="pdfTitle" @onClose="handleClose" /> | ||
| 11 | + </div> | ||
| 12 | +</template> | ||
| 13 | + | ||
| 14 | +<script setup> | ||
| 15 | +import { computed } from 'vue' | ||
| 16 | +import { useRoute, useRouter } from 'vue-router' | ||
| 17 | +import PdfViewer from '@/components/ui/PdfViewer.vue' | ||
| 18 | + | ||
| 19 | +const route = useRoute() | ||
| 20 | +const router = useRouter() | ||
| 21 | + | ||
| 22 | +// 从路由查询参数获取PDF的URL和标题 | ||
| 23 | +const pdfUrl = computed(() => { | ||
| 24 | + const url = route.query.url || '' | ||
| 25 | + // 兼容可能存在的编码 | ||
| 26 | + return typeof url === 'string' ? decodeURIComponent(url) : '' | ||
| 27 | +}) | ||
| 28 | + | ||
| 29 | +const pdfTitle = computed(() => { | ||
| 30 | + const title = route.query.title || '' | ||
| 31 | + return typeof title === 'string' ? decodeURIComponent(title) : '' | ||
| 32 | +}) | ||
| 33 | + | ||
| 34 | +const handleClose = () => { | ||
| 35 | + const returnId = route.query.returnId | ||
| 36 | + const openMaterials = route.query.openMaterials | ||
| 37 | + if (returnId) { | ||
| 38 | + // 使用 replace 跳回学习详情页并打开学习资料弹框,避免历史中保留PDF预览 | ||
| 39 | + router.replace({ path: `/studyDetail/${returnId}`, query: { openMaterials: openMaterials || '1' } }) | ||
| 40 | + } else { | ||
| 41 | + // 无返回ID时,使用 replace 导航到学习页,避免返回进入PDF预览 | ||
| 42 | + router.replace({ path: '/study' }) | ||
| 43 | + } | ||
| 44 | +} | ||
| 45 | +</script> | ||
| 46 | + | ||
| 47 | +<style scoped> | ||
| 48 | +.pdf-preview-page { | ||
| 49 | + height: 100vh; | ||
| 50 | + width: 100vw; | ||
| 51 | + background: #fff; | ||
| 52 | + display: flex; | ||
| 53 | + flex-direction: column; | ||
| 54 | +} | ||
| 55 | +</style> |
| ... | @@ -260,8 +260,7 @@ | ... | @@ -260,8 +260,7 @@ |
| 260 | </div> | 260 | </div> |
| 261 | </van-popup> | 261 | </van-popup> |
| 262 | 262 | ||
| 263 | - <!-- PDF预览 --> | 263 | + <!-- PDF预览改为独立页面,点击资源时跳转到 /pdfPreview --> |
| 264 | - <PdfViewer v-model:show="pdfShow" :url="pdfUrl" :title="pdfTitle" @onLoad="onPdfLoad" @onProgress="onPdfProgress" @onComplete="onPdfComplete" /> | ||
| 265 | 264 | ||
| 266 | <!-- Office 文档预览弹窗 --> | 265 | <!-- Office 文档预览弹窗 --> |
| 267 | <van-popup | 266 | <van-popup |
| ... | @@ -877,7 +876,10 @@ const popupVideoPlayerRef = ref(null); // 弹窗视频播放器引用 | ... | @@ -877,7 +876,10 @@ const popupVideoPlayerRef = ref(null); // 弹窗视频播放器引用 |
| 877 | const showPdf = ({ title, url, meta_id }) => { | 876 | const showPdf = ({ title, url, meta_id }) => { |
| 878 | pdfTitle.value = title; | 877 | pdfTitle.value = title; |
| 879 | pdfUrl.value = url; | 878 | pdfUrl.value = url; |
| 880 | - pdfShow.value = true; | 879 | + // 跳转到PDF预览页面,并带上返回的课程ID和打开资料弹框的标记 |
| 880 | + const encodedUrl = encodeURIComponent(url); | ||
| 881 | + const encodedTitle = encodeURIComponent(title); | ||
| 882 | + router.replace({ name: 'PdfPreview', query: { url: encodedUrl, title: encodedTitle, returnId: courseId.value, openMaterials: '1' } }); | ||
| 881 | // 新增记录 | 883 | // 新增记录 |
| 882 | let paramsObj = { | 884 | let paramsObj = { |
| 883 | schedule_id: courseId.value, | 885 | schedule_id: courseId.value, |
| ... | @@ -1270,6 +1272,22 @@ const downloadFailInfo = ref({ | ... | @@ -1270,6 +1272,22 @@ const downloadFailInfo = ref({ |
| 1270 | // 学习资料弹窗状态 | 1272 | // 学习资料弹窗状态 |
| 1271 | const showMaterialsPopup = ref(false); | 1273 | const showMaterialsPopup = ref(false); |
| 1272 | 1274 | ||
| 1275 | +// 路由参数监听:如果openMaterials=1,则打开学习资料弹框 | ||
| 1276 | +watch(() => route.query.openMaterials, (val) => { | ||
| 1277 | + if (val === '1' || val === 1 || val === true) { | ||
| 1278 | + showMaterialsPopup.value = true; | ||
| 1279 | + } | ||
| 1280 | +}, { immediate: true }); | ||
| 1281 | + | ||
| 1282 | +// 监听弹框关闭:关闭时移除URL中的openMaterials参数,防止刷新再次打开 | ||
| 1283 | +watch(showMaterialsPopup, (val, oldVal) => { | ||
| 1284 | + if (oldVal && !val) { | ||
| 1285 | + const newQuery = { ...route.query }; | ||
| 1286 | + delete newQuery.openMaterials; | ||
| 1287 | + router.replace({ path: route.path, query: newQuery }); | ||
| 1288 | + } | ||
| 1289 | +}); | ||
| 1290 | + | ||
| 1273 | /** | 1291 | /** |
| 1274 | * 复制文件地址到剪贴板 | 1292 | * 复制文件地址到剪贴板 |
| 1275 | * @param {string} url - 要复制的文件地址 | 1293 | * @param {string} url - 要复制的文件地址 | ... | ... |
-
Please register or login to post a comment