diff --git a/app/admin/results/detail/[testResultId]/page.tsx b/app/admin/results/detail/[testResultId]/page.tsx
index d283e2e..d3adce6 100644
--- a/app/admin/results/detail/[testResultId]/page.tsx
+++ b/app/admin/results/detail/[testResultId]/page.tsx
@@ -26,6 +26,7 @@ interface TestResult {
type: "logic" | "creative" | "combined"
score: number
completedAt: string
+ isTimeout?: boolean
details?: {
logicScore?: number
creativeScore?: number
@@ -437,11 +438,18 @@ function AdminResultDetailContent() {
>
{result.score}
- 邏輯測試完成!
+
+ 邏輯測試{result.isTimeout ? '(時間到)' : ''}完成!
+
{scoreLevel.level}
+ {result.isTimeout && (
+
+ 時間到強制提交
+
+ )}
{scoreLevel.description}
@@ -482,11 +490,18 @@ function AdminResultDetailContent() {
>
{result.score}
- 創意測試完成!
+
+ 創意測試{result.isTimeout ? '(時間到)' : ''}完成!
+
{scoreLevel.level}
+ {result.isTimeout && (
+
+ 時間到強制提交
+
+ )}
{scoreLevel.description}
diff --git a/app/api/admin/test-results/detail/route.ts b/app/api/admin/test-results/detail/route.ts
index ce4ed7c..8b2aaa8 100644
--- a/app/api/admin/test-results/detail/route.ts
+++ b/app/api/admin/test-results/detail/route.ts
@@ -37,6 +37,7 @@ export async function GET(request: NextRequest) {
type: "combined",
score: combinedResult.overall_score,
completedAt: combinedResult.completed_at,
+ isTimeout: combinedResult.is_timeout || false,
details: {
logicScore: combinedResult.logic_score,
creativeScore: combinedResult.creativity_score,
diff --git a/app/api/test-results/combined/route.ts b/app/api/test-results/combined/route.ts
index eaab2a2..27f5444 100644
--- a/app/api/test-results/combined/route.ts
+++ b/app/api/test-results/combined/route.ts
@@ -15,7 +15,8 @@ export async function POST(request: NextRequest) {
logicBreakdown,
creativityBreakdown,
balanceScore,
- completedAt
+ completedAt,
+ isTimeout = false
} = body
// 驗證必要欄位
@@ -51,7 +52,8 @@ export async function POST(request: NextRequest) {
logic_breakdown: logicBreakdown || null,
creativity_breakdown: creativityBreakdown || null,
balance_score: balanceScore || 0,
- completed_at: mysqlCompletedAt
+ completed_at: mysqlCompletedAt,
+ is_timeout: isTimeout
})
if (!testResult) {
diff --git a/app/api/test-results/logic/route.ts b/app/api/test-results/logic/route.ts
index 2e4a697..95f8029 100644
--- a/app/api/test-results/logic/route.ts
+++ b/app/api/test-results/logic/route.ts
@@ -6,10 +6,11 @@ import { getAllLogicQuestions } from '@/lib/database/models/logic_question'
export async function POST(request: NextRequest) {
try {
const body = await request.json()
- const {
+ const {
userId,
answers,
- completedAt
+ completedAt,
+ isTimeout = false
} = body
// 驗證必要欄位
@@ -75,7 +76,8 @@ export async function POST(request: NextRequest) {
score: score,
total_questions: questions.length,
correct_answers: correctAnswers,
- completed_at: mysqlCompletedAt
+ completed_at: mysqlCompletedAt,
+ is_timeout: isTimeout
})
console.log('測試結果建立結果:', testResult)
diff --git a/app/tests/combined/page.tsx b/app/tests/combined/page.tsx
index d712e7d..ad10cd0 100644
--- a/app/tests/combined/page.tsx
+++ b/app/tests/combined/page.tsx
@@ -41,7 +41,8 @@ export default function CombinedTestPage() {
const [currentQuestion, setCurrentQuestion] = useState(0)
const [logicAnswers, setLogicAnswers] = useState>({})
const [creativeAnswers, setCreativeAnswers] = useState>({})
- const [timeRemaining, setTimeRemaining] = useState(45 * 60) // 45 minutes total
+ const [timeRemaining, setTimeRemaining] = useState(30 * 60) // 30 minutes total
+ const [hasShownWarning, setHasShownWarning] = useState(false)
const [logicQuestions, setLogicQuestions] = useState([])
const [creativeQuestions, setCreativeQuestions] = useState([])
const [isLoading, setIsLoading] = useState(true)
@@ -81,16 +82,27 @@ export default function CombinedTestPage() {
const timer = setInterval(() => {
setTimeRemaining((prev) => {
- if (prev <= 1) {
- handleSubmit()
+ const newTime = prev - 1
+
+ // 檢查是否剩餘5分鐘(300秒)且尚未顯示警告
+ if (newTime <= 300 && !hasShownWarning) {
+ setHasShownWarning(true)
+ alert('⚠️ 注意:距離測試結束還有5分鐘,請盡快完成剩餘題目!')
+ }
+
+ // 時間到,強制提交
+ if (newTime <= 0) {
+ console.log('⏰ 時間到!強制提交測驗...')
+ handleTimeoutSubmit()
return 0
}
- return prev - 1
+
+ return newTime
})
}, 1000)
return () => clearInterval(timer)
- }, [logicQuestions, creativeQuestions])
+ }, [logicQuestions, creativeQuestions, hasShownWarning])
const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60)
@@ -151,6 +163,121 @@ export default function CombinedTestPage() {
}
}
+ const handleTimeoutSubmit = async () => {
+ console.log('⏰ 時間到!強制提交綜合測試...')
+ console.log('用戶狀態:', user)
+
+ if (!user) {
+ console.log('❌ 用戶未登入')
+ alert('⏰ 時間到!但用戶未登入,無法提交結果。')
+ return
+ }
+
+ console.log('✅ 用戶已登入,用戶ID:', user.id)
+ setIsSubmitting(true)
+
+ try {
+ // Calculate logic score
+ let logicCorrect = 0
+ logicQuestions.forEach((question, index) => {
+ if (logicAnswers[index] === question.correct_answer) {
+ logicCorrect++
+ }
+ })
+ const logicScore = Math.round((logicCorrect / logicQuestions.length) * 100)
+
+ // Calculate creativity score
+ let creativityTotal = 0
+ const processedCreativeAnswers: Record = {}
+ creativeQuestions.forEach((question, index) => {
+ const answer = creativeAnswers[index] || 1
+ const processedScore = question.is_reverse ? 6 - answer : answer
+ creativityTotal += processedScore
+ processedCreativeAnswers[index] = processedScore
+ })
+ const creativityMaxScore = creativeQuestions.length * 5
+ const creativityScore = Math.round((creativityTotal / creativityMaxScore) * 100)
+
+ // Calculate combined score
+ const combinedResult = calculateCombinedScore(logicScore, creativityScore)
+
+ // Store results in localStorage with timeout flag
+ const results = {
+ type: "combined",
+ logicScore,
+ creativityScore,
+ overallScore: combinedResult.overallScore,
+ level: combinedResult.level,
+ description: combinedResult.description,
+ breakdown: combinedResult.breakdown,
+ logicAnswers,
+ creativeAnswers: processedCreativeAnswers,
+ logicCorrect,
+ creativityTotal,
+ creativityMaxScore,
+ completedAt: new Date().toISOString(),
+ isTimeout: true // 標記為時間到強制提交
+ }
+
+ localStorage.setItem("combinedTestResults", JSON.stringify(results))
+ console.log('✅ 強制提交結果已儲存到 localStorage')
+
+ // Upload to database with timeout flag
+ console.log('🔄 開始上傳強制提交結果到資料庫...')
+ const uploadData = {
+ userId: user.id,
+ logicScore,
+ creativityScore,
+ overallScore: combinedResult.overallScore,
+ level: combinedResult.level,
+ description: combinedResult.description,
+ logicBreakdown: {
+ correct: logicCorrect,
+ total: logicQuestions.length,
+ answers: logicAnswers
+ },
+ creativityBreakdown: {
+ total: creativityTotal,
+ maxScore: creativityMaxScore,
+ answers: processedCreativeAnswers
+ },
+ balanceScore: combinedResult.breakdown.balance,
+ completedAt: new Date().toISOString(),
+ isTimeout: true // 標記為時間到強制提交
+ }
+ console.log('強制提交上傳數據:', uploadData)
+
+ const uploadResponse = await fetch('/api/test-results/combined', {
+ 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)
+ } else {
+ console.error('❌ 強制提交上傳到資料庫失敗:', uploadResult.error)
+ }
+
+ // 顯示時間到提示
+ alert('⏰ 測試時間已到!系統已自動提交您的答案。')
+ router.push("/results/combined")
+
+ } catch (error) {
+ console.error('❌ 強制提交測驗失敗:', error)
+ alert('⏰ 時間到!但提交失敗,請聯繫管理員。')
+ } finally {
+ setIsSubmitting(false)
+ }
+ }
+
const handleSubmit = async () => {
console.log('🔍 開始提交綜合測試...')
console.log('用戶狀態:', user)
@@ -204,6 +331,7 @@ export default function CombinedTestPage() {
creativityTotal,
creativityMaxScore,
completedAt: new Date().toISOString(),
+ isTimeout: false // 標記為正常提交
}
localStorage.setItem("combinedTestResults", JSON.stringify(results))
@@ -229,7 +357,8 @@ export default function CombinedTestPage() {
answers: processedCreativeAnswers
},
balanceScore: combinedResult.breakdown.balance,
- completedAt: new Date().toISOString()
+ completedAt: new Date().toISOString(),
+ isTimeout: false // 標記為正常提交
}
console.log('上傳數據:', uploadData)
diff --git a/lib/database/models/combined_test_result.ts b/lib/database/models/combined_test_result.ts
index c65b213..04a4e40 100644
--- a/lib/database/models/combined_test_result.ts
+++ b/lib/database/models/combined_test_result.ts
@@ -13,6 +13,7 @@ export interface CombinedTestResult {
creativity_breakdown: any | null // JSON 格式
balance_score: number
completed_at: string
+ is_timeout: boolean
created_at?: string
}
@@ -27,6 +28,7 @@ export interface CreateCombinedTestResultData {
creativity_breakdown: any | null
balance_score: number
completed_at: string
+ is_timeout: boolean
}
// 建立綜合測試結果表(如果不存在)
@@ -44,6 +46,7 @@ export async function createCombinedTestResultsTable(): Promise {
creativity_breakdown JSON NULL,
balance_score INT NOT NULL,
completed_at TIMESTAMP NOT NULL,
+ is_timeout BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_completed_at (completed_at)
@@ -62,8 +65,8 @@ export async function createCombinedTestResult(resultData: CreateCombinedTestRes
INSERT INTO combined_test_results (
id, user_id, logic_score, creativity_score, overall_score,
level, description, logic_breakdown, creativity_breakdown,
- balance_score, completed_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ balance_score, completed_at, is_timeout
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`
const values = [
@@ -77,7 +80,8 @@ export async function createCombinedTestResult(resultData: CreateCombinedTestRes
resultData.logic_breakdown ? JSON.stringify(resultData.logic_breakdown) : null,
resultData.creativity_breakdown ? JSON.stringify(resultData.creativity_breakdown) : null,
resultData.balance_score,
- resultData.completed_at
+ resultData.completed_at,
+ resultData.is_timeout
]
try {
diff --git a/lib/database/models/test_result.ts b/lib/database/models/test_result.ts
index 6b778c3..da5b36b 100644
--- a/lib/database/models/test_result.ts
+++ b/lib/database/models/test_result.ts
@@ -8,6 +8,7 @@ export interface TestResult {
total_questions: number
correct_answers: number
completed_at: string
+ is_timeout: boolean
created_at?: string
}
@@ -18,6 +19,7 @@ export interface CreateTestResultData {
total_questions: number
correct_answers: number
completed_at: string
+ is_timeout: boolean
}
// 建立測試結果表(如果不存在)
@@ -31,6 +33,7 @@ export async function createTestResultsTable(): Promise {
total_questions INT NOT NULL,
correct_answers INT NOT NULL,
completed_at TIMESTAMP NOT NULL,
+ is_timeout BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_test_type (test_type),
@@ -50,8 +53,8 @@ export async function createTestResult(resultData: CreateTestResultData): Promis
const insertQuery = `
INSERT INTO test_results (
id, user_id, test_type, score, total_questions,
- correct_answers, completed_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?)
+ correct_answers, completed_at, is_timeout
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`
await executeQuery(insertQuery, [
@@ -61,7 +64,8 @@ export async function createTestResult(resultData: CreateTestResultData): Promis
resultData.score,
resultData.total_questions,
resultData.correct_answers,
- resultData.completed_at
+ resultData.completed_at,
+ resultData.is_timeout
])
const result = await getTestResultById(id)