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,76 @@
'use client';
import { calculateCareerAnchorsResults, CareerAnchor } from '../../test/private/CareerAnchorsCalculator';
interface CareerAnchorsResultProps {
answers: string[];
}
const descriptions: Record<CareerAnchor, string> = {
technical: "适合持续积累专业深度,通过专业能力获得成就和认可。",
managerial: "适合整合资源、带团队、处理复杂组织目标和责任。",
autonomy: "适合自由度较高、能自主安排方法和节奏的工作模式。",
security: "适合稳定、规则明确、风险可控且保障清晰的环境。",
entrepreneurial: "适合从零创造、开拓机会、主导项目或业务方向。",
service: "适合使命驱动、对他人或社会有明确贡献感的工作。",
challenge: "适合高难度、高竞争、需要突破限制的问题场景。",
lifestyle: "适合能与健康、家庭、自由时间和整体生活协调的职业路径。",
};
function width(score: number) {
return `${Math.max(0, Math.min(100, ((score - 1) / 4) * 100))}%`;
}
export function CareerAnchorsResult({ answers }: CareerAnchorsResultProps) {
const results = calculateCareerAnchorsResults(answers);
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">Career Anchors </h3>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<MetricCard title="主要职业锚" value={results.primary.name} score={results.primary.score.toFixed(2)} />
<MetricCard title="辅助职业锚" value={results.secondary.name} score={results.secondary.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">
{results.primary.name} + {results.secondary.name}
</h3>
<p className="text-sm">
</p>
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{results.ranked.map((item) => (
<div key={item.id} className="border bg-white p-5 shadow-sm">
<div className="mb-3 flex items-center justify-between gap-3">
<h4 className="font-semibold">{item.name}</h4>
<span className="text-sm text-muted-foreground">{item.score.toFixed(2)} / 5</span>
</div>
<div className="h-2 overflow-hidden rounded-full bg-gray-100">
<div className="h-full rounded-full bg-emerald-500" style={{ width: width(item.score) }} />
</div>
<p className="mt-3 text-sm text-gray-700">{descriptions[item.id]}</p>
</div>
))}
</div>
<div className="border bg-gray-50 p-4 text-sm text-gray-700">
</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-2xl font-semibold text-indigo-600">{value}</div>
<div className="text-xs text-muted-foreground">{score} / 5</div>
</div>
);
}