feat: 重构导航和博客系统,支持多级菜单和API数据源
- 重构导航菜单支持多级子菜单结构 - 博客系统改为从API获取数据,移除本地文件存储 - 删除旧的关于页面,准备重构 - 修复博客详情页slug匹配问题 - 默认首页重定向到中文版本
This commit is contained in:
@@ -1,5 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="container mx-auto px-4 py-12">基础介绍</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="container mx-auto px-4 py-12">发展历程</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="container mx-auto px-4 py-12">企业文化</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="container mx-auto px-4 py-12">绿色发展</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="container mx-auto px-4 py-12">荣誉资质</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="container mx-auto px-4 py-12">公司介绍</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -22,8 +22,9 @@ export async function generateMetadata({
|
|||||||
}: MetadataProps): Promise<Metadata> {
|
}: MetadataProps): Promise<Metadata> {
|
||||||
const { locale, slug } = await params;
|
const { locale, slug } = await params;
|
||||||
let { posts }: { posts: BlogPost[] } = await getPosts(locale);
|
let { posts }: { posts: BlogPost[] } = await getPosts(locale);
|
||||||
const post = posts.find((post) => post.slug === "/" + slug);
|
const post = posts.find((post) => post.slug === slug);
|
||||||
|
|
||||||
|
console.log(post, posts);
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return constructMetadata({
|
return constructMetadata({
|
||||||
title: "404",
|
title: "404",
|
||||||
@@ -50,7 +51,7 @@ export default async function BlogPage({ params }: { params: Params }) {
|
|||||||
const { locale, slug } = await params;
|
const { locale, slug } = await params;
|
||||||
let { posts }: { posts: BlogPost[] } = await getPosts(locale);
|
let { posts }: { posts: BlogPost[] } = await getPosts(locale);
|
||||||
|
|
||||||
const post = posts.find((item) => item.slug === "/" + slug);
|
const post = posts.find((item) => item.slug === slug);
|
||||||
|
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return notFound();
|
return notFound();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { getTranslations } from "next-intl/server";
|
|||||||
|
|
||||||
type Params = Promise<{ locale: string }>;
|
type Params = Promise<{ locale: string }>;
|
||||||
|
|
||||||
type SearchParams = { page?: string; type?: string };
|
type SearchParams = { page?: string; category?: string };
|
||||||
|
|
||||||
type MetadataProps = {
|
type MetadataProps = {
|
||||||
params: Params;
|
params: Params;
|
||||||
@@ -36,34 +36,18 @@ export default async function Page({
|
|||||||
searchParams,
|
searchParams,
|
||||||
}: {
|
}: {
|
||||||
params: Params;
|
params: Params;
|
||||||
searchParams?: SearchParams;
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
}) {
|
}) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
let { posts } = await getPosts(locale);
|
const resolvedSearchParams = await searchParams;
|
||||||
|
const category = resolvedSearchParams.category as string || "";
|
||||||
|
|
||||||
|
let { posts } = await getPosts(locale, category);
|
||||||
|
|
||||||
const t = await getTranslations("Blog");
|
const t = await getTranslations("Blog");
|
||||||
|
|
||||||
// 分类筛选(公司新闻/专家访谈/行业动态/公告)
|
const pageRaw = resolvedSearchParams.page as string || "1";
|
||||||
const type = (searchParams?.type || "").toLowerCase();
|
const page = Math.max(1, parseInt(pageRaw, 10));
|
||||||
const typeLabelMap: Record<string, string> = {
|
|
||||||
company: "公司新闻",
|
|
||||||
experts: "专家访谈",
|
|
||||||
industry: "行业动态",
|
|
||||||
notice: "公告",
|
|
||||||
};
|
|
||||||
const typeLabel = typeLabelMap[type];
|
|
||||||
if (type) {
|
|
||||||
posts = posts.filter((p) => {
|
|
||||||
const metaType = String((p.metadata as any)?.type || "").toLowerCase();
|
|
||||||
const tags: string[] = (p.tags as any) || [];
|
|
||||||
const hitMeta = metaType === type;
|
|
||||||
const hitTag = Array.isArray(tags) && tags.some((t) => String(t).toLowerCase() === type);
|
|
||||||
return hitMeta || hitTag;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const pageRaw = searchParams?.page;
|
|
||||||
const page = Math.max(1, parseInt(pageRaw || "1", 10));
|
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const totalPages = Math.max(1, Math.ceil(posts.length / pageSize));
|
const totalPages = Math.max(1, Math.ceil(posts.length / pageSize));
|
||||||
const start = (page - 1) * pageSize;
|
const start = (page - 1) * pageSize;
|
||||||
@@ -77,14 +61,14 @@ export default async function Page({
|
|||||||
{/* 顶部操作区:标签 + 面包屑 */}
|
{/* 顶部操作区:标签 + 面包屑 */}
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mt-4">
|
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mt-4">
|
||||||
<div className="flex gap-3">
|
{/* <div className="flex gap-3">
|
||||||
<button className="px-4 py-2 rounded-md border bg-white text-gray-700 shadow-sm hover:bg-gray-50">
|
<button className="px-4 py-2 rounded-md border bg-white text-gray-700 shadow-sm hover:bg-gray-50">
|
||||||
投资者保护
|
投资者保护
|
||||||
</button>
|
</button>
|
||||||
<button className="px-4 py-2 rounded-md border bg-white text-gray-700 shadow-sm hover:bg-gray-50">
|
<button className="px-4 py-2 rounded-md border bg-white text-gray-700 shadow-sm hover:bg-gray-50">
|
||||||
公司公告
|
公司公告
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div> */}
|
||||||
<div className="flex items-center gap-2 text-sm text-gray-500">
|
<div className="flex items-center gap-2 text-sm text-gray-500">
|
||||||
<I18nLink href="/" prefetch={false} className="hover:underline">
|
<I18nLink href="/" prefetch={false} className="hover:underline">
|
||||||
首页
|
首页
|
||||||
@@ -93,12 +77,12 @@ export default async function Page({
|
|||||||
<I18nLink href="/blog" prefetch={false} className="hover:underline">
|
<I18nLink href="/blog" prefetch={false} className="hover:underline">
|
||||||
新闻中心
|
新闻中心
|
||||||
</I18nLink>
|
</I18nLink>
|
||||||
{typeLabel && (
|
{/* {typeLabel && (
|
||||||
<>
|
<>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span className="text-gray-700">{typeLabel}</span>
|
<span className="text-gray-700">{typeLabel}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -111,7 +95,7 @@ export default async function Page({
|
|||||||
return (
|
return (
|
||||||
<I18nLink
|
<I18nLink
|
||||||
key={post.slug}
|
key={post.slug}
|
||||||
href={`/blog${post.slug}`}
|
href={`/blog/${post.slug}`}
|
||||||
prefetch={false}
|
prefetch={false}
|
||||||
className="block rounded-md mb-4 bg-gray-100 px-6 py-5 transition-all duration-200 shadow hover:bg-gray-200 hover:translate-y-[1px] hover:shadow-inner active:translate-y-[2px] active:shadow-inner focus:outline-none focus:ring-1 focus:ring-gray-300"
|
className="block rounded-md mb-4 bg-gray-100 px-6 py-5 transition-all duration-200 shadow hover:bg-gray-200 hover:translate-y-[1px] hover:shadow-inner active:translate-y-[2px] active:shadow-inner focus:outline-none focus:ring-1 focus:ring-gray-300"
|
||||||
>
|
>
|
||||||
@@ -139,9 +123,8 @@ export default async function Page({
|
|||||||
<I18nLink
|
<I18nLink
|
||||||
href={`/blog?page=${Math.max(1, page - 1)}`}
|
href={`/blog?page=${Math.max(1, page - 1)}`}
|
||||||
prefetch={false}
|
prefetch={false}
|
||||||
className={`px-2.5 py-1 border rounded-sm text-sm ${
|
className={`px-2.5 py-1 border rounded-sm text-sm ${page === 1 ? "bg-gray-100 text-gray-400" : "bg-white hover:bg-gray-50"
|
||||||
page === 1 ? "bg-gray-100 text-gray-400" : "bg-white hover:bg-gray-50"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{"<"}
|
{"<"}
|
||||||
</I18nLink>
|
</I18nLink>
|
||||||
@@ -167,11 +150,10 @@ export default async function Page({
|
|||||||
key={it}
|
key={it}
|
||||||
href={`/blog?page=${it}`}
|
href={`/blog?page=${it}`}
|
||||||
prefetch={false}
|
prefetch={false}
|
||||||
className={`px-2.5 py-1 border rounded-sm text-sm ${
|
className={`px-2.5 py-1 border rounded-sm text-sm ${isActive
|
||||||
isActive
|
? "bg-red-600 text-white border-red-600"
|
||||||
? "bg-red-600 text-white border-red-600"
|
: "bg-white hover:bg-gray-50"
|
||||||
: "bg-white hover:bg-gray-50"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{it}
|
{it}
|
||||||
</I18nLink>
|
</I18nLink>
|
||||||
@@ -181,9 +163,8 @@ export default async function Page({
|
|||||||
<I18nLink
|
<I18nLink
|
||||||
href={`/blog?page=${Math.min(totalPages, page + 1)}`}
|
href={`/blog?page=${Math.min(totalPages, page + 1)}`}
|
||||||
prefetch={false}
|
prefetch={false}
|
||||||
className={`px-2.5 py-1 border rounded-sm text-sm ${
|
className={`px-2.5 py-1 border rounded-sm text-sm ${page === totalPages ? "bg-gray-100 text-gray-400" : "bg-white hover:bg-gray-50"
|
||||||
page === totalPages ? "bg-gray-100 text-gray-400" : "bg-white hover:bg-gray-50"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{">"}
|
{">"}
|
||||||
</I18nLink>
|
</I18nLink>
|
||||||
|
|||||||
6
app/page.tsx
Normal file
6
app/page.tsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// 默认跳转到中文版本
|
||||||
|
import { redirect } from 'next/navigation';
|
||||||
|
|
||||||
|
export default function HomePage() {
|
||||||
|
redirect('/zh');
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
import { Link as I18nLink, usePathname, useRouter } from "@/i18n/routing";
|
import { Link as I18nLink, usePathname, useRouter } from "@/i18n/routing";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { HeaderLink } from "@/types/common";
|
import { HeaderLink } from "@/types/common";
|
||||||
import { ExternalLink } from "lucide-react";
|
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const HeaderLinks = () => {
|
const HeaderLinks = () => {
|
||||||
@@ -17,102 +16,34 @@ const HeaderLinks = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="hidden md:flex flex-row items-center gap-x-2 text-sm font-medium text-muted-500">
|
<div className="hidden md:flex flex-row items-center gap-x-2 text-sm font-medium text-muted-500">
|
||||||
{headerLinks.map((link) => {
|
{headerLinks.map((link) => {
|
||||||
const isAbout = link.href === "/about";
|
|
||||||
const isNews = link.href === "/blog";
|
|
||||||
if (isAbout) {
|
|
||||||
return (
|
|
||||||
<div key={link.name} className="relative group">
|
|
||||||
<I18nLink
|
|
||||||
href={link.href}
|
|
||||||
title={link.name}
|
|
||||||
prefetch={true}
|
|
||||||
className={cn(
|
|
||||||
"rounded-xl px-4 py-2 flex items-center gap-x-1 hover:bg-accent-foreground/10 hover:text-accent-foreground",
|
|
||||||
pathname === link.href && "font-semibold text-accent-foreground"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{link.name}
|
|
||||||
</I18nLink>
|
|
||||||
{/* 移除触发器与菜单间的间隙,使用 pt-2 保持视觉间距但不中断 hover 区域 */}
|
|
||||||
<div className="absolute left-0 top-full hidden group-hover:block z-50 pt-2">
|
|
||||||
<div className="w-56 rounded-md border bg-white shadow-md overflow-hidden">
|
|
||||||
<I18nLink prefetch={false} href="/about/arch#arch-vision" className="block px-4 py-2 hover:bg-red-600 hover:text-white">友发愿景</I18nLink>
|
|
||||||
<I18nLink prefetch={false} href="/about/arch#arch-products" className="block px-4 py-2 hover:bg-red-600 hover:text-white">产品体系</I18nLink>
|
|
||||||
<I18nLink prefetch={false} href="/about/arch#arch-application" className="block px-4 py-2 hover:bg-red-600 hover:text-white">应用场景</I18nLink>
|
|
||||||
<I18nLink prefetch={false} href="/about/arch#arch-contact" className="block px-4 py-2 hover:bg-red-600 hover:text-white">联系方式</I18nLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (isNews) {
|
|
||||||
return (
|
|
||||||
<div key={link.name} className="relative group">
|
|
||||||
<I18nLink
|
|
||||||
href={link.href}
|
|
||||||
title={link.name}
|
|
||||||
prefetch={true}
|
|
||||||
className={cn(
|
|
||||||
"rounded-xl px-4 py-2 flex items-center gap-x-1 hover:bg-accent-foreground/10 hover:text-accent-foreground",
|
|
||||||
pathname === link.href && "font-semibold text-accent-foreground"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{link.name}
|
|
||||||
</I18nLink>
|
|
||||||
<div className="absolute left-0 top-full hidden group-hover:block z-50 pt-2">
|
|
||||||
<div className="w-44 rounded-md border bg-white shadow-md overflow-hidden">
|
|
||||||
{[
|
|
||||||
{ key: "company", label: "公司新闻" },
|
|
||||||
{ key: "experts", label: "专家访谈" },
|
|
||||||
{ key: "industry", label: "行业动态" },
|
|
||||||
{ key: "notice", label: "公告" },
|
|
||||||
].map((it) => (
|
|
||||||
<button
|
|
||||||
key={it.key}
|
|
||||||
className="block w-full text-left px-4 py-2 hover:bg-red-600 hover:text-white"
|
|
||||||
onMouseDown={(e) => {
|
|
||||||
const url = `${localePrefix}/blog?type=${it.key}`;
|
|
||||||
try { router.push(url as any); } catch {}
|
|
||||||
// 兜底,确保跳转
|
|
||||||
setTimeout(() => { if (typeof window !== 'undefined') window.location.href = url; }, 0);
|
|
||||||
}}
|
|
||||||
onClick={(e) => {
|
|
||||||
const url = `${localePrefix}/blog?type=${it.key}`;
|
|
||||||
try { router.push(url as any); } catch {}
|
|
||||||
}}
|
|
||||||
onTouchStart={() => {
|
|
||||||
const url = `${localePrefix}/blog?type=${it.key}`;
|
|
||||||
try { router.push(url as any); } catch {}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{it.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<I18nLink
|
<div key={link.name} className="relative group">
|
||||||
key={link.name}
|
<I18nLink
|
||||||
href={link.href}
|
href={link.href}
|
||||||
title={link.name}
|
title={link.name}
|
||||||
prefetch={link.target && link.target === "_blank" ? false : true}
|
prefetch={true}
|
||||||
target={link.target || "_self"}
|
className={cn(
|
||||||
rel={link.rel || undefined}
|
"rounded-xl px-4 py-2 flex items-center gap-x-1 hover:bg-accent-foreground/10 hover:text-accent-foreground",
|
||||||
className={cn(
|
pathname === link.href && "font-semibold text-accent-foreground"
|
||||||
"rounded-xl px-4 py-2 flex items-center gap-x-1 hover:bg-accent-foreground/10 hover:text-accent-foreground",
|
)}
|
||||||
pathname === link.href && "font-semibold text-accent-foreground"
|
>
|
||||||
)}
|
{link.name}
|
||||||
>
|
</I18nLink>
|
||||||
{link.name}
|
{
|
||||||
{link.target && link.target === "_blank" && (
|
link?.children && (
|
||||||
<span className="text-xs">
|
<div className="absolute left-0 top-full hidden group-hover:block z-50 pt-2">
|
||||||
<ExternalLink className="w-4 h-4" />
|
<div className="w-56 rounded-md border bg-white shadow-md overflow-hidden">
|
||||||
</span>
|
{link.children.map((child) => (
|
||||||
)}
|
<I18nLink key={child.name} prefetch={false} href={child.href} className="block px-4 py-2 hover:bg-red-600 hover:text-white">
|
||||||
</I18nLink>
|
{child.name}
|
||||||
|
</I18nLink>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,33 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "走进福安德",
|
"name": "走进福安德",
|
||||||
"href": "/about"
|
"href": "/about",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "公司简介",
|
||||||
|
"href": "/about?section=company"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "企业文化",
|
||||||
|
"href": "/about?section=culture"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "生产基地",
|
||||||
|
"href": "/about?section=base"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "组织架构",
|
||||||
|
"href": "/about?section=organization"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "荣誉资质",
|
||||||
|
"href": "/about?section=awards"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "发展历程",
|
||||||
|
"href": "/about?section=history"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "产品中心",
|
"name": "产品中心",
|
||||||
@@ -21,7 +47,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "新闻中心",
|
"name": "新闻中心",
|
||||||
"href": "/blog"
|
"href": "/blog",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "公告",
|
||||||
|
"href": "/blog?category=announce"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "新闻",
|
||||||
|
"href": "/blog?category=news"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "活动",
|
||||||
|
"href": "/blog?category=event"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -35,32 +75,32 @@
|
|||||||
"title": "关于我们",
|
"title": "关于我们",
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"href": "/about?section=company",
|
"href": "/zh/about?section=company",
|
||||||
"name": "公司简介",
|
"name": "公司简介",
|
||||||
"useA": true
|
"useA": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"href": "/about?section=culture",
|
"href": "/zh/about?section=culture",
|
||||||
"name": "企业文化",
|
"name": "企业文化",
|
||||||
"useA": true
|
"useA": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"href": "/about?section=base",
|
"href": "/zh/about?section=base",
|
||||||
"name": "生产基地",
|
"name": "生产基地",
|
||||||
"useA": true
|
"useA": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"href": "/about?section=organization",
|
"href": "/zh/about?section=organization",
|
||||||
"name": "组织架构",
|
"name": "组织架构",
|
||||||
"useA": true
|
"useA": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"href": "/about?section=awards",
|
"href": "/zh/about?section=awards",
|
||||||
"name": "荣誉资质",
|
"name": "荣誉资质",
|
||||||
"useA": true
|
"useA": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"href": "/about?section=history",
|
"href": "/zh/about?section=history",
|
||||||
"name": "发展历程",
|
"name": "发展历程",
|
||||||
"useA": true
|
"useA": true
|
||||||
}
|
}
|
||||||
|
|||||||
118
lib/getBlogs.ts
118
lib/getBlogs.ts
@@ -1,66 +1,92 @@
|
|||||||
import { DEFAULT_LOCALE } from '@/i18n/routing';
|
import { DEFAULT_LOCALE } from '@/i18n/routing';
|
||||||
import { BlogPost } from '@/types/blog';
|
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, category?: string): Promise<{ posts: BlogPost[], total: number }> {
|
||||||
|
const Id_Map: Record<string, string> = {
|
||||||
export async function getPosts(locale: string = DEFAULT_LOCALE): Promise<{ posts: BlogPost[] }> {
|
'announce': '1989174108560080897',
|
||||||
const postsDirectory = path.join(process.cwd(), 'blogs', locale);
|
'news': '1988814504336605185',
|
||||||
|
'event': '1989174018231549954',
|
||||||
// is directory exist
|
|
||||||
if (!fs.existsSync(postsDirectory)) {
|
|
||||||
return { posts: [] };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let filenames = await fs.promises.readdir(postsDirectory);
|
let url = 'http://49.232.154.205:18081/export/article/list?pageNum=1&pageSize=10&langCode=' + locale;
|
||||||
filenames = filenames.reverse();
|
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
|
// read file by batch
|
||||||
for (let i = 0; i < filenames.length; 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 batchFilenames = filenames.slice(i, i + POSTS_BATCH_SIZE);
|
||||||
|
|
||||||
const batchPosts: BlogPost[] = await Promise.all(
|
// const batchPosts: BlogPost[] = await Promise.all(
|
||||||
batchFilenames.map(async (filename) => {
|
// batchFilenames.map(async (filename) => {
|
||||||
const fullPath = path.join(postsDirectory, filename);
|
// const fullPath = path.join(postsDirectory, filename);
|
||||||
const fileContents = await fs.promises.readFile(fullPath, 'utf8');
|
// const fileContents = await fs.promises.readFile(fullPath, 'utf8');
|
||||||
|
|
||||||
const { data, content } = matter(fileContents);
|
// const { data, content } = matter(fileContents);
|
||||||
|
|
||||||
return {
|
// return {
|
||||||
locale, // use locale parameter
|
// locale, // use locale parameter
|
||||||
title: data.title,
|
// title: data.title,
|
||||||
description: data.description,
|
// description: data.description,
|
||||||
image: data.image || '',
|
// image: data.image || '',
|
||||||
slug: data.slug,
|
// slug: data.slug,
|
||||||
tags: data.tags,
|
// tags: data.tags,
|
||||||
date: data.date,
|
// date: data.date,
|
||||||
visible: data.visible || 'published',
|
// visible: data.visible || 'published',
|
||||||
pin: data.pin || false,
|
// pin: data.pin || false,
|
||||||
content,
|
// content,
|
||||||
metadata: data,
|
// metadata: data,
|
||||||
};
|
// };
|
||||||
})
|
// })
|
||||||
);
|
// );
|
||||||
|
|
||||||
allPosts.push(...batchPosts);
|
// allPosts.push(...batchPosts);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// filter out non-published articles
|
// 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
|
// sort posts by pin and date
|
||||||
allPosts = allPosts.sort((a, b) => {
|
// allPosts = allPosts.sort((a, b) => {
|
||||||
if (a.pin !== b.pin) {
|
// if (a.pin !== b.pin) {
|
||||||
return (b.pin ? 1 : 0) - (a.pin ? 1 : 0);
|
// return (b.pin ? 1 : 0) - (a.pin ? 1 : 0);
|
||||||
}
|
// }
|
||||||
return new Date(b.date).getTime() - new Date(a.date).getTime();
|
// return new Date(b.date).getTime() - new Date(a.date).getTime();
|
||||||
});
|
// });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
posts: allPosts,
|
posts,
|
||||||
|
total: data.total,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ export interface HeaderLink {
|
|||||||
href: string;
|
href: string;
|
||||||
target?: string;
|
target?: string;
|
||||||
rel?: string;
|
rel?: string;
|
||||||
|
children?: HeaderLink[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface FooterLink {
|
export interface FooterLink {
|
||||||
|
|||||||
Reference in New Issue
Block a user