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 (

软件管理

管理启动器全量包和热更新包,客户端通过 slug 分别检查更新

{softwareItems.map((item) => { const serializedVersions = item.versions.map((v) => ({ ...v, createdAt: v.createdAt.toISOString(), })); return (

{item.name}

slug: {item.slug}
{(["1.18", "1.17"] as const).map((wv) => { const latest = item.versions.find( (v) => v.isLatest && v.wowVersion === wv ); const total = item.versions.filter( (v) => v.wowVersion === wv ).length; const downloads = item.versions .filter((v) => v.wowVersion === wv) .reduce((s, v) => s + v.downloadCount, 0); return ( WoW {wv} ({total} 个版本 · {downloads} 次下载)

{latest ? `v${latest.version}` : "未发布"}

); })}
版本历史
); })}
); }