實作邏輯題結果與資料庫整合
This commit is contained in:
27
app/api/test-db/route.ts
Normal file
27
app/api/test-db/route.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { testConnection } from '@/lib/database/connection'
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
const isConnected = await testConnection()
|
||||||
|
|
||||||
|
if (isConnected) {
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
message: '資料庫連接正常'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: '資料庫連接失敗'
|
||||||
|
}, { status: 500 })
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('資料庫測試失敗:', error)
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: '資料庫測試失敗',
|
||||||
|
error: error instanceof Error ? error.message : '未知錯誤'
|
||||||
|
}, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
149
app/api/test-results/logic/route.ts
Normal file
149
app/api/test-results/logic/route.ts
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
|
import { createTestResult, getTestResultsByUserId } from '@/lib/database/models/test_result'
|
||||||
|
import { createLogicTestAnswers } from '@/lib/database/models/logic_test_answer'
|
||||||
|
import { getAllLogicQuestions } from '@/lib/database/models/logic_question'
|
||||||
|
|
||||||
|
export async function POST(request: NextRequest) {
|
||||||
|
try {
|
||||||
|
const body = await request.json()
|
||||||
|
const {
|
||||||
|
userId,
|
||||||
|
answers,
|
||||||
|
completedAt
|
||||||
|
} = body
|
||||||
|
|
||||||
|
// 驗證必要欄位
|
||||||
|
if (!userId || !answers || !completedAt) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ success: false, error: '缺少必要欄位' },
|
||||||
|
{ status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 獲取邏輯題目
|
||||||
|
const questions = await getAllLogicQuestions()
|
||||||
|
if (questions.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ success: false, error: '無法獲取題目' },
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 計算分數
|
||||||
|
let correctAnswers = 0
|
||||||
|
const answerRecords = []
|
||||||
|
|
||||||
|
for (let i = 0; i < questions.length; i++) {
|
||||||
|
const question = questions[i]
|
||||||
|
const userAnswer = answers[i] || ''
|
||||||
|
const isCorrect = userAnswer === question.correct_answer
|
||||||
|
|
||||||
|
if (isCorrect) {
|
||||||
|
correctAnswers++
|
||||||
|
}
|
||||||
|
|
||||||
|
answerRecords.push({
|
||||||
|
test_result_id: '', // 稍後填入
|
||||||
|
question_id: question.id,
|
||||||
|
user_answer: userAnswer as 'A' | 'B' | 'C' | 'D' | 'E',
|
||||||
|
is_correct: isCorrect
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const score = Math.round((correctAnswers / questions.length) * 100)
|
||||||
|
|
||||||
|
// 建立測試結果
|
||||||
|
console.log('🔄 開始建立測試結果...')
|
||||||
|
console.log('測試結果數據:', {
|
||||||
|
user_id: userId,
|
||||||
|
test_type: 'logic',
|
||||||
|
score: score,
|
||||||
|
total_questions: questions.length,
|
||||||
|
correct_answers: correctAnswers,
|
||||||
|
completed_at: completedAt
|
||||||
|
})
|
||||||
|
|
||||||
|
const testResult = await createTestResult({
|
||||||
|
user_id: userId,
|
||||||
|
test_type: 'logic',
|
||||||
|
score: score,
|
||||||
|
total_questions: questions.length,
|
||||||
|
correct_answers: correctAnswers,
|
||||||
|
completed_at: completedAt
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('測試結果建立結果:', testResult)
|
||||||
|
|
||||||
|
if (!testResult) {
|
||||||
|
console.error('❌ 建立測試結果失敗')
|
||||||
|
return NextResponse.json(
|
||||||
|
{ success: false, error: '建立測試結果失敗' },
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ 測試結果建立成功:', testResult.id)
|
||||||
|
|
||||||
|
// 更新答案記錄的 test_result_id
|
||||||
|
answerRecords.forEach(record => {
|
||||||
|
record.test_result_id = testResult.id
|
||||||
|
})
|
||||||
|
|
||||||
|
// 建立答案記錄
|
||||||
|
const answerResults = await createLogicTestAnswers(answerRecords)
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
testResult,
|
||||||
|
answerCount: answerResults.length
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('上傳邏輯測驗結果失敗:', error)
|
||||||
|
console.error('錯誤詳情:', {
|
||||||
|
message: error instanceof Error ? error.message : '未知錯誤',
|
||||||
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
|
body: body
|
||||||
|
})
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
error: '伺服器錯誤',
|
||||||
|
details: error instanceof Error ? error.message : '未知錯誤'
|
||||||
|
},
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GET(request: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { searchParams } = new URL(request.url)
|
||||||
|
const userId = searchParams.get('userId')
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ success: false, error: '缺少用戶ID' },
|
||||||
|
{ status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 獲取用戶的邏輯測驗結果
|
||||||
|
const results = await getTestResultsByUserId(userId)
|
||||||
|
const logicResults = results.filter(result => result.test_type === 'logic')
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: logicResults
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取邏輯測驗結果失敗:', error)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ success: false, error: '伺服器錯誤' },
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
123
app/api/user/test-results/route.ts
Normal file
123
app/api/user/test-results/route.ts
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
|
import { getTestResultsByUserId } from '@/lib/database/models/test_result'
|
||||||
|
|
||||||
|
export async function GET(request: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { searchParams } = new URL(request.url)
|
||||||
|
const userId = searchParams.get('userId')
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ success: false, error: '缺少用戶ID' },
|
||||||
|
{ status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 獲取用戶的所有測試結果
|
||||||
|
const allResults = await getTestResultsByUserId(userId)
|
||||||
|
|
||||||
|
if (allResults.length === 0) {
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
results: [],
|
||||||
|
stats: {
|
||||||
|
totalTests: 0,
|
||||||
|
averageScore: 0,
|
||||||
|
bestScore: 0,
|
||||||
|
lastTestDate: null,
|
||||||
|
testCounts: {
|
||||||
|
logic: 0,
|
||||||
|
creative: 0,
|
||||||
|
combined: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按測試類型分組,只保留每種類型的最新結果
|
||||||
|
const latestResults = {
|
||||||
|
logic: allResults.filter(r => r.test_type === 'logic').sort((a, b) =>
|
||||||
|
new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime()
|
||||||
|
)[0],
|
||||||
|
creative: allResults.filter(r => r.test_type === 'creative').sort((a, b) =>
|
||||||
|
new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime()
|
||||||
|
)[0],
|
||||||
|
combined: allResults.filter(r => r.test_type === 'combined').sort((a, b) =>
|
||||||
|
new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime()
|
||||||
|
)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只保留有結果的測試類型
|
||||||
|
const results = Object.values(latestResults).filter(result => result !== undefined)
|
||||||
|
|
||||||
|
// 計算統計數據
|
||||||
|
// 完成測試:基於每種類型測試是否有最新結果
|
||||||
|
const totalTests = Object.values(latestResults).filter(result => result !== undefined).length
|
||||||
|
|
||||||
|
// 平均分數:基於每種類型測試的最新分數計算
|
||||||
|
const latestScores = Object.values(latestResults)
|
||||||
|
.filter(result => result !== undefined)
|
||||||
|
.map(result => result.score)
|
||||||
|
|
||||||
|
const averageScore = latestScores.length > 0
|
||||||
|
? Math.round(latestScores.reduce((sum, score) => sum + score, 0) / latestScores.length)
|
||||||
|
: 0
|
||||||
|
|
||||||
|
// 最高分數:基於每種類型測試的最新分數
|
||||||
|
const bestScore = latestScores.length > 0 ? Math.max(...latestScores) : 0
|
||||||
|
|
||||||
|
// 最近測試日期:基於所有測試結果
|
||||||
|
const lastTestDate = allResults.length > 0
|
||||||
|
? allResults.sort((a, b) =>
|
||||||
|
new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime()
|
||||||
|
)[0]?.completed_at || null
|
||||||
|
: null
|
||||||
|
|
||||||
|
// 計算各類型測試次數
|
||||||
|
const testCounts = {
|
||||||
|
logic: allResults.filter(r => r.test_type === 'logic').length,
|
||||||
|
creative: allResults.filter(r => r.test_type === 'creative').length,
|
||||||
|
combined: allResults.filter(r => r.test_type === 'combined').length
|
||||||
|
}
|
||||||
|
|
||||||
|
// 轉換為前端需要的格式
|
||||||
|
const formattedResults = results.map(result => ({
|
||||||
|
type: result.test_type,
|
||||||
|
score: result.score,
|
||||||
|
completedAt: result.completed_at,
|
||||||
|
testCount: testCounts[result.test_type as keyof typeof testCounts],
|
||||||
|
details: {
|
||||||
|
id: result.id,
|
||||||
|
total_questions: result.total_questions,
|
||||||
|
correct_answers: result.correct_answers,
|
||||||
|
created_at: result.created_at
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 按完成時間排序(最新的在前)
|
||||||
|
formattedResults.sort((a, b) => new Date(b.completedAt).getTime() - new Date(a.completedAt).getTime())
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
results: formattedResults,
|
||||||
|
stats: {
|
||||||
|
totalTests,
|
||||||
|
averageScore,
|
||||||
|
bestScore,
|
||||||
|
lastTestDate,
|
||||||
|
testCounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取用戶測試結果失敗:', error)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ success: false, error: '伺服器錯誤' },
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -204,7 +204,7 @@ export default function CombinedResultsPage() {
|
|||||||
<div>
|
<div>
|
||||||
<h1 className="text-xl font-bold text-foreground">綜合能力測試結果</h1>
|
<h1 className="text-xl font-bold text-foreground">綜合能力測試結果</h1>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
完成時間:{new Date(results.completedAt).toLocaleString("zh-TW")}
|
完成時間:{new Date(results.completedAt).toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -113,7 +113,7 @@ export default function CreativeResultsPage() {
|
|||||||
<div>
|
<div>
|
||||||
<h1 className="text-xl font-bold text-foreground">創意能力測試結果</h1>
|
<h1 className="text-xl font-bold text-foreground">創意能力測試結果</h1>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
完成時間:{new Date(results.completedAt).toLocaleString("zh-TW")}
|
完成時間:{new Date(results.completedAt).toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -138,7 +138,7 @@ export default function LogicResultsPage() {
|
|||||||
<div>
|
<div>
|
||||||
<h1 className="text-xl font-bold text-foreground">邏輯思維測試結果</h1>
|
<h1 className="text-xl font-bold text-foreground">邏輯思維測試結果</h1>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
完成時間:{new Date(results.completedAt).toLocaleString("zh-TW")}
|
完成時間:{new Date(results.completedAt).toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -14,6 +14,7 @@ interface TestResult {
|
|||||||
type: "logic" | "creative" | "combined"
|
type: "logic" | "creative" | "combined"
|
||||||
score: number
|
score: number
|
||||||
completedAt: string
|
completedAt: string
|
||||||
|
testCount?: number
|
||||||
details?: any
|
details?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,66 +34,34 @@ function ResultsContent() {
|
|||||||
averageScore: 0,
|
averageScore: 0,
|
||||||
bestScore: 0,
|
bestScore: 0,
|
||||||
lastTestDate: null as string | null,
|
lastTestDate: null as string | null,
|
||||||
|
testCounts: {
|
||||||
|
logic: 0,
|
||||||
|
creative: 0,
|
||||||
|
combined: 0
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Load all test results from localStorage
|
const loadUserResults = async () => {
|
||||||
const logicResults = localStorage.getItem("logicTestResults")
|
if (!user) return
|
||||||
const creativeResults = localStorage.getItem("creativeTestResults")
|
|
||||||
const combinedResults = localStorage.getItem("combinedTestResults")
|
|
||||||
|
|
||||||
const allResults: TestResult[] = []
|
try {
|
||||||
|
const response = await fetch(`/api/user/test-results?userId=${user.id}`)
|
||||||
|
const data = await response.json()
|
||||||
|
|
||||||
if (logicResults) {
|
if (data.success) {
|
||||||
const data = JSON.parse(logicResults)
|
setResults(data.data.results)
|
||||||
allResults.push({
|
setStats(data.data.stats)
|
||||||
type: "logic",
|
} else {
|
||||||
score: data.score,
|
console.error('Failed to load user results:', data.error)
|
||||||
completedAt: data.completedAt,
|
}
|
||||||
details: data,
|
} catch (error) {
|
||||||
})
|
console.error('Error loading user results:', error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creativeResults) {
|
loadUserResults()
|
||||||
const data = JSON.parse(creativeResults)
|
}, [user])
|
||||||
allResults.push({
|
|
||||||
type: "creative",
|
|
||||||
score: data.score,
|
|
||||||
completedAt: data.completedAt,
|
|
||||||
details: data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (combinedResults) {
|
|
||||||
const data = JSON.parse(combinedResults)
|
|
||||||
allResults.push({
|
|
||||||
type: "combined",
|
|
||||||
score: data.overallScore,
|
|
||||||
completedAt: data.completedAt,
|
|
||||||
details: data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort by completion date (newest first)
|
|
||||||
allResults.sort((a, b) => new Date(b.completedAt).getTime() - new Date(a.completedAt).getTime())
|
|
||||||
|
|
||||||
setResults(allResults)
|
|
||||||
|
|
||||||
// Calculate statistics
|
|
||||||
if (allResults.length > 0) {
|
|
||||||
const totalScore = allResults.reduce((sum, result) => sum + result.score, 0)
|
|
||||||
const averageScore = Math.round(totalScore / allResults.length)
|
|
||||||
const bestScore = Math.max(...allResults.map((r) => r.score))
|
|
||||||
const lastTestDate = allResults[0].completedAt
|
|
||||||
|
|
||||||
setStats({
|
|
||||||
totalTests: allResults.length,
|
|
||||||
averageScore,
|
|
||||||
bestScore,
|
|
||||||
lastTestDate,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const getTestTypeInfo = (type: string) => {
|
const getTestTypeInfo = (type: string) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -263,7 +232,7 @@ function ResultsContent() {
|
|||||||
<Calendar className="w-6 h-6 text-accent" />
|
<Calendar className="w-6 h-6 text-accent" />
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm font-bold text-foreground mb-1">
|
<div className="text-sm font-bold text-foreground mb-1">
|
||||||
{stats.lastTestDate ? new Date(stats.lastTestDate).toLocaleDateString("zh-TW") : "無"}
|
{stats.lastTestDate ? new Date(stats.lastTestDate).toLocaleDateString("zh-TW", { timeZone: "Asia/Taipei" }) : "無"}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-muted-foreground">最近測試</div>
|
<div className="text-sm text-muted-foreground">最近測試</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -295,8 +264,13 @@ function ResultsContent() {
|
|||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="font-medium text-foreground">{testInfo.name}</h3>
|
<h3 className="font-medium text-foreground">{testInfo.name}</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
完成時間:{new Date(result.completedAt).toLocaleString("zh-TW")}
|
完成時間:{new Date(result.completedAt).toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}
|
||||||
</p>
|
</p>
|
||||||
|
{result.testCount && result.testCount > 1 && (
|
||||||
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
|
已測驗 {result.testCount} 次
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -290,11 +290,11 @@ export default function CombinedTestPage() {
|
|||||||
{phase === "logic"
|
{phase === "logic"
|
||||||
? // Logic question options
|
? // Logic question options
|
||||||
[
|
[
|
||||||
{ value: 'A', text: currentQ.option_a },
|
{ value: 'A', text: (currentQ as LogicQuestion).option_a },
|
||||||
{ value: 'B', text: currentQ.option_b },
|
{ value: 'B', text: (currentQ as LogicQuestion).option_b },
|
||||||
{ value: 'C', text: currentQ.option_c },
|
{ value: 'C', text: (currentQ as LogicQuestion).option_c },
|
||||||
{ value: 'D', text: currentQ.option_d },
|
{ value: 'D', text: (currentQ as LogicQuestion).option_d },
|
||||||
{ value: 'E', text: currentQ.option_e }
|
{ value: 'E', text: (currentQ as LogicQuestion).option_e }
|
||||||
].map((option, index) => (
|
].map((option, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
|
@@ -7,6 +7,7 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
|
import { useAuth } from "@/lib/hooks/use-auth"
|
||||||
|
|
||||||
interface LogicQuestion {
|
interface LogicQuestion {
|
||||||
id: number
|
id: number
|
||||||
@@ -23,11 +24,13 @@ interface LogicQuestion {
|
|||||||
|
|
||||||
export default function LogicTestPage() {
|
export default function LogicTestPage() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const { user } = useAuth()
|
||||||
const [questions, setQuestions] = useState<LogicQuestion[]>([])
|
const [questions, setQuestions] = useState<LogicQuestion[]>([])
|
||||||
const [currentQuestion, setCurrentQuestion] = useState(0)
|
const [currentQuestion, setCurrentQuestion] = useState(0)
|
||||||
const [answers, setAnswers] = useState<Record<number, string>>({})
|
const [answers, setAnswers] = useState<Record<number, string>>({})
|
||||||
const [timeRemaining, setTimeRemaining] = useState(20 * 60) // 20 minutes in seconds
|
const [timeRemaining, setTimeRemaining] = useState(20 * 60) // 20 minutes in seconds
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
|
||||||
// Load questions from database
|
// Load questions from database
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -93,29 +96,88 @@ export default function LogicTestPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = async () => {
|
||||||
// Calculate score
|
console.log('🔍 開始提交邏輯測驗...')
|
||||||
let correctAnswers = 0
|
console.log('用戶狀態:', user)
|
||||||
questions.forEach((question, index) => {
|
|
||||||
if (answers[index] === question.correct_answer) {
|
|
||||||
correctAnswers++
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const score = Math.round((correctAnswers / questions.length) * 100)
|
if (!user) {
|
||||||
|
console.log('❌ 用戶未登入')
|
||||||
// Store results in localStorage
|
alert('請先登入')
|
||||||
const results = {
|
return
|
||||||
type: "logic",
|
|
||||||
score,
|
|
||||||
correctAnswers,
|
|
||||||
totalQuestions: questions.length,
|
|
||||||
answers,
|
|
||||||
completedAt: new Date().toISOString(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem("logicTestResults", JSON.stringify(results))
|
console.log('✅ 用戶已登入,用戶ID:', user.id)
|
||||||
router.push("/results/logic")
|
setIsSubmitting(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Calculate score
|
||||||
|
let correctAnswers = 0
|
||||||
|
questions.forEach((question, index) => {
|
||||||
|
if (answers[index] === question.correct_answer) {
|
||||||
|
correctAnswers++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const score = Math.round((correctAnswers / questions.length) * 100)
|
||||||
|
const completedAt = new Date().toISOString().replace('Z', '').replace('T', ' ')
|
||||||
|
|
||||||
|
console.log('📊 測驗結果計算:')
|
||||||
|
console.log('答對題數:', correctAnswers)
|
||||||
|
console.log('總題數:', questions.length)
|
||||||
|
console.log('分數:', score)
|
||||||
|
console.log('完成時間:', completedAt)
|
||||||
|
|
||||||
|
// Store results in localStorage (for backward compatibility)
|
||||||
|
const results = {
|
||||||
|
type: "logic",
|
||||||
|
score,
|
||||||
|
correctAnswers,
|
||||||
|
totalQuestions: questions.length,
|
||||||
|
answers,
|
||||||
|
completedAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem("logicTestResults", JSON.stringify(results))
|
||||||
|
console.log('✅ 結果已儲存到 localStorage')
|
||||||
|
|
||||||
|
// Upload to database
|
||||||
|
console.log('🔄 開始上傳到資料庫...')
|
||||||
|
const uploadData = {
|
||||||
|
userId: user.id,
|
||||||
|
answers: Object.values(answers),
|
||||||
|
completedAt: completedAt
|
||||||
|
}
|
||||||
|
console.log('上傳數據:', uploadData)
|
||||||
|
|
||||||
|
const uploadResponse = await fetch('/api/test-results/logic', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(uploadData)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('📡 API 響應狀態:', uploadResponse.status)
|
||||||
|
const uploadResult = await uploadResponse.json()
|
||||||
|
console.log('📡 API 響應內容:', uploadResult)
|
||||||
|
|
||||||
|
if (uploadResult.success) {
|
||||||
|
console.log('✅ 邏輯測驗結果已上傳到資料庫')
|
||||||
|
console.log('測試結果ID:', uploadResult.data.testResult.id)
|
||||||
|
console.log('答案記錄數量:', uploadResult.data.answerCount)
|
||||||
|
} else {
|
||||||
|
console.error('❌ 上傳到資料庫失敗:', uploadResult.error)
|
||||||
|
// 即使上傳失敗,也繼續顯示結果
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push("/results/logic")
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 提交測驗失敗:', error)
|
||||||
|
alert('提交測驗失敗,請重試')
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -204,11 +266,11 @@ export default function LogicTestPage() {
|
|||||||
{isLastQuestion ? (
|
{isLastQuestion ? (
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
disabled={!hasAnswer}
|
disabled={!hasAnswer || isSubmitting}
|
||||||
className="bg-green-600 hover:bg-green-700"
|
className="bg-green-600 hover:bg-green-700"
|
||||||
size="sm"
|
size="sm"
|
||||||
>
|
>
|
||||||
提交測試
|
{isSubmitting ? '提交中...' : '提交測試'}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button onClick={handleNext} disabled={!hasAnswer} size="sm">
|
<Button onClick={handleNext} disabled={!hasAnswer} size="sm">
|
||||||
|
@@ -2,6 +2,8 @@ import { testConnection } from './connection'
|
|||||||
import { createUsersTable } from './models/user'
|
import { createUsersTable } from './models/user'
|
||||||
import { createLogicQuestionsTable } from './models/logic_question'
|
import { createLogicQuestionsTable } from './models/logic_question'
|
||||||
import { createCreativeQuestionsTable } from './models/creative_question'
|
import { createCreativeQuestionsTable } from './models/creative_question'
|
||||||
|
import { createTestResultsTable } from './models/test_result'
|
||||||
|
import { createLogicTestAnswersTable } from './models/logic_test_answer'
|
||||||
|
|
||||||
// 初始化資料庫
|
// 初始化資料庫
|
||||||
export async function initializeDatabase(): Promise<boolean> {
|
export async function initializeDatabase(): Promise<boolean> {
|
||||||
@@ -24,6 +26,12 @@ export async function initializeDatabase(): Promise<boolean> {
|
|||||||
// 建立創意能力測試題目表
|
// 建立創意能力測試題目表
|
||||||
await createCreativeQuestionsTable()
|
await createCreativeQuestionsTable()
|
||||||
|
|
||||||
|
// 建立測試結果表
|
||||||
|
await createTestResultsTable()
|
||||||
|
|
||||||
|
// 建立邏輯測驗答案表
|
||||||
|
await createLogicTestAnswersTable()
|
||||||
|
|
||||||
console.log('✅ 資料庫初始化完成')
|
console.log('✅ 資料庫初始化完成')
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@@ -84,13 +84,13 @@ export async function findLogicQuestionById(id: number): Promise<LogicQuestion |
|
|||||||
// 獲取所有題目
|
// 獲取所有題目
|
||||||
export async function getAllLogicQuestions(): Promise<LogicQuestion[]> {
|
export async function getAllLogicQuestions(): Promise<LogicQuestion[]> {
|
||||||
const query = 'SELECT * FROM logic_questions ORDER BY created_at'
|
const query = 'SELECT * FROM logic_questions ORDER BY created_at'
|
||||||
return await executeQuery<LogicQuestion[]>(query)
|
return await executeQuery<LogicQuestion>(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 獲取隨機題目
|
// 獲取隨機題目
|
||||||
export async function getRandomLogicQuestions(limit: number = 10): Promise<LogicQuestion[]> {
|
export async function getRandomLogicQuestions(limit: number = 10): Promise<LogicQuestion[]> {
|
||||||
const query = 'SELECT * FROM logic_questions ORDER BY RAND() LIMIT ?'
|
const query = 'SELECT * FROM logic_questions ORDER BY RAND() LIMIT ?'
|
||||||
return await executeQuery<LogicQuestion[]>(query, [limit])
|
return await executeQuery<LogicQuestion>(query, [limit])
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空所有題目
|
// 清空所有題目
|
||||||
|
140
lib/database/models/logic_test_answer.ts
Normal file
140
lib/database/models/logic_test_answer.ts
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import { executeQuery, executeQueryOne } from '../connection'
|
||||||
|
|
||||||
|
export interface LogicTestAnswer {
|
||||||
|
id: string
|
||||||
|
test_result_id: string
|
||||||
|
question_id: number
|
||||||
|
user_answer: 'A' | 'B' | 'C' | 'D' | 'E'
|
||||||
|
is_correct: boolean
|
||||||
|
created_at?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateLogicTestAnswerData {
|
||||||
|
test_result_id: string
|
||||||
|
question_id: number
|
||||||
|
user_answer: 'A' | 'B' | 'C' | 'D' | 'E'
|
||||||
|
is_correct: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建立邏輯測驗答案表(如果不存在)
|
||||||
|
export async function createLogicTestAnswersTable(): Promise<void> {
|
||||||
|
const createTableQuery = `
|
||||||
|
CREATE TABLE IF NOT EXISTS logic_test_answers (
|
||||||
|
id VARCHAR(50) PRIMARY KEY,
|
||||||
|
test_result_id VARCHAR(50) NOT NULL,
|
||||||
|
question_id INT NOT NULL,
|
||||||
|
user_answer ENUM('A', 'B', 'C', 'D', 'E') NOT NULL,
|
||||||
|
is_correct TINYINT(1) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_test_result_id (test_result_id),
|
||||||
|
INDEX idx_question_id (question_id),
|
||||||
|
FOREIGN KEY (test_result_id) REFERENCES test_results(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (question_id) REFERENCES logic_questions(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
await executeQuery(createTableQuery)
|
||||||
|
console.log('✅ 邏輯測驗答案表建立成功')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建立新邏輯測驗答案
|
||||||
|
export async function createLogicTestAnswer(answerData: CreateLogicTestAnswerData): Promise<LogicTestAnswer | null> {
|
||||||
|
try {
|
||||||
|
const id = `answer_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||||
|
|
||||||
|
const insertQuery = `
|
||||||
|
INSERT INTO logic_test_answers (
|
||||||
|
id, test_result_id, question_id, user_answer, is_correct
|
||||||
|
) VALUES (?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
|
||||||
|
await executeQuery(insertQuery, [
|
||||||
|
id,
|
||||||
|
answerData.test_result_id,
|
||||||
|
answerData.question_id,
|
||||||
|
answerData.user_answer,
|
||||||
|
answerData.is_correct ? 1 : 0
|
||||||
|
])
|
||||||
|
|
||||||
|
return await getLogicTestAnswerById(id)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('建立邏輯測驗答案失敗:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量建立邏輯測驗答案
|
||||||
|
export async function createLogicTestAnswers(answersData: CreateLogicTestAnswerData[]): Promise<LogicTestAnswer[]> {
|
||||||
|
try {
|
||||||
|
const results: LogicTestAnswer[] = []
|
||||||
|
|
||||||
|
for (const answerData of answersData) {
|
||||||
|
const result = await createLogicTestAnswer(answerData)
|
||||||
|
if (result) {
|
||||||
|
results.push(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
} catch (error) {
|
||||||
|
console.error('批量建立邏輯測驗答案失敗:', error)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據ID獲取邏輯測驗答案
|
||||||
|
export async function getLogicTestAnswerById(id: string): Promise<LogicTestAnswer | null> {
|
||||||
|
try {
|
||||||
|
const query = 'SELECT * FROM logic_test_answers WHERE id = ?'
|
||||||
|
return await executeQueryOne<LogicTestAnswer>(query, [id])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取邏輯測驗答案失敗:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據測試結果ID獲取所有答案
|
||||||
|
export async function getLogicTestAnswersByTestResultId(testResultId: string): Promise<LogicTestAnswer[]> {
|
||||||
|
try {
|
||||||
|
const query = 'SELECT * FROM logic_test_answers WHERE test_result_id = ? ORDER BY question_id'
|
||||||
|
return await executeQuery<LogicTestAnswer>(query, [testResultId])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取測試結果答案失敗:', error)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據問題ID獲取所有答案
|
||||||
|
export async function getLogicTestAnswersByQuestionId(questionId: number): Promise<LogicTestAnswer[]> {
|
||||||
|
try {
|
||||||
|
const query = 'SELECT * FROM logic_test_answers WHERE question_id = ? ORDER BY created_at DESC'
|
||||||
|
return await executeQuery<LogicTestAnswer>(query, [questionId])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取問題答案失敗:', error)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刪除測試結果的所有答案
|
||||||
|
export async function deleteLogicTestAnswersByTestResultId(testResultId: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const query = 'DELETE FROM logic_test_answers WHERE test_result_id = ?'
|
||||||
|
await executeQuery(query, [testResultId])
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
console.error('刪除測試結果答案失敗:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刪除邏輯測驗答案
|
||||||
|
export async function deleteLogicTestAnswer(id: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const query = 'DELETE FROM logic_test_answers WHERE id = ?'
|
||||||
|
await executeQuery(query, [id])
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
console.error('刪除邏輯測驗答案失敗:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
130
lib/database/models/test_result.ts
Normal file
130
lib/database/models/test_result.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import { executeQuery, executeQueryOne } from '../connection'
|
||||||
|
|
||||||
|
export interface TestResult {
|
||||||
|
id: string
|
||||||
|
user_id: string
|
||||||
|
test_type: 'logic' | 'creative' | 'combined'
|
||||||
|
score: number
|
||||||
|
total_questions: number
|
||||||
|
correct_answers: number
|
||||||
|
completed_at: string
|
||||||
|
created_at?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateTestResultData {
|
||||||
|
user_id: string
|
||||||
|
test_type: 'logic' | 'creative' | 'combined'
|
||||||
|
score: number
|
||||||
|
total_questions: number
|
||||||
|
correct_answers: number
|
||||||
|
completed_at: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建立測試結果表(如果不存在)
|
||||||
|
export async function createTestResultsTable(): Promise<void> {
|
||||||
|
const createTableQuery = `
|
||||||
|
CREATE TABLE IF NOT EXISTS test_results (
|
||||||
|
id VARCHAR(50) PRIMARY KEY,
|
||||||
|
user_id VARCHAR(50) NOT NULL,
|
||||||
|
test_type ENUM('logic', 'creative', 'combined') NOT NULL,
|
||||||
|
score INT NOT NULL,
|
||||||
|
total_questions INT NOT NULL,
|
||||||
|
correct_answers INT NOT NULL,
|
||||||
|
completed_at TIMESTAMP NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_user_id (user_id),
|
||||||
|
INDEX idx_test_type (test_type),
|
||||||
|
INDEX idx_completed_at (completed_at)
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
await executeQuery(createTableQuery)
|
||||||
|
console.log('✅ 測試結果表建立成功')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建立新測試結果
|
||||||
|
export async function createTestResult(resultData: CreateTestResultData): Promise<TestResult | null> {
|
||||||
|
try {
|
||||||
|
const id = `test_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||||
|
|
||||||
|
const insertQuery = `
|
||||||
|
INSERT INTO test_results (
|
||||||
|
id, user_id, test_type, score, total_questions,
|
||||||
|
correct_answers, completed_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
|
||||||
|
await executeQuery(insertQuery, [
|
||||||
|
id,
|
||||||
|
resultData.user_id,
|
||||||
|
resultData.test_type,
|
||||||
|
resultData.score,
|
||||||
|
resultData.total_questions,
|
||||||
|
resultData.correct_answers,
|
||||||
|
resultData.completed_at
|
||||||
|
])
|
||||||
|
|
||||||
|
const result = await getTestResultById(id)
|
||||||
|
console.log('建立的測試結果:', result)
|
||||||
|
return result
|
||||||
|
} catch (error) {
|
||||||
|
console.error('建立測試結果失敗:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據ID獲取測試結果
|
||||||
|
export async function getTestResultById(id: string): Promise<TestResult | null> {
|
||||||
|
try {
|
||||||
|
const query = 'SELECT * FROM test_results WHERE id = ?'
|
||||||
|
return await executeQueryOne<TestResult>(query, [id])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取測試結果失敗:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據用戶ID獲取測試結果
|
||||||
|
export async function getTestResultsByUserId(userId: string): Promise<TestResult[]> {
|
||||||
|
try {
|
||||||
|
const query = 'SELECT * FROM test_results WHERE user_id = ? ORDER BY completed_at DESC'
|
||||||
|
return await executeQuery<TestResult>(query, [userId])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取用戶測試結果失敗:', error)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據測試類型獲取測試結果
|
||||||
|
export async function getTestResultsByType(testType: 'logic' | 'creative' | 'combined'): Promise<TestResult[]> {
|
||||||
|
try {
|
||||||
|
const query = 'SELECT * FROM test_results WHERE test_type = ? ORDER BY completed_at DESC'
|
||||||
|
return await executeQuery<TestResult>(query, [testType])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取測試結果失敗:', error)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 獲取所有測試結果
|
||||||
|
export async function getAllTestResults(): Promise<TestResult[]> {
|
||||||
|
try {
|
||||||
|
const query = 'SELECT * FROM test_results ORDER BY completed_at DESC'
|
||||||
|
return await executeQuery<TestResult>(query)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取所有測試結果失敗:', error)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刪除測試結果
|
||||||
|
export async function deleteTestResult(id: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const query = 'DELETE FROM test_results WHERE id = ?'
|
||||||
|
await executeQuery(query, [id])
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
console.error('刪除測試結果失敗:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
12
package.json
12
package.json
@@ -31,6 +31,18 @@
|
|||||||
"test-logic-instructions": "node scripts/test-logic-instructions.js",
|
"test-logic-instructions": "node scripts/test-logic-instructions.js",
|
||||||
"test-logic-simple-instructions": "node scripts/test-logic-simple-instructions.js",
|
"test-logic-simple-instructions": "node scripts/test-logic-simple-instructions.js",
|
||||||
"test-combined-logic-instructions": "node scripts/test-combined-logic-instructions.js",
|
"test-combined-logic-instructions": "node scripts/test-combined-logic-instructions.js",
|
||||||
|
"check-db-tables": "node scripts/check-db-tables.js",
|
||||||
|
"test-logic-db-upload": "node scripts/test-logic-db-upload.js",
|
||||||
|
"test-logic-api": "node scripts/test-logic-api.js",
|
||||||
|
"fix-logic-answers-table": "node scripts/fix-logic-answers-table.js",
|
||||||
|
"check-test-results": "node scripts/check-test-results.js",
|
||||||
|
"test-api-direct": "node scripts/test-api-direct.js",
|
||||||
|
"test-db-models": "npx tsx scripts/test-db-models.js",
|
||||||
|
"test-direct-insert": "node scripts/test-direct-insert.js",
|
||||||
|
"check-user-exists": "node scripts/check-user-exists.js",
|
||||||
|
"test-create-result": "node scripts/test-create-result.js",
|
||||||
|
"test-simple-insert": "node scripts/test-simple-insert.js",
|
||||||
|
"test-user-results-api": "node scripts/test-user-results-detailed.js",
|
||||||
"update-logic-table": "node scripts/update-logic-table.js",
|
"update-logic-table": "node scripts/update-logic-table.js",
|
||||||
"seed-db": "npx tsx lib/database/seed.ts",
|
"seed-db": "npx tsx lib/database/seed.ts",
|
||||||
"seed-logic-questions": "npx tsx lib/database/seed-logic-questions.ts",
|
"seed-logic-questions": "npx tsx lib/database/seed-logic-questions.ts",
|
||||||
|
75
scripts/check-db-tables.js
Normal file
75
scripts/check-db-tables.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
async function checkDatabaseTables() {
|
||||||
|
const config = {
|
||||||
|
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||||
|
port: parseInt(process.env.DB_PORT || '33306'),
|
||||||
|
user: process.env.DB_USER || 'hr_assessment',
|
||||||
|
password: process.env.DB_PASSWORD || 'QFOts8FlibiI',
|
||||||
|
database: process.env.DB_NAME || 'db_hr_assessment',
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🔍 檢查資料庫表結構...')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = await mysql.createConnection(config)
|
||||||
|
|
||||||
|
// 檢查所有表
|
||||||
|
console.log('\n📋 所有資料表:')
|
||||||
|
const [tables] = await connection.execute("SHOW TABLES")
|
||||||
|
tables.forEach(table => {
|
||||||
|
const tableName = Object.values(table)[0]
|
||||||
|
console.log(`- ${tableName}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 檢查 test_results 表結構
|
||||||
|
console.log('\n📊 test_results 表結構:')
|
||||||
|
try {
|
||||||
|
const [columns] = await connection.execute("DESCRIBE test_results")
|
||||||
|
columns.forEach(col => {
|
||||||
|
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? `(${col.Key})` : ''}`)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ test_results 表不存在')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查 logic_test_answers 表結構
|
||||||
|
console.log('\n📝 logic_test_answers 表結構:')
|
||||||
|
try {
|
||||||
|
const [columns] = await connection.execute("DESCRIBE logic_test_answers")
|
||||||
|
columns.forEach(col => {
|
||||||
|
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? `(${col.Key})` : ''}`)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ logic_test_answers 表不存在')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查 users 表結構
|
||||||
|
console.log('\n👥 users 表結構:')
|
||||||
|
try {
|
||||||
|
const [columns] = await connection.execute("DESCRIBE users")
|
||||||
|
columns.forEach(col => {
|
||||||
|
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? `(${col.Key})` : ''}`)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ users 表不存在')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查 logic_questions 表結構
|
||||||
|
console.log('\n🧠 logic_questions 表結構:')
|
||||||
|
try {
|
||||||
|
const [columns] = await connection.execute("DESCRIBE logic_questions")
|
||||||
|
columns.forEach(col => {
|
||||||
|
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? `(${col.Key})` : ''}`)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ logic_questions 表不存在')
|
||||||
|
}
|
||||||
|
|
||||||
|
await connection.end()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 檢查失敗:', error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkDatabaseTables()
|
102
scripts/check-test-results.js
Normal file
102
scripts/check-test-results.js
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
async function checkTestResults() {
|
||||||
|
const config = {
|
||||||
|
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||||
|
port: parseInt(process.env.DB_PORT || '33306'),
|
||||||
|
user: process.env.DB_USER || 'hr_assessment',
|
||||||
|
password: process.env.DB_PASSWORD || 'QFOts8FlibiI',
|
||||||
|
database: process.env.DB_NAME || 'db_hr_assessment',
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🔍 檢查資料庫中的測試結果...')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = await mysql.createConnection(config)
|
||||||
|
|
||||||
|
// 檢查 test_results 表中的邏輯測驗結果
|
||||||
|
console.log('\n📊 test_results 表中的邏輯測驗結果:')
|
||||||
|
const [testResults] = await connection.execute(`
|
||||||
|
SELECT id, user_id, test_type, score, total_questions, correct_answers, completed_at, created_at
|
||||||
|
FROM test_results
|
||||||
|
WHERE test_type = 'logic'
|
||||||
|
ORDER BY completed_at DESC
|
||||||
|
LIMIT 10
|
||||||
|
`)
|
||||||
|
|
||||||
|
if (testResults.length > 0) {
|
||||||
|
console.log(`找到 ${testResults.length} 筆邏輯測驗結果:`)
|
||||||
|
testResults.forEach((result, index) => {
|
||||||
|
console.log(`${index + 1}. ID: ${result.id}`)
|
||||||
|
console.log(` 用戶ID: ${result.user_id}`)
|
||||||
|
console.log(` 分數: ${result.score}`)
|
||||||
|
console.log(` 答對題數: ${result.correct_answers}/${result.total_questions}`)
|
||||||
|
console.log(` 完成時間: ${result.completed_at}`)
|
||||||
|
console.log(` 建立時間: ${result.created_at}`)
|
||||||
|
console.log('')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('❌ 沒有找到邏輯測驗結果')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查 logic_test_answers 表中的答案記錄
|
||||||
|
console.log('\n📝 logic_test_answers 表中的答案記錄:')
|
||||||
|
const [answerResults] = await connection.execute(`
|
||||||
|
SELECT lta.id, lta.test_result_id, lta.question_id, lta.user_answer, lta.is_correct, lta.created_at,
|
||||||
|
tr.user_id, tr.score
|
||||||
|
FROM logic_test_answers lta
|
||||||
|
JOIN test_results tr ON lta.test_result_id = tr.id
|
||||||
|
WHERE tr.test_type = 'logic'
|
||||||
|
ORDER BY lta.created_at DESC
|
||||||
|
LIMIT 20
|
||||||
|
`)
|
||||||
|
|
||||||
|
if (answerResults.length > 0) {
|
||||||
|
console.log(`找到 ${answerResults.length} 筆答案記錄:`)
|
||||||
|
answerResults.forEach((answer, index) => {
|
||||||
|
console.log(`${index + 1}. 答案ID: ${answer.id}`)
|
||||||
|
console.log(` 測試結果ID: ${answer.test_result_id}`)
|
||||||
|
console.log(` 用戶ID: ${answer.user_id}`)
|
||||||
|
console.log(` 題目ID: ${answer.question_id}`)
|
||||||
|
console.log(` 用戶答案: ${answer.user_answer}`)
|
||||||
|
console.log(` 是否正確: ${answer.is_correct ? '是' : '否'}`)
|
||||||
|
console.log(` 建立時間: ${answer.created_at}`)
|
||||||
|
console.log('')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('❌ 沒有找到答案記錄')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查最近的測試結果統計
|
||||||
|
console.log('\n📈 測試結果統計:')
|
||||||
|
const [stats] = await connection.execute(`
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_tests,
|
||||||
|
AVG(score) as avg_score,
|
||||||
|
MAX(score) as max_score,
|
||||||
|
MIN(score) as min_score,
|
||||||
|
COUNT(CASE WHEN score >= 80 THEN 1 END) as high_scores,
|
||||||
|
COUNT(CASE WHEN score < 60 THEN 1 END) as low_scores
|
||||||
|
FROM test_results
|
||||||
|
WHERE test_type = 'logic'
|
||||||
|
`)
|
||||||
|
|
||||||
|
if (stats[0].total_tests > 0) {
|
||||||
|
const stat = stats[0]
|
||||||
|
console.log(`總測試次數: ${stat.total_tests}`)
|
||||||
|
console.log(`平均分數: ${Math.round(stat.avg_score)}`)
|
||||||
|
console.log(`最高分數: ${stat.max_score}`)
|
||||||
|
console.log(`最低分數: ${stat.min_score}`)
|
||||||
|
console.log(`高分數 (≥80): ${stat.high_scores}`)
|
||||||
|
console.log(`低分數 (<60): ${stat.low_scores}`)
|
||||||
|
} else {
|
||||||
|
console.log('❌ 沒有測試結果統計')
|
||||||
|
}
|
||||||
|
|
||||||
|
await connection.end()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 檢查失敗:', error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTestResults()
|
43
scripts/check-user-auth.js
Normal file
43
scripts/check-user-auth.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
const checkUserAuth = () => {
|
||||||
|
console.log('👤 檢查用戶認證狀態')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
// 模擬瀏覽器環境檢查 localStorage
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const currentUser = localStorage.getItem("hr_current_user")
|
||||||
|
|
||||||
|
if (currentUser) {
|
||||||
|
try {
|
||||||
|
const user = JSON.parse(currentUser)
|
||||||
|
console.log('✅ 用戶已登入:')
|
||||||
|
console.log('用戶ID:', user.id)
|
||||||
|
console.log('用戶名稱:', user.name)
|
||||||
|
console.log('用戶郵箱:', user.email)
|
||||||
|
console.log('用戶部門:', user.department)
|
||||||
|
console.log('用戶角色:', user.role)
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ 用戶資料解析失敗:', error.message)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('❌ 用戶未登入')
|
||||||
|
console.log('localStorage 中沒有 hr_current_user')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('⚠️ 非瀏覽器環境,無法檢查 localStorage')
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n🔍 檢查要點:')
|
||||||
|
console.log('1. 用戶是否已登入')
|
||||||
|
console.log('2. localStorage 中是否有 hr_current_user')
|
||||||
|
console.log('3. 用戶資料格式是否正確')
|
||||||
|
console.log('4. 用戶ID是否存在')
|
||||||
|
|
||||||
|
console.log('\n💡 如果用戶未登入:')
|
||||||
|
console.log('1. 請先登入系統')
|
||||||
|
console.log('2. 檢查登入功能是否正常')
|
||||||
|
console.log('3. 檢查 localStorage 是否被清除')
|
||||||
|
|
||||||
|
console.log('\n✅ 用戶認證檢查完成')
|
||||||
|
}
|
||||||
|
|
||||||
|
checkUserAuth()
|
48
scripts/check-user-exists.js
Normal file
48
scripts/check-user-exists.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
async function checkUserExists() {
|
||||||
|
const config = {
|
||||||
|
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||||
|
port: parseInt(process.env.DB_PORT || '33306'),
|
||||||
|
user: process.env.DB_USER || 'hr_assessment',
|
||||||
|
password: process.env.DB_PASSWORD || 'QFOts8FlibiI',
|
||||||
|
database: process.env.DB_NAME || 'db_hr_assessment',
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('👤 檢查用戶是否存在')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = await mysql.createConnection(config)
|
||||||
|
|
||||||
|
const userId = 'user-1759073326705-m06y3wacd'
|
||||||
|
console.log('檢查用戶ID:', userId)
|
||||||
|
|
||||||
|
// 檢查用戶是否存在
|
||||||
|
const [users] = await connection.execute('SELECT * FROM users WHERE id = ?', [userId])
|
||||||
|
|
||||||
|
if (users.length > 0) {
|
||||||
|
console.log('✅ 用戶存在:')
|
||||||
|
console.log('ID:', users[0].id)
|
||||||
|
console.log('姓名:', users[0].name)
|
||||||
|
console.log('郵箱:', users[0].email)
|
||||||
|
console.log('部門:', users[0].department)
|
||||||
|
console.log('角色:', users[0].role)
|
||||||
|
} else {
|
||||||
|
console.log('❌ 用戶不存在')
|
||||||
|
|
||||||
|
// 列出所有用戶
|
||||||
|
console.log('\n📋 所有用戶列表:')
|
||||||
|
const [allUsers] = await connection.execute('SELECT id, name, email FROM users LIMIT 10')
|
||||||
|
allUsers.forEach((user, index) => {
|
||||||
|
console.log(`${index + 1}. ID: ${user.id}, 姓名: ${user.name}, 郵箱: ${user.email}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await connection.end()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 檢查失敗:', error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkUserExists()
|
40
scripts/fix-logic-answers-table.js
Normal file
40
scripts/fix-logic-answers-table.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
async function fixLogicAnswersTable() {
|
||||||
|
const config = {
|
||||||
|
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||||
|
port: parseInt(process.env.DB_PORT || '33306'),
|
||||||
|
user: process.env.DB_USER || 'hr_assessment',
|
||||||
|
password: process.env.DB_PASSWORD || 'QFOts8FlibiI',
|
||||||
|
database: process.env.DB_NAME || 'db_hr_assessment',
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🔧 修正 logic_test_answers 表結構...')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = await mysql.createConnection(config)
|
||||||
|
|
||||||
|
// 檢查當前的 user_answer 欄位定義
|
||||||
|
console.log('\n📊 檢查當前 user_answer 欄位定義:')
|
||||||
|
const [columns] = await connection.execute("SHOW COLUMNS FROM logic_test_answers LIKE 'user_answer'")
|
||||||
|
console.log('當前定義:', columns[0])
|
||||||
|
|
||||||
|
// 更新 user_answer 欄位以支援 E 選項
|
||||||
|
console.log('\n🔧 更新 user_answer 欄位以支援 E 選項...')
|
||||||
|
await connection.execute("ALTER TABLE logic_test_answers MODIFY COLUMN user_answer ENUM('A', 'B', 'C', 'D', 'E') NOT NULL")
|
||||||
|
|
||||||
|
console.log('✅ user_answer 欄位更新成功')
|
||||||
|
|
||||||
|
// 驗證更新結果
|
||||||
|
console.log('\n📊 驗證更新結果:')
|
||||||
|
const [updatedColumns] = await connection.execute("SHOW COLUMNS FROM logic_test_answers LIKE 'user_answer'")
|
||||||
|
console.log('更新後定義:', updatedColumns[0])
|
||||||
|
|
||||||
|
await connection.end()
|
||||||
|
console.log('\n✅ logic_test_answers 表修正完成')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 修正失敗:', error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fixLogicAnswersTable()
|
73
scripts/test-api-direct.js
Normal file
73
scripts/test-api-direct.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const testAPIDirect = async () => {
|
||||||
|
console.log('🧪 直接測試 API 路由')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
// 模擬測試數據
|
||||||
|
const testData = {
|
||||||
|
userId: 'user-1759073326705-m06y3wacd',
|
||||||
|
answers: ['A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E'], // 10個答案
|
||||||
|
completedAt: new Date().toISOString().replace('Z', '').replace('T', ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n📝 測試數據:')
|
||||||
|
console.log(JSON.stringify(testData, null, 2))
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('\n🔄 測試 API 路由...')
|
||||||
|
|
||||||
|
// 先測試資料庫連接
|
||||||
|
console.log('1. 測試資料庫連接...')
|
||||||
|
const dbTestResponse = await fetch('http://localhost:3000/api/test-db')
|
||||||
|
if (dbTestResponse.ok) {
|
||||||
|
console.log('✅ 資料庫連接正常')
|
||||||
|
} else {
|
||||||
|
console.log('❌ 資料庫連接失敗')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 測試邏輯測驗 API
|
||||||
|
console.log('\n2. 測試邏輯測驗 API...')
|
||||||
|
const response = await fetch('http://localhost:3000/api/test-results/logic', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(testData)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('📊 響應狀態:', response.status)
|
||||||
|
console.log('📊 響應狀態文字:', response.statusText)
|
||||||
|
|
||||||
|
let result
|
||||||
|
try {
|
||||||
|
const text = await response.text()
|
||||||
|
console.log('📊 原始響應:', text)
|
||||||
|
result = JSON.parse(text)
|
||||||
|
console.log('📊 解析後響應:', JSON.stringify(result, null, 2))
|
||||||
|
} catch (parseError) {
|
||||||
|
console.log('❌ JSON 解析失敗:', parseError.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
console.log('\n✅ API 測試成功!')
|
||||||
|
} else {
|
||||||
|
console.log('\n❌ API 測試失敗!')
|
||||||
|
console.log('錯誤訊息:', result.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('\n❌ 請求失敗:')
|
||||||
|
console.log('錯誤類型:', error.name)
|
||||||
|
console.log('錯誤訊息:', error.message)
|
||||||
|
|
||||||
|
if (error.code === 'ECONNREFUSED') {
|
||||||
|
console.log('\n💡 建議:')
|
||||||
|
console.log('1. 確保開發伺服器正在運行 (npm run dev)')
|
||||||
|
console.log('2. 檢查端口 3000 是否可用')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n✅ API 直接測試完成')
|
||||||
|
}
|
||||||
|
|
||||||
|
testAPIDirect()
|
72
scripts/test-create-result.js
Normal file
72
scripts/test-create-result.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
async function testCreateResult() {
|
||||||
|
const config = {
|
||||||
|
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||||
|
port: parseInt(process.env.DB_PORT || '33306'),
|
||||||
|
user: process.env.DB_USER || 'hr_assessment',
|
||||||
|
password: process.env.DB_PASSWORD || 'QFOts8FlibiI',
|
||||||
|
database: process.env.DB_NAME || 'db_hr_assessment',
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🧪 測試 createTestResult 函數')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = await mysql.createConnection(config)
|
||||||
|
|
||||||
|
// 模擬 createTestResult 函數的邏輯
|
||||||
|
const testResultData = {
|
||||||
|
user_id: 'user-1759073326705-m06y3wacd',
|
||||||
|
test_type: 'logic',
|
||||||
|
score: 80,
|
||||||
|
total_questions: 10,
|
||||||
|
correct_answers: 8,
|
||||||
|
completed_at: new Date().toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('測試數據:', testResultData)
|
||||||
|
|
||||||
|
const id = `test_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||||
|
console.log('生成的ID:', id)
|
||||||
|
|
||||||
|
const insertQuery = `
|
||||||
|
INSERT INTO test_results (
|
||||||
|
id, user_id, test_type, score, total_questions,
|
||||||
|
correct_answers, completed_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
|
||||||
|
const insertData = [
|
||||||
|
id,
|
||||||
|
testResultData.user_id,
|
||||||
|
testResultData.test_type,
|
||||||
|
testResultData.score,
|
||||||
|
testResultData.total_questions,
|
||||||
|
testResultData.correct_answers,
|
||||||
|
testResultData.completed_at
|
||||||
|
]
|
||||||
|
|
||||||
|
console.log('插入數據:', insertData)
|
||||||
|
|
||||||
|
await connection.execute(insertQuery, insertData)
|
||||||
|
console.log('✅ 插入成功')
|
||||||
|
|
||||||
|
// 驗證插入結果
|
||||||
|
const [results] = await connection.execute('SELECT * FROM test_results WHERE id = ?', [id])
|
||||||
|
console.log('插入結果:', results[0])
|
||||||
|
|
||||||
|
// 清理測試數據
|
||||||
|
await connection.execute('DELETE FROM test_results WHERE id = ?', [id])
|
||||||
|
console.log('✅ 測試數據已清理')
|
||||||
|
|
||||||
|
await connection.end()
|
||||||
|
console.log('\n✅ createTestResult 測試成功')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 測試失敗:', error.message)
|
||||||
|
console.error('錯誤詳情:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testCreateResult()
|
73
scripts/test-db-models.js
Normal file
73
scripts/test-db-models.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const testDBModels = async () => {
|
||||||
|
console.log('🧪 測試資料庫模型')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 動態導入 ES 模組
|
||||||
|
const testResultModule = await import('../lib/database/models/test_result.ts')
|
||||||
|
const logicAnswerModule = await import('../lib/database/models/logic_test_answer.ts')
|
||||||
|
const logicQuestionModule = await import('../lib/database/models/logic_question.ts')
|
||||||
|
|
||||||
|
console.log('✅ 成功導入資料庫模型')
|
||||||
|
console.log('testResultModule exports:', Object.keys(testResultModule))
|
||||||
|
console.log('logicAnswerModule exports:', Object.keys(logicAnswerModule))
|
||||||
|
console.log('logicQuestionModule exports:', Object.keys(logicQuestionModule))
|
||||||
|
|
||||||
|
const { createTestResult } = testResultModule
|
||||||
|
const { createLogicTestAnswers } = logicAnswerModule
|
||||||
|
const { getAllLogicQuestions } = logicQuestionModule
|
||||||
|
|
||||||
|
// 測試獲取邏輯題目
|
||||||
|
console.log('\n📝 測試獲取邏輯題目...')
|
||||||
|
const questions = await getAllLogicQuestions()
|
||||||
|
console.log(`找到 ${questions.length} 題邏輯題目`)
|
||||||
|
|
||||||
|
if (questions.length > 0) {
|
||||||
|
console.log('第一題:', {
|
||||||
|
id: questions[0].id,
|
||||||
|
question: questions[0].question.substring(0, 50) + '...',
|
||||||
|
correct_answer: questions[0].correct_answer
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 測試建立測試結果
|
||||||
|
console.log('\n📊 測試建立測試結果...')
|
||||||
|
const testResultData = {
|
||||||
|
user_id: 'test_user_123',
|
||||||
|
test_type: 'logic',
|
||||||
|
score: 80,
|
||||||
|
total_questions: 10,
|
||||||
|
correct_answers: 8,
|
||||||
|
completed_at: new Date().toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
|
const testResult = await createTestResult(testResultData)
|
||||||
|
if (testResult) {
|
||||||
|
console.log('✅ 測試結果建立成功:', testResult.id)
|
||||||
|
|
||||||
|
// 測試建立答案記錄
|
||||||
|
console.log('\n📝 測試建立答案記錄...')
|
||||||
|
const answerData = [
|
||||||
|
{
|
||||||
|
test_result_id: testResult.id,
|
||||||
|
question_id: questions[0].id,
|
||||||
|
user_answer: 'A',
|
||||||
|
is_correct: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const answers = await createLogicTestAnswers(answerData)
|
||||||
|
console.log(`✅ 答案記錄建立成功: ${answers.length} 筆`)
|
||||||
|
} else {
|
||||||
|
console.log('❌ 測試結果建立失敗')
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ 測試失敗:', error.message)
|
||||||
|
console.log('錯誤詳情:', error.stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n✅ 資料庫模型測試完成')
|
||||||
|
}
|
||||||
|
|
||||||
|
testDBModels()
|
101
scripts/test-direct-insert.js
Normal file
101
scripts/test-direct-insert.js
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
async function testDirectInsert() {
|
||||||
|
const config = {
|
||||||
|
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||||
|
port: parseInt(process.env.DB_PORT || '33306'),
|
||||||
|
user: process.env.DB_USER || 'hr_assessment',
|
||||||
|
password: process.env.DB_PASSWORD || 'QFOts8FlibiI',
|
||||||
|
database: process.env.DB_NAME || 'db_hr_assessment',
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🧪 直接測試資料庫插入')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = await mysql.createConnection(config)
|
||||||
|
|
||||||
|
// 測試插入 test_results
|
||||||
|
console.log('\n📊 測試插入 test_results...')
|
||||||
|
const testResultId = `test_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||||
|
|
||||||
|
const insertTestResultQuery = `
|
||||||
|
INSERT INTO test_results (
|
||||||
|
id, user_id, test_type, score, total_questions,
|
||||||
|
correct_answers, completed_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
|
||||||
|
const testResultData = [
|
||||||
|
testResultId,
|
||||||
|
'test_user_123',
|
||||||
|
'logic',
|
||||||
|
80,
|
||||||
|
10,
|
||||||
|
8,
|
||||||
|
new Date().toISOString()
|
||||||
|
]
|
||||||
|
|
||||||
|
console.log('插入數據:', testResultData)
|
||||||
|
|
||||||
|
await connection.execute(insertTestResultQuery, testResultData)
|
||||||
|
console.log('✅ test_results 插入成功')
|
||||||
|
|
||||||
|
// 測試插入 logic_test_answers
|
||||||
|
console.log('\n📝 測試插入 logic_test_answers...')
|
||||||
|
|
||||||
|
// 先獲取一個題目ID
|
||||||
|
const [questions] = await connection.execute('SELECT id FROM logic_questions LIMIT 1')
|
||||||
|
if (questions.length === 0) {
|
||||||
|
console.log('❌ 沒有找到邏輯題目')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const questionId = questions[0].id
|
||||||
|
console.log('使用題目ID:', questionId)
|
||||||
|
|
||||||
|
const answerId = `answer_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||||
|
|
||||||
|
const insertAnswerQuery = `
|
||||||
|
INSERT INTO logic_test_answers (
|
||||||
|
id, test_result_id, question_id, user_answer, is_correct
|
||||||
|
) VALUES (?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
|
||||||
|
const answerData = [
|
||||||
|
answerId,
|
||||||
|
testResultId,
|
||||||
|
questionId,
|
||||||
|
'A',
|
||||||
|
1
|
||||||
|
]
|
||||||
|
|
||||||
|
console.log('插入答案數據:', answerData)
|
||||||
|
|
||||||
|
await connection.execute(insertAnswerQuery, answerData)
|
||||||
|
console.log('✅ logic_test_answers 插入成功')
|
||||||
|
|
||||||
|
// 驗證插入結果
|
||||||
|
console.log('\n🔍 驗證插入結果...')
|
||||||
|
const [testResults] = await connection.execute('SELECT * FROM test_results WHERE id = ?', [testResultId])
|
||||||
|
console.log('test_results 記錄:', testResults[0])
|
||||||
|
|
||||||
|
const [answers] = await connection.execute('SELECT * FROM logic_test_answers WHERE id = ?', [answerId])
|
||||||
|
console.log('logic_test_answers 記錄:', answers[0])
|
||||||
|
|
||||||
|
// 清理測試數據
|
||||||
|
console.log('\n🧹 清理測試數據...')
|
||||||
|
await connection.execute('DELETE FROM logic_test_answers WHERE id = ?', [answerId])
|
||||||
|
await connection.execute('DELETE FROM test_results WHERE id = ?', [testResultId])
|
||||||
|
console.log('✅ 測試數據已清理')
|
||||||
|
|
||||||
|
await connection.end()
|
||||||
|
console.log('\n✅ 直接插入測試成功')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 插入測試失敗:', error.message)
|
||||||
|
console.error('錯誤詳情:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testDirectInsert()
|
66
scripts/test-logic-api.js
Normal file
66
scripts/test-logic-api.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
const testLogicAPI = async () => {
|
||||||
|
console.log('🧪 測試邏輯測驗 API')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
// 模擬測試數據
|
||||||
|
const testData = {
|
||||||
|
userId: 'test_user_123',
|
||||||
|
answers: ['A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E'], // 10個答案
|
||||||
|
completedAt: new Date().toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n📝 測試數據:')
|
||||||
|
console.log('用戶ID:', testData.userId)
|
||||||
|
console.log('答案數量:', testData.answers.length)
|
||||||
|
console.log('完成時間:', testData.completedAt)
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('\n🔄 發送 POST 請求到 /api/test-results/logic...')
|
||||||
|
|
||||||
|
const response = await fetch('http://localhost:3000/api/test-results/logic', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(testData)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('📊 響應狀態:', response.status)
|
||||||
|
console.log('📊 響應狀態文字:', response.statusText)
|
||||||
|
|
||||||
|
const result = await response.json()
|
||||||
|
console.log('📊 響應內容:', JSON.stringify(result, null, 2))
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
console.log('\n✅ API 測試成功!')
|
||||||
|
console.log('測試結果ID:', result.data.testResult.id)
|
||||||
|
console.log('答案記錄數量:', result.data.answerCount)
|
||||||
|
} else {
|
||||||
|
console.log('\n❌ API 測試失敗!')
|
||||||
|
console.log('錯誤訊息:', result.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('\n❌ 請求失敗:')
|
||||||
|
console.log('錯誤類型:', error.name)
|
||||||
|
console.log('錯誤訊息:', error.message)
|
||||||
|
|
||||||
|
if (error.code === 'ECONNREFUSED') {
|
||||||
|
console.log('\n💡 建議:')
|
||||||
|
console.log('1. 確保開發伺服器正在運行 (npm run dev)')
|
||||||
|
console.log('2. 檢查端口 3000 是否可用')
|
||||||
|
console.log('3. 檢查防火牆設定')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n🔍 檢查要點:')
|
||||||
|
console.log('1. 開發伺服器是否運行')
|
||||||
|
console.log('2. API 路由是否正確')
|
||||||
|
console.log('3. 資料庫連接是否正常')
|
||||||
|
console.log('4. 用戶認證是否有效')
|
||||||
|
console.log('5. 資料庫表是否存在')
|
||||||
|
|
||||||
|
console.log('\n✅ 邏輯測驗 API 測試完成')
|
||||||
|
}
|
||||||
|
|
||||||
|
testLogicAPI()
|
100
scripts/test-logic-db-upload.js
Normal file
100
scripts/test-logic-db-upload.js
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
const testLogicDbUpload = () => {
|
||||||
|
console.log('🧠 邏輯測驗資料庫上傳功能測試')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
console.log('\n📊 資料庫表結構分析:')
|
||||||
|
console.log('test_results 表:')
|
||||||
|
console.log('- id: varchar(50) PRIMARY KEY')
|
||||||
|
console.log('- user_id: varchar(50) NOT NULL')
|
||||||
|
console.log('- test_type: enum("logic","creative","combined") NOT NULL')
|
||||||
|
console.log('- score: int NOT NULL')
|
||||||
|
console.log('- total_questions: int NOT NULL')
|
||||||
|
console.log('- correct_answers: int NOT NULL')
|
||||||
|
console.log('- completed_at: timestamp NOT NULL')
|
||||||
|
console.log('- created_at: timestamp DEFAULT CURRENT_TIMESTAMP')
|
||||||
|
|
||||||
|
console.log('\nlogic_test_answers 表:')
|
||||||
|
console.log('- id: varchar(50) PRIMARY KEY')
|
||||||
|
console.log('- test_result_id: varchar(50) NOT NULL (FK to test_results)')
|
||||||
|
console.log('- question_id: int NOT NULL (FK to logic_questions)')
|
||||||
|
console.log('- user_answer: enum("A","B","C","D","E") NOT NULL')
|
||||||
|
console.log('- is_correct: tinyint(1) NOT NULL')
|
||||||
|
console.log('- created_at: timestamp DEFAULT CURRENT_TIMESTAMP')
|
||||||
|
|
||||||
|
console.log('\n🔧 已實現的功能:')
|
||||||
|
console.log('1. ✅ 資料庫模型檔案:')
|
||||||
|
console.log(' - lib/database/models/test_result.ts')
|
||||||
|
console.log(' - lib/database/models/logic_test_answer.ts')
|
||||||
|
console.log(' - 包含 CRUD 操作和關聯查詢')
|
||||||
|
|
||||||
|
console.log('\n2. ✅ API 路由:')
|
||||||
|
console.log(' - app/api/test-results/logic/route.ts')
|
||||||
|
console.log(' - POST: 上傳邏輯測驗結果')
|
||||||
|
console.log(' - GET: 獲取用戶邏輯測驗結果')
|
||||||
|
|
||||||
|
console.log('\n3. ✅ 前端整合:')
|
||||||
|
console.log(' - 修改 app/tests/logic/page.tsx')
|
||||||
|
console.log(' - 添加用戶認證檢查')
|
||||||
|
console.log(' - 添加資料庫上傳功能')
|
||||||
|
console.log(' - 保持 localStorage 向後兼容')
|
||||||
|
|
||||||
|
console.log('\n📝 上傳流程:')
|
||||||
|
console.log('1. 用戶完成邏輯測驗')
|
||||||
|
console.log('2. 計算分數和正確答案數')
|
||||||
|
console.log('3. 儲存到 localStorage (向後兼容)')
|
||||||
|
console.log('4. 上傳到資料庫:')
|
||||||
|
console.log(' - 建立 test_results 記錄')
|
||||||
|
console.log(' - 建立 logic_test_answers 記錄')
|
||||||
|
console.log('5. 跳轉到結果頁面')
|
||||||
|
|
||||||
|
console.log('\n🎯 資料庫上傳內容:')
|
||||||
|
console.log('test_results 記錄:')
|
||||||
|
console.log('- user_id: 用戶ID')
|
||||||
|
console.log('- test_type: "logic"')
|
||||||
|
console.log('- score: 分數 (0-100)')
|
||||||
|
console.log('- total_questions: 總題數')
|
||||||
|
console.log('- correct_answers: 答對題數')
|
||||||
|
console.log('- completed_at: 完成時間')
|
||||||
|
|
||||||
|
console.log('\nlogic_test_answers 記錄:')
|
||||||
|
console.log('- test_result_id: 測試結果ID')
|
||||||
|
console.log('- question_id: 題目ID')
|
||||||
|
console.log('- user_answer: 用戶答案 (A-E)')
|
||||||
|
console.log('- is_correct: 是否正確 (0/1)')
|
||||||
|
|
||||||
|
console.log('\n🔍 錯誤處理:')
|
||||||
|
console.log('- 用戶未登入: 顯示提示並停止')
|
||||||
|
console.log('- 上傳失敗: 記錄錯誤但繼續顯示結果')
|
||||||
|
console.log('- 網路錯誤: 顯示錯誤訊息')
|
||||||
|
console.log('- 資料庫錯誤: 記錄到控制台')
|
||||||
|
|
||||||
|
console.log('\n📱 用戶體驗:')
|
||||||
|
console.log('- 提交按鈕顯示載入狀態')
|
||||||
|
console.log('- 防止重複提交')
|
||||||
|
console.log('- 保持原有功能不變')
|
||||||
|
console.log('- 向後兼容 localStorage')
|
||||||
|
|
||||||
|
console.log('\n🧪 測試要點:')
|
||||||
|
console.log('1. 用戶登入狀態檢查')
|
||||||
|
console.log('2. 測驗結果計算正確性')
|
||||||
|
console.log('3. 資料庫記錄建立')
|
||||||
|
console.log('4. 答案記錄關聯')
|
||||||
|
console.log('5. 錯誤處理機制')
|
||||||
|
console.log('6. 向後兼容性')
|
||||||
|
|
||||||
|
console.log('\n✅ 預期結果:')
|
||||||
|
console.log('- 用戶完成測驗後,結果自動上傳到資料庫')
|
||||||
|
console.log('- 管理員可以在後台查看所有測試結果')
|
||||||
|
console.log('- 支援詳細的答案分析')
|
||||||
|
console.log('- 保持現有功能正常運作')
|
||||||
|
|
||||||
|
console.log('\n🚀 下一步:')
|
||||||
|
console.log('1. 測試實際的資料庫上傳功能')
|
||||||
|
console.log('2. 驗證資料完整性和正確性')
|
||||||
|
console.log('3. 檢查管理員後台顯示')
|
||||||
|
console.log('4. 考慮添加創意測驗和綜合測驗上傳')
|
||||||
|
|
||||||
|
console.log('\n✅ 邏輯測驗資料庫上傳功能測試完成')
|
||||||
|
}
|
||||||
|
|
||||||
|
testLogicDbUpload()
|
73
scripts/test-multi-type-results.js
Normal file
73
scripts/test-multi-type-results.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const https = require('https')
|
||||||
|
const http = require('http')
|
||||||
|
|
||||||
|
const testMultiTypeResults = async () => {
|
||||||
|
console.log('🧪 測試多種類型測試結果的計算邏輯')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
// 測試用戶 user-1759073650899-9c5yx0gjn (目前只有邏輯題)
|
||||||
|
const userId = 'user-1759073650899-9c5yx0gjn'
|
||||||
|
const url = `http://localhost:3000/api/user/test-results?userId=${userId}`
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`\n📊 測試用戶ID: ${userId}`)
|
||||||
|
console.log(`🔗 API URL: ${url}`)
|
||||||
|
|
||||||
|
const response = await new Promise((resolve, reject) => {
|
||||||
|
const req = http.get(url, (res) => {
|
||||||
|
let data = ''
|
||||||
|
res.on('data', chunk => data += chunk)
|
||||||
|
res.on('end', () => resolve({ status: res.statusCode, data }))
|
||||||
|
})
|
||||||
|
req.on('error', reject)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('📊 響應狀態:', response.status)
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
const result = JSON.parse(response.data)
|
||||||
|
console.log('\n✅ API 測試成功!')
|
||||||
|
|
||||||
|
console.log(`\n📈 統計數據:`)
|
||||||
|
console.log(`- 總測試次數: ${result.data.stats.totalTests}`)
|
||||||
|
console.log(`- 平均分數: ${result.data.stats.averageScore}`)
|
||||||
|
console.log(`- 最高分數: ${result.data.stats.bestScore}`)
|
||||||
|
console.log(`- 最近測試: ${result.data.stats.lastTestDate}`)
|
||||||
|
console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`)
|
||||||
|
console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`)
|
||||||
|
console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`)
|
||||||
|
|
||||||
|
console.log(`\n📋 測試結果 (${result.data.results.length} 個):`)
|
||||||
|
result.data.results.forEach((testResult, index) => {
|
||||||
|
console.log(`${index + 1}. ${testResult.type} - 分數: ${testResult.score}, 測驗次數: ${testResult.testCount || 1}`)
|
||||||
|
console.log(` 完成時間: ${testResult.completedAt}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 驗證計算邏輯
|
||||||
|
console.log(`\n🧮 驗證計算邏輯:`)
|
||||||
|
console.log(`目前只有邏輯題有最新結果: 70分`)
|
||||||
|
console.log(`- 完成測試: 1次 (只有邏輯題有最新結果)`)
|
||||||
|
console.log(`- 平均分數: 70分 (70/1)`)
|
||||||
|
console.log(`- 最高分數: 70分 (70)`)
|
||||||
|
|
||||||
|
console.log(`\n💡 假設有多種類型測試:`)
|
||||||
|
console.log(`- 邏輯題最新: 70分`)
|
||||||
|
console.log(`- 創意題最新: 80分`)
|
||||||
|
console.log(`- 綜合題最新: 60分`)
|
||||||
|
console.log(`- 完成測試: 3次 (3種類型都有最新結果)`)
|
||||||
|
console.log(`- 平均分數: 70分 ((70+80+60)/3)`)
|
||||||
|
console.log(`- 最高分數: 80分 (創意題)`)
|
||||||
|
} else {
|
||||||
|
console.log('❌ API 響應失敗,狀態碼:', response.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('\n❌ 請求失敗:')
|
||||||
|
console.error('錯誤類型:', error.name)
|
||||||
|
console.error('錯誤訊息:', error.message)
|
||||||
|
} finally {
|
||||||
|
console.log('\n✅ 多種類型測試結果計算邏輯測試完成')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testMultiTypeResults()
|
64
scripts/test-other-user-results.js
Normal file
64
scripts/test-other-user-results.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
const https = require('https')
|
||||||
|
const http = require('http')
|
||||||
|
|
||||||
|
const testOtherUserResults = async () => {
|
||||||
|
console.log('🧪 測試其他用戶的測試結果')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
// 測試用戶 user-1759073650899-9c5yx0gjn (有70分和50分的測試)
|
||||||
|
const userId = 'user-1759073650899-9c5yx0gjn'
|
||||||
|
const url = `http://localhost:3000/api/user/test-results?userId=${userId}`
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`\n📊 測試用戶ID: ${userId}`)
|
||||||
|
console.log(`🔗 API URL: ${url}`)
|
||||||
|
|
||||||
|
const response = await new Promise((resolve, reject) => {
|
||||||
|
const req = http.get(url, (res) => {
|
||||||
|
let data = ''
|
||||||
|
res.on('data', chunk => data += chunk)
|
||||||
|
res.on('end', () => resolve({ status: res.statusCode, data }))
|
||||||
|
})
|
||||||
|
req.on('error', reject)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('📊 響應狀態:', response.status)
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
const result = JSON.parse(response.data)
|
||||||
|
console.log('\n✅ API 測試成功!')
|
||||||
|
|
||||||
|
console.log(`\n📈 統計數據:`)
|
||||||
|
console.log(`- 總測試次數: ${result.data.stats.totalTests}`)
|
||||||
|
console.log(`- 平均分數: ${result.data.stats.averageScore}`)
|
||||||
|
console.log(`- 最高分數: ${result.data.stats.bestScore}`)
|
||||||
|
console.log(`- 最近測試: ${result.data.stats.lastTestDate}`)
|
||||||
|
console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`)
|
||||||
|
console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`)
|
||||||
|
console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`)
|
||||||
|
|
||||||
|
console.log(`\n📋 測試結果 (${result.data.results.length} 個):`)
|
||||||
|
result.data.results.forEach((testResult, index) => {
|
||||||
|
console.log(`${index + 1}. ${testResult.type} - 分數: ${testResult.score}, 測驗次數: ${testResult.testCount || 1}`)
|
||||||
|
console.log(` 完成時間: ${testResult.completedAt}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 手動驗證平均分數計算
|
||||||
|
console.log(`\n🧮 手動驗證平均分數計算:`)
|
||||||
|
console.log(`用戶 ${userId} 的測試分數: 70, 50`)
|
||||||
|
console.log(`手動計算平均: (70 + 50) / 2 = ${(70 + 50) / 2}`)
|
||||||
|
console.log(`API 返回平均: ${result.data.stats.averageScore}`)
|
||||||
|
} else {
|
||||||
|
console.log('❌ API 響應失敗,狀態碼:', response.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('\n❌ 請求失敗:')
|
||||||
|
console.error('錯誤類型:', error.name)
|
||||||
|
console.error('錯誤訊息:', error.message)
|
||||||
|
} finally {
|
||||||
|
console.log('\n✅ 其他用戶測試結果 API 測試完成')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testOtherUserResults()
|
61
scripts/test-simple-insert.js
Normal file
61
scripts/test-simple-insert.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
async function testSimpleInsert() {
|
||||||
|
const config = {
|
||||||
|
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||||
|
port: parseInt(process.env.DB_PORT || '33306'),
|
||||||
|
user: process.env.DB_USER || 'hr_assessment',
|
||||||
|
password: process.env.DB_PASSWORD || 'QFOts8FlibiI',
|
||||||
|
database: process.env.DB_NAME || 'db_hr_assessment',
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🧪 簡單插入測試')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = await mysql.createConnection(config)
|
||||||
|
|
||||||
|
const id = `test_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||||
|
console.log('生成的ID:', id)
|
||||||
|
|
||||||
|
// 直接插入
|
||||||
|
const insertQuery = `
|
||||||
|
INSERT INTO test_results (
|
||||||
|
id, user_id, test_type, score, total_questions,
|
||||||
|
correct_answers, completed_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
|
||||||
|
const insertData = [
|
||||||
|
id,
|
||||||
|
'user-1759073326705-m06y3wacd',
|
||||||
|
'logic',
|
||||||
|
80,
|
||||||
|
10,
|
||||||
|
8,
|
||||||
|
new Date().toISOString()
|
||||||
|
]
|
||||||
|
|
||||||
|
console.log('插入數據:', insertData)
|
||||||
|
|
||||||
|
const [result] = await connection.execute(insertQuery, insertData)
|
||||||
|
console.log('插入結果:', result)
|
||||||
|
|
||||||
|
// 查詢插入的數據
|
||||||
|
const [rows] = await connection.execute('SELECT * FROM test_results WHERE id = ?', [id])
|
||||||
|
console.log('查詢結果:', rows[0])
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
await connection.execute('DELETE FROM test_results WHERE id = ?', [id])
|
||||||
|
console.log('✅ 清理完成')
|
||||||
|
|
||||||
|
await connection.end()
|
||||||
|
console.log('✅ 測試成功')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 測試失敗:', error.message)
|
||||||
|
console.error('錯誤詳情:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testSimpleInsert()
|
21
scripts/test-taiwan-time.js
Normal file
21
scripts/test-taiwan-time.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// 測試台灣時間顯示
|
||||||
|
const testTime = "2025-09-28T10:35:12.000Z"
|
||||||
|
|
||||||
|
console.log('🧪 測試台灣時間顯示')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
console.log('\n📅 原始時間 (UTC):', testTime)
|
||||||
|
|
||||||
|
// 測試不同的時間格式
|
||||||
|
const date = new Date(testTime)
|
||||||
|
|
||||||
|
console.log('\n🌏 台灣時間格式:')
|
||||||
|
console.log('1. 完整日期時間:', date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }))
|
||||||
|
console.log('2. 只有日期:', date.toLocaleDateString("zh-TW", { timeZone: "Asia/Taipei" }))
|
||||||
|
console.log('3. 只有時間:', date.toLocaleTimeString("zh-TW", { timeZone: "Asia/Taipei" }))
|
||||||
|
|
||||||
|
console.log('\n📊 比較 (無時區 vs 台灣時區):')
|
||||||
|
console.log('無時區:', date.toLocaleString("zh-TW"))
|
||||||
|
console.log('台灣時區:', date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }))
|
||||||
|
|
||||||
|
console.log('\n✅ 測試完成')
|
57
scripts/test-user-results-api.js
Normal file
57
scripts/test-user-results-api.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
const fetch = require('node-fetch')
|
||||||
|
|
||||||
|
const testUserResultsAPI = async () => {
|
||||||
|
console.log('🧪 測試用戶測試結果 API')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
const userId = 'user-1759073326705-m06y3wacd' // 使用現有用戶ID
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`\n📊 測試用戶ID: ${userId}`)
|
||||||
|
|
||||||
|
const response = await fetch(`http://localhost:3000/api/user/test-results?userId=${userId}`)
|
||||||
|
|
||||||
|
console.log('📊 響應狀態:', response.status)
|
||||||
|
console.log('📊 響應狀態文字:', response.statusText)
|
||||||
|
|
||||||
|
let result
|
||||||
|
try {
|
||||||
|
const text = await response.text()
|
||||||
|
console.log('📊 原始響應:', text)
|
||||||
|
result = JSON.parse(text)
|
||||||
|
console.log('📊 解析後響應:', JSON.stringify(result, null, 2))
|
||||||
|
} catch (parseError) {
|
||||||
|
console.log('❌ JSON 解析失敗:', parseError.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
console.log('\n✅ API 測試成功!')
|
||||||
|
console.log(`📈 統計數據:`)
|
||||||
|
console.log(`- 總測試次數: ${result.data.stats.totalTests}`)
|
||||||
|
console.log(`- 平均分數: ${result.data.stats.averageScore}`)
|
||||||
|
console.log(`- 最高分數: ${result.data.stats.bestScore}`)
|
||||||
|
console.log(`- 最近測試: ${result.data.stats.lastTestDate}`)
|
||||||
|
console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`)
|
||||||
|
console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`)
|
||||||
|
console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`)
|
||||||
|
|
||||||
|
console.log(`\n📋 測試結果 (${result.data.results.length} 個):`)
|
||||||
|
result.data.results.forEach((result, index) => {
|
||||||
|
console.log(`${index + 1}. ${result.type} - 分數: ${result.score}, 測驗次數: ${result.testCount || 1}`)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('\n❌ API 測試失敗!')
|
||||||
|
console.log('錯誤訊息:', result.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('\n❌ 請求失敗:')
|
||||||
|
console.error('錯誤類型:', error.name)
|
||||||
|
console.error('錯誤訊息:', error.message)
|
||||||
|
} finally {
|
||||||
|
console.log('\n✅ 用戶測試結果 API 測試完成')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testUserResultsAPI()
|
57
scripts/test-user-results-detailed.js
Normal file
57
scripts/test-user-results-detailed.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
const https = require('https')
|
||||||
|
const http = require('http')
|
||||||
|
|
||||||
|
const testUserResultsAPI = async () => {
|
||||||
|
console.log('🧪 測試用戶測試結果 API (詳細版)')
|
||||||
|
console.log('=' .repeat(50))
|
||||||
|
|
||||||
|
const userId = 'user-1759073326705-m06y3wacd'
|
||||||
|
const url = `http://localhost:3000/api/user/test-results?userId=${userId}`
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`\n📊 測試用戶ID: ${userId}`)
|
||||||
|
console.log(`🔗 API URL: ${url}`)
|
||||||
|
|
||||||
|
const response = await new Promise((resolve, reject) => {
|
||||||
|
const req = http.get(url, (res) => {
|
||||||
|
let data = ''
|
||||||
|
res.on('data', chunk => data += chunk)
|
||||||
|
res.on('end', () => resolve({ status: res.statusCode, data }))
|
||||||
|
})
|
||||||
|
req.on('error', reject)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('📊 響應狀態:', response.status)
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
const result = JSON.parse(response.data)
|
||||||
|
console.log('\n✅ API 測試成功!')
|
||||||
|
|
||||||
|
console.log(`\n📈 統計數據:`)
|
||||||
|
console.log(`- 總測試次數: ${result.data.stats.totalTests}`)
|
||||||
|
console.log(`- 平均分數: ${result.data.stats.averageScore}`)
|
||||||
|
console.log(`- 最高分數: ${result.data.stats.bestScore}`)
|
||||||
|
console.log(`- 最近測試: ${result.data.stats.lastTestDate}`)
|
||||||
|
console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`)
|
||||||
|
console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`)
|
||||||
|
console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`)
|
||||||
|
|
||||||
|
console.log(`\n📋 測試結果 (${result.data.results.length} 個):`)
|
||||||
|
result.data.results.forEach((testResult, index) => {
|
||||||
|
console.log(`${index + 1}. ${testResult.type} - 分數: ${testResult.score}, 測驗次數: ${testResult.testCount || 1}`)
|
||||||
|
console.log(` 完成時間: ${testResult.completedAt}`)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('❌ API 響應失敗,狀態碼:', response.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('\n❌ 請求失敗:')
|
||||||
|
console.error('錯誤類型:', error.name)
|
||||||
|
console.error('錯誤訊息:', error.message)
|
||||||
|
} finally {
|
||||||
|
console.log('\n✅ 用戶測試結果 API 測試完成')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testUserResultsAPI()
|
Reference in New Issue
Block a user