{ARTICLE_EXPIRY_CONFIG.warningMessage}
--- import { getCollection, render } from "astro:content"; import { getSpecialPath } from "@/content.config"; import Layout from "@/components/Layout.astro"; import Breadcrumb from "@/components/Breadcrumb.astro"; import { ARTICLE_EXPIRY_CONFIG } from "@/consts"; import "@/styles/articles.css"; // 定义文章类型 interface ArticleEntry { id: string; data: { title: string; date: Date; tags?: string[]; summary?: string; }; } // 定义标题类型 interface Heading { depth: number; slug: string; text: string; } export async function getStaticPaths() { const articles = await getCollection("articles"); // 为每篇文章生成路由参数 const paths = []; for (const article of articles) { // 获取所有可能的路径形式 const possiblePaths = new Set([ article.id, // 只保留原始路径 ]); // 如果是多级目录,检查是否需要特殊处理 if (article.id.includes("/")) { const parts = article.id.split("/"); const fileName = parts[parts.length - 1]; const dirName = parts[parts.length - 2]; // 只有当文件名与其父目录名相同时才添加特殊路径 if (fileName === dirName) { possiblePaths.add(getSpecialPath(article.id)); } } // 为每个可能的路径生成路由 for (const path of possiblePaths) { paths.push({ params: { id: path }, props: { article, section: article.id.includes("/") ? article.id.split("/").slice(0, -1).join("/") : "", originalId: path !== article.id ? article.id : undefined, }, }); } } return paths; } // 获取文章内容 const { article, section, originalId } = Astro.props; // 获取搜索参数 const searchParams = new URLSearchParams(Astro.url.search); // 如果有原始ID,使用它来渲染内容 const articleToRender = originalId ? { ...article, id: originalId } : article; // 渲染文章内容 const { Content, headings } = await render(articleToRender); // 获取面包屑路径段 const pathSegments = section ? section.split("/") : []; // 获取相关文章 const allArticles = await getCollection("articles"); // 1. 尝试通过标签匹配相关文章 let relatedArticles = allArticles .filter((a: ArticleEntry) => { const hasCommonTags = a.id !== article.id && a.data.tags && article.data.tags && a.data.tags.length > 0 && article.data.tags.length > 0 && a.data.tags.some((tag: string) => article.data.tags?.includes(tag)); return hasCommonTags; }) .sort( (a: ArticleEntry, b: ArticleEntry) => b.data.date.getTime() - a.data.date.getTime(), ) .slice(0, 3); // 跟踪相关文章的匹配方式: "tag", "directory", "latest" let relatedArticlesMatchType = relatedArticles.length > 0 ? "tag" : ""; // 2. 如果标签匹配没有找到足够的相关文章,尝试根据目录结构匹配 if (relatedArticles.length < 3) { // 获取当前文章的目录路径 const currentPath = article.id.includes("/") ? article.id.substring(0, article.id.lastIndexOf("/")) : ""; // 如果有目录路径,查找同目录的其他文章 if (currentPath) { // 收集同目录下的文章,但排除已经通过标签匹配的和当前文章 const dirRelatedArticles = allArticles .filter( (a: ArticleEntry) => a.id !== article.id && a.id.startsWith(currentPath + "/") && !relatedArticles.some((r: ArticleEntry) => r.id === a.id), ) .sort( (a: ArticleEntry, b: ArticleEntry) => b.data.date.getTime() - a.data.date.getTime(), ) .slice(0, 3 - relatedArticles.length); if (dirRelatedArticles.length > 0) { relatedArticles = [...relatedArticles, ...dirRelatedArticles]; relatedArticlesMatchType = relatedArticles.length > 0 && !relatedArticlesMatchType ? "directory" : relatedArticlesMatchType; } } } // 3. 如果仍然没有找到足够的相关文章,则选择最新的文章(排除当前文章和已选择的文章) if (relatedArticles.length < 3) { const latestArticles = allArticles .filter( (a: ArticleEntry) => a.id !== article.id && !relatedArticles.some((r: ArticleEntry) => r.id === a.id), ) .sort( (a: ArticleEntry, b: ArticleEntry) => b.data.date.getTime() - a.data.date.getTime(), ) .slice(0, 3 - relatedArticles.length); if (latestArticles.length > 0) { relatedArticles = [...relatedArticles, ...latestArticles]; relatedArticlesMatchType = relatedArticles.length > 0 && !relatedArticlesMatchType ? "latest" : relatedArticlesMatchType; } } // 准备文章描述 const description = article.data.summary || `${article.data.title} - 发布于 ${article.data.date.toLocaleDateString("zh-CN")}`; // 处理特殊ID的函数 function getArticleUrl(articleId: string) { return `/articles/${getSpecialPath(articleId)}${searchParams.toString() ? `?${searchParams.toString()}` : ""}`; } // 预先生成目录结构 function generateTableOfContents(headings: Heading[]) { if (!headings || headings.length === 0) { return '
此文章没有目录
'; } // 查找最低级别的标题(数值最小) const minDepth = Math.min(...headings.map((h) => h.depth)); // 按照标题层级构建嵌套结构 const tocTree: any[] = []; const levelMap: Record{ARTICLE_EXPIRY_CONFIG.warningMessage}