feat: 重构导航和博客系统,支持多级菜单和API数据源

- 重构导航菜单支持多级子菜单结构
- 博客系统改为从API获取数据,移除本地文件存储
- 删除旧的关于页面,准备重构
- 修复博客详情页slug匹配问题
- 默认首页重定向到中文版本
This commit is contained in:
砂糖
2025-11-21 17:49:17 +08:00
parent 0a420f2dbb
commit 216076ff2a
13 changed files with 178 additions and 222 deletions

View File

@@ -1,66 +1,92 @@
import { DEFAULT_LOCALE } from '@/i18n/routing';
import { BlogPost } from '@/types/blog';
import fs from 'fs';
import matter from 'gray-matter';
import path from 'path';
const POSTS_BATCH_SIZE = 10;
export async function getPosts(locale: string = DEFAULT_LOCALE): Promise<{ posts: BlogPost[] }> {
const postsDirectory = path.join(process.cwd(), 'blogs', locale);
// is directory exist
if (!fs.existsSync(postsDirectory)) {
return { posts: [] };
export async function getPosts(locale: string = DEFAULT_LOCALE, category?: string): Promise<{ posts: BlogPost[], total: number }> {
const Id_Map: Record<string, string> = {
'announce': '1989174108560080897',
'news': '1988814504336605185',
'event': '1989174018231549954',
}
let filenames = await fs.promises.readdir(postsDirectory);
filenames = filenames.reverse();
let url = 'http://49.232.154.205:18081/export/article/list?pageNum=1&pageSize=10&langCode=' + locale;
if (category) {
url += '&categoryId=' + Id_Map[category || 'announce']
}
let allPosts: BlogPost[] = [];
console.log(url);
const response = await fetch(url);
const data = await response.json();
const posts = data.rows.map((item: any) => {
return {
locale, // use locale parameter
title: item.title,
description: item.summary,
image: item.cover || '',
slug: item.articleId,
tags: '',
date: item.publishedTime,
// visible: data.visible || 'published',
pin: false,
content: item.content,
metadata: data,
}
}) || [];
// // is directory exist
// if (!fs.existsSync(postsDirectory)) {
// return { posts: [] };
// }
// let filenames = await fs.promises.readdir(postsDirectory);
// filenames = filenames.reverse();
// let allPosts: BlogPost[] = [];
// read file by batch
for (let i = 0; i < filenames.length; i += POSTS_BATCH_SIZE) {
const batchFilenames = filenames.slice(i, i + POSTS_BATCH_SIZE);
// for (let i = 0; i < filenames.length; i += POSTS_BATCH_SIZE) {
// const batchFilenames = filenames.slice(i, i + POSTS_BATCH_SIZE);
const batchPosts: BlogPost[] = await Promise.all(
batchFilenames.map(async (filename) => {
const fullPath = path.join(postsDirectory, filename);
const fileContents = await fs.promises.readFile(fullPath, 'utf8');
// const batchPosts: BlogPost[] = await Promise.all(
// batchFilenames.map(async (filename) => {
// const fullPath = path.join(postsDirectory, filename);
// const fileContents = await fs.promises.readFile(fullPath, 'utf8');
const { data, content } = matter(fileContents);
// const { data, content } = matter(fileContents);
return {
locale, // use locale parameter
title: data.title,
description: data.description,
image: data.image || '',
slug: data.slug,
tags: data.tags,
date: data.date,
visible: data.visible || 'published',
pin: data.pin || false,
content,
metadata: data,
};
})
);
// return {
// locale, // use locale parameter
// title: data.title,
// description: data.description,
// image: data.image || '',
// slug: data.slug,
// tags: data.tags,
// date: data.date,
// visible: data.visible || 'published',
// pin: data.pin || false,
// content,
// metadata: data,
// };
// })
// );
allPosts.push(...batchPosts);
}
// allPosts.push(...batchPosts);
// }
// filter out non-published articles
allPosts = allPosts.filter(post => post.visible === 'published');
// allPosts = allPosts.filter(post => post.visible === 'published');
// sort posts by pin and date
allPosts = allPosts.sort((a, b) => {
if (a.pin !== b.pin) {
return (b.pin ? 1 : 0) - (a.pin ? 1 : 0);
}
return new Date(b.date).getTime() - new Date(a.date).getTime();
});
// allPosts = allPosts.sort((a, b) => {
// if (a.pin !== b.pin) {
// return (b.pin ? 1 : 0) - (a.pin ? 1 : 0);
// }
// return new Date(b.date).getTime() - new Date(a.date).getTime();
// });
return {
posts: allPosts,
posts,
total: data.total,
};
}