feat: 完善中文心理测评平台

This commit is contained in:
mikemoi
2026-06-22 22:59:01 +02:00
commit 9227c687fc
160 changed files with 16974 additions and 0 deletions
@@ -0,0 +1,140 @@
'use client';
import { calculateVIAResults, VIAStrength, VIAVirtue } from '../../test/private/VIACalculator';
interface VIAResultProps {
answers: string[];
}
const strengthDescriptions: Record<VIAStrength, string> = {
creativity: "用新颖有效的方式思考和行动。",
curiosity: "主动探索未知,持续提问和观察。",
judgment: "开放评估证据,避免草率判断。",
loveOfLearning: "从学习和掌握新知识中获得满足。",
perspective: "能整合经验,为自己或他人提供有用视角。",
bravery: "在压力、风险或恐惧中坚持重要行动。",
perseverance: "面对困难仍持续完成目标。",
honesty: "真实、可靠,不依赖伪装获得认可。",
zest: "带着能量、投入和生命力行动。",
love: "重视亲密、信任和双向关心。",
kindness: "愿意照顾他人并提供实际帮助。",
socialIntelligence: "理解他人情绪、动机和场景需求。",
teamwork: "愿意合作并承担团队责任。",
fairness: "重视公正、平等和不偏袒。",
leadership: "组织、协调并带动群体前进。",
forgiveness: "能在合适时机放下怨气,重新看待关系。",
humility: "不过度夸大自己,承认仍需学习。",
prudence: "行动前考虑风险、后果和边界。",
selfRegulation: "管理冲动、情绪和行为节奏。",
appreciation: "感受自然、艺术和卓越表现中的美。",
gratitude: "看见并珍惜已经拥有和被给予的东西。",
hope: "相信未来可以改善,并愿意为此行动。",
humor: "用轻松方式缓和压力、连接他人。",
spirituality: "感到自己与更大的意义、信念或整体有关联。",
};
const virtueDescriptions: Record<VIAVirtue, string> = {
wisdom: "认知探索、学习、判断和形成视角的优势。",
courage: "面对困难仍行动、坚持和保持真实的优势。",
humanity: "建立亲密、善意和人际理解的优势。",
justice: "合作、公平和组织群体行动的优势。",
temperance: "克制、审慎、谦逊和修复关系的优势。",
transcendence: "连接意义、美、希望、感恩和幽默的优势。",
};
function width(score: number) {
return `${Math.max(0, Math.min(100, ((score - 1) / 4) * 100))}%`;
}
export function VIAResult({ answers }: VIAResultProps) {
const results = calculateVIAResults(answers);
const signature = results.rankedStrengths.slice(0, 5);
return (
<div className="mt-6 space-y-6">
<div className="border bg-white p-6 shadow-sm">
<h3 className="text-lg font-semibold mb-4">VIA </h3>
<div className="grid grid-cols-1 gap-4 md:grid-cols-5">
{signature.map((item, index) => (
<MetricCard key={item.id} title={`优势 ${index + 1}`} value={item.name} score={item.score.toFixed(2)} />
))}
</div>
</div>
<div className="border bg-blue-50 p-6 text-blue-900 shadow-sm">
<h3 className="text-lg font-semibold mb-3">
{signature.map((item) => item.name).join(" / ")}
</h3>
<p className="text-sm">
VIA结果重点看你最自然
</p>
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{results.rankedVirtues.map((item) => (
<ScoreCard
key={item.id}
title={item.name}
score={item.score}
description={virtueDescriptions[item.id]}
color="bg-indigo-500"
/>
))}
</div>
<div className="border bg-white p-6 shadow-sm">
<h3 className="text-lg font-semibold mb-4">24</h3>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{results.rankedStrengths.map((item) => (
<ScoreCard
key={item.id}
title={item.name}
score={item.score}
description={strengthDescriptions[item.id]}
color="bg-emerald-500"
/>
))}
</div>
</div>
<div className="border bg-gray-50 p-4 text-sm text-gray-700">
VIA-IS题库5
</div>
</div>
);
}
function MetricCard({ title, value, score }: { title: string; value: string; score: string }) {
return (
<div className="rounded-lg bg-gray-50 p-4 text-center">
<div className="text-sm text-muted-foreground">{title}</div>
<div className="mt-1 text-xl font-semibold text-indigo-600">{value}</div>
<div className="text-xs text-muted-foreground">{score} / 5</div>
</div>
);
}
function ScoreCard({
title,
score,
description,
color,
}: {
title: string;
score: number;
description: string;
color: string;
}) {
return (
<div className="border bg-white p-5 shadow-sm">
<div className="mb-3 flex items-center justify-between gap-3">
<h4 className="font-semibold">{title}</h4>
<span className="text-sm text-muted-foreground">{score.toFixed(2)} / 5</span>
</div>
<div className="h-2 overflow-hidden rounded-full bg-gray-100">
<div className={`h-full rounded-full ${color}`} style={{ width: width(score) }} />
</div>
<p className="mt-3 text-sm text-gray-700">{description}</p>
</div>
);
}