diff --git a/app/admin/results/detail/[testResultId]/page.tsx b/app/admin/results/detail/[testResultId]/page.tsx index 8d89d43..a11d489 100644 --- a/app/admin/results/detail/[testResultId]/page.tsx +++ b/app/admin/results/detail/[testResultId]/page.tsx @@ -9,6 +9,7 @@ import { Badge } from "@/components/ui/badge" import { Progress } from "@/components/ui/progress" import { CheckCircle, XCircle, Brain, Lightbulb, BarChart3, ArrowLeft, Loader2 } from "lucide-react" import Link from "next/link" +import { CreativeAnalysis } from "@/components/creative-analysis" interface User { id: string @@ -30,6 +31,12 @@ interface TestResult { abilityBalance?: number breakdown?: any } + dimensionScores?: { + innovation: { percentage: number, rawScore: number, maxScore: number } + imagination: { percentage: number, rawScore: number, maxScore: number } + flexibility: { percentage: number, rawScore: number, maxScore: number } + originality: { percentage: number, rawScore: number, maxScore: number } + } } interface Question { @@ -172,6 +179,46 @@ function AdminResultDetailContent() { } } + const getDimensionInfo = (category: string) => { + switch (category) { + case "innovation": + return { + name: "創新能力", + color: "bg-blue-500", + textColor: "text-blue-600", + borderColor: "border-blue-200" + } + case "imagination": + return { + name: "想像力", + color: "bg-purple-500", + textColor: "text-purple-600", + borderColor: "border-purple-200" + } + case "flexibility": + return { + name: "靈活性", + color: "bg-green-500", + textColor: "text-green-600", + borderColor: "border-green-200" + } + case "originality": + return { + name: "原創性", + color: "bg-orange-500", + textColor: "text-orange-600", + borderColor: "border-orange-200" + } + default: + return { + name: "未知維度", + color: "bg-gray-500", + textColor: "text-gray-600", + borderColor: "border-gray-200" + } + } + } + const getScoreLevel = (score: number, type: string) => { if (type === "logic") { if (score === 100) return { @@ -211,29 +258,29 @@ function AdminResultDetailContent() { description: "你的創意如泉水般源源不絕,總能提出令人驚豔的解決方案!", suggestion: "繼續保持這種創意精神,並嘗試將創意轉化為實際行動。" } - if (score >= 80) return { - level: "創意高手", - color: "bg-green-500", - description: "創意思維活躍,能夠從不同角度思考問題,提出新穎的見解。", - suggestion: "多接觸不同領域的知識,豐富你的創意素材庫。" - } - if (score >= 60) return { - level: "創意探索者", + if (score >= 75) return { + level: "創意引領者", color: "bg-blue-500", - description: "有一定的創意思維,能夠在既有框架內提出改進建議。", - suggestion: "嘗試跳出舒適圈,挑戰更多創意性的任務。" + description: "你是靈感的推動者!總是能在團體中主動拋出新想法,激發別人跟進。", + suggestion: "持續累積學習,讓你的靈感不僅是點子,而能帶動真正的行動。" } - if (score >= 40) return { - level: "創意學習者", + if (score >= 55) return { + level: "創意實踐者", + color: "bg-green-500", + description: "靈感已經隨手可得,在團體中也常被認為是「有創意的人」。", + suggestion: "再給自己一點勇氣,不要害怕挑戰慣例,你的創意將更有力量。" + } + if (score >= 35) return { + level: "創意開拓者", color: "bg-yellow-500", - description: "正在學習如何發揮創意,需要更多練習和啟發。", - suggestion: "多觀察身邊的事物,培養對細節的敏感度。" + description: "你其實有自己的想法,但有時習慣跟隨大多數人的步伐。", + suggestion: "試著勇敢說出腦中天馬行空的念頭,你會發現,這些點子或許就是團隊需要的突破口。" } return { - level: "創意新手", + level: "創意萌芽者", color: "bg-red-500", - description: "創意思維還需要培養,建議多接觸創意相關的活動。", - suggestion: "從簡單的創意練習開始,逐步提升創意思維能力。" + description: "還在創意旅程的起點。雖然暫時表現平淡,但這正是無限潛力的開端!", + suggestion: "觀察生活小事,或閱讀不同領域的內容,讓靈感一點一滴積累。" } } else { // combined @@ -280,6 +327,16 @@ function AdminResultDetailContent() { const correctAnswers = logicQuestions.filter(q => q.isCorrect).length const totalQuestions = questions.length + // 計算創意測試的統計數據 + const creativeTotalScore = creativeQuestions.reduce((sum, q) => sum + (q.score || 0), 0) + const creativeMaxScore = creativeQuestions.length * 5 + const creativeScorePercentage = creativeQuestions.length > 0 ? Math.round((creativeTotalScore / creativeMaxScore) * 100) : 0 + + // 如果沒有從答案中獲得分數,使用結果中的分數 + const displayTotalScore = creativeTotalScore > 0 ? creativeTotalScore : result.score + const displayMaxScore = creativeMaxScore > 0 ? creativeMaxScore : 100 + const displayScorePercentage = creativeScorePercentage > 0 ? creativeScorePercentage : result.score + return (
{/* Header */} @@ -360,20 +417,41 @@ function AdminResultDetailContent() {
-
-
{correctAnswers}
-
答對題數
-
-
-
{totalQuestions}
-
總題數
-
-
-
- {totalQuestions > 0 ? Math.round((correctAnswers / totalQuestions) * 100) : 0}% -
-
正確率
-
+ {result.type === 'creative' ? ( + <> +
+
{displayTotalScore}
+
總得分
+
+
+
{displayMaxScore}
+
滿分
+
+
+
+ {displayScorePercentage}% +
+
得分率
+
+ + ) : ( + <> +
+
{correctAnswers}
+
答對題數
+
+
+
{totalQuestions}
+
總題數
+
+
+
+ {totalQuestions > 0 ? Math.round((correctAnswers / totalQuestions) * 100) : 0}% +
+
正確率
+
+ + )}
@@ -404,6 +482,17 @@ function AdminResultDetailContent() { )} + {/* Creative Analysis for Creative Tests */} + {result.type === 'creative' && result.dimensionScores && ( + + )} + {/* Detailed Results */} {questions.length > 0 && ( @@ -491,34 +580,42 @@ function AdminResultDetailContent() { 創意能力題目
- {creativeQuestions.map((question, index) => ( -
-
-

第 {index + 1} 題

- - {question.score} 分 - -
- -
-
- -

{question.statement}

+ {creativeQuestions.map((question, index) => { + const dimensionInfo = getDimensionInfo(question.category) + return ( +
+
+
+

第 {index + 1} 題

+ + {dimensionInfo.name} + +
+ + {question.score} 分 +
+ +
+
+ +

{question.statement}

+
-
-
- -

{question.userAnswer}

-
-
- -

{question.score} 分

+
+
+ +

{question.userAnswer}

+
+
+ +

{question.score} 分

+
-
- ))} + ) + })}
)} diff --git a/app/api/admin/test-results/detail/route.ts b/app/api/admin/test-results/detail/route.ts index 454bff0..ce4ed7c 100644 --- a/app/api/admin/test-results/detail/route.ts +++ b/app/api/admin/test-results/detail/route.ts @@ -127,7 +127,91 @@ export async function GET(request: NextRequest) { // 獲取詳細答案 try { - if (testType === "logic") { + if (testType === "creative") { + console.log('Debug: 查詢創意測試答案,testResultId:', testResultId) + + // 先嘗試從 creative_test_answers 表獲取 + const creativeAnswersQuery = ` + SELECT cta.*, cq.statement, cq.is_reverse, cq.category + FROM creative_test_answers cta + LEFT JOIN creative_questions cq ON cta.question_id = cq.id + WHERE cta.test_result_id = ? + ORDER BY cta.created_at ASC + ` + const creativeAnswers = await executeQuery(creativeAnswersQuery, [testResultId]) + console.log('Debug: 創意測試答案數量:', creativeAnswers.length) + + if (creativeAnswers.length > 0) { + // 處理創意題答案 + for (const answer of creativeAnswers) { + if (answer.statement) { + questions.push({ + id: answer.question_id, + statement: answer.statement, + is_reverse: answer.is_reverse, + category: answer.category, + type: 'creative', + userAnswer: answer.user_answer, + score: answer.score, + isReverse: answer.is_reverse + }) + } + } + + // 計算維度分數 + const dimensionScores = { + innovation: { total: 0, count: 0 }, + imagination: { total: 0, count: 0 }, + flexibility: { total: 0, count: 0 }, + originality: { total: 0, count: 0 } + } + + creativeAnswers.forEach((answer: any) => { + if (answer.category && dimensionScores[answer.category as keyof typeof dimensionScores]) { + dimensionScores[answer.category as keyof typeof dimensionScores].total += answer.score + dimensionScores[answer.category as keyof typeof dimensionScores].count += 1 + } + }) + + // 計算百分比分數 + const resultDimensionScores = { + innovation: { percentage: 0, rawScore: 0, maxScore: 0 }, + imagination: { percentage: 0, rawScore: 0, maxScore: 0 }, + flexibility: { percentage: 0, rawScore: 0, maxScore: 0 }, + originality: { percentage: 0, rawScore: 0, maxScore: 0 } + } + + Object.keys(dimensionScores).forEach(category => { + const { total, count } = dimensionScores[category as keyof typeof dimensionScores] + const maxScore = count * 5 + const percentage = count > 0 ? Math.round((total / maxScore) * 100) : 0 + + resultDimensionScores[category as keyof typeof resultDimensionScores] = { + percentage: percentage, + rawScore: total, + maxScore: maxScore + } + }) + + // 將維度分數添加到結果中 + result.dimensionScores = resultDimensionScores + } else { + // 如果沒有找到答案,只顯示題目不顯示假答案 + console.log('Debug: 沒有找到創意答案,只顯示題目') + const allCreativeQuestions = await executeQuery('SELECT * FROM creative_questions ORDER BY id') + + for (let i = 0; i < allCreativeQuestions.length; i++) { + const question = allCreativeQuestions[i] + questions.push({ + ...question, + type: 'creative', + userAnswer: null, // 不顯示假答案 + score: null, // 不顯示假分數 + isReverse: question.is_reverse + }) + } + } + } else if (testType === "logic") { console.log('Debug: 查詢邏輯測試答案,testResultId:', testResultId) @@ -180,51 +264,6 @@ export async function GET(request: NextRequest) { }) } } - } else if (testType === "creative") { - console.log('Debug: 查詢創意測試答案,testResultId:', testResultId) - - // 先嘗試從 creative_test_answers 表獲取 - const creativeAnswersQuery = ` - SELECT cta.*, cq.statement, cq.is_reverse - FROM creative_test_answers cta - LEFT JOIN creative_questions cq ON cta.question_id = cq.id - WHERE cta.test_result_id = ? - ORDER BY cta.created_at ASC - ` - const creativeAnswers = await executeQuery(creativeAnswersQuery, [testResultId]) - console.log('Debug: 創意測試答案數量:', creativeAnswers.length) - - if (creativeAnswers.length > 0) { - // 處理創意題答案 - for (const answer of creativeAnswers) { - if (answer.statement) { - questions.push({ - id: answer.question_id, - statement: answer.statement, - is_reverse: answer.is_reverse, - type: 'creative', - userAnswer: answer.user_answer, - score: answer.score, - isReverse: answer.is_reverse - }) - } - } - } else { - // 如果沒有找到答案,只顯示題目不顯示假答案 - console.log('Debug: 沒有找到創意答案,只顯示題目') - const allCreativeQuestions = await executeQuery('SELECT * FROM creative_questions ORDER BY id') - - for (let i = 0; i < allCreativeQuestions.length; i++) { - const question = allCreativeQuestions[i] - questions.push({ - ...question, - type: 'creative', - userAnswer: null, // 不顯示假答案 - score: null, // 不顯示假分數 - isReverse: question.is_reverse - }) - } - } } } catch (error) { console.error('獲取詳細答案失敗:', error) diff --git a/components/creative-analysis.tsx b/components/creative-analysis.tsx new file mode 100644 index 0000000..f334876 --- /dev/null +++ b/components/creative-analysis.tsx @@ -0,0 +1,308 @@ +"use client" + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Progress } from "@/components/ui/progress" +import { TrendingUp } from "lucide-react" + +interface DimensionScore { + percentage: number + rawScore: number + maxScore: number +} + +interface CreativeAnalysisProps { + score: number + dimensionScores: { + innovation: DimensionScore + imagination: DimensionScore + flexibility: DimensionScore + originality: DimensionScore + } + creativityLevel: { + level: string + description: string + suggestion: string + } + totalScore?: number + maxScore?: number +} + +export function CreativeAnalysis({ score, dimensionScores, creativityLevel, totalScore, maxScore }: CreativeAnalysisProps) { + // 計算各維度分數 + const categoryResults = [ + { + category: 'innovation', + name: '創新能力', + score: dimensionScores.innovation.percentage, + rawScore: dimensionScores.innovation.rawScore, + maxRawScore: dimensionScores.innovation.maxScore + }, + { + category: 'imagination', + name: '想像力', + score: dimensionScores.imagination.percentage, + rawScore: dimensionScores.imagination.rawScore, + maxRawScore: dimensionScores.imagination.maxScore + }, + { + category: 'flexibility', + name: '靈活性', + score: dimensionScores.flexibility.percentage, + rawScore: dimensionScores.flexibility.rawScore, + maxRawScore: dimensionScores.flexibility.maxScore + }, + { + category: 'originality', + name: '原創性', + score: dimensionScores.originality.percentage, + rawScore: dimensionScores.originality.rawScore, + maxRawScore: dimensionScores.originality.maxScore + } + ] + + return ( +
+ {/* 創意能力評估 */} + + + + + 創意能力評估 + + + +
+

創意能力評估

+

+ 基於您的測試結果,您在創意思維方面表現為「{creativityLevel.level}」水平。 + {score >= 75 && + "您具備出色的創新思維能力,善於從不同角度思考問題,能夠產生獨特的想法和解決方案。"} + {score >= 50 && + score < 75 && + "您具有一定的創造性思維潛力,建議多參與創新活動,培養發散性思維。"} + {score < 50 && "建議您多接觸創新思維訓練,培養好奇心和探索精神,提升創造性解決問題的能力。"} +

+
+
+
+ + {/* 能力維度分析 */} + + + + + 能力維度分析 + + + +
+ {categoryResults.map((category) => ( +
+
+

{category.name}

+ {category.score}分 +
+ +

+ {category.rawScore} / {category.maxRawScore} 分 +

+
+ ))} +
+
+
+ + {/* 創意能力分析圖表 */} + + + + + 創意能力分析圖表 + + + +
+ {/* 能力維度雷達圖 */} +
+

能力維度雷達圖

+
+
+ {/* Radar Chart Background */} + + {/* Grid circles */} + + + + + + {/* Grid lines - 4 axes for 4 dimensions */} + {[0, 90, 180, 270].map((angle, index) => { + const x1 = 100 + 60 * Math.cos((angle - 90) * Math.PI / 180) + const y1 = 100 + 60 * Math.sin((angle - 90) * Math.PI / 180) + return ( + + ) + })} + + {/* Data points and area */} + {categoryResults.map((category, index) => { + const angle = (index * 90 - 90) * Math.PI / 180 + const radius = (category.score / 100) * 60 + const x = 100 + radius * Math.cos(angle) + const y = 100 + radius * Math.sin(angle) + + // Calculate label position - more space for text + let labelRadius = 75 + let labelX = 100 + labelRadius * Math.cos(angle) + let labelY = 100 + labelRadius * Math.sin(angle) + + // Special adjustments for imagination and originality + if (angle === 0) { // Right - 想像力 + labelRadius = 70 + labelX = 100 + labelRadius * Math.cos(angle) + labelY = 100 + labelRadius * Math.sin(angle) + } else if (angle === 180 * Math.PI / 180) { // Left - 原創性 + labelRadius = 70 + labelX = 100 + labelRadius * Math.cos(angle) + labelY = 100 + labelRadius * Math.sin(angle) + } + + // Adjust text anchor based on position + let textAnchor: "middle" | "start" | "end" = "middle" + let dominantBaseline: "middle" | "hanging" | "alphabetic" = "middle" + + if (angle === -90 * Math.PI / 180) { // Top + dominantBaseline = "hanging" + } else if (angle === 90 * Math.PI / 180) { // Bottom + dominantBaseline = "alphabetic" + } else if (angle === 0) { // Right + textAnchor = "start" + } else if (angle === 180 * Math.PI / 180) { // Left + textAnchor = "end" + } + + return ( + + {/* Data point */} + + {/* Label - positioned closer to the chart */} + + {category.name} + + {/* Score label - positioned above the data point */} + + {category.score}% + + + ) + })} + + {/* Area fill */} + { + const angle = (index * 90 - 90) * Math.PI / 180 + const radius = (category.score / 100) * 60 + const x = 100 + radius * Math.cos(angle) + const y = 100 + radius * Math.sin(angle) + return `${x},${y}` + }).join(' ')} + fill="rgba(59, 130, 246, 0.2)" + stroke="#3b82f6" + strokeWidth="2" + /> + +
+
+ + {/* Legend */} +
+
+ {categoryResults.map((category) => ( +
+
+ {category.name} +
+ ))} +
+
+ + {/* Dimension Details */} +
+ {categoryResults.map((category) => { + const getDescription = (categoryName: string) => { + switch (categoryName) { + case '創新能力': + return '善於提出新想法,勇於嘗試不同的解決方案' + case '想像力': + return '能夠從不同角度思考,具有豐富的創意思維' + case '靈活性': + return '適應變化能力強,能夠靈活調整思維方式' + case '原創性': + return '具有獨特的創見,能夠產生原創性想法' + default: + return '' + } + } + + const getLevel = (score: number) => { + if (score >= 80) return { text: '優秀', color: 'text-green-600' } + if (score >= 60) return { text: '良好', color: 'text-blue-600' } + if (score >= 40) return { text: '一般', color: 'text-yellow-600' } + return { text: '待提升', color: 'text-red-600' } + } + + const level = getLevel(category.score) + + return ( +
+
+
{category.name}
+
+ {category.score}% + {level.text} +
+
+

+ {getDescription(category.name)} +

+
+ ) + })} +
+
+
+
+
+
+ ) +}