Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions src/layouts/Paper.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
<template>
<div class="pdf-layout">
<!-- 顶部导航栏 -->
<div class="pdf-header">
<el-button
type="primary"
class="back-button"
@click="$router.push('/database')"
circle
>
<el-icon><Back /></el-icon>
</el-button>
<div class="pdf-title">
<span class="title-text">文献阅读</span>
<span class="subtitle" v-if="documentTitle">{{ documentTitle }}</span>
</div>
</div>

<!-- PDF 查看区域 -->
<div class="pdf-container">
<PdfViewer
v-if="pdfUrl"
:fileUrl="pdfUrl"
:fileName="documentTitle"
:articleId="articleId"
:write="false"
/>
<div v-else class="pdf-loading">
<el-icon class="loading-icon is-loading"><Loading /></el-icon>
<span>正在加载 PDF 文件,请稍候...</span>
</div>
</div>
</div>
</template>

<script>
import { Back, Loading } from '@element-plus/icons-vue';
import PdfViewer from '@/components/Pdfview/PdfViewer.vue';
import http from '@/utils/http';
import { ElMessage } from 'element-plus';

export default {
name: "PdfReader",
components: {
Back,
Loading,
PdfViewer,
},
data() {
return {
pdfUrl: null,
documentTitle: "",
};
},
methods: {
async fetchPdf(articleId) {
try {
const response = await http.get("/article/readArticle", {
params: {
article_id: articleId,
},
responseType: "blob",
});

const blob = new Blob([response.data], { type: "application/pdf" });
this.pdfUrl = URL.createObjectURL(blob);
this.documentTitle = `文献 ID: ${articleId}`; // 临时设置标题
} catch (error) {
console.error("获取 PDF 文件失败:", error);
ElMessage.error("加载 PDF 文件失败,请检查后端服务!");
}
},
},
mounted() {
const articleId = this.$route.query.article_id;
if (articleId) {
this.fetchPdf(articleId);
} else {
ElMessage.error("请先选择要阅读的文献");
this.$router.push("/database");
}
},
};
</script>

<style scoped lang="scss">
.pdf-layout {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
background-color: #f8fafc;
overflow: hidden;
}

.pdf-header {
display: flex;
align-items: center;
padding: 0.5rem 1.5rem;
background: linear-gradient(135deg, #059669 0%, #047857 100%);
color: white;
height: 60px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 10;
}

.back-button {
margin-right: 1rem;
background-color: rgba(255, 255, 255, 0.2);
border: none;
transition: all 0.3s ease;

&:hover {
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
}

&:active {
transform: translateY(0);
}
}

.pdf-title {
display: flex;
flex-direction: column;
justify-content: center;

.title-text {
font-size: 1.25rem;
font-weight: 600;
letter-spacing: 0.5px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.subtitle {
font-size: 0.875rem;
opacity: 0.85;
margin-top: 0.25rem;
}
}

.pdf-container {
flex: 1;
background-color: #f0f2f5;
position: relative;
border: 1px solid #e2e8f0;
border-radius: 0.375rem;
margin: 0.25rem;
overflow: hidden;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05);
}

.pdf-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: #64748b;

.loading-icon {
font-size: 2.5rem;
margin-bottom: 1rem;
animation: rotating 2s linear infinite;
}
}

@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>
6 changes: 5 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createApp } from "vue";
import { createWebHistory, createRouter } from "vue-router";
import 'flowbite';


import Paper from "@/layouts/Paper.vue";
import PaperNote from '@/layouts/PaperNote.vue';
// styles

Expand Down Expand Up @@ -131,6 +131,10 @@ const routes = [
path: "/paper-note",
component: PaperNote,
},
{
path: "/paper",
component: Paper,
},
{
path: "/",
component: Index,
Expand Down
36 changes: 32 additions & 4 deletions src/views/admin/Maps.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
class="literature-simple-item"
>
<span class="literature-icon"><svg t="1748777710670" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1020" data-spm-anchor-id="a313x.collections_detail.0.i0.223b3a81QSiUzk" width="200" height="200"><path d="M911.232 536.064a30.784 30.784 0 0 1 14.912 57.6c-24 13.44-86.464 60.16-86.464 113.024 0 76.672 64.832 115.84 80.896 124.352l3.456 1.792a30.784 30.784 0 0 1-12.8 58.624H260.672a177.92 177.92 0 0 1-177.728-177.728 177.92 177.92 0 0 1 177.728-177.728h407.552c-15.616 0.064-28.16 10.944-30.784 25.28l-0.512 5.504c0 16.96 13.76 30.72 30.72 30.72l-0.704-0.128 0.704 0.064c10.368 0 4.928-8.576-16.384-25.792l-6.144-4.928c26.304-20.48 33.856-30.72 22.528-30.72h0.576l243.008 0.064z m-244.288 61.312l-406.272 0.064a116.48 116.48 0 0 0-116.288 116.288 116.48 116.48 0 0 0 116.288 116.288h563.008a187.712 187.712 0 0 1-45.44-123.328c0-44.16 22.08-81.28 47.104-109.184h-157.696l-0.704-0.128z m-63.296 106.368a30.72 30.72 0 1 1 0 61.44H266.24a30.72 30.72 0 0 1 0-61.44h337.344z m160.64-576.64a177.92 177.92 0 0 1 177.664 177.728 177.92 177.92 0 0 1-177.728 177.664H113.664a30.784 30.784 0 0 1-14.976-57.536c24.064-13.504 86.528-60.16 86.528-113.088 0-85.696-80.96-124.544-84.416-126.08a30.784 30.784 0 0 1 12.864-58.624h650.624z m0 61.44h-93.248l-0.832 0.064H201.216c24.448 29.12 45.44 69.696 45.44 123.328 0 44.16-22.016 81.28-47.104 109.184h564.736a116.48 116.48 0 0 0 116.224-116.288 116.48 116.48 0 0 0-116.224-116.288z m-9.984 110.528a30.72 30.72 0 1 1 0 61.44h-337.28a30.72 30.72 0 0 1 0-61.44h337.28z m-84.096-171.904l-5.504 0.448a30.72 30.72 0 0 0 5.504 60.928h0.832l1.6-0.128c6.72-1.408 0.128-9.984-19.776-25.6l-6.4-4.928c27.136-20.48 35.072-30.72 23.744-30.72z" fill="#505766" p-id="1021"></path><path d="M911.232 523.264a43.584 43.584 0 0 1 21.184 81.472c-40.32 22.72-79.936 65.28-79.936 101.952 0 30.784 11.392 56.96 31.168 79.232 13.568 15.168 29.056 26.496 42.688 33.728l3.136 1.6a43.52 43.52 0 0 1-18.24 83.008H260.672a190.72 190.72 0 0 1-190.528-190.528 190.72 190.72 0 0 1 190.528-190.528h406.976l243.584 0.064z m-283.072 25.472l-367.488 0.064a165.12 165.12 0 0 0-164.928 164.928 165.12 165.12 0 0 0 164.928 164.928h650.496a17.92 17.92 0 0 0 17.472-14.08 18.112 18.112 0 0 0-10.368-20.352l-3.712-1.856a182.08 182.08 0 0 1-50.048-39.424 141.44 141.44 0 0 1-37.632-96.256c0-48.768 45.376-97.408 93.056-124.288a17.92 17.92 0 0 0-8.704-33.536l-228.928-0.128-1.536 2.56a92.16 92.16 0 0 1-13.312 13.632l-2.048 1.728c6.4 5.568 10.88 9.984 14.08 13.824l2.624 3.648 0.256 0.512 171.648 0.064-19.136 21.312c-27.904 31.168-43.84 64.896-43.84 100.672 0 44.8 15.488 83.008 42.432 115.072l17.728 21.056H260.672a129.28 129.28 0 0 1-129.088-129.088 129.28 129.28 0 0 1 129.088-129.088h367.616l-0.704-1.408a45.44 45.44 0 0 1-3.008-11.456l-0.384-6.144 0.64-6.656a43.392 43.392 0 0 1 1.792-6.656l1.536-3.584z m170.56 61.504l-131.072-0.128H665.6l-404.992 0.128a103.68 103.68 0 0 0-103.04 94.08l-0.448 9.408a103.68 103.68 0 0 0 103.488 103.488h537.6l-1.216-1.728a196.48 196.48 0 0 1-31.104-93.632l-0.512-15.168c0-34.304 11.904-66.368 32.96-96l0.32-0.448z m-195.072 80.64a43.52 43.52 0 1 1 0 87.04H266.24a43.52 43.52 0 0 1 0-87.04h337.344z m0 25.6H266.304a17.92 17.92 0 0 0 0 35.84h337.28a17.92 17.92 0 0 0 0.064-35.84z m351.104-411.648a190.72 190.72 0 0 1-190.528 190.464H113.664a43.584 43.584 0 0 1-21.248-81.472c40.32-22.72 80-65.28 80-101.952 0-58.304-38.464-96.64-76.992-114.56a43.52 43.52 0 0 1 18.24-82.944h650.624a190.72 190.72 0 0 1 190.464 190.464z m-270.144-164.992l-1.728 2.816a96.96 96.96 0 0 1-13.76 13.632l-1.92 1.536 4.8 4.224c3.2 2.816 5.888 5.376 8.064 7.68l2.816 3.392 1.728 2.56 79.68 0.064a129.28 129.28 0 0 1 129.024 129.088 129.28 129.28 0 0 1-129.024 129.088H170.88l19.072-21.312c27.904-31.168 43.84-64.896 43.84-100.672 0-44.8-15.424-83.008-42.432-115.072l-17.728-21.056h27.52l429.376 0.064-2.048-5.44a43.2 43.2 0 0 1-1.408-6.144l-0.384-5.504-1.344-0.96 1.28-1.088 0.448-5.12a42.688 42.688 0 0 1 3.392-11.648H113.664a17.792 17.792 0 0 0-16.064 10.176l-1.344 3.84a17.92 17.92 0 0 0 9.92 20.16c46.656 21.568 91.84 66.624 91.84 137.728 0 48.768-45.376 97.408-93.056 124.288a17.92 17.92 0 0 0 8.704 33.536h650.56a165.12 165.12 0 0 0 164.928-164.864 165.12 165.12 0 0 0-164.864-164.928h-79.68z m-11.2 61.312l-1.408 0.128H672l-1.728 0.128H226.624l1.216 1.728c17.728 27.584 28.672 58.816 31.104 93.632l0.512 15.168c0 34.304-11.904 66.368-32.896 96l-0.32 0.32 538.048 0.064a103.68 103.68 0 0 0 103.04-94.08l0.384-9.408a103.68 103.68 0 0 0-103.424-103.488l-90.88-0.192z m80.896 85.12a43.52 43.52 0 1 1 0 87.04h-337.28a43.52 43.52 0 0 1 0-87.04h337.28z m0 25.6h-337.28a17.92 17.92 0 0 0 0 35.84h337.28a17.92 17.92 0 0 0 0-35.84z" fill="#505766" p-id="1022" data-spm-anchor-id="a313x.collections_detail.0.i1.223b3a81QSiUzk" class="selected"></path></svg></span>
<div class="literature-info">
<div class="literature-info" @click="handlePreview(article.id)">
<span class="literature-title-text" :title="article.title">{{ article.title }}</span>
<div v-if="article.author" class="literature-author-text">
<el-icon style="font-size:16px;color:#2563eb;margin-right:4px;"><i class="el-icon-user" /></el-icon>
Expand Down Expand Up @@ -152,12 +152,14 @@
<script setup>
import { ref, watch ,computed } from 'vue'
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus'
import { defineExpose } from 'vue'
import { searchLiterature, getLiteratureList, getSelfFolders, copyArticleToFolder, generateArticleIntro } from '@/api/database'
import { searchLiterature, getRecommendLiterature, getSelfFolders, copyArticleToFolder, generateArticleIntro } from '@/api/database'
import patternVue from "@/assets/img/logo4.png"

const route = useRoute()
const router = useRouter();
const articles = ref([])
const isLoading = ref(true)
const searchQuery = ref('')
Expand Down Expand Up @@ -230,6 +232,10 @@ function handleBackToRecommend() {
fetchLiteratureList()
}

function handlePreview(articleId) {
router.push(`/paper?article_id=${articleId}`); // 跳转到 PDF 阅读页面
}

async function fetchArticleIntro(article) {
if (article.loadingIntro) return; // 防止重复加载
article.loadingIntro = true; // 标记为加载中
Expand Down Expand Up @@ -267,7 +273,7 @@ async function handleSearch() {
async function fetchLiteratureList() {
isLoading.value = true;
try {
const response = await getLiteratureList();
const response = await getRecommendLiterature({size: 10});
const data = response.data || {};
articles.value = (data.articles || []).map(article => ({
...article,
Expand Down Expand Up @@ -335,7 +341,8 @@ defineExpose({
handlePageSizeChange,
goToPage,
jumpToPage,
fetchArticleIntro
fetchArticleIntro,
handlePreview,
})
</script>

Expand Down Expand Up @@ -729,5 +736,26 @@ defineExpose({
text-align: center;
}

.literature-info {
cursor: pointer; /* 鼠标样式为手型,表示可点击 */
transition: background 0.2s;
}

.literature-info:hover {
background: #f0f9ff; /* 鼠标悬停时背景颜色变化 */
}

.literature-action-icon {
margin-left: auto;
cursor: pointer; /* 鼠标样式为手型,表示可点击 */
display: flex;
align-items: center;
padding: 4px;
border-radius: 4px;
transition: background 0.2s;
}

.literature-action-icon:hover {
background: #d1fae5; /* 鼠标悬停时背景颜色变化 */
}
</style>