You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

153 lines
4.4 KiB

import fs from "fs";
import path from "path";
import { cache } from "react";
import type {
Floor,
NavItem,
HeroData,
AboutData,
TechData,
SolutionsData,
CasesData,
PartnersData,
NewsData,
CareersData,
ContactData,
} from "../types";
// 内存缓存,避免重复读取文件
const fileCache = new Map<string, { data: unknown; mtime: number }>();
function readJson<T>(relativePath: string): T {
const filePath = path.join(process.cwd(), relativePath);
// 检查文件修改时间
let stats: fs.Stats;
try {
stats = fs.statSync(filePath);
} catch {
throw new Error(`File not found: ${relativePath}`);
}
// 检查缓存
const cached = fileCache.get(filePath);
if (cached && cached.mtime === stats.mtimeMs) {
return cached.data as T;
}
// 读取并缓存
const raw = fs.readFileSync(filePath, "utf-8");
const data = JSON.parse(raw) as T;
fileCache.set(filePath, { data, mtime: stats.mtimeMs });
return data;
}
function dataPathFor(locale: string | undefined, filename: string): string {
const base = "data";
const candidates = [
locale ? path.join(base, locale, filename) : undefined,
path.join(base, filename),
].filter(Boolean) as string[];
for (const p of candidates) {
if (fs.existsSync(path.join(process.cwd(), p))) return p;
}
return path.join(base, filename);
}
// 使用 React cache 包装所有数据读取函数,实现请求级别的缓存
export const getMainNav = cache((locale?: string) => {
return readJson<NavItem[]>(dataPathFor(locale, "mainnav.json"));
});
export const getFloors = cache((locale?: string) => {
return readJson<Floor[]>(dataPathFor(locale, "products.json"));
});
export const getFloorBySlug = cache((slug: string, locale?: string) => {
const floors = getFloors(locale);
// 允许 id 带前缀,如 floor-phone,对应 slug phone
return floors.find((f) => f.id === slug || f.id === `floor-${slug}`);
});
export const getProductById = cache((id: string, locale?: string) => {
const floors = getFloors(locale);
for (const f of floors) {
const p = f.products.find((x) => x.id === id);
if (p) return { product: p, floor: f } as const;
}
return undefined;
});
export const getHero = cache((locale?: string) => {
return readJson<HeroData>(dataPathFor(locale, "hero.json"));
});
export const getAbout = cache((locale?: string) => {
return readJson<AboutData>(dataPathFor(locale, "about.json"));
});
const getAboutMarkdownFile = cache((locale?: string): string => {
const candidates = [
locale ? path.join("data", locale, "about.md") : undefined,
path.join("data", "about.md"),
path.join("..", "..", "关于我们.md"),
].filter(Boolean) as string[];
for (const relativePath of candidates) {
const filePath = path.join(process.cwd(), relativePath);
if (fs.existsSync(filePath)) {
try {
// 检查缓存
const stats = fs.statSync(filePath);
const cached = fileCache.get(filePath);
if (cached && cached.mtime === stats.mtimeMs && typeof cached.data === 'string') {
return cached.data;
}
const content = fs.readFileSync(filePath, "utf-8");
fileCache.set(filePath, { data: content, mtime: stats.mtimeMs });
return content;
} catch (error) {
console.warn(`Failed to load ${relativePath}`, error);
}
}
}
console.warn("About markdown not found in any candidate path.");
return "";
});
export const getAboutMarkdown = cache((locale?: string): string => {
return getAboutMarkdownFile(locale);
});
export const getTech = cache((locale?: string) => {
return readJson<TechData>(dataPathFor(locale, "tech.json"));
});
export const getSolutions = cache((locale?: string) => {
return readJson<SolutionsData>(dataPathFor(locale, "solutions.json"));
});
export const getCases = cache((locale?: string) => {
return readJson<CasesData>(dataPathFor(locale, "cases.json"));
});
export const getPartners = cache((locale?: string) => {
return readJson<PartnersData>(dataPathFor(locale, "partners.json"));
});
export const getNews = cache((locale?: string) => {
return readJson<NewsData>(dataPathFor(locale, "news.json"));
});
export const getCareers = cache((locale?: string) => {
return readJson<CareersData>(dataPathFor(locale, "careers.json"));
});
export const getContact = cache((locale?: string) => {
return readJson<ContactData>(dataPathFor(locale, "contact.json"));
});