2025-09-16 16:15:57 +08:00

124 lines
4.1 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import Link from 'next/link';
import { ArticleClient } from './ArticleClient';
interface ArticleData {
content: string;
meta: {
title: string;
description: string;
author: string;
date: string;
readTime: number;
category: string;
};
}
export async function generateStaticParams() {
// 只基于 content 目录中实际存在的文章生成参数
const contentDir = path.join(process.cwd(), 'content');
const slugs: string[] = [];
try {
if (fs.existsSync(contentDir)) {
const folders = fs
.readdirSync(contentDir, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name);
slugs.push(...folders);
}
} catch (error) {
console.warn('generateStaticParams: unable to read content dir', error);
}
return slugs.map(slug => ({ slug }));
}
async function getArticleData(slug: string): Promise<ArticleData | null> {
try {
const contentDir = path.join(process.cwd(), 'content');
const articleDir = path.join(contentDir, slug);
if (!fs.existsSync(articleDir)) {
return null;
}
// 优先读取中文内容
let contentFile = '';
let lang = 'zh';
if (fs.existsSync(path.join(articleDir, 'zh.md'))) {
contentFile = 'zh.md';
lang = 'zh';
} else if (fs.existsSync(path.join(articleDir, 'en.md'))) {
contentFile = 'en.md';
lang = 'en';
} else if (fs.existsSync(path.join(articleDir, 'zh-tw.md'))) {
contentFile = 'zh-tw.md';
lang = 'zh-tw';
}
if (!contentFile) {
return null;
}
const filePath = path.join(articleDir, contentFile);
const content = fs.readFileSync(filePath, 'utf-8');
// 从内容中提取元数据
const titleMatch = content.match(/^#\s+(.+)$/m);
const title = titleMatch ? titleMatch[1] : slug;
// 提取摘要(第一段非标题内容)
const lines = content.split('\n').filter((line: string) =>
line.trim() && !line.startsWith('#') && !line.startsWith('---')
);
const excerpt = lines[0] || title;
// 根据文件夹名称推断分类
let category = 'tech';
if (slug.includes('ecs') || slug.includes('rds') || slug.includes('oss')) {
category = 'product';
} else if (slug.includes('deployment') || slug.includes('guide') || slug.includes('tutorial')) {
category = 'tutorial';
} else if (slug.includes('market') || slug.includes('trend')) {
category = 'industry';
}
return {
content,
meta: {
title,
description: excerpt.length > 200 ? excerpt.substring(0, 200) + '...' : excerpt,
author: 'CloudPro 技术团队',
date: new Date().toISOString().split('T')[0],
readTime: Math.ceil(content.split('\n').length / 20),
category,
}
};
} catch (error) {
console.error('Error reading article:', error);
return null;
}
}
export default async function Page({ params }: { params: { slug: string } }) {
const articleData = await getArticleData(params.slug);
if (!articleData) {
return (
<div className="min-h-screen bg-gradient-to-br from-amber-50 to-yellow-50 flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold text-amber-900 mb-4"></h1>
<Link href="/news" className="text-amber-600 hover:text-amber-700">
</Link>
</div>
</div>
);
}
return <ArticleClient slug={params.slug} initialData={articleData} />;
}