Files
backend/dev-check.txt
T

899 lines
92 KiB
Plaintext
Raw Normal View History

import { createHotContext as __vite__createHotContext } from "/@vite/client";import.meta.hot = __vite__createHotContext("/src/views/public/HomeView.vue?v=1");/* unplugin-vue-components disabled */import __unplugin_components_2 from "/src/components/literature/LiteraturePreviewDrawer.vue?t=1783728117686";
import __unplugin_components_1 from "/src/components/literature/LiteratureCard.vue?t=1783728117686";
import __unplugin_components_0 from "/src/components/search/AdvancedSearchPanel.vue?t=1783728117686";
import { defineComponent as _defineComponent } from "/node_modules/.vite/deps/vue.js?v=3cfd8f60";
import { ref, computed, onMounted, onBeforeUnmount, watch } from "/node_modules/.vite/deps/vue.js?v=3cfd8f60";
import { useRouter, useRoute } from "/node_modules/.vite/deps/vue-router.js?v=3cfd8f60";
import { NButton, NEmpty, NIcon } from "/node_modules/.vite/deps/naive-ui.js?v=6ae179ec";
import { ChevronDownOutline, ChevronUpOutline, CloseCircleOutline, OptionsOutline, PersonAddOutline, RefreshOutline, SearchOutline } from "/node_modules/.vite/deps/@vicons_ionicons5.js?v=78995c2b";
import { api } from "/src/api/client.ts?t=1783728117686&v=1";
import { useAuthStore } from "/src/stores/auth.ts?t=1783728117686&v=1";
import { useToast } from "/src/composables/useToast.ts?v=1";
import { useLiteraturePreview } from "/src/composables/useLiteraturePreview.ts?v=1";
import PageSkeleton from "/src/components/common/PageSkeleton.vue?v=1";
const hotPageSize = 5;
const hotMaxPage = 6;
const _sfc_main = /* @__PURE__ */ _defineComponent({
__name: "HomeView",
setup(__props, { expose: __expose }) {
__expose();
const router = useRouter();
const route = useRoute();
const auth = useAuthStore();
const toast = useToast();
const searchParams = ref({
query: "",
field: "all",
tag_ids: [],
date_from: null,
date_to: null,
retracted: "",
negative_result: "",
precision_mode: "majr",
page: 1,
page_size: 20,
sort: "date"
});
const feedItems = ref([]);
const feedTotal = ref(0);
const loading = ref(false);
const searched = ref(false);
const platformStats = ref({ literature_total: 0, journal_total: 0, daily_avg_30d: 0 });
const statsLoading = ref(true);
const hotArticles = ref([]);
const hotPage = ref(1);
const hotTotal = ref(0);
const hotAvailablePages = computed(() => Math.min(hotMaxPage, Math.ceil(hotTotal.value / hotPageSize)));
async function loadHotArticles() {
try {
const { data } = await api.get("/public/hot-articles", { params: { page: hotPage.value, page_size: hotPageSize } });
hotArticles.value = data.items || [];
hotTotal.value = data.total || 0;
} catch (e) {
}
}
function refreshHot() {
const max = Math.min(hotMaxPage, Math.ceil(hotTotal.value / hotPageSize) || 1);
hotPage.value = hotPage.value >= max ? 1 : hotPage.value + 1;
loadHotArticles();
}
async function loadStats() {
try {
const { data } = await api.get("/public/stats");
platformStats.value = data;
} catch (e) {
} finally {
statsLoading.value = false;
}
}
const allTags = ref([]);
const selectedTagIds = ref([]);
const showAllTags = ref(false);
const isMobile = ref(window.innerWidth < 768);
const showAdvanced = ref(false);
function onDocumentMouseDown(e) {
if (!showAdvanced.value) return;
if (!e.target?.closest(".adv-filter-panel")) {
showAdvanced.value = false;
}
}
const localQuery = ref("");
const { showPreview, previewPmid, openPreview: setPreviewPmid, closePreview } = useLiteraturePreview();
const saving = ref(/* @__PURE__ */ new Set());
const savedPmids = ref(/* @__PURE__ */ new Set());
const lastVisitStr = localStorage.getItem("home_last_visit");
const dividerIndex = computed(() => {
if (!lastVisitStr || !feedItems.value.length) return -1;
const lastDt = new Date(parseInt(lastVisitStr)).toLocaleDateString("sv");
const idx = feedItems.value.findIndex((item) => {
const d = item.pub_date?.slice(0, 10);
return d && d <= lastDt;
});
return idx > 0 ? idx : -1;
});
async function fetchData(resetPage = true) {
if (resetPage) searchParams.value.page = 1;
loading.value = true;
try {
const body = { page: searchParams.value.page, page_size: searchParams.value.page_size, sort: searchParams.value.sort };
if (searchParams.value.query) body.query = searchParams.value.query;
if (searchParams.value.field !== "all") body.field = searchParams.value.field;
if (searchParams.value.tag_ids.length) body.tag_ids = searchParams.value.tag_ids;
if (searchParams.value.date_from) body.date_from = searchParams.value.date_from;
if (searchParams.value.date_to) body.date_to = searchParams.value.date_to;
if (searchParams.value.retracted) body.retracted = searchParams.value.retracted;
if (searchParams.value.negative_result) body.negative_result = searchParams.value.negative_result;
if (searchParams.value.precision_mode) body.precision_mode = searchParams.value.precision_mode;
const { data } = await api.post("/features/search/advanced", body);
if (resetPage) {
feedItems.value = data.items || [];
} else {
feedItems.value.push(...data.items || []);
}
feedTotal.value = data.total || 0;
searched.value = true;
} catch (e) {
toast.apiError(e, "搜索文献失败,请重试");
} finally {
loading.value = false;
}
}
function toggleTag(tagId) {
const id = String(tagId);
const idx = selectedTagIds.value.indexOf(id);
if (idx >= 0) {
selectedTagIds.value.splice(idx, 1);
} else {
selectedTagIds.value.push(id);
}
searchParams.value.tag_ids = [...selectedTagIds.value];
fetchData();
}
const cancerTags = computed(() => allTags.value.filter((t) => t.tag_category === "cancer" && t.level === 2));
const hasMoreTags = computed(() => cancerTags.value.length > 7);
const visibleTags = computed(() => {
if (showAllTags.value) return cancerTags.value;
return cancerTags.value.slice(0, 7);
});
function doLocalSearch() {
showAdvanced.value = false;
searchParams.value.field = "all";
if (localQuery.value.trim()) {
searchParams.value.query = localQuery.value;
} else {
searchParams.value.query = "";
}
fetchData();
}
function clearSearch() {
localQuery.value = "";
searchParams.value = {
query: "",
field: "all",
tag_ids: [],
date_from: null,
date_to: null,
retracted: "",
negative_result: "",
precision_mode: "majr",
page: 1,
page_size: 20,
sort: "date"
};
selectedTagIds.value = [];
showAdvanced.value = false;
fetchData();
}
function handleAdvancedSearch(params) {
searchParams.value.query = params.query;
searchParams.value.field = params.field;
searchParams.value.date_from = params.date_from;
searchParams.value.date_to = params.date_to;
searchParams.value.tag_ids = params.tag_ids;
searchParams.value.retracted = params.retracted;
searchParams.value.negative_result = params.negative_result;
selectedTagIds.value = [...params.tag_ids];
showAdvanced.value = false;
fetchData();
}
async function saveLiterature(item) {
if (!auth.isAuthenticated) {
router.push("/auth/login");
return;
}
if (saving.value.has(item.pmid) || savedPmids.value.has(item.pmid)) return;
saving.value = new Set(saving.value).add(item.pmid);
try {
await api.post(`/literature/${item.pmid}/save`);
savedPmids.value = new Set(savedPmids.value).add(item.pmid);
toast.success("已收藏");
} catch (e) {
toast.apiError(e, "收藏文献失败,请重试");
} finally {
const s = new Set(saving.value);
s.delete(item.pmid);
saving.value = s;
}
}
function openPreview(item) {
if (item.pmid) setPreviewPmid(item.pmid);
}
function goDetail(item) {
closePreview();
const q = searchParams.value.query;
router.push(q ? `/literature/${item.pmid}?q=${encodeURIComponent(q)}` : `/literature/${item.pmid}`);
}
async function loadSavedPmids() {
if (!auth.isAuthenticated) return;
try {
const { data } = await api.get("/literature/saved");
savedPmids.value = new Set((data.items || []).map((i) => i.pmid));
} catch (e) {
toast.apiError(e, "加载收藏状态失败");
}
}
const loadingMore = ref(false);
const hasMore = computed(() => feedItems.value.length < feedTotal.value);
const showScrollTop = ref(false);
function onScroll() {
showScrollTop.value = window.scrollY > window.innerHeight;
}
function scrollToTop() {
window.scrollTo({ top: 0, behavior: "smooth" });
}
function onResize() {
isMobile.value = window.innerWidth < 768;
}
async function loadMore() {
if (loadingMore.value || !hasMore.value) return;
loadingMore.value = true;
searchParams.value.page++;
try {
const body = { page: searchParams.value.page, page_size: searchParams.value.page_size, sort: searchParams.value.sort };
if (searchParams.value.query) body.query = searchParams.value.query;
if (searchParams.value.field !== "all") body.field = searchParams.value.field;
if (searchParams.value.tag_ids.length) body.tag_ids = searchParams.value.tag_ids;
if (searchParams.value.date_from) body.date_from = searchParams.value.date_from;
if (searchParams.value.date_to) body.date_to = searchParams.value.date_to;
if (searchParams.value.retracted) body.retracted = searchParams.value.retracted;
if (searchParams.value.negative_result) body.negative_result = searchParams.value.negative_result;
if (searchParams.value.precision_mode) body.precision_mode = searchParams.value.precision_mode;
const { data } = await api.post("/features/search/advanced", body);
feedItems.value.push(...data.items || []);
feedTotal.value = data.total || 0;
} catch (e) {
toast.apiError(e, "加载更多失败,请重试");
} finally {
loadingMore.value = false;
}
}
function restoreFromUrl() {
const tag = route.query.tag;
const date = route.query.date;
const q = route.query.q;
if (tag) {
const ids = tag.split(",");
selectedTagIds.value = ids;
searchParams.value.tag_ids = ids;
}
if (date) {
searchParams.value.date_from = date;
searchParams.value.date_to = date;
}
if (q) {
searchParams.value.query = q;
localQuery.value = q;
}
const p = route.query.page;
if (p) {
searchParams.value.page = parseInt(p) || 1;
}
}
const searchKey = computed(
() => JSON.stringify([searchParams.value.query, searchParams.value.tag_ids, searchParams.value.date_from, searchParams.value.date_to, searchParams.value.page, searchParams.value.sort])
);
watch(searchKey, () => {
const query = {};
if (searchParams.value.tag_ids.length) query.tag = searchParams.value.tag_ids.join(",");
if (searchParams.value.date_from) query.date = searchParams.value.date_from;
if (searchParams.value.query) query.q = searchParams.value.query;
router.replace({ query });
});
watch(() => route.query, (q) => {
if (q && q._t) {
clearSearch();
}
});
onMounted(async () => {
restoreFromUrl();
loadStats();
loadHotArticles();
try {
const { data } = await api.get("/public/tags");
allTags.value = data.tags || [];
} catch (e) {
toast.apiError(e, "加载标签失败");
}
await fetchData();
await loadSavedPmids();
localStorage.setItem("home_last_visit", String(Date.now()));
window.addEventListener("scroll", onScroll);
window.addEventListener("resize", onResize);
document.addEventListener("mousedown", onDocumentMouseDown);
});
onBeforeUnmount(() => {
window.removeEventListener("scroll", onScroll);
window.removeEventListener("resize", onResize);
document.removeEventListener("mousedown", onDocumentMouseDown);
});
const __returned__ = { router, route, auth, toast, searchParams, feedItems, feedTotal, loading, searched, platformStats, statsLoading, hotArticles, hotPage, hotPageSize, hotTotal, hotMaxPage, hotAvailablePages, loadHotArticles, refreshHot, loadStats, allTags, selectedTagIds, showAllTags, isMobile, showAdvanced, onDocumentMouseDown, localQuery, showPreview, previewPmid, setPreviewPmid, closePreview, saving, savedPmids, lastVisitStr, dividerIndex, fetchData, toggleTag, cancerTags, hasMoreTags, visibleTags, doLocalSearch, clearSearch, handleAdvancedSearch, saveLiterature, openPreview, goDetail, loadSavedPmids, loadingMore, hasMore, showScrollTop, onScroll, scrollToTop, onResize, loadMore, restoreFromUrl, searchKey, get NButton() {
return NButton;
}, get NEmpty() {
return NEmpty;
}, get NIcon() {
return NIcon;
}, get ChevronDownOutline() {
return ChevronDownOutline;
}, get ChevronUpOutline() {
return ChevronUpOutline;
}, get CloseCircleOutline() {
return CloseCircleOutline;
}, get OptionsOutline() {
return OptionsOutline;
}, get PersonAddOutline() {
return PersonAddOutline;
}, get RefreshOutline() {
return RefreshOutline;
}, get SearchOutline() {
return SearchOutline;
}, PageSkeleton };
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
return __returned__;
}
});
import { createElementVNode as _createElementVNode, createCommentVNode as _createCommentVNode, vModelText as _vModelText, withKeys as _withKeys, withDirectives as _withDirectives, createVNode as _createVNode, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, createTextVNode as _createTextVNode, resolveComponent as _resolveComponent, renderList as _renderList, Fragment as _Fragment, createElementBlock as _createElementBlock, toDisplayString as _toDisplayString, normalizeClass as _normalizeClass } from "/node_modules/.vite/deps/vue.js?v=3cfd8f60";
const _hoisted_1 = { class: "home" };
const _hoisted_2 = { class: "content-grid" };
const _hoisted_3 = { class: "content-grid-main" };
const _hoisted_4 = { class: "section section-toolbar" };
const _hoisted_5 = { class: "search-row" };
const _hoisted_6 = { class: "search-row-left" };
const _hoisted_7 = { class: "search-input-group" };
const _hoisted_8 = { class: "search-input-top" };
const _hoisted_9 = { class: "search-input-actions" };
const _hoisted_10 = {
key: 0,
class: "section"
};
const _hoisted_11 = { class: "tag-bar" };
const _hoisted_12 = ["onClick"];
const _hoisted_13 = {
key: 0,
class: "tag-x"
};
const _hoisted_14 = { class: "section section-list" };
const _hoisted_15 = {
key: 0,
class: "read-divider"
};
const _hoisted_16 = {
key: 0,
class: "load-more"
};
const _hoisted_17 = { class: "content-grid-side" };
const _hoisted_18 = {
key: 0,
class: "section-hot-side"
};
const _hoisted_19 = { class: "hot-header" };
const _hoisted_20 = { class: "hot-header-right" };
const _hoisted_21 = { class: "hot-page-dots" };
const _hoisted_22 = { class: "hot-list" };
const _hoisted_23 = ["href"];
const _hoisted_24 = { class: "hot-content" };
const _hoisted_25 = ["title"];
const _hoisted_26 = { class: "hot-meta" };
const _hoisted_27 = {
key: 1,
class: "sidebar-stats"
};
const _hoisted_28 = { class: "sidebar-stat-item" };
const _hoisted_29 = { class: "sidebar-stat-num" };
const _hoisted_30 = { class: "sidebar-stat-item" };
const _hoisted_31 = { class: "sidebar-stat-num" };
const _hoisted_32 = { class: "sidebar-stat-item" };
const _hoisted_33 = { class: "sidebar-stat-num" };
const _hoisted_34 = {
key: 0,
class: "section section-cta"
};
const _hoisted_35 = { class: "cta-banner" };
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_AdvancedSearchPanel = __unplugin_components_0;
const _component_LiteratureCard = __unplugin_components_1;
const _component_LiteraturePreviewDrawer = __unplugin_components_2;
return _openBlock(), _createElementBlock("div", _hoisted_1, [
_cache[18] || (_cache[18] = _createElementVNode(
"h1",
{ class: "visually-hidden" },
"OncoLit 肿瘤科研文献中心——每日更新的肿瘤学文献平台",
-1
/* CACHED */
)),
_createCommentVNode(" ====== 内容网格:左侧(搜索 + 标签 + 文献)+ 右侧(热榜) ====== "),
_createElementVNode("div", _hoisted_2, [
_createElementVNode("div", _hoisted_3, [
_createCommentVNode(" 搜索工具栏 "),
_createElementVNode("section", _hoisted_4, [
_createElementVNode("div", _hoisted_5, [
_createElementVNode("div", _hoisted_6, [
_createElementVNode("div", _hoisted_7, [
_createElementVNode("div", _hoisted_8, [
_withDirectives(_createElementVNode(
"input",
{
class: "search-input",
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $setup.localQuery = $event),
placeholder: "搜索标题、摘要、PMID、DOI...",
onKeyup: _withKeys($setup.doLocalSearch, ["enter"])
},
null,
544
/* NEED_HYDRATION, NEED_PATCH */
), [
[_vModelText, $setup.localQuery]
]),
$setup.localQuery ? (_openBlock(), _createBlock($setup["NButton"], {
key: 0,
text: "",
size: "tiny",
onClick: $setup.clearSearch,
class: "clear-search-btn",
title: "清除搜索"
}, {
icon: _withCtx(() => [
_createVNode($setup["NIcon"], { size: "16" }, {
default: _withCtx(() => [
_createVNode($setup["CloseCircleOutline"])
]),
_: 1
/* STABLE */
})
]),
_: 1
/* STABLE */
})) : _createCommentVNode("v-if", true)
]),
_createElementVNode("div", _hoisted_9, [
_createVNode($setup["NButton"], {
text: "",
size: "tiny",
onClick: _cache[1] || (_cache[1] = ($event) => $setup.showAdvanced = !$setup.showAdvanced),
title: $setup.showAdvanced ? "收起筛选" : "高级搜索",
class: "adv-icon-btn"
}, {
icon: _withCtx(() => [
_createVNode($setup["NIcon"], { size: "16" }, {
default: _withCtx(() => [
_createVNode($setup["OptionsOutline"])
]),
_: 1
/* STABLE */
})
]),
_: 1
/* STABLE */
}, 8, ["title"]),
_createVNode($setup["NButton"], {
size: "small",
type: "primary",
onClick: $setup.doLocalSearch,
class: "sky-btn search-submit-btn"
}, {
icon: _withCtx(() => [
_createVNode($setup["NIcon"], { size: "14" }, {
default: _withCtx(() => [
_createVNode($setup["SearchOutline"])
]),
_: 1
/* STABLE */
})
]),
default: _withCtx(() => [
_cache[5] || (_cache[5] = _createTextVNode(
"搜索 ",
-1
/* CACHED */
))
]),
_: 1
/* STABLE */
})
])
])
])
]),
_createVNode(_component_AdvancedSearchPanel, {
show: $setup.showAdvanced,
loading: $setup.loading,
onSearch: $setup.handleAdvancedSearch
}, null, 8, ["show", "loading"])
]),
_createCommentVNode(" 热门标签快速筛选 "),
$setup.cancerTags.length ? (_openBlock(), _createElementBlock("section", _hoisted_10, [
_createElementVNode("div", _hoisted_11, [
_cache[8] || (_cache[8] = _createElementVNode(
"span",
{ class: "tag-label" },
"热门",
-1
/* CACHED */
)),
(_openBlock(true), _createElementBlock(
_Fragment,
null,
_renderList($setup.visibleTags, (t) => {
return _openBlock(), _createElementBlock("span", {
key: t.id,
class: _normalizeClass(["tag-pill", { active: $setup.selectedTagIds.includes(String(t.id)) }]),
onClick: ($event) => $setup.toggleTag(t.id)
}, [
_createTextVNode(
_toDisplayString(t.name_zh),
1
/* TEXT */
),
$setup.selectedTagIds.includes(String(t.id)) ? (_openBlock(), _createElementBlock("span", _hoisted_13, "✕")) : _createCommentVNode("v-if", true)
], 10, _hoisted_12);
}),
128
/* KEYED_FRAGMENT */
)),
$setup.hasMoreTags && !$setup.showAllTags ? (_openBlock(), _createElementBlock("span", {
key: 0,
class: "tag-expand-btn",
onClick: _cache[2] || (_cache[2] = ($event) => $setup.showAllTags = true)
}, [
_cache[6] || (_cache[6] = _createTextVNode(
"更多 ",
-1
/* CACHED */
)),
_createVNode($setup["NIcon"], {
size: "13",
style: { "vertical-align": "-2px" }
}, {
default: _withCtx(() => [
_createVNode($setup["ChevronDownOutline"])
]),
_: 1
/* STABLE */
})
])) : _createCommentVNode("v-if", true),
$setup.showAllTags ? (_openBlock(), _createElementBlock("span", {
key: 1,
class: "tag-expand-btn",
onClick: _cache[3] || (_cache[3] = ($event) => $setup.showAllTags = false)
}, [
_cache[7] || (_cache[7] = _createTextVNode(
"收起 ",
-1
/* CACHED */
)),
_createVNode($setup["NIcon"], {
size: "13",
style: { "vertical-align": "-2px" }
}, {
default: _withCtx(() => [
_createVNode($setup["ChevronUpOutline"])
]),
_: 1
/* STABLE */
})
])) : _createCommentVNode("v-if", true)
])
])) : _createCommentVNode("v-if", true),
_createCommentVNode(" 文献列表 "),
_createElementVNode("section", _hoisted_14, [
_createVNode($setup["PageSkeleton"], {
loading: $setup.loading && !$setup.feedItems.length
}, {
default: _withCtx(() => [
!$setup.loading && !$setup.feedItems.length ? (_openBlock(), _createBlock($setup["NEmpty"], {
key: 0,
description: "暂无文献"
})) : _createCommentVNode("v-if", true),
$setup.feedItems.length ? (_openBlock(), _createElementBlock(
_Fragment,
{ key: 1 },
[
(_openBlock(true), _createElementBlock(
_Fragment,
null,
_renderList($setup.feedItems, (item, idx) => {
return _openBlock(), _createElementBlock(
_Fragment,
{
key: item.id || item.pmid
},
[
idx === $setup.dividerIndex ? (_openBlock(), _createElementBlock("div", _hoisted_15, [..._cache[9] || (_cache[9] = [
_createElementVNode(
"span",
{ class: "read-divider-line" },
null,
-1
/* CACHED */
),
_createElementVNode(
"span",
{ class: "read-divider-text" },
"—— 上次看到这里 ——",
-1
/* CACHED */
),
_createElementVNode(
"span",
{ class: "read-divider-line" },
null,
-1
/* CACHED */
)
])])) : _createCommentVNode("v-if", true),
_createVNode(_component_LiteratureCard, {
item,
showSave: $setup.auth.isAuthenticated,
savedPmids: $setup.savedPmids,
searchQuery: $setup.searchParams.query,
onDetail: $setup.goDetail,
onPreview: $setup.openPreview,
onSave: $setup.saveLiterature
}, null, 8, ["item", "showSave", "savedPmids", "searchQuery"])
],
64
/* STABLE_FRAGMENT */
);
}),
128
/* KEYED_FRAGMENT */
)),
$setup.hasMore ? (_openBlock(), _createElementBlock("div", _hoisted_16, [
_createVNode($setup["NButton"], {
class: "sky-btn",
loading: $setup.loadingMore,
onClick: $setup.loadMore,
size: "small"
}, {
icon: _withCtx(() => [
_createVNode($setup["NIcon"], { size: "14" }, {
default: _withCtx(() => [
_createVNode($setup["ChevronDownOutline"])
]),
_: 1
/* STABLE */
})
]),
default: _withCtx(() => [
_cache[10] || (_cache[10] = _createTextVNode(
"展示更多",
-1
/* CACHED */
))
]),
_: 1
/* STABLE */
}, 8, ["loading"])
])) : _createCommentVNode("v-if", true)
],
64
/* STABLE_FRAGMENT */
)) : _createCommentVNode("v-if", true)
]),
_: 1
/* STABLE */
}, 8, ["loading"])
])
]),
_createElementVNode("div", _hoisted_17, [
$setup.hotArticles.length ? (_openBlock(), _createElementBlock("section", _hoisted_18, [
_createElementVNode("div", _hoisted_19, [
_cache[12] || (_cache[12] = _createElementVNode(
"span",
null,
"🔥 热搜",
-1
/* CACHED */
)),
_createElementVNode("div", _hoisted_20, [
_createElementVNode("span", _hoisted_21, [
(_openBlock(true), _createElementBlock(
_Fragment,
null,
_renderList($setup.hotAvailablePages, (p) => {
return _openBlock(), _createElementBlock(
"span",
{
key: p,
class: _normalizeClass(["hot-page-dot", { active: $setup.hotPage === p }])
},
null,
2
/* CLASS */
);
}),
128
/* KEYED_FRAGMENT */
))
]),
_createVNode($setup["NButton"], {
text: "",
size: "tiny",
style: { "font-size": "12px", "color": "var(--text-muted)" },
onClick: $setup.refreshHot
}, {
icon: _withCtx(() => [
_createVNode($setup["NIcon"], { size: "12" }, {
default: _withCtx(() => [
_createVNode($setup["RefreshOutline"])
]),
_: 1
/* STABLE */
})
]),
default: _withCtx(() => [
_cache[11] || (_cache[11] = _createTextVNode(
"换一批 ",
-1
/* CACHED */
))
]),
_: 1
/* STABLE */
})
])
]),
_createElementVNode("div", _hoisted_22, [
(_openBlock(true), _createElementBlock(
_Fragment,
null,
_renderList($setup.hotArticles, (art, i) => {
return _openBlock(), _createElementBlock("a", {
key: art.id,
class: "hot-item",
href: `/literature/${art.pmid}`
}, [
_createElementVNode(
"span",
{
class: _normalizeClass(["hot-rank", { "hot-rank-top": ($setup.hotPage - 1) * $setup.hotPageSize + i + 1 <= 3 }])
},
_toDisplayString(($setup.hotPage - 1) * $setup.hotPageSize + i + 1),
3
/* TEXT, CLASS */
),
_createElementVNode("div", _hoisted_24, [
_createElementVNode("span", {
class: "hot-title",
title: art.title
}, _toDisplayString(art.title), 9, _hoisted_25),
_createElementVNode(
"span",
_hoisted_26,
_toDisplayString(art.journal) + " · " + _toDisplayString(art.cited_by_count ?? 0) + " 被引",
1
/* TEXT */
)
])
], 8, _hoisted_23);
}),
128
/* KEYED_FRAGMENT */
))
])
])) : _createCommentVNode("v-if", true),
!$setup.statsLoading && $setup.platformStats.literature_total > 0 ? (_openBlock(), _createElementBlock("div", _hoisted_27, [
_createElementVNode("div", _hoisted_28, [
_createElementVNode(
"span",
_hoisted_29,
_toDisplayString($setup.platformStats.literature_total.toLocaleString()),
1
/* TEXT */
),
_cache[13] || (_cache[13] = _createElementVNode(
"span",
{ class: "sidebar-stat-label" },
"文献总量",
-1
/* CACHED */
))
]),
_createElementVNode("div", _hoisted_30, [
_createElementVNode(
"span",
_hoisted_31,
_toDisplayString($setup.platformStats.journal_total),
1
/* TEXT */
),
_cache[14] || (_cache[14] = _createElementVNode(
"span",
{ class: "sidebar-stat-label" },
"收录期刊",
-1
/* CACHED */
))
]),
_createElementVNode("div", _hoisted_32, [
_createElementVNode(
"span",
_hoisted_33,
_toDisplayString($setup.platformStats.daily_avg_30d.toFixed(1)),
1
/* TEXT */
),
_cache[15] || (_cache[15] = _createElementVNode(
"span",
{ class: "sidebar-stat-label" },
"日均新增",
-1
/* CACHED */
))
])
])) : _createCommentVNode("v-if", true)
])
]),
_createCommentVNode(" ====== 注册引导 CTA(未登录) ====== "),
!$setup.auth.isAuthenticated && $setup.feedItems.length > 3 ? (_openBlock(), _createElementBlock("section", _hoisted_34, [
_createElementVNode("div", _hoisted_35, [
_cache[17] || (_cache[17] = _createElementVNode(
"div",
{ class: "cta-text" },
[
_createElementVNode("div", { class: "cta-title" }, "🔒 注册后获得完整功能"),
_createElementVNode("div", { class: "cta-desc" }, "收藏文献 · 设置关注领域 · 每日精准推送 · 团队共享")
],
-1
/* CACHED */
)),
_createVNode($setup["NButton"], {
class: "sky-btn",
type: "primary",
size: "large",
onClick: _cache[4] || (_cache[4] = ($event) => $setup.router.push("/auth/register"))
}, {
icon: _withCtx(() => [
_createVNode($setup["NIcon"], { size: "14" }, {
default: _withCtx(() => [
_createVNode($setup["PersonAddOutline"])
]),
_: 1
/* STABLE */
})
]),
default: _withCtx(() => [
_cache[16] || (_cache[16] = _createTextVNode(
"免费注册",
-1
/* CACHED */
))
]),
_: 1
/* STABLE */
})
])
])) : _createCommentVNode("v-if", true),
_createCommentVNode(" ====== 文献预览抽屉 ====== "),
_createVNode(_component_LiteraturePreviewDrawer, {
show: $setup.showPreview,
pmid: $setup.previewPmid,
onClose: $setup.closePreview,
onGoDetail: $setup.goDetail
}, null, 8, ["show", "pmid", "onClose"]),
_createCommentVNode(" 回到顶部 "),
$setup.showScrollTop ? (_openBlock(), _createElementBlock("button", {
key: 1,
class: "scroll-top",
onClick: $setup.scrollToTop
}, "↑")) : _createCommentVNode("v-if", true)
]);
}
import "/src/views/public/HomeView.vue?v=1&vue&type=style&index=0&scoped=790ec39d&lang.css";
_sfc_main.__hmrId = "790ec39d";
typeof __VUE_HMR_RUNTIME__ !== "undefined" && __VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main);
import.meta.hot.on("file-changed", ({ file }) => {
__VUE_HMR_RUNTIME__.CHANGED_FILE = file;
});
import.meta.hot.accept((mod) => {
if (!mod) return;
const { default: updated, _rerender_only } = mod;
if (_rerender_only) {
__VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render);
} else {
__VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated);
}
});
import _export_sfc from "/@id/__x00__plugin-vue:export-helper";
export default /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-790ec39d"], ["__file", "D:/ClaudeCode/frontend/src/views/public/HomeView.vue"]]);
//# sourceMappingURL=data:application/json;base64,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