"use client"; import { useState, useEffect, useCallback, Suspense } from "react"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; import { Card, CardContent } from "@/components/ui/card"; interface ReviewItem { id: number; overall: number; capability: number; devExp: number; costLicense: number; community: number; performance: number; reviews?: Record; skill: { id: number; name: string; slug: string; description: string; sourceUrl: string; category: { name: string; slug: string } | null; }; reviewedAt: string; } const dimLabels: Record = { capability: "能力", devExp: "体验", costLicense: "成本", community: "社区", performance: "性能", }; function getScoreColor(score: number): string { if (score >= 4) return "text-emerald-700"; if (score >= 3) return "text-amber-700"; return "text-red-600"; } function getScoreBg(score: number): string { if (score >= 4) return "bg-emerald-50"; if (score >= 3) return "bg-amber-50"; return "bg-red-50"; } function getOverallLabel(score: number): string { if (score >= 4.5) return "卓越"; if (score >= 4) return "优秀"; if (score >= 3.5) return "良好"; if (score >= 3) return "中等"; return "一般"; } function MiniRadar({ scores }: { scores: number[] }) { const size = 80; const cx = size / 2; const cy = size / 2; const r = 30; const angles = scores.map((_, i) => (Math.PI * 2 * i) / scores.length - Math.PI / 2); const points = scores.map((s, i) => { const val = (s / 5) * r; return `${cx + val * Math.cos(angles[i])},${cy + val * Math.sin(angles[i])}`; }).join(" "); const gridRings = [1, 2, 3, 4, 5].map((level) => { const gridPoints = angles.map((a) => { const val = (level / 5) * r; return `${cx + val * Math.cos(a)},${cy + val * Math.sin(a)}`; }).join(" "); return ; }); const axisLines = angles.map((a, i) => ( )); return ( {gridRings} {axisLines} {scores.map((s, i) => ( = 4 ? "#10b981" : s >= 3 ? "#f59e0b" : "#ef4444"} /> ))} ); } function ReviewCard({ review }: { review: ReviewItem }) { const scores = [review.capability, review.devExp, review.costLicense, review.community, review.performance]; const reviewEntries = review.reviews ? (Object.entries(review.reviews).filter( ([, v]) => v && typeof v === "object" && "score" in v ) as [string, { score: number; summary: string; detail: string }][]) : []; return (

{review.skill.name}

{review.skill.category && ( {review.skill.category.name} )}
{review.overall} {getOverallLabel(review.overall)}
{scores.map((s, i) => (
{dimLabels[Object.keys(dimLabels)[i]]}
= 4 ? "bg-emerald-500" : s >= 3 ? "bg-amber-500" : "bg-red-500"}`} style={{ width: `${(s / 5) * 100}%` }} />
{s}
))}
{reviewEntries.length > 0 && (
{reviewEntries.slice(0, 3).map(([key, dim]) => (
{dimLabels[key]} {dim.summary}
))}
)} {review.skill.description && (

{review.skill.description}

)} ); } function ReviewsContent() { const searchParams = useSearchParams(); const [reviews, setReviews] = useState([]); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(true); const [page, setPage] = useState(1); const pageSize = 12; const fetchReviews = useCallback(async () => { setLoading(true); try { const res = await fetch(`/api/skill-reviews?page=${page}&pageSize=${pageSize}`); if (res.ok) { const data = await res.json(); setReviews(data.reviews || []); setTotal(data.total || 0); } } catch {} setLoading(false); }, [page]); useEffect(() => { fetchReviews(); }, [fetchReviews]); const totalPages = Math.ceil(total / pageSize); return (

AI评测

基于五维模型的AI技能深度评测,涵盖场景能力、开发体验、成本许可、社区健康、性能稳定

共 {total} 项评测 按综合评分排序
{loading ? (
{Array.from({ length: 6 }).map((_, i) => (
))}
) : reviews.length === 0 ? (

暂无评测数据

评测正在生成中,请稍后再来

) : ( <>
{reviews.map((review) => ( ))}
{totalPages > 1 && (
{page} / {totalPages}
)} )}
); } export default function ReviewsPage() { return (

加载中...

}> ); }