feat(StudyDetailPage): 添加文件下载功能
为StudyDetailPage页面添加文件下载功能,用户点击非PDF文件时触发下载操作。通过axios获取文件数据,并使用Blob对象处理下载流程,提升用户体验。
Showing
1 changed file
with
61 additions
and
3 deletions
| ... | @@ -54,8 +54,12 @@ | ... | @@ -54,8 +54,12 @@ |
| 54 | <font-awesome-icon icon="file-alt" class="text-gray-400 text-lg flex-shrink-0" /> | 54 | <font-awesome-icon icon="file-alt" class="text-gray-400 text-lg flex-shrink-0" /> |
| 55 | <h3 class="text-x font-medium text-gray-900 truncate">{{ item.title }}</h3> | 55 | <h3 class="text-x font-medium text-gray-900 truncate">{{ item.title }}</h3> |
| 56 | </div> | 56 | </div> |
| 57 | - <div v-if="item.url.toLowerCase().endsWith('.pdf')" class="text-x text-blue-600 hover:text-blue-800 hover:underline whitespace-nowrap" @click="showPdf(item)">查看文件</div> | 57 | + <div v-if="item.url.toLowerCase().endsWith('.pdf')" |
| 58 | - <a v-else :href="item.url" target="_blank" class="text-x text-blue-600 hover:text-blue-800 hover:underline whitespace-nowrap">查看文件</a> | 58 | + class="text-x text-blue-600 hover:text-blue-800 hover:underline whitespace-nowrap" |
| 59 | + @click="showPdf(item)">查看文件</div> | ||
| 60 | + <div v-else @click="downloadFile(item)" | ||
| 61 | + class="text-x text-blue-600 hover:text-blue-800 hover:underline whitespace-nowrap"> | ||
| 62 | + 下载文件</div> | ||
| 59 | </div> | 63 | </div> |
| 60 | </div> | 64 | </div> |
| 61 | </div> | 65 | </div> |
| ... | @@ -238,6 +242,7 @@ import VideoPlayer from '@/components/ui/VideoPlayer.vue'; | ... | @@ -238,6 +242,7 @@ import VideoPlayer from '@/components/ui/VideoPlayer.vue'; |
| 238 | import AudioPlayer from '@/components/ui/AudioPlayer.vue'; | 242 | import AudioPlayer from '@/components/ui/AudioPlayer.vue'; |
| 239 | import dayjs from 'dayjs'; | 243 | import dayjs from 'dayjs'; |
| 240 | import { formatDate } from '@/utils/tools' | 244 | import { formatDate } from '@/utils/tools' |
| 245 | +import axios from 'axios'; | ||
| 241 | 246 | ||
| 242 | import PdfPreview from '@/components/ui/PdfPreview.vue'; | 247 | import PdfPreview from '@/components/ui/PdfPreview.vue'; |
| 243 | 248 | ||
| ... | @@ -360,7 +365,7 @@ const pdfShow = ref(false); | ... | @@ -360,7 +365,7 @@ const pdfShow = ref(false); |
| 360 | const pdfTitle = ref(''); | 365 | const pdfTitle = ref(''); |
| 361 | const pdfUrl = ref(''); | 366 | const pdfUrl = ref(''); |
| 362 | 367 | ||
| 363 | -const showPdf = ({title, url}) => { | 368 | +const showPdf = ({ title, url }) => { |
| 364 | pdfTitle.value = title; | 369 | pdfTitle.value = title; |
| 365 | pdfUrl.value = url; | 370 | pdfUrl.value = url; |
| 366 | pdfShow.value = true; | 371 | pdfShow.value = true; |
| ... | @@ -584,6 +589,59 @@ watch(showCommentPopup, async (newVal) => { | ... | @@ -584,6 +589,59 @@ watch(showCommentPopup, async (newVal) => { |
| 584 | onPopupLoad(); | 589 | onPopupLoad(); |
| 585 | } | 590 | } |
| 586 | }); | 591 | }); |
| 592 | + | ||
| 593 | +// 下载文件 | ||
| 594 | +const downloadFile = ({ title, url }) => { | ||
| 595 | + // 获取文件URL和文件名 | ||
| 596 | + const fileUrl = url; | ||
| 597 | + const fileName = title; | ||
| 598 | + | ||
| 599 | + // 根据文件URL后缀获取MIME类型 | ||
| 600 | + const getMimeType = (url) => { | ||
| 601 | + const extension = url.split('.').pop().toLowerCase(); | ||
| 602 | + const mimeTypes = { | ||
| 603 | + 'pdf': 'application/pdf', | ||
| 604 | + 'doc': 'application/msword', | ||
| 605 | + 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', | ||
| 606 | + 'xls': 'application/vnd.ms-excel', | ||
| 607 | + 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', | ||
| 608 | + 'ppt': 'application/vnd.ms-powerpoint', | ||
| 609 | + 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', | ||
| 610 | + 'txt': 'text/plain', | ||
| 611 | + 'zip': 'application/zip', | ||
| 612 | + 'rar': 'application/x-rar-compressed', | ||
| 613 | + '7z': 'application/x-7z-compressed', | ||
| 614 | + 'mp3': 'audio/mpeg', | ||
| 615 | + 'mp4': 'video/mp4', | ||
| 616 | + 'jpg': 'image/jpeg', | ||
| 617 | + 'jpeg': 'image/jpeg', | ||
| 618 | + 'png': 'image/png', | ||
| 619 | + 'gif': 'image/gif' | ||
| 620 | + }; | ||
| 621 | + return mimeTypes[extension] || 'application/octet-stream'; | ||
| 622 | + }; | ||
| 623 | + | ||
| 624 | + axios({ | ||
| 625 | + method: 'get', | ||
| 626 | + url: fileUrl, | ||
| 627 | + responseType: 'blob' // 表示返回的数据类型是Blob | ||
| 628 | + }).then((response) => { | ||
| 629 | + const blob = new Blob([response.data], { type: getMimeType(fileUrl) }); | ||
| 630 | + const url = window.URL.createObjectURL(blob); | ||
| 631 | + | ||
| 632 | + const a = document.createElement('a'); | ||
| 633 | + a.href = url; | ||
| 634 | + a.download = fileName; | ||
| 635 | + a.style.display = 'none'; | ||
| 636 | + document.body.appendChild(a); | ||
| 637 | + a.click(); | ||
| 638 | + document.body.removeChild(a); | ||
| 639 | + | ||
| 640 | + window.URL.revokeObjectURL(url); | ||
| 641 | + }).catch((error) => { | ||
| 642 | + console.error('下载文件出错:', error); | ||
| 643 | + }); | ||
| 644 | +} | ||
| 587 | </script> | 645 | </script> |
| 588 | 646 | ||
| 589 | <style lang="less" scoped> | 647 | <style lang="less" scoped> | ... | ... |
-
Please register or login to post a comment