"use client"; /** * 模型詳情 — /models/[id] * * 對齊 pages.md §8.2。F6 做資訊顯示 + 刪除;部署 / 比較 留到 F7+。 */ import { useEffect, useState } from "react"; import Link from "next/link"; import { ArrowLeft, Trash2 } from "lucide-react"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { useT } from "@/lib/i18n/context"; import { useModelStore } from "@/stores/model-store"; import { useRouter } from "next/navigation"; import { toast } from "sonner"; function formatFileSize(bytes: number): string { if (!bytes) return "—"; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`; } /** input_shape(NCHW,如 [1,3,224,224])→ 易讀字串 `1 × 3 × 224 × 224`。 */ function formatInputShape(shape: number[]): string { return shape.join(" × "); } /** classes 多時只展示前幾個 Badge,其餘以 `+N` 表示,避免塞爆版面。 */ const CLASSES_PREVIEW_LIMIT = 8; interface ModelDetailClientProps { id: string; } export function ModelDetailClient({ id }: ModelDetailClientProps) { const t = useT(); const router = useRouter(); const selectedModel = useModelStore((s) => s.selectedModel); const isLoading = useModelStore((s) => s.isLoading); const fetchModel = useModelStore((s) => s.fetchModel); const deleteModel = useModelStore((s) => s.deleteModel); const [deleting, setDeleting] = useState(false); useEffect(() => { if (id) void fetchModel(id); }, [id, fetchModel]); async function handleDelete() { setDeleting(true); const ok = await deleteModel(id); setDeleting(false); if (ok) { toast.success(t("common.save")); router.push("/models"); } else { toast.error(t("common.error")); } } if (isLoading && !selectedModel) { return (
{t("common.loading")}
{selectedModel.description}
) : (—
)}