官网 初版
This commit is contained in:
133
src/app/admin/(dashboard)/software/page.tsx
Normal file
133
src/app/admin/(dashboard)/software/page.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import Link from "next/link";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
} from "@/components/ui/card";
|
||||
import { Plus } from "lucide-react";
|
||||
import { SoftwareVersionTable } from "@/components/admin/SoftwareVersionTable";
|
||||
|
||||
const SOFTWARE_DEFS = [
|
||||
{
|
||||
slug: "nanami-launcher",
|
||||
name: "Nanami 启动器(全量包)",
|
||||
description: "Nanami 插件启动器完整安装包,用户首次下载或大版本更新",
|
||||
badgeLabel: "全量",
|
||||
},
|
||||
{
|
||||
slug: "nanami-launcher-patch",
|
||||
name: "Nanami 热更新包",
|
||||
description: "app.asar 热更新包,客户端静默下载替换实现热更新",
|
||||
badgeLabel: "热更新",
|
||||
},
|
||||
];
|
||||
|
||||
async function ensureSoftware(slug: string, name: string, description: string) {
|
||||
let sw = await prisma.software.findUnique({ where: { slug } });
|
||||
if (!sw) {
|
||||
sw = await prisma.software.create({ data: { name, slug, description } });
|
||||
}
|
||||
return sw;
|
||||
}
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminSoftwarePage() {
|
||||
const softwareItems = await Promise.all(
|
||||
SOFTWARE_DEFS.map(async (def) => {
|
||||
const sw = await ensureSoftware(def.slug, def.name, def.description);
|
||||
const versions = await prisma.softwareVersion.findMany({
|
||||
where: { softwareId: sw.id },
|
||||
orderBy: { versionCode: "desc" },
|
||||
});
|
||||
const totalDownloads = versions.reduce((s, v) => s + v.downloadCount, 0);
|
||||
const latestVersion = versions.find((v) => v.isLatest);
|
||||
return { ...def, sw, versions, totalDownloads, latestVersion };
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-10">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">软件管理</h1>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
管理启动器全量包和热更新包,客户端通过 slug 分别检查更新
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{softwareItems.map((item) => {
|
||||
const serializedVersions = item.versions.map((v) => ({
|
||||
...v,
|
||||
createdAt: v.createdAt.toISOString(),
|
||||
}));
|
||||
|
||||
return (
|
||||
<div key={item.slug} className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<h2 className="text-xl font-semibold">{item.name}</h2>
|
||||
<span className="rounded-md bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground">
|
||||
slug: {item.slug}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
render={
|
||||
<Link
|
||||
href={`/admin/software/${item.sw.id}/versions/new`}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
发布新版本
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription>当前版本</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-2xl font-bold">
|
||||
{item.latestVersion
|
||||
? `v${item.latestVersion.version}`
|
||||
: "未发布"}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription>版本总数</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-2xl font-bold">{item.versions.length}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription>总下载量</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-2xl font-bold">{item.totalDownloads}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>版本历史</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<SoftwareVersionTable versions={serializedVersions} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user