52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import Link from "next/link";
|
||
import { readdir, stat } from "node:fs/promises";
|
||
import { WEBSITE_FILE_DIR } from "@/lib/config";
|
||
|
||
export const dynamic = "force-dynamic";
|
||
|
||
export default async function SitesPage() {
|
||
let sites: string[] = [];
|
||
try {
|
||
const entries = await readdir(WEBSITE_FILE_DIR, { withFileTypes: true });
|
||
for (const e of entries) {
|
||
if (e.isDirectory()) {
|
||
try {
|
||
const s = await stat(`${WEBSITE_FILE_DIR}/${e.name}/log/access.log`);
|
||
if (s.isFile()) sites.push(e.name);
|
||
} catch {}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
// 显示错误信息
|
||
return (
|
||
<div className="max-w-5xl mx-auto py-10">
|
||
<h1 className="text-3xl font-semibold mb-6">Site 列表</h1>
|
||
<p className="text-red-500">读取目录失败:{String(error)}</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
sites.sort();
|
||
|
||
return (
|
||
<div className="max-w-5xl mx-auto py-10">
|
||
<h1 className="text-3xl font-semibold mb-6">Site 列表</h1>
|
||
<ul className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{sites.map((s) => (
|
||
<li key={s} className="border rounded-lg p-4 hover:shadow">
|
||
<div className="font-mono text-sm text-gray-500 mb-2">{s}</div>
|
||
<div className="flex gap-3">
|
||
<Link className="text-blue-600 hover:underline" href={`/sites/${encodeURIComponent(s)}`}>
|
||
仪表盘
|
||
</Link>
|
||
<a className="text-blue-600 hover:underline" href={`/api/sites/${encodeURIComponent(s)}/raw`} target="_blank">
|
||
原始日志
|
||
</a>
|
||
</div>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
);
|
||
}
|