修正 vercal 部署失敗問題

This commit is contained in:
2025-09-29 21:21:52 +08:00
parent 426deafbb8
commit 3aba1451bd
144 changed files with 321 additions and 11283 deletions

View File

@@ -446,7 +446,7 @@ function UsersManagementContent() {
{user.role === "admin" ? "管理員" : "一般用戶"} {user.role === "admin" ? "管理員" : "一般用戶"}
</Badge> </Badge>
</TableCell> </TableCell>
<TableCell>{new Date(user.created_at).toLocaleDateString("zh-TW")}</TableCell> <TableCell>{new Date(user.createdAt).toLocaleDateString("zh-TW")}</TableCell>
<TableCell> <TableCell>
<div className="flex gap-2"> <div className="flex gap-2">
<Button variant="ghost" size="sm" onClick={() => handleEditUser(user)}> <Button variant="ghost" size="sm" onClick={() => handleEditUser(user)}>

View File

@@ -94,14 +94,14 @@ export async function GET(request: NextRequest) {
console.log('Debug: 所有創意題目數量:', allCreativeQuestions.length) console.log('Debug: 所有創意題目數量:', allCreativeQuestions.length)
for (let i = 0; i < answerEntries.length; i++) { for (let i = 0; i < answerEntries.length; i++) {
const [questionIndex, score] = answerEntries[i] const [questionIndex, score] = answerEntries[i] as [string, number]
const question = allCreativeQuestions[parseInt(questionIndex)] // 使用索引獲取題目 const question = allCreativeQuestions[parseInt(questionIndex)] // 使用索引獲取題目
if (question) { if (question) {
questions.push({ questions.push({
...question, ...question,
type: 'creative', type: 'creative',
userAnswer: score.toString(), // 創意題的答案就是分數 userAnswer: score.toString(), // 創意題的答案就是分數
score: score as number, score: score,
isReverse: question.is_reverse isReverse: question.is_reverse
}) })
} }

View File

@@ -35,21 +35,24 @@ export async function GET(request: NextRequest) {
if (result.test_type === 'logic') { if (result.test_type === 'logic') {
const logicAnswers = await getLogicTestAnswersByTestResultId(result.id) const logicAnswers = await getLogicTestAnswersByTestResultId(result.id)
if (logicAnswers.length > 0) { if (logicAnswers.length > 0) {
const logicAnswer = logicAnswers[0] const correctAnswers = logicAnswers.filter(answer => answer.is_correct).length
const totalQuestions = logicAnswers.length
const accuracy = totalQuestions > 0 ? Math.round((correctAnswers / totalQuestions) * 100) : 0
details = { details = {
correctAnswers: logicAnswer.correct_answers, correctAnswers,
totalQuestions: logicAnswer.total_questions, totalQuestions,
accuracy: logicAnswer.accuracy accuracy
} }
} }
} else if (result.test_type === 'creative') { } else if (result.test_type === 'creative') {
const creativeAnswers = await getCreativeTestAnswersByTestResultId(result.id) const creativeAnswers = await getCreativeTestAnswersByTestResultId(result.id)
if (creativeAnswers.length > 0) { if (creativeAnswers.length > 0) {
const creativeAnswer = creativeAnswers[0] const totalScore = creativeAnswers.reduce((sum, answer) => sum + answer.score, 0)
const maxScore = creativeAnswers.length * 5 // Assuming max score per question is 5
details = { details = {
dimensionScores: creativeAnswer.dimension_scores, dimensionScores: {}, // This would need to be calculated based on question categories
totalScore: creativeAnswer.total_score, totalScore,
maxScore: creativeAnswer.max_score maxScore
} }
} }
} }

View File

@@ -37,21 +37,24 @@ export async function GET(request: NextRequest) {
if (result.test_type === 'logic') { if (result.test_type === 'logic') {
const logicAnswers = await getLogicTestAnswersByTestResultId(result.id) const logicAnswers = await getLogicTestAnswersByTestResultId(result.id)
if (logicAnswers.length > 0) { if (logicAnswers.length > 0) {
const logicAnswer = logicAnswers[0] // 取第一個答案記錄 const correctAnswers = logicAnswers.filter(answer => answer.is_correct).length
const totalQuestions = logicAnswers.length
const accuracy = totalQuestions > 0 ? Math.round((correctAnswers / totalQuestions) * 100) : 0
details = { details = {
correctAnswers: logicAnswer.correct_answers, correctAnswers,
totalQuestions: logicAnswer.total_questions, totalQuestions,
accuracy: logicAnswer.accuracy accuracy
} }
} }
} else if (result.test_type === 'creative') { } else if (result.test_type === 'creative') {
const creativeAnswers = await getCreativeTestAnswersByTestResultId(result.id) const creativeAnswers = await getCreativeTestAnswersByTestResultId(result.id)
if (creativeAnswers.length > 0) { if (creativeAnswers.length > 0) {
const creativeAnswer = creativeAnswers[0] // 取第一個答案記錄 const totalScore = creativeAnswers.reduce((sum, answer) => sum + answer.score, 0)
const maxScore = creativeAnswers.length * 5 // Assuming max score per question is 5
details = { details = {
dimensionScores: creativeAnswer.dimension_scores, dimensionScores: {}, // This would need to be calculated based on question categories
totalScore: creativeAnswer.total_score, totalScore,
maxScore: creativeAnswer.max_score maxScore
} }
} }
} }

View File

@@ -2,13 +2,11 @@ import { NextRequest, NextResponse } from "next/server"
import * as XLSX from "xlsx" import * as XLSX from "xlsx"
import { import {
createLogicQuestion, createLogicQuestion,
updateLogicQuestion,
getAllLogicQuestions, getAllLogicQuestions,
clearLogicQuestions clearLogicQuestions
} from "@/lib/database/models/logic_question" } from "@/lib/database/models/logic_question"
import { import {
createCreativeQuestion, createCreativeQuestion,
updateCreativeQuestion,
getAllCreativeQuestions, getAllCreativeQuestions,
clearCreativeQuestions clearCreativeQuestions
} from "@/lib/database/models/creative_question" } from "@/lib/database/models/creative_question"

View File

@@ -110,8 +110,7 @@ export async function POST(request: NextRequest) {
console.error('上傳邏輯測驗結果失敗:', error) console.error('上傳邏輯測驗結果失敗:', error)
console.error('錯誤詳情:', { console.error('錯誤詳情:', {
message: error instanceof Error ? error.message : '未知錯誤', message: error instanceof Error ? error.message : '未知錯誤',
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined
body: body
}) })
return NextResponse.json( return NextResponse.json(
{ {

View File

@@ -42,7 +42,7 @@ export default function CreativeResultsPage() {
if (data.success && data.data.length > 0) { if (data.success && data.data.length > 0) {
// 按創建時間排序,取最新的結果 // 按創建時間排序,取最新的結果
const sortedResults = data.data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) const sortedResults = data.data.sort((a: any, b: any) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
const latestResult = sortedResults[0] const latestResult = sortedResults[0]
// 獲取題目資料來計算各維度分數 // 獲取題目資料來計算各維度分數

View File

@@ -12,7 +12,7 @@ export interface JWTPayload {
// 生成 JWT Token // 生成 JWT Token
export function generateToken(payload: JWTPayload): string { export function generateToken(payload: JWTPayload): string {
return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN }) return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN as string | number })
} }
// 驗證 JWT Token // 驗證 JWT Token

View File

@@ -6,48 +6,7 @@
"build": "next build", "build": "next build",
"dev": "next dev", "dev": "next dev",
"lint": "next lint", "lint": "next lint",
"start": "next start", "start": "next start"
"test-db": "node scripts/test-db.js",
"test-login": "node scripts/test-login.js",
"check-passwords": "node scripts/check-passwords.js",
"check-logic-questions": "node scripts/check-logic-questions.js",
"check-creative-questions": "node scripts/check-creative-questions.js",
"test-score-levels": "node scripts/test-score-levels.js",
"test-responsive-design": "node scripts/test-responsive-design.js",
"test-reverse-scoring": "node scripts/test-reverse-scoring.js",
"test-creative-flow": "node scripts/test-creative-flow.js",
"test-creative-score-levels": "node scripts/test-creative-score-levels.js",
"test-creative-responsive-design": "node scripts/test-creative-responsive-design.js",
"test-creative-chart": "node scripts/test-creative-chart.js",
"test-combined-integration": "node scripts/test-combined-integration.js",
"test-combined-scoring": "node scripts/test-combined-scoring.js",
"test-combined-scoring-logic": "node scripts/test-combined-scoring-logic.js",
"test-combined-logic-answers": "node scripts/test-combined-logic-answers.js",
"test-combined-mobile-ui": "node scripts/test-combined-mobile-ui.js",
"test-combined-logic-levels": "node scripts/test-combined-logic-levels.js",
"test-combined-creativity-levels": "node scripts/test-combined-creativity-levels.js",
"test-combined-score-display": "node scripts/test-combined-score-display.js",
"test-combined-mobile-buttons": "node scripts/test-combined-mobile-buttons.js",
"test-logic-instructions": "node scripts/test-logic-instructions.js",
"test-logic-simple-instructions": "node scripts/test-logic-simple-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",
"seed-db": "npx tsx lib/database/seed.ts",
"seed-logic-questions": "npx tsx lib/database/seed-logic-questions.ts",
"seed-creative-questions": "npx tsx lib/database/seed-creative-questions.ts",
"reset-users": "npx tsx lib/database/reset-users.ts"
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^3.10.0", "@hookform/resolvers": "^3.10.0",

292
pnpm-lock.yaml generated
View File

@@ -92,12 +92,18 @@ importers:
'@radix-ui/react-tooltip': '@radix-ui/react-tooltip':
specifier: 1.1.6 specifier: 1.1.6
version: 1.1.6(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.1.6(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/uuid':
specifier: ^10.0.0
version: 10.0.0
'@vercel/analytics': '@vercel/analytics':
specifier: 1.3.1 specifier: 1.3.1
version: 1.3.1(next@14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) version: 1.3.1(next@14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
autoprefixer: autoprefixer:
specifier: ^10.4.20 specifier: ^10.4.20
version: 10.4.21(postcss@8.5.6) version: 10.4.21(postcss@8.5.6)
bcryptjs:
specifier: ^3.0.2
version: 3.0.2
class-variance-authority: class-variance-authority:
specifier: ^0.7.1 specifier: ^0.7.1
version: 0.7.1 version: 0.7.1
@@ -119,15 +125,24 @@ importers:
input-otp: input-otp:
specifier: 1.4.1 specifier: 1.4.1
version: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
jsonwebtoken:
specifier: ^9.0.2
version: 9.0.2
lucide-react: lucide-react:
specifier: ^0.454.0 specifier: ^0.454.0
version: 0.454.0(react@18.3.1) version: 0.454.0(react@18.3.1)
mysql2:
specifier: ^3.15.1
version: 3.15.1
next: next:
specifier: 14.2.16 specifier: 14.2.16
version: 14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-themes: next-themes:
specifier: ^0.4.6 specifier: ^0.4.6
version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
node-fetch:
specifier: ^3.3.2
version: 3.3.2
react: react:
specifier: ^18 specifier: ^18
version: 18.3.1 version: 18.3.1
@@ -155,6 +170,9 @@ importers:
tailwindcss-animate: tailwindcss-animate:
specifier: ^1.0.7 specifier: ^1.0.7
version: 1.0.7(tailwindcss@4.1.13) version: 1.0.7(tailwindcss@4.1.13)
uuid:
specifier: ^13.0.0
version: 13.0.0
vaul: vaul:
specifier: ^0.9.9 specifier: ^0.9.9
version: 0.9.9(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 0.9.9(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -168,6 +186,12 @@ importers:
'@tailwindcss/postcss': '@tailwindcss/postcss':
specifier: ^4.1.9 specifier: ^4.1.9
version: 4.1.13 version: 4.1.13
'@types/bcryptjs':
specifier: ^2.4.6
version: 2.4.6
'@types/jsonwebtoken':
specifier: ^9.0.10
version: 9.0.10
'@types/node': '@types/node':
specifier: ^22 specifier: ^22
version: 22.18.6 version: 22.18.6
@@ -1137,6 +1161,9 @@ packages:
'@tailwindcss/postcss@4.1.13': '@tailwindcss/postcss@4.1.13':
resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==} resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==}
'@types/bcryptjs@2.4.6':
resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==}
'@types/d3-array@3.2.2': '@types/d3-array@3.2.2':
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
@@ -1164,6 +1191,12 @@ packages:
'@types/d3-timer@3.0.2': '@types/d3-timer@3.0.2':
resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
'@types/jsonwebtoken@9.0.10':
resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
'@types/node@22.18.6': '@types/node@22.18.6':
resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==}
@@ -1178,6 +1211,9 @@ packages:
'@types/react@18.3.24': '@types/react@18.3.24':
resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==} resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==}
'@types/uuid@10.0.0':
resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
'@vercel/analytics@1.3.1': '@vercel/analytics@1.3.1':
resolution: {integrity: sha512-xhSlYgAuJ6Q4WQGkzYTLmXwhYl39sWjoMA3nHxfkvG+WdBT25c563a7QhwwKivEOZtPJXifYHR1m2ihoisbWyA==} resolution: {integrity: sha512-xhSlYgAuJ6Q4WQGkzYTLmXwhYl39sWjoMA3nHxfkvG+WdBT25c563a7QhwwKivEOZtPJXifYHR1m2ihoisbWyA==}
peerDependencies: peerDependencies:
@@ -1204,15 +1240,26 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.1.0 postcss: ^8.1.0
aws-ssl-profiles@1.1.2:
resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
engines: {node: '>= 6.0.0'}
baseline-browser-mapping@2.8.9: baseline-browser-mapping@2.8.9:
resolution: {integrity: sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==} resolution: {integrity: sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==}
hasBin: true hasBin: true
bcryptjs@3.0.2:
resolution: {integrity: sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==}
hasBin: true
browserslist@4.26.2: browserslist@4.26.2:
resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==} resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true hasBin: true
buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
busboy@1.6.0: busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'} engines: {node: '>=10.16.0'}
@@ -1300,6 +1347,10 @@ packages:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'} engines: {node: '>=12'}
data-uri-to-buffer@4.0.1:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
date-fns-jalali@4.1.0-0: date-fns-jalali@4.1.0-0:
resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==}
@@ -1309,6 +1360,10 @@ packages:
decimal.js-light@2.5.1: decimal.js-light@2.5.1:
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
detect-libc@2.1.1: detect-libc@2.1.1:
resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1319,6 +1374,9 @@ packages:
dom-helpers@5.2.1: dom-helpers@5.2.1:
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
ecdsa-sig-formatter@1.0.11:
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
electron-to-chromium@1.5.227: electron-to-chromium@1.5.227:
resolution: {integrity: sha512-ITxuoPfJu3lsNWUi2lBM2PaBPYgH3uqmxut5vmBxgYvyI4AlJ6P3Cai1O76mOrkJCBzq0IxWg/NtqOrpu/0gKA==} resolution: {integrity: sha512-ITxuoPfJu3lsNWUi2lBM2PaBPYgH3uqmxut5vmBxgYvyI4AlJ6P3Cai1O76mOrkJCBzq0IxWg/NtqOrpu/0gKA==}
@@ -1350,6 +1408,14 @@ packages:
resolution: {integrity: sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ==} resolution: {integrity: sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
fetch-blob@3.2.0:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
frac@1.1.2: frac@1.1.2:
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
@@ -1362,6 +1428,9 @@ packages:
peerDependencies: peerDependencies:
next: '>=13.2.0' next: '>=13.2.0'
generate-function@2.3.1:
resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==}
get-nonce@1.0.1: get-nonce@1.0.1:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -1369,6 +1438,10 @@ packages:
graceful-fs@4.2.11: graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
iconv-lite@0.7.0:
resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==}
engines: {node: '>=0.10.0'}
input-otp@1.4.1: input-otp@1.4.1:
resolution: {integrity: sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==} resolution: {integrity: sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==}
peerDependencies: peerDependencies:
@@ -1379,6 +1452,9 @@ packages:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'} engines: {node: '>=12'}
is-property@1.0.2:
resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
jiti@2.6.0: jiti@2.6.0:
resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==} resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==}
hasBin: true hasBin: true
@@ -1386,6 +1462,16 @@ packages:
js-tokens@4.0.0: js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
jsonwebtoken@9.0.2:
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
engines: {node: '>=12', npm: '>=6'}
jwa@1.4.2:
resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==}
jws@3.2.2:
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
lightningcss-darwin-arm64@1.30.1: lightningcss-darwin-arm64@1.30.1:
resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
@@ -1450,13 +1536,45 @@ packages:
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
lodash.includes@4.3.0:
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
lodash.isboolean@3.0.3:
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
lodash.isinteger@4.0.4:
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
lodash.isnumber@3.0.3:
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
lodash.isstring@4.0.1:
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
lodash.once@4.1.1:
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
lodash@4.17.21: lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
long@5.3.2:
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
loose-envify@1.4.0: loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true hasBin: true
lru-cache@7.18.3:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
engines: {node: '>=12'}
lru.min@1.1.2:
resolution: {integrity: sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==}
engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'}
lucide-react@0.454.0: lucide-react@0.454.0:
resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==} resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==}
peerDependencies: peerDependencies:
@@ -1473,6 +1591,17 @@ packages:
resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
engines: {node: '>= 18'} engines: {node: '>= 18'}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
mysql2@3.15.1:
resolution: {integrity: sha512-WZMIRZstT2MFfouEaDz/AGFnGi1A2GwaDe7XvKTdRJEYiAHbOrh4S3d8KFmQeh11U85G+BFjIvS1Di5alusZsw==}
engines: {node: '>= 8.0'}
named-placeholders@1.1.3:
resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==}
engines: {node: '>=12.0.0'}
nanoid@3.3.11: nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -1502,6 +1631,15 @@ packages:
sass: sass:
optional: true optional: true
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
deprecated: Use your platform's native DOMException instead
node-fetch@3.3.2:
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
node-releases@2.0.21: node-releases@2.0.21:
resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==}
@@ -1615,9 +1753,23 @@ packages:
react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
scheduler@0.23.2: scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
semver@7.7.2:
resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
engines: {node: '>=10'}
hasBin: true
seq-queue@0.0.5:
resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==}
server-only@0.0.1: server-only@0.0.1:
resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
@@ -1631,6 +1783,10 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
sqlstring@2.3.3:
resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==}
engines: {node: '>= 0.6'}
ssf@0.11.2: ssf@0.11.2:
resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
@@ -1719,6 +1875,10 @@ packages:
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
uuid@13.0.0:
resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==}
hasBin: true
vaul@0.9.9: vaul@0.9.9:
resolution: {integrity: sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ==} resolution: {integrity: sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ==}
peerDependencies: peerDependencies:
@@ -1728,6 +1888,10 @@ packages:
victory-vendor@36.9.2: victory-vendor@36.9.2:
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
wmf@1.0.2: wmf@1.0.2:
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
@@ -2674,6 +2838,8 @@ snapshots:
postcss: 8.5.6 postcss: 8.5.6
tailwindcss: 4.1.13 tailwindcss: 4.1.13
'@types/bcryptjs@2.4.6': {}
'@types/d3-array@3.2.2': {} '@types/d3-array@3.2.2': {}
'@types/d3-color@3.1.3': {} '@types/d3-color@3.1.3': {}
@@ -2698,6 +2864,13 @@ snapshots:
'@types/d3-timer@3.0.2': {} '@types/d3-timer@3.0.2': {}
'@types/jsonwebtoken@9.0.10':
dependencies:
'@types/ms': 2.1.0
'@types/node': 22.18.6
'@types/ms@2.1.0': {}
'@types/node@22.18.6': '@types/node@22.18.6':
dependencies: dependencies:
undici-types: 6.21.0 undici-types: 6.21.0
@@ -2713,6 +2886,8 @@ snapshots:
'@types/prop-types': 15.7.15 '@types/prop-types': 15.7.15
csstype: 3.1.3 csstype: 3.1.3
'@types/uuid@10.0.0': {}
'@vercel/analytics@1.3.1(next@14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': '@vercel/analytics@1.3.1(next@14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
server-only: 0.0.1 server-only: 0.0.1
@@ -2736,8 +2911,12 @@ snapshots:
postcss: 8.5.6 postcss: 8.5.6
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
aws-ssl-profiles@1.1.2: {}
baseline-browser-mapping@2.8.9: {} baseline-browser-mapping@2.8.9: {}
bcryptjs@3.0.2: {}
browserslist@4.26.2: browserslist@4.26.2:
dependencies: dependencies:
baseline-browser-mapping: 2.8.9 baseline-browser-mapping: 2.8.9
@@ -2746,6 +2925,8 @@ snapshots:
node-releases: 2.0.21 node-releases: 2.0.21
update-browserslist-db: 1.1.3(browserslist@4.26.2) update-browserslist-db: 1.1.3(browserslist@4.26.2)
buffer-equal-constant-time@1.0.1: {}
busboy@1.6.0: busboy@1.6.0:
dependencies: dependencies:
streamsearch: 1.1.0 streamsearch: 1.1.0
@@ -2823,12 +3004,16 @@ snapshots:
d3-timer@3.0.1: {} d3-timer@3.0.1: {}
data-uri-to-buffer@4.0.1: {}
date-fns-jalali@4.1.0-0: {} date-fns-jalali@4.1.0-0: {}
date-fns@4.1.0: {} date-fns@4.1.0: {}
decimal.js-light@2.5.1: {} decimal.js-light@2.5.1: {}
denque@2.1.0: {}
detect-libc@2.1.1: {} detect-libc@2.1.1: {}
detect-node-es@1.1.0: {} detect-node-es@1.1.0: {}
@@ -2838,6 +3023,10 @@ snapshots:
'@babel/runtime': 7.28.4 '@babel/runtime': 7.28.4
csstype: 3.1.3 csstype: 3.1.3
ecdsa-sig-formatter@1.0.11:
dependencies:
safe-buffer: 5.2.1
electron-to-chromium@1.5.227: {} electron-to-chromium@1.5.227: {}
embla-carousel-react@8.5.1(react@18.3.1): embla-carousel-react@8.5.1(react@18.3.1):
@@ -2863,6 +3052,15 @@ snapshots:
fast-equals@5.3.2: {} fast-equals@5.3.2: {}
fetch-blob@3.2.0:
dependencies:
node-domexception: 1.0.0
web-streams-polyfill: 3.3.3
formdata-polyfill@4.0.10:
dependencies:
fetch-blob: 3.2.0
frac@1.1.2: {} frac@1.1.2: {}
fraction.js@4.3.7: {} fraction.js@4.3.7: {}
@@ -2871,10 +3069,18 @@ snapshots:
dependencies: dependencies:
next: 14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: 14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
generate-function@2.3.1:
dependencies:
is-property: 1.0.2
get-nonce@1.0.1: {} get-nonce@1.0.1: {}
graceful-fs@4.2.11: {} graceful-fs@4.2.11: {}
iconv-lite@0.7.0:
dependencies:
safer-buffer: 2.1.2
input-otp@1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): input-otp@1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -2882,10 +3088,36 @@ snapshots:
internmap@2.0.3: {} internmap@2.0.3: {}
is-property@1.0.2: {}
jiti@2.6.0: {} jiti@2.6.0: {}
js-tokens@4.0.0: {} js-tokens@4.0.0: {}
jsonwebtoken@9.0.2:
dependencies:
jws: 3.2.2
lodash.includes: 4.3.0
lodash.isboolean: 3.0.3
lodash.isinteger: 4.0.4
lodash.isnumber: 3.0.3
lodash.isplainobject: 4.0.6
lodash.isstring: 4.0.1
lodash.once: 4.1.1
ms: 2.1.3
semver: 7.7.2
jwa@1.4.2:
dependencies:
buffer-equal-constant-time: 1.0.1
ecdsa-sig-formatter: 1.0.11
safe-buffer: 5.2.1
jws@3.2.2:
dependencies:
jwa: 1.4.2
safe-buffer: 5.2.1
lightningcss-darwin-arm64@1.30.1: lightningcss-darwin-arm64@1.30.1:
optional: true optional: true
@@ -2931,12 +3163,32 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-arm64-msvc: 1.30.1
lightningcss-win32-x64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1
lodash.includes@4.3.0: {}
lodash.isboolean@3.0.3: {}
lodash.isinteger@4.0.4: {}
lodash.isnumber@3.0.3: {}
lodash.isplainobject@4.0.6: {}
lodash.isstring@4.0.1: {}
lodash.once@4.1.1: {}
lodash@4.17.21: {} lodash@4.17.21: {}
long@5.3.2: {}
loose-envify@1.4.0: loose-envify@1.4.0:
dependencies: dependencies:
js-tokens: 4.0.0 js-tokens: 4.0.0
lru-cache@7.18.3: {}
lru.min@1.1.2: {}
lucide-react@0.454.0(react@18.3.1): lucide-react@0.454.0(react@18.3.1):
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -2951,6 +3203,24 @@ snapshots:
dependencies: dependencies:
minipass: 7.1.2 minipass: 7.1.2
ms@2.1.3: {}
mysql2@3.15.1:
dependencies:
aws-ssl-profiles: 1.1.2
denque: 2.1.0
generate-function: 2.3.1
iconv-lite: 0.7.0
long: 5.3.2
lru.min: 1.1.2
named-placeholders: 1.1.3
seq-queue: 0.0.5
sqlstring: 2.3.3
named-placeholders@1.1.3:
dependencies:
lru-cache: 7.18.3
nanoid@3.3.11: {} nanoid@3.3.11: {}
next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
@@ -2983,6 +3253,14 @@ snapshots:
- '@babel/core' - '@babel/core'
- babel-plugin-macros - babel-plugin-macros
node-domexception@1.0.0: {}
node-fetch@3.3.2:
dependencies:
data-uri-to-buffer: 4.0.1
fetch-blob: 3.2.0
formdata-polyfill: 4.0.10
node-releases@2.0.21: {} node-releases@2.0.21: {}
normalize-range@0.1.2: {} normalize-range@0.1.2: {}
@@ -3102,10 +3380,18 @@ snapshots:
tiny-invariant: 1.3.3 tiny-invariant: 1.3.3
victory-vendor: 36.9.2 victory-vendor: 36.9.2
safe-buffer@5.2.1: {}
safer-buffer@2.1.2: {}
scheduler@0.23.2: scheduler@0.23.2:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
semver@7.7.2: {}
seq-queue@0.0.5: {}
server-only@0.0.1: {} server-only@0.0.1: {}
sonner@1.7.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): sonner@1.7.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
@@ -3115,6 +3401,8 @@ snapshots:
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
sqlstring@2.3.3: {}
ssf@0.11.2: ssf@0.11.2:
dependencies: dependencies:
frac: 1.1.2 frac: 1.1.2
@@ -3179,6 +3467,8 @@ snapshots:
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
uuid@13.0.0: {}
vaul@0.9.9(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): vaul@0.9.9(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
'@radix-ui/react-dialog': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dialog': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -3205,6 +3495,8 @@ snapshots:
d3-time: 3.1.0 d3-time: 3.1.0
d3-timer: 3.0.1 d3-timer: 3.0.1
web-streams-polyfill@3.3.3: {}
wmf@1.0.2: {} wmf@1.0.2: {}
word@0.3.0: {} word@0.3.0: {}

View File

@@ -1,129 +0,0 @@
const https = require('https')
const http = require('http')
const checkActualUploadTimes = async () => {
console.log('🔍 檢查實際上傳時間')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查邏輯測試結果
console.log('\n📊 檢查邏輯測試結果...')
const logicResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/logic?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (logicResponse.status === 200) {
const logicData = JSON.parse(logicResponse.data)
if (logicData.success && logicData.data.length > 0) {
console.log('邏輯測試結果 (按創建時間排序):')
logicData.data
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
.forEach((result, index) => {
console.log(`\n${index + 1}. 邏輯測試:`)
console.log(` ID: ${result.id}`)
console.log(` completed_at: ${result.completed_at}`)
console.log(` created_at: ${result.created_at}`)
const completedDate = new Date(result.completed_at)
const createdDate = new Date(result.created_at)
console.log(` completed_at 台灣時間: ${completedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` created_at 台灣時間: ${createdDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
// 計算時間差
const timeDiff = createdDate.getTime() - completedDate.getTime()
const hoursDiff = timeDiff / (1000 * 60 * 60)
console.log(` 時間差: ${hoursDiff.toFixed(2)} 小時`)
})
}
}
// 檢查創意測試結果
console.log('\n📊 檢查創意測試結果...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success && creativeData.data.length > 0) {
console.log('創意測試結果 (按創建時間排序):')
creativeData.data
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
.forEach((result, index) => {
console.log(`\n${index + 1}. 創意測試:`)
console.log(` ID: ${result.id}`)
console.log(` completed_at: ${result.completed_at}`)
console.log(` created_at: ${result.created_at}`)
const completedDate = new Date(result.completed_at)
const createdDate = new Date(result.created_at)
console.log(` completed_at 台灣時間: ${completedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` created_at 台灣時間: ${createdDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
// 計算時間差
const timeDiff = createdDate.getTime() - completedDate.getTime()
const hoursDiff = timeDiff / (1000 * 60 * 60)
console.log(` 時間差: ${hoursDiff.toFixed(2)} 小時`)
})
}
}
// 檢查綜合測試結果
console.log('\n📊 檢查綜合測試結果...')
const combinedResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/combined?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (combinedResponse.status === 200) {
const combinedData = JSON.parse(combinedResponse.data)
if (combinedData.success && combinedData.data.length > 0) {
console.log('綜合測試結果 (按創建時間排序):')
combinedData.data
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
.forEach((result, index) => {
console.log(`\n${index + 1}. 綜合測試:`)
console.log(` ID: ${result.id}`)
console.log(` completed_at: ${result.completed_at}`)
console.log(` created_at: ${result.created_at}`)
const completedDate = new Date(result.completed_at)
const createdDate = new Date(result.created_at)
console.log(` completed_at 台灣時間: ${completedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` created_at 台灣時間: ${createdDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
// 計算時間差
const timeDiff = createdDate.getTime() - completedDate.getTime()
const hoursDiff = timeDiff / (1000 * 60 * 60)
console.log(` 時間差: ${hoursDiff.toFixed(2)} 小時`)
})
}
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 實際上傳時間檢查完成')
}
}
checkActualUploadTimes()

View File

@@ -1,67 +0,0 @@
const https = require('https')
const http = require('http')
const checkAllCombinedTimes = async () => {
console.log('🔍 檢查所有綜合測試結果時間')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查綜合測試結果 API
console.log('\n📊 檢查所有綜合測試結果...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/combined?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success) {
console.log(`找到 ${data.data.length} 筆綜合測試結果:`)
data.data.forEach((result, index) => {
console.log(`\n${index + 1}. 綜合測試結果:`)
console.log(` ID: ${result.id}`)
console.log(` 原始時間: ${result.completed_at}`)
const date = new Date(result.completed_at)
console.log(` 台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` 台灣時間 (詳細): ${date.toLocaleString("zh-TW", {
timeZone: "Asia/Taipei",
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: true
})}`)
// 檢查是否是今天
const now = new Date()
const testDate = new Date(result.completed_at)
const isToday = now.toDateString() === testDate.toDateString()
console.log(` 是否為今天: ${isToday}`)
// 計算時間差
const timeDiff = now.getTime() - testDate.getTime()
const hoursDiff = Math.floor(timeDiff / (1000 * 60 * 60))
const minutesDiff = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60))
console.log(` 距離現在: ${hoursDiff} 小時 ${minutesDiff} 分鐘`)
})
}
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 所有綜合測試結果時間檢查完成')
}
}
checkAllCombinedTimes()

View File

@@ -1,73 +0,0 @@
const https = require('https')
const http = require('http')
const checkAllTestTimes = async () => {
console.log('🔍 檢查所有測試結果的時間顯示')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查用戶測試結果 API
console.log('\n📊 檢查用戶測試結果 API...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/user/test-results?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.results.length > 0) {
console.log(`找到 ${data.data.results.length} 筆測試結果:`)
data.data.results.forEach((result, index) => {
console.log(`\n${index + 1}. ${result.type} 測試:`)
console.log(` 原始時間: ${result.completedAt}`)
const date = new Date(result.completedAt)
console.log(` UTC 時間: ${date.toISOString()}`)
console.log(` 台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` 台灣時間 (詳細): ${date.toLocaleString("zh-TW", {
timeZone: "Asia/Taipei",
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: true
})}`)
// 檢查是否是今天
const now = new Date()
const testDate = new Date(result.completedAt)
const isToday = now.toDateString() === testDate.toDateString()
console.log(` 是否為今天: ${isToday}`)
// 計算時間差
const timeDiff = now.getTime() - testDate.getTime()
const hoursDiff = Math.floor(timeDiff / (1000 * 60 * 60))
const minutesDiff = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60))
console.log(` 距離現在: ${hoursDiff} 小時 ${minutesDiff} 分鐘`)
})
}
}
// 檢查當前時間
console.log('\n📊 當前時間:')
const now = new Date()
console.log(`UTC 時間: ${now.toISOString()}`)
console.log(`台灣時間: ${now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 所有測試結果時間檢查完成')
}
}
checkAllTestTimes()

View File

@@ -1,58 +0,0 @@
const { executeQuery } = require('../lib/database/connection');
async function checkCombinedBreakdown() {
console.log('🔍 檢查綜合測試的 breakdown 資料');
console.log('==============================');
try {
// 檢查 combined_test_results 的 breakdown 資料
const results = await executeQuery('SELECT id, user_id, logic_breakdown, creativity_breakdown FROM combined_test_results LIMIT 3');
results.forEach((result, index) => {
console.log(`\n📋 綜合測試 ${index + 1}:`);
console.log('ID:', result.id);
console.log('User ID:', result.user_id);
console.log('Logic Breakdown 類型:', typeof result.logic_breakdown);
console.log('Creativity Breakdown 類型:', typeof result.creativity_breakdown);
if (result.logic_breakdown) {
console.log('Logic Breakdown 內容:', JSON.stringify(result.logic_breakdown, null, 2));
}
if (result.creativity_breakdown) {
console.log('Creativity Breakdown 內容:', JSON.stringify(result.creativity_breakdown, null, 2));
}
});
// 檢查 logic_test_answers 資料
console.log('\n📋 Logic Test Answers:');
const logicAnswers = await executeQuery('SELECT * FROM logic_test_answers LIMIT 3');
logicAnswers.forEach((answer, index) => {
console.log(`答案 ${index + 1}:`, {
test_result_id: answer.test_result_id,
question_id: answer.question_id,
user_answer: answer.user_answer,
is_correct: answer.is_correct
});
});
// 檢查 creative_test_answers 資料
console.log('\n📋 Creative Test Answers:');
const creativeAnswers = await executeQuery('SELECT * FROM creative_test_answers LIMIT 3');
creativeAnswers.forEach((answer, index) => {
console.log(`答案 ${index + 1}:`, {
test_result_id: answer.test_result_id,
question_id: answer.question_id,
user_answer: answer.user_answer,
score: answer.score
});
});
} catch (error) {
console.error('❌ 檢查失敗:', error.message);
}
console.log('==============================\n');
}
checkCombinedBreakdown();

View File

@@ -1,38 +0,0 @@
const { executeQuery } = require('../lib/database/connection')
const checkCombinedTableFields = async () => {
console.log('🔍 檢查 combined_test_results 表的實際欄位')
console.log('=' .repeat(50))
try {
// 檢查表結構
console.log('\n📊 檢查表結構...')
const structureQuery = 'DESCRIBE combined_test_results'
const structure = await executeQuery(structureQuery)
console.log('📋 表欄位:')
structure.forEach(field => {
console.log(` ${field.Field}: ${field.Type} ${field.Null === 'YES' ? '(可為空)' : '(不可為空)'}`)
})
// 檢查實際資料
console.log('\n📊 檢查實際資料...')
const dataQuery = 'SELECT * FROM combined_test_results LIMIT 2'
const data = await executeQuery(dataQuery)
console.log('📋 實際資料:')
data.forEach((row, index) => {
console.log(`\n 記錄 ${index + 1}:`)
Object.keys(row).forEach(key => {
console.log(` ${key}: ${row[key]}`)
})
})
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 資料庫欄位檢查完成')
}
}
checkCombinedTableFields()

View File

@@ -1,38 +0,0 @@
const { executeQuery } = require('../lib/database/connection')
const checkCombinedTableStructure = async () => {
console.log('🔍 檢查綜合測試結果表結構')
console.log('=' .repeat(40))
try {
// 檢查表結構
console.log('\n📊 檢查表結構...')
const structureQuery = 'DESCRIBE combined_test_results'
const structure = await executeQuery(structureQuery)
console.log('📋 表欄位:')
structure.forEach(field => {
console.log(` ${field.Field}: ${field.Type} ${field.Null === 'YES' ? '(可為空)' : '(不可為空)'}`)
})
// 檢查實際資料
console.log('\n📊 檢查實際資料...')
const dataQuery = 'SELECT * FROM combined_test_results LIMIT 3'
const data = await executeQuery(dataQuery)
console.log('📋 實際資料範例:')
data.forEach((row, index) => {
console.log(`\n 記錄 ${index + 1}:`)
Object.keys(row).forEach(key => {
console.log(` ${key}: ${row[key]}`)
})
})
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 綜合測試結果表結構檢查完成')
}
}
checkCombinedTableStructure()

View File

@@ -1,52 +0,0 @@
const http = require('http')
const checkCombinedTestData = async () => {
console.log('🔍 檢查綜合測試資料結構')
console.log('=' .repeat(40))
try {
// 獲取所有測試結果
const response = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success) {
console.log('✅ 成功獲取測試結果')
// 找出綜合測試結果
const combinedResults = data.data.results.filter(result => result.type === 'combined')
console.log(`📊 綜合測試結果數量: ${combinedResults.length}`)
combinedResults.forEach((result, index) => {
console.log(`\n📋 綜合測試 ${index + 1}:`)
console.log(` 用戶: ${result.userName}`)
console.log(` 分數: ${result.score}`)
console.log(` 完成時間: ${result.completedAt}`)
console.log(` 詳細資料:`, JSON.stringify(result.details, null, 2))
})
} else {
console.log('❌ 獲取資料失敗:', data.message)
}
} else {
console.log('❌ 獲取資料失敗,狀態碼:', response.status)
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 綜合測試資料檢查完成')
}
}
checkCombinedTestData()

View File

@@ -1,42 +0,0 @@
const { executeQuery } = require('../lib/database/connection')
async function checkCombinedTestResultsTable() {
console.log('🔍 檢查 combined_test_results 表結構...')
console.log('=' .repeat(50))
try {
// 檢查表結構
console.log('\n📊 combined_test_results 表結構:')
const columns = await executeQuery('DESCRIBE combined_test_results')
columns.forEach(column => {
console.log(`- ${column.Field}: ${column.Type} ${column.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${column.Key ? `(${column.Key})` : ''}`)
})
// 檢查表數據
console.log('\n📋 combined_test_results 表數據:')
const rows = await executeQuery('SELECT * FROM combined_test_results LIMIT 5')
if (rows.length > 0) {
console.log(`找到 ${rows.length} 筆記錄:`)
rows.forEach((row, index) => {
console.log(`\n記錄 ${index + 1}:`)
Object.entries(row).forEach(([key, value]) => {
console.log(` ${key}: ${value}`)
})
})
} else {
console.log('表中沒有數據')
}
// 檢查表索引
console.log('\n🔍 表索引:')
const indexes = await executeQuery('SHOW INDEX FROM combined_test_results')
indexes.forEach(index => {
console.log(`- ${index.Key_name}: ${index.Column_name} (${index.Index_type})`)
})
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
}
}
checkCombinedTestResultsTable()

View File

@@ -1,42 +0,0 @@
import { executeQuery } from '../lib/database/connection'
async function checkCombinedTestResultsTable() {
console.log('🔍 檢查 combined_test_results 表結構...')
console.log('=' .repeat(50))
try {
// 檢查表結構
console.log('\n📊 combined_test_results 表結構:')
const columns = await executeQuery('DESCRIBE combined_test_results')
columns.forEach((column: any) => {
console.log(`- ${column.Field}: ${column.Type} ${column.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${column.Key ? `(${column.Key})` : ''}`)
})
// 檢查表數據
console.log('\n📋 combined_test_results 表數據:')
const rows = await executeQuery('SELECT * FROM combined_test_results LIMIT 5')
if (rows.length > 0) {
console.log(`找到 ${rows.length} 筆記錄:`)
rows.forEach((row: any, index: number) => {
console.log(`\n記錄 ${index + 1}:`)
Object.entries(row).forEach(([key, value]) => {
console.log(` ${key}: ${value}`)
})
})
} else {
console.log('表中沒有數據')
}
// 檢查表索引
console.log('\n🔍 表索引:')
const indexes = await executeQuery('SHOW INDEX FROM combined_test_results')
indexes.forEach((index: any) => {
console.log(`- ${index.Key_name}: ${index.Column_name} (${index.Index_type})`)
})
} catch (error) {
console.error('❌ 檢查失敗:', error instanceof Error ? error.message : '未知錯誤')
}
}
checkCombinedTestResultsTable()

View File

@@ -1,64 +0,0 @@
const https = require('https')
const http = require('http')
const checkCombinedTime = async () => {
console.log('🔍 檢查綜合測試結果時間')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查綜合測試結果 API
console.log('\n📊 檢查綜合測試結果 API...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/combined?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.length > 0) {
const result = data.data[0]
console.log('📋 綜合測試結果時間詳情:')
console.log(`原始時間: ${result.completed_at}`)
const date = new Date(result.completed_at)
console.log(`UTC 時間: ${date.toISOString()}`)
console.log(`台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(`台灣時間 (詳細): ${date.toLocaleString("zh-TW", {
timeZone: "Asia/Taipei",
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: true
})}`)
// 檢查是否是今天
const now = new Date()
const testDate = new Date(result.completed_at)
const isToday = now.toDateString() === testDate.toDateString()
console.log(`是否為今天: ${isToday}`)
// 計算時間差
const timeDiff = now.getTime() - testDate.getTime()
const hoursDiff = Math.floor(timeDiff / (1000 * 60 * 60))
const minutesDiff = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60))
console.log(`距離現在: ${hoursDiff} 小時 ${minutesDiff} 分鐘`)
}
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 綜合測試結果時間檢查完成')
}
}
checkCombinedTime()

View File

@@ -1,49 +0,0 @@
const mysql = require('mysql2/promise')
async function checkCreativeQuestionsTable() {
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('🔍 檢查 creative_questions 表結構...')
let connection
try {
connection = await mysql.createConnection(config)
// 檢查表結構
const [columns] = await connection.execute("DESCRIBE creative_questions")
console.log('\n📊 creative_questions 表結構:')
columns.forEach(col => {
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? `(${col.Key})` : ''}`)
})
// 檢查表內容
const [rows] = await connection.execute("SELECT * FROM creative_questions LIMIT 3")
console.log('\n📝 creative_questions 表內容 (前3筆):')
if (rows.length > 0) {
rows.forEach((row, index) => {
console.log(`${index + 1}. ID: ${row.id}`)
console.log(` 題目: ${row.statement}`)
console.log(` 類別: ${row.category}`)
console.log(` 是否反向: ${row.is_reverse}`)
console.log('')
})
} else {
console.log('❌ 沒有找到創意題目數據')
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
if (connection) {
await connection.end()
}
}
}
checkCreativeQuestionsTable()

View File

@@ -1,52 +0,0 @@
const mysql = require('mysql2/promise')
async function checkCreativeQuestions() {
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)
const [rows] = await connection.execute('SELECT * FROM creative_questions ORDER BY id')
console.log(`\n📋 共找到 ${rows.length} 道創意能力測試題目:`)
console.log('=' .repeat(80))
rows.forEach((question, index) => {
const reverseText = question.is_reverse ? ' (反向題)' : ''
console.log(`\n${index + 1}. ID: ${question.id}`)
console.log(` 題目: ${question.statement}`)
console.log(` 類別: ${question.category}`)
console.log(` 反向題: ${question.is_reverse ? '是' : '否'}${reverseText}`)
})
console.log('\n📊 統計:')
const reverseCount = rows.filter(q => q.is_reverse).length
const normalCount = rows.length - reverseCount
const categoryCount = {}
rows.forEach(q => {
categoryCount[q.category] = (categoryCount[q.category] || 0) + 1
})
console.log(`- 一般題目: ${normalCount}`)
console.log(`- 反向題目: ${reverseCount}`)
console.log('- 類別分布:')
Object.entries(categoryCount).forEach(([category, count]) => {
console.log(` - ${category}: ${count}`)
})
await connection.end()
console.log('\n✅ 檢查完成')
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
}
}
checkCreativeQuestions()

View File

@@ -1,40 +0,0 @@
const mysql = require('mysql2/promise')
async function checkCreativeTableStructure() {
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('🔄 正在檢查 creative_questions 表結構...')
try {
const connection = await mysql.createConnection(config)
// 檢查表是否存在
const [tables] = await connection.execute("SHOW TABLES LIKE 'creative_questions'")
if (tables.length === 0) {
console.log('❌ creative_questions 表不存在')
} else {
console.log('✅ creative_questions 表存在')
// 檢查表結構
const [columns] = await connection.execute("DESCRIBE creative_questions")
console.log('\n📋 表結構:')
columns.forEach(col => {
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? `(${col.Key})` : ''} ${col.Default ? `DEFAULT ${col.Default}` : ''}`)
})
}
await connection.end()
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
}
}
checkCreativeTableStructure()

View File

@@ -1,41 +0,0 @@
const mysql = require('mysql2/promise')
async function checkCreativeTestAnswersTable() {
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('🔍 檢查 creative_test_answers 表結構...')
let connection
try {
connection = await mysql.createConnection(config)
// 檢查表是否存在
const [tables] = await connection.execute("SHOW TABLES LIKE 'creative_test_answers'")
if (tables.length === 0) {
console.log('❌ creative_test_answers 表不存在')
return
}
// 檢查表結構
const [columns] = await connection.execute("DESCRIBE creative_test_answers")
console.log('\n📊 creative_test_answers 表結構:')
columns.forEach(col => {
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? `(${col.Key})` : ''}`)
})
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
if (connection) {
await connection.end()
}
}
}
checkCreativeTestAnswersTable()

View File

@@ -1,84 +0,0 @@
const mysql = require('mysql2/promise')
async function checkCreativeTestResults() {
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('🔍 檢查創意測驗結果...')
let connection
try {
connection = await mysql.createConnection(config)
// 檢查 test_results 表中的創意測驗結果
const [creativeResults] = await connection.execute(
`SELECT tr.*, u.name as user_name
FROM test_results tr
JOIN users u ON tr.user_id = u.id
WHERE tr.test_type = 'creative'
ORDER BY tr.completed_at DESC`
)
console.log('\n📊 test_results 表中的創意測驗結果:')
if (creativeResults.length > 0) {
console.log(`找到 ${creativeResults.length} 筆創意測驗結果:`)
creativeResults.forEach((result, index) => {
console.log(`${index + 1}. ID: ${result.id}`)
console.log(` 用戶ID: ${result.user_id}`)
console.log(` 用戶名稱: ${result.user_name}`)
console.log(` 分數: ${result.score}`)
console.log(` 總分數: ${result.correct_answers}`)
console.log(` 總題數: ${result.total_questions}`)
console.log(` 完成時間: ${new Date(result.completed_at)}`)
console.log(` 建立時間: ${new Date(result.created_at)}`)
console.log('')
})
} else {
console.log('❌ 沒有找到創意測驗結果')
}
// 檢查 creative_test_answers 表中的答案記錄
const [answerRecords] = await connection.execute(
`SELECT cta.*, u.id as user_id, cq.statement as question_text, cq.is_reverse
FROM creative_test_answers cta
JOIN test_results tr ON cta.test_result_id = tr.id
JOIN users u ON tr.user_id = u.id
JOIN creative_questions cq ON cta.question_id = cq.id
ORDER BY cta.created_at ASC
LIMIT 10`
)
console.log('\n📝 creative_test_answers 表中的答案記錄 (前10筆):')
if (answerRecords.length > 0) {
console.log(`找到 ${answerRecords.length} 筆答案記錄:`)
answerRecords.forEach((record, index) => {
console.log(`${index + 1}. 答案ID: ${record.id}`)
console.log(` 測試結果ID: ${record.test_result_id}`)
console.log(` 用戶ID: ${record.user_id}`)
console.log(` 題目ID: ${record.question_id}`)
console.log(` 題目: ${record.question_text}`)
console.log(` 用戶答案: ${record.user_answer}`)
console.log(` 計算分數: ${record.score}`)
console.log(` 是否反向題: ${record.is_reverse ? '是' : '否'}`)
console.log(` 建立時間: ${new Date(record.created_at)}`)
console.log('')
})
} else {
console.log('❌ 沒有找到答案記錄')
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
if (connection) {
await connection.end()
}
}
}
checkCreativeTestResults()

View File

@@ -1,146 +0,0 @@
const { executeQuery } = require('../lib/database/connection')
const checkDatabasePassword = async () => {
console.log('🔍 檢查資料庫中的密碼')
console.log('=' .repeat(50))
try {
// 1. 創建一個測試用戶
console.log('\n📊 1. 創建測試用戶...')
const testUser = {
name: '資料庫密碼檢查用戶',
email: 'db.password@company.com',
password: 'password123',
department: '測試部',
role: 'user'
}
const createResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(testUser)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/admin/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = require('http').request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
let testUserId = null
if (createResponse.status === 200) {
const createData = JSON.parse(createResponse.data)
if (createData.success) {
testUserId = createData.data.id
console.log('✅ 測試用戶創建成功')
console.log(' 用戶ID:', createData.data.id)
console.log(' 電子郵件:', createData.data.email)
} else {
console.log('❌ 創建測試用戶失敗:', createData.error)
return
}
}
// 2. 直接查詢資料庫
console.log('\n📊 2. 直接查詢資料庫...')
try {
const query = 'SELECT id, name, email, password, department, role, created_at FROM users WHERE email = ?'
const result = await executeQuery(query, ['db.password@company.com'])
if (result && result.length > 0) {
const user = result[0]
console.log('✅ 資料庫查詢成功:')
console.log(' ID:', user.id)
console.log(' 姓名:', user.name)
console.log(' 電子郵件:', user.email)
console.log(' 部門:', user.department)
console.log(' 角色:', user.role)
console.log(' 建立時間:', user.created_at)
console.log(' 密碼長度:', user.password ? user.password.length : 'null')
console.log(' 密碼前綴:', user.password ? user.password.substring(0, 20) + '...' : 'null')
console.log(' 密碼是否為 bcrypt 格式:', user.password ? user.password.startsWith('$2b$') : false)
} else {
console.log('❌ 在資料庫中找不到用戶')
}
} catch (dbError) {
console.log('❌ 資料庫查詢失敗:', dbError.message)
}
// 3. 測試密碼驗證
console.log('\n📊 3. 測試密碼驗證...')
try {
const bcrypt = require('bcryptjs')
const query = 'SELECT password FROM users WHERE email = ?'
const result = await executeQuery(query, ['db.password@company.com'])
if (result && result.length > 0) {
const hashedPassword = result[0].password
const testPassword = 'password123'
console.log(' 測試密碼:', testPassword)
console.log(' 資料庫密碼雜湊:', hashedPassword.substring(0, 20) + '...')
const isValid = await bcrypt.compare(testPassword, hashedPassword)
console.log(' 密碼驗證結果:', isValid ? '✅ 成功' : '❌ 失敗')
if (!isValid) {
// 測試其他可能的密碼
const testPasswords = ['Password123', 'PASSWORD123', 'password', '123456']
for (const pwd of testPasswords) {
const testResult = await bcrypt.compare(pwd, hashedPassword)
console.log(` 測試密碼 "${pwd}":`, testResult ? '✅ 成功' : '❌ 失敗')
if (testResult) break
}
}
}
} catch (verifyError) {
console.log('❌ 密碼驗證測試失敗:', verifyError.message)
}
// 4. 清理測試用戶
console.log('\n📊 4. 清理測試用戶...')
if (testUserId) {
const deleteResponse = await new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 3000,
path: `/api/admin/users?id=${testUserId}`,
method: 'DELETE'
}
const req = require('http').request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.end()
})
if (deleteResponse.status === 200) {
console.log(`✅ 已刪除測試用戶: ${testUserId}`)
}
}
console.log('\n📝 資料庫密碼檢查總結:')
console.log('🔍 請查看以上詳細資訊,找出密碼問題')
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 資料庫密碼檢查完成')
}
}
checkDatabasePassword()

View File

@@ -1,68 +0,0 @@
const { executeQuery } = require('../lib/database/connection');
async function checkDatabaseStructure() {
console.log('🔍 檢查資料庫結構');
console.log('==============================');
try {
// 檢查 combined_test_results 的結構
console.log('\n📋 combined_test_results 範例:');
const combinedResults = await executeQuery('SELECT * FROM combined_test_results LIMIT 1');
if (combinedResults.length > 0) {
const result = combinedResults[0];
console.log('ID:', result.id);
console.log('User ID:', result.user_id);
console.log('Logic Score:', result.logic_score);
console.log('Creativity Score:', result.creativity_score);
console.log('Balance Score:', result.balance_score);
console.log('Overall Score:', result.overall_score);
console.log('Logic Breakdown:', typeof result.logic_breakdown, result.logic_breakdown);
console.log('Creativity Breakdown:', typeof result.creativity_breakdown, result.creativity_breakdown);
} else {
console.log('沒有 combined_test_results 資料');
}
// 檢查 logic_test_answers 的結構
console.log('\n📋 logic_test_answers 範例:');
const logicAnswers = await executeQuery('SELECT * FROM logic_test_answers LIMIT 3');
if (logicAnswers.length > 0) {
logicAnswers.forEach((answer, index) => {
console.log(`答案 ${index + 1}:`, {
id: answer.id,
test_result_id: answer.test_result_id,
question_id: answer.question_id,
user_answer: answer.user_answer,
correct_answer: answer.correct_answer,
is_correct: answer.is_correct,
explanation: answer.explanation
});
});
} else {
console.log('沒有 logic_test_answers 資料');
}
// 檢查 creative_test_answers 的結構
console.log('\n📋 creative_test_answers 範例:');
const creativeAnswers = await executeQuery('SELECT * FROM creative_test_answers LIMIT 3');
if (creativeAnswers.length > 0) {
creativeAnswers.forEach((answer, index) => {
console.log(`答案 ${index + 1}:`, {
id: answer.id,
test_result_id: answer.test_result_id,
question_id: answer.question_id,
user_answer: answer.user_answer,
score: answer.score
});
});
} else {
console.log('沒有 creative_test_answers 資料');
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message);
}
console.log('==============================\n');
}
checkDatabaseStructure();

View File

@@ -1,41 +0,0 @@
const { executeQuery } = require('../lib/database/connection')
const checkDbFields = async () => {
console.log('🔍 檢查資料庫欄位名稱')
console.log('=' .repeat(40))
try {
// 檢查表結構
console.log('\n📊 檢查 combined_test_results 表結構...')
const structureQuery = 'DESCRIBE combined_test_results'
const structure = await executeQuery(structureQuery)
console.log('📋 表欄位:')
structure.forEach(field => {
console.log(` ${field.Field}: ${field.Type}`)
})
// 檢查實際資料
console.log('\n📊 檢查實際資料...')
const dataQuery = 'SELECT id, user_id, logic_score, creativity_score, balance_score, overall_score FROM combined_test_results LIMIT 2'
const data = await executeQuery(dataQuery)
console.log('📋 實際資料:')
data.forEach((row, index) => {
console.log(`\n 記錄 ${index + 1}:`)
console.log(` id: ${row.id}`)
console.log(` user_id: ${row.user_id}`)
console.log(` logic_score: ${row.logic_score}`)
console.log(` creativity_score: ${row.creativity_score}`)
console.log(` balance_score: ${row.balance_score}`)
console.log(` overall_score: ${row.overall_score}`)
})
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 資料庫欄位檢查完成')
}
}
checkDbFields()

View File

@@ -1,75 +0,0 @@
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()

View File

@@ -1,78 +0,0 @@
const mysql = require('mysql2/promise')
const checkDbTimeFormat = async () => {
console.log('🔍 檢查資料庫中的時間格式')
console.log('=' .repeat(50))
const connection = await mysql.createConnection({
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || 3306,
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'hr_assessment'
})
try {
// 檢查 test_results 表的時間格式
console.log('\n📊 檢查 test_results 表的時間格式...')
const [testResults] = await connection.execute(`
SELECT id, test_type, completed_at, created_at
FROM test_results
WHERE user_id = 'user-1759073326705-m06y3wacd'
ORDER BY completed_at DESC
`)
testResults.forEach((result, index) => {
console.log(`\n${index + 1}. ${result.test_type} 測試:`)
console.log(` ID: ${result.id}`)
console.log(` completed_at (原始): ${result.completed_at}`)
console.log(` completed_at (類型): ${typeof result.completed_at}`)
console.log(` created_at (原始): ${result.created_at}`)
console.log(` created_at (類型): ${typeof result.created_at}`)
// 測試時間轉換
const completedDate = new Date(result.completed_at)
const createdDate = new Date(result.created_at)
console.log(` completed_at 轉換: ${completedDate.toISOString()}`)
console.log(` completed_at 台灣時間: ${completedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` created_at 轉換: ${createdDate.toISOString()}`)
console.log(` created_at 台灣時間: ${createdDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
})
// 檢查 combined_test_results 表的時間格式
console.log('\n📊 檢查 combined_test_results 表的時間格式...')
const [combinedResults] = await connection.execute(`
SELECT id, completed_at, created_at
FROM combined_test_results
WHERE user_id = 'user-1759073326705-m06y3wacd'
ORDER BY completed_at DESC
`)
combinedResults.forEach((result, index) => {
console.log(`\n${index + 1}. 綜合測試:`)
console.log(` ID: ${result.id}`)
console.log(` completed_at (原始): ${result.completed_at}`)
console.log(` completed_at (類型): ${typeof result.completed_at}`)
console.log(` created_at (原始): ${result.created_at}`)
console.log(` created_at (類型): ${typeof result.created_at}`)
// 測試時間轉換
const completedDate = new Date(result.completed_at)
const createdDate = new Date(result.created_at)
console.log(` completed_at 轉換: ${completedDate.toISOString()}`)
console.log(` completed_at 台灣時間: ${completedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` created_at 轉換: ${createdDate.toISOString()}`)
console.log(` created_at 台灣時間: ${createdDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
})
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
await connection.end()
console.log('\n✅ 資料庫時間格式檢查完成')
}
}
checkDbTimeFormat()

View File

@@ -1,72 +0,0 @@
const https = require('https')
const http = require('http')
const checkLatestCreativeTime = async () => {
console.log('🔍 檢查最新創意測驗結果時間')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查創意測試結果 API
console.log('\n📊 檢查創意測試結果 API...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.length > 0) {
console.log(`找到 ${data.data.length} 筆創意測試結果:`)
// 按創建時間排序,取最新的
const sortedResults = data.data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
const latestResult = sortedResults[0]
console.log('\n📋 最新創意測試結果:')
console.log(`ID: ${latestResult.id}`)
console.log(`completed_at: ${latestResult.completed_at}`)
console.log(`created_at: ${latestResult.created_at}`)
const completedDate = new Date(latestResult.completed_at)
const createdDate = new Date(latestResult.created_at)
console.log(`completed_at 台灣時間: ${completedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(`created_at 台灣時間: ${createdDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
// 檢查時間差
const timeDiff = createdDate.getTime() - completedDate.getTime()
const hoursDiff = timeDiff / (1000 * 60 * 60)
console.log(`時間差: ${hoursDiff.toFixed(2)} 小時`)
// 檢查是否是今天
const now = new Date()
const isToday = now.toDateString() === completedDate.toDateString()
console.log(`是否為今天: ${isToday}`)
// 計算距離現在的時間
const nowDiff = now.getTime() - completedDate.getTime()
const nowHoursDiff = nowDiff / (1000 * 60 * 60)
console.log(`距離現在: ${nowHoursDiff.toFixed(2)} 小時`)
}
}
// 檢查當前時間
console.log('\n📊 當前時間:')
const now = new Date()
console.log(`UTC 時間: ${now.toISOString()}`)
console.log(`台灣時間: ${now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 最新創意測驗結果時間檢查完成')
}
}
checkLatestCreativeTime()

View File

@@ -1,56 +0,0 @@
const https = require('https')
const http = require('http')
const checkLatestTestResults = async () => {
console.log('🔍 檢查最新的測試結果')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查所有測試結果
console.log('\n📊 檢查所有測試結果...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/user/test-results?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.results.length > 0) {
console.log(`找到 ${data.data.results.length} 筆測試結果:`)
data.data.results.forEach((result, index) => {
console.log(`\n${index + 1}. ${result.type} 測試:`)
console.log(` completedAt: ${result.completedAt}`)
const date = new Date(result.completedAt)
const isValid = !isNaN(date.getTime())
console.log(` 解析是否有效: ${isValid ? '✅' : '❌'}`)
if (isValid) {
const taiwanTime = date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(` 台灣時間: ${taiwanTime}`)
}
})
}
}
// 檢查當前時間
console.log('\n📊 當前時間:')
const now = new Date()
console.log(`UTC 時間: ${now.toISOString()}`)
console.log(`台灣時間: ${now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 最新測試結果檢查完成')
}
}
checkLatestTestResults()

View File

@@ -1,38 +0,0 @@
const { executeQuery } = require('../lib/database/connection');
async function checkLogicAnswers() {
try {
console.log('=== 檢查 logic_test_answers 表 ===');
const answers = await executeQuery('SELECT * FROM logic_test_answers');
console.log('logic_test_answers 資料總數:', answers.length);
if (answers.length > 0) {
console.log('前3筆資料:', answers.slice(0, 3));
}
console.log('\n=== 檢查 test_results 表 ===');
const results = await executeQuery('SELECT * FROM test_results WHERE type = "logic" ORDER BY created_at DESC LIMIT 5');
console.log('logic test_results 資料總數:', results.length);
if (results.length > 0) {
console.log('前3筆資料:', results);
console.log('\n=== 檢查關聯資料 ===');
for (const result of results.slice(0, 2)) {
console.log(`\n檢查 test_result_id: ${result.id}`);
const relatedAnswers = await executeQuery('SELECT * FROM logic_test_answers WHERE test_result_id = ?', [result.id]);
console.log(`關聯的答案數量: ${relatedAnswers.length}`);
if (relatedAnswers.length > 0) {
console.log('答案資料:', relatedAnswers);
}
}
}
console.log('\n=== 檢查所有 test_results 類型 ===');
const allResults = await executeQuery('SELECT type, COUNT(*) as count FROM test_results GROUP BY type');
console.log('各類型測試結果數量:', allResults);
} catch (error) {
console.error('錯誤:', error.message);
}
}
checkLogicAnswers();

View File

@@ -1,45 +0,0 @@
const mysql = require('mysql2/promise')
async function checkLogicQuestions() {
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)
const [rows] = await connection.execute('SELECT * FROM logic_questions ORDER BY id')
console.log(`\n📋 共找到 ${rows.length} 道邏輯思維題目:`)
console.log('=' .repeat(80))
rows.forEach((question, index) => {
console.log(`\n${index + 1}. ID: ${question.id}`)
console.log(` 題目: ${question.question}`)
console.log(` A. ${question.option_a}`)
console.log(` B. ${question.option_b}`)
console.log(` C. ${question.option_c}`)
console.log(` D. ${question.option_d}`)
if (question.option_e) {
console.log(` E. ${question.option_e}`)
}
console.log(` 正確答案: ${question.correct_answer}`)
if (question.explanation) {
console.log(` 解說: ${question.explanation}`)
}
})
await connection.end()
console.log('\n✅ 檢查完成')
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
}
}
checkLogicQuestions()

View File

@@ -1,40 +0,0 @@
const mysql = require('mysql2/promise')
async function checkPasswords() {
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)
const [rows] = await connection.execute('SELECT id, name, email, password FROM users ORDER BY created_at')
console.log('\n📋 用戶密碼狀態:')
console.log('=' .repeat(80))
rows.forEach((user, index) => {
const isHashed = user.password.startsWith('$2b$') || user.password.startsWith('$2a$')
const passwordStatus = isHashed ? '✅ 已雜湊' : '❌ 明文'
const passwordPreview = isHashed ? user.password.substring(0, 20) + '...' : user.password
console.log(`${index + 1}. ${user.name} (${user.email})`)
console.log(` 密碼狀態: ${passwordStatus}`)
console.log(` 密碼內容: ${passwordPreview}`)
console.log('')
})
await connection.end()
console.log('✅ 檢查完成')
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
}
}
checkPasswords()

View File

@@ -1,72 +0,0 @@
const https = require('https')
const http = require('http')
const checkRawTestData = async () => {
console.log('🔍 檢查原始測試數據')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查邏輯測試結果
console.log('\n📊 檢查邏輯測試結果...')
const logicResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/logic?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (logicResponse.status === 200) {
const logicData = JSON.parse(logicResponse.data)
if (logicData.success && logicData.data.length > 0) {
console.log('邏輯測試結果:')
logicData.data.forEach((result, index) => {
console.log(`\n${index + 1}. 邏輯測試:`)
console.log(` ID: ${result.id}`)
console.log(` 原始時間: ${result.completed_at}`)
console.log(` 創建時間: ${result.created_at}`)
const date = new Date(result.completed_at)
console.log(` 台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
})
}
}
// 檢查創意測試結果
console.log('\n📊 檢查創意測試結果...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success && creativeData.data.length > 0) {
console.log('創意測試結果:')
creativeData.data.forEach((result, index) => {
console.log(`\n${index + 1}. 創意測試:`)
console.log(` ID: ${result.id}`)
console.log(` 原始時間: ${result.completed_at}`)
console.log(` 創建時間: ${result.created_at}`)
const date = new Date(result.completed_at)
console.log(` 台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
})
}
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 原始測試數據檢查完成')
}
}
checkRawTestData()

View File

@@ -1,66 +0,0 @@
const { executeQuery } = require('../lib/database/connection');
async function checkSingleTestAnswers() {
console.log('🔍 檢查單一測試類型的答案資料');
console.log('==============================');
try {
// 檢查 test_results 表
console.log('\n📋 Test Results:');
const testResults = await executeQuery('SELECT id, user_id, test_type, score, completed_at FROM test_results ORDER BY completed_at DESC LIMIT 5');
testResults.forEach((result, index) => {
console.log(`測試 ${index + 1}:`, {
id: result.id,
user_id: result.user_id,
test_type: result.test_type,
score: result.score,
completed_at: result.completed_at
});
});
// 檢查 logic_test_answers 表
console.log('\n📋 Logic Test Answers:');
const logicAnswers = await executeQuery('SELECT * FROM logic_test_answers ORDER BY created_at DESC LIMIT 5');
logicAnswers.forEach((answer, index) => {
console.log(`邏輯答案 ${index + 1}:`, {
id: answer.id,
test_result_id: answer.test_result_id,
question_id: answer.question_id,
user_answer: answer.user_answer,
is_correct: answer.is_correct
});
});
// 檢查 creative_test_answers 表
console.log('\n📋 Creative Test Answers:');
const creativeAnswers = await executeQuery('SELECT * FROM creative_test_answers ORDER BY created_at DESC LIMIT 5');
creativeAnswers.forEach((answer, index) => {
console.log(`創意答案 ${index + 1}:`, {
id: answer.id,
test_result_id: answer.test_result_id,
question_id: answer.question_id,
user_answer: answer.user_answer,
score: answer.score
});
});
// 檢查是否有匹配的答案
if (testResults.length > 0) {
const firstTest = testResults[0];
console.log(`\n🔍 檢查測試 ${firstTest.id} 的答案:`);
const matchingLogicAnswers = await executeQuery('SELECT * FROM logic_test_answers WHERE test_result_id = ?', [firstTest.id]);
console.log(`邏輯答案匹配數量: ${matchingLogicAnswers.length}`);
const matchingCreativeAnswers = await executeQuery('SELECT * FROM creative_test_answers WHERE test_result_id = ?', [firstTest.id]);
console.log(`創意答案匹配數量: ${matchingCreativeAnswers.length}`);
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message);
}
console.log('==============================\n');
}
checkSingleTestAnswers();

View File

@@ -1,39 +0,0 @@
const mysql = require('mysql2/promise')
async function checkTableStructure() {
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)
// 檢查 logic_questions 表是否存在
const [tables] = await connection.execute("SHOW TABLES LIKE 'logic_questions'")
if (tables.length === 0) {
console.log('❌ logic_questions 表不存在')
} else {
console.log('✅ logic_questions 表存在')
// 檢查表結構
const [columns] = await connection.execute("DESCRIBE logic_questions")
console.log('\n📋 logic_questions 表結構:')
columns.forEach(col => {
console.log(` ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Key ? col.Key : ''}`)
})
}
await connection.end()
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
}
}
checkTableStructure()

View File

@@ -1,102 +0,0 @@
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()

View File

@@ -1,68 +0,0 @@
const https = require('https')
const http = require('http')
const checkTimezoneIssue = async () => {
console.log('🔍 檢查時區問題')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 1. 檢查用戶測試結果 API 返回的時間
console.log('\n📊 1. 檢查用戶測試結果 API 返回的時間...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/user/test-results?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.results.length > 0) {
console.log('📋 測試結果時間:')
data.data.results.forEach((result, index) => {
console.log(`\n${index + 1}. ${result.type}:`)
console.log(` 原始時間: ${result.completedAt}`)
// 測試不同的時間格式化方式
const date = new Date(result.completedAt)
console.log(` UTC 時間: ${date.toISOString()}`)
console.log(` 本地時間: ${date.toLocaleString()}`)
console.log(` 台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` 台灣時間 (en): ${date.toLocaleString("en-US", { timeZone: "Asia/Taipei" })}`)
})
}
}
// 2. 檢查當前時間
console.log('\n📊 2. 檢查當前時間...')
const now = new Date()
console.log(`當前 UTC 時間: ${now.toISOString()}`)
console.log(`當前本地時間: ${now.toLocaleString()}`)
console.log(`當前台灣時間: ${now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
// 3. 測試時間轉換
console.log('\n📊 3. 測試時間轉換...')
const testTimes = [
'2025-09-29T01:07:00.000Z', // 從 API 返回的時間
'2025-09-29T09:08:17.000Z', // 可能的另一個時間
]
testTimes.forEach((timeStr, index) => {
console.log(`\n測試時間 ${index + 1}: ${timeStr}`)
const testDate = new Date(timeStr)
console.log(` UTC: ${testDate.toISOString()}`)
console.log(` 台灣時間: ${testDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
})
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 時區問題檢查完成')
}
}
checkTimezoneIssue()

View File

@@ -1,43 +0,0 @@
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()

View File

@@ -1,48 +0,0 @@
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()

View File

@@ -1,91 +0,0 @@
const https = require('https')
const http = require('http')
const checkUserPassword = async () => {
console.log('🔍 檢查用戶密碼格式')
console.log('=' .repeat(50))
const testUserId = 'user-1759073326705-m06y3wacd'
try {
// 檢查用戶資料
console.log('\n📊 檢查用戶資料...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/user/profile?userId=${testUserId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success) {
console.log('✅ 用戶資料:')
console.log(` ID: ${data.data.id}`)
console.log(` 姓名: ${data.data.name}`)
console.log(` 電子郵件: ${data.data.email}`)
console.log(` 部門: ${data.data.department}`)
console.log(` 角色: ${data.data.role}`)
console.log(` 密碼: ${data.data.password ? '已隱藏' : '未返回'}`)
}
}
// 測試不同的密碼
console.log('\n📊 測試密碼更新...')
const testPasswords = ['password123', 'test123', '123456', 'admin123']
for (const password of testPasswords) {
console.log(`\n測試密碼: ${password}`)
const updateData = {
userId: testUserId,
currentPassword: password,
newPassword: 'newpassword123'
}
const updateResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(updateData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/user/profile',
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (updateResponse.status === 200) {
const updateResult = JSON.parse(updateResponse.data)
if (updateResult.success) {
console.log(`✅ 密碼 ${password} 正確,更新成功`)
break
} else {
console.log(`❌ 密碼 ${password} 錯誤: ${updateResult.error}`)
}
} else {
console.log(`❌ API 請求失敗: ${updateResponse.status}`)
}
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 用戶密碼檢查完成')
}
}
checkUserPassword()

View File

@@ -1,132 +0,0 @@
const https = require('https')
const http = require('http')
const debugDimensionScoring = async () => {
console.log('🔍 調試維度分數計算')
console.log('=' .repeat(50))
const testResultId = 'test_1759086508812_xv2pof6lk' // 使用最新的測試結果ID
try {
// 1. 獲取測試結果
console.log('\n📊 1. 獲取測試結果...')
const resultResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=user-1759073326705-m06y3wacd`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (resultResponse.status === 200) {
const resultData = JSON.parse(resultResponse.data)
if (resultData.success && resultData.data.length > 0) {
const testResult = resultData.data[0]
console.log('測試結果:', {
id: testResult.id,
score: testResult.score,
total_questions: testResult.total_questions,
correct_answers: testResult.correct_answers
})
}
}
// 2. 獲取題目資料
console.log('\n📊 2. 獲取題目資料...')
const questionsResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/creative-questions', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
let questions = []
if (questionsResponse.status === 200) {
const questionsData = JSON.parse(questionsResponse.data)
if (questionsData.success) {
questions = questionsData.questions
console.log(`獲取到 ${questions.length} 個題目`)
}
}
// 3. 獲取詳細答案
console.log('\n📊 3. 獲取詳細答案...')
const answersResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/creative-test-answers?testResultId=${testResultId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (answersResponse.status === 200) {
const answersData = JSON.parse(answersResponse.data)
if (answersData.success) {
const answers = answersData.data
console.log(`獲取到 ${answers.length} 個答案`)
// 4. 按維度分組計算
console.log('\n📊 4. 按維度分組計算...')
const dimensionScores = {
innovation: { total: 0, count: 0, answers: [] },
imagination: { total: 0, count: 0, answers: [] },
flexibility: { total: 0, count: 0, answers: [] },
originality: { total: 0, count: 0, answers: [] }
}
answers.forEach((answer) => {
const question = questions.find(q => q.id === answer.question_id)
if (question && dimensionScores[question.category]) {
dimensionScores[question.category].total += answer.score
dimensionScores[question.category].count += 1
dimensionScores[question.category].answers.push({
question_id: answer.question_id,
user_answer: answer.user_answer,
score: answer.score,
is_reverse: question.is_reverse
})
}
})
// 5. 顯示詳細計算過程
console.log('\n📊 5. 詳細計算過程:')
Object.keys(dimensionScores).forEach(category => {
const { total, count, answers } = dimensionScores[category]
const maxPossible = count * 5
const percentage = count > 0 ? Math.round((total / maxPossible) * 100) : 0
console.log(`\n${category}:`)
console.log(` 題目數量: ${count}`)
console.log(` 總分數: ${total}`)
console.log(` 最大可能分數: ${maxPossible}`)
console.log(` 百分比: ${percentage}%`)
console.log(` 答案詳情:`)
answers.forEach((ans, index) => {
console.log(` ${index + 1}. 題目${ans.question_id}: 用戶答案${ans.user_answer} → 計算分數${ans.score} (反向題: ${ans.is_reverse ? '是' : '否'})`)
})
})
// 6. 總分驗證
console.log('\n📊 6. 總分驗證:')
const totalScore = answers.reduce((sum, answer) => sum + answer.score, 0)
const maxTotalScore = answers.length * 5
const totalPercentage = Math.round((totalScore / maxTotalScore) * 100)
console.log(`所有答案總分數: ${totalScore}`)
console.log(`最大可能總分數: ${maxTotalScore}`)
console.log(`總百分比: ${totalPercentage}%`)
}
}
} catch (error) {
console.error('❌ 調試失敗:', error.message)
} finally {
console.log('\n✅ 維度分數計算調試完成')
}
}
debugDimensionScoring()

View File

@@ -1,74 +0,0 @@
const https = require('https')
const http = require('http')
const debugInvalidDate = async () => {
console.log('🔍 調試 Invalid Date 問題')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查創意測試結果 API
console.log('\n📊 檢查創意測試結果 API...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.length > 0) {
console.log(`找到 ${data.data.length} 筆創意測試結果:`)
// 按創建時間排序,取最新的
const sortedResults = data.data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
const latestResult = sortedResults[0]
console.log('\n📋 最新創意測試結果:')
console.log(`ID: ${latestResult.id}`)
console.log(`completed_at: ${latestResult.completed_at}`)
console.log(`completed_at 類型: ${typeof latestResult.completed_at}`)
// 測試不同的解析方式
console.log('\n📊 測試時間解析:')
// 方式1直接解析
const directParse = new Date(latestResult.completed_at)
console.log(`直接解析: ${directParse.toISOString()} (${directParse.toString()})`)
// 方式2添加 Z 後解析
const withZ = new Date(latestResult.completed_at + 'Z')
console.log(`添加 Z 後解析: ${withZ.toISOString()} (${withZ.toString()})`)
// 方式3檢查是否為有效日期
console.log(`直接解析是否有效: ${!isNaN(directParse.getTime())}`)
console.log(`添加 Z 後是否有效: ${!isNaN(withZ.getTime())}`)
// 測試台灣時間轉換
if (!isNaN(withZ.getTime())) {
const taiwanTime = withZ.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(`台灣時間: ${taiwanTime}`)
}
// 檢查時間格式
console.log('\n📊 時間格式分析:')
console.log(`原始格式: "${latestResult.completed_at}"`)
console.log(`長度: ${latestResult.completed_at.length}`)
console.log(`包含 T: ${latestResult.completed_at.includes('T')}`)
console.log(`包含 Z: ${latestResult.completed_at.includes('Z')}`)
console.log(`包含空格: ${latestResult.completed_at.includes(' ')}`)
}
}
} catch (error) {
console.error('❌ 調試失敗:', error.message)
} finally {
console.log('\n✅ Invalid Date 問題調試完成')
}
}
debugInvalidDate()

View File

@@ -1,218 +0,0 @@
const https = require('https')
const http = require('http')
const debugPasswordHash = async () => {
console.log('🔍 調試密碼雜湊問題')
console.log('=' .repeat(50))
try {
// 1. 創建一個測試用戶並記錄詳細資訊
console.log('\n📊 1. 創建測試用戶並記錄詳細資訊...')
const testUser = {
name: '密碼雜湊調試用戶',
email: 'hash.debug@company.com',
password: 'password123',
department: '測試部',
role: 'user'
}
console.log(' 原始密碼:', testUser.password)
const createResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(testUser)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/admin/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
let testUserId = null
if (createResponse.status === 200) {
const createData = JSON.parse(createResponse.data)
if (createData.success) {
testUserId = createData.data.id
console.log('✅ 測試用戶創建成功')
console.log(' 用戶ID:', createData.data.id)
console.log(' 電子郵件:', createData.data.email)
} else {
console.log('❌ 創建測試用戶失敗:', createData.error)
return
}
} else {
console.log('❌ 創建用戶 API 回應錯誤:', createResponse.status)
console.log(' 回應內容:', createResponse.data)
return
}
// 2. 嘗試登入並記錄詳細錯誤
console.log('\n📊 2. 嘗試登入並記錄詳細錯誤...')
const loginData = {
email: 'hash.debug@company.com',
password: 'password123'
}
console.log(' 登入嘗試 - 電子郵件:', loginData.email)
console.log(' 登入嘗試 - 密碼:', loginData.password)
const loginResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(loginData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
console.log(' 登入回應狀態碼:', loginResponse.status)
console.log(' 登入回應內容:', loginResponse.data)
if (loginResponse.status === 200) {
const loginResult = JSON.parse(loginResponse.data)
if (loginResult.success) {
console.log('✅ 登入成功!')
} else {
console.log('❌ 登入失敗:', loginResult.error)
}
} else {
const errorData = JSON.parse(loginResponse.data)
console.log('❌ 登入 API 錯誤:', errorData.error)
}
// 3. 檢查資料庫中的用戶資料
console.log('\n📊 3. 檢查資料庫中的用戶資料...')
const getUsersResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/users', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (getUsersResponse.status === 200) {
const usersData = JSON.parse(getUsersResponse.data)
if (usersData.success) {
const testUserInDB = usersData.data.find(user => user.id === testUserId)
if (testUserInDB) {
console.log('✅ 資料庫中的用戶資料:')
console.log(' ID:', testUserInDB.id)
console.log(' 姓名:', testUserInDB.name)
console.log(' 電子郵件:', testUserInDB.email)
console.log(' 部門:', testUserInDB.department)
console.log(' 角色:', testUserInDB.role)
console.log(' 建立時間:', testUserInDB.created_at)
console.log(' 更新時間:', testUserInDB.updated_at)
// 注意:密碼欄位不會在 API 回應中返回,這是正常的
} else {
console.log('❌ 在資料庫中找不到測試用戶')
}
}
}
// 4. 測試現有用戶的登入(作為對照)
console.log('\n📊 4. 測試現有用戶的登入(作為對照)...')
const existingUserLogin = {
email: 'admin@company.com',
password: 'admin123'
}
const existingLoginResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(existingUserLogin)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (existingLoginResponse.status === 200) {
const existingLoginResult = JSON.parse(existingLoginResponse.data)
if (existingLoginResult.success) {
console.log('✅ 現有用戶登入成功(對照組)')
} else {
console.log('❌ 現有用戶登入失敗:', existingLoginResult.error)
}
} else {
const errorData = JSON.parse(existingLoginResponse.data)
console.log('❌ 現有用戶登入 API 錯誤:', errorData.error)
}
// 5. 清理測試用戶
console.log('\n📊 5. 清理測試用戶...')
if (testUserId) {
const deleteResponse = await new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 3000,
path: `/api/admin/users?id=${testUserId}`,
method: 'DELETE'
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.end()
})
if (deleteResponse.status === 200) {
console.log(`✅ 已刪除測試用戶: ${testUserId}`)
}
}
console.log('\n📝 調試總結:')
console.log('🔍 請檢查以上詳細資訊,找出密碼雜湊和驗證的問題')
} catch (error) {
console.error('❌ 調試失敗:', error.message)
} finally {
console.log('\n✅ 密碼雜湊調試完成')
}
}
debugPasswordHash()

View File

@@ -1,204 +0,0 @@
const https = require('https')
const http = require('http')
const debugPasswordVerification = async () => {
console.log('🔍 調試密碼驗證問題')
console.log('=' .repeat(50))
try {
// 1. 創建一個測試用戶
console.log('\n📊 1. 創建測試用戶...')
const testUser = {
name: '密碼調試用戶',
email: 'debug.password@company.com',
password: 'password123',
department: '測試部',
role: 'user'
}
const createResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(testUser)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/admin/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
let testUserId = null
if (createResponse.status === 200) {
const createData = JSON.parse(createResponse.data)
if (createData.success) {
testUserId = createData.data.id
console.log('✅ 測試用戶創建成功')
} else {
console.log('❌ 創建測試用戶失敗:', createData.error)
return
}
}
// 2. 直接查詢資料庫中的密碼雜湊
console.log('\n📊 2. 檢查資料庫中的密碼雜湊...')
// 這裡我們需要直接查詢資料庫來看看密碼是如何儲存的
// 由於我們無法直接訪問資料庫,我們可以通過 API 來檢查
// 3. 測試不同的密碼組合
console.log('\n📊 3. 測試不同的密碼組合...')
const testPasswords = [
'password123', // 原始密碼
'Password123', // 大寫開頭
'PASSWORD123', // 全大寫
'password', // 沒有數字
'123456', // 只有數字
]
for (const testPassword of testPasswords) {
console.log(`\n 測試密碼: "${testPassword}"`)
const loginData = {
email: 'debug.password@company.com',
password: testPassword
}
const loginResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(loginData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (loginResponse.status === 200) {
const loginResult = JSON.parse(loginResponse.data)
if (loginResult.success) {
console.log(` ✅ 登入成功!正確密碼是: "${testPassword}"`)
break
} else {
console.log(` ❌ 登入失敗: ${loginResult.error}`)
}
} else {
const errorData = JSON.parse(loginResponse.data)
console.log(` ❌ 登入失敗: ${errorData.error}`)
}
}
// 4. 檢查現有用戶的登入情況
console.log('\n📊 4. 檢查現有用戶的登入情況...')
const existingUsers = [
{ email: 'admin@company.com', password: 'admin123' },
{ email: 'user@company.com', password: 'user123' },
{ email: 'test@company.com', password: 'password123' }
]
for (const user of existingUsers) {
console.log(`\n 測試現有用戶: ${user.email}`)
const loginData = {
email: user.email,
password: user.password
}
const loginResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(loginData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (loginResponse.status === 200) {
const loginResult = JSON.parse(loginResponse.data)
if (loginResult.success) {
console.log(` ✅ 登入成功`)
} else {
console.log(` ❌ 登入失敗: ${loginResult.error}`)
}
} else {
const errorData = JSON.parse(loginResponse.data)
console.log(` ❌ 登入失敗: ${errorData.error}`)
}
}
// 5. 清理測試用戶
console.log('\n📊 5. 清理測試用戶...')
if (testUserId) {
const deleteResponse = await new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 3000,
path: `/api/admin/users?id=${testUserId}`,
method: 'DELETE'
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.end()
})
if (deleteResponse.status === 200) {
console.log(`✅ 已刪除測試用戶: ${testUserId}`)
}
}
console.log('\n📝 調試總結:')
console.log('🔍 請檢查以上測試結果,找出密碼驗證問題的原因')
} catch (error) {
console.error('❌ 調試失敗:', error.message)
} finally {
console.log('\n✅ 密碼驗證調試完成')
}
}
debugPasswordVerification()

View File

@@ -1,61 +0,0 @@
const https = require('https')
const http = require('http')
const fixExistingTimes = async () => {
console.log('🔍 修正現有測試結果的時間')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查現有的測試結果
console.log('\n📊 檢查現有測試結果...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/user/test-results?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.results.length > 0) {
console.log('發現需要修正的測試結果:')
data.data.results.forEach((result, index) => {
console.log(`\n${index + 1}. ${result.type} 測試:`)
console.log(` 原始時間: ${result.completedAt}`)
const date = new Date(result.completedAt)
const taiwanTime = date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(` 台灣時間: ${taiwanTime}`)
// 檢查時間是否合理
const now = new Date()
const timeDiff = now.getTime() - date.getTime()
const hoursDiff = Math.floor(timeDiff / (1000 * 60 * 60))
if (hoursDiff > 24) {
console.log(` ⚠️ 時間可能不正確 (${hoursDiff} 小時前)`)
} else {
console.log(` ✅ 時間看起來正確 (${hoursDiff} 小時前)`)
}
})
}
}
console.log('\n📝 建議:')
console.log('1. 時間格式已修正,新的測試結果會使用正確的 UTC 時間')
console.log('2. 現有的錯誤時間數據可能需要手動修正或重新測試')
console.log('3. 建議重新進行一次測試來驗證修正效果')
} catch (error) {
console.error('❌ 檢查失敗:', error.message)
} finally {
console.log('\n✅ 現有時間檢查完成')
}
}
fixExistingTimes()

View File

@@ -1,40 +0,0 @@
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()

View File

@@ -1,170 +0,0 @@
const http = require('http')
const testAdminResults = async () => {
console.log('🔍 測試管理員測驗結果功能')
console.log('=' .repeat(40))
try {
// 測試基本 API 呼叫
console.log('\n📊 測試基本 API 呼叫...')
const basicResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (basicResponse.status === 200) {
const basicData = JSON.parse(basicResponse.data)
if (basicData.success) {
console.log('✅ 基本 API 呼叫成功')
console.log(`📈 統計資料:`)
console.log(` 總測試次數: ${basicData.data.stats.totalResults}`)
console.log(` 平均分數: ${basicData.data.stats.averageScore}`)
console.log(` 總用戶數: ${basicData.data.stats.totalUsers}`)
console.log(` 參與率: ${basicData.data.stats.participationRate}%`)
console.log(` 測試類型分布:`)
console.log(` 邏輯思維: ${basicData.data.stats.testTypeCounts.logic}`)
console.log(` 創意能力: ${basicData.data.stats.testTypeCounts.creative}`)
console.log(` 綜合能力: ${basicData.data.stats.testTypeCounts.combined}`)
console.log(`📄 分頁資訊:`)
console.log(` 當前頁: ${basicData.data.pagination.currentPage}`)
console.log(` 總頁數: ${basicData.data.pagination.totalPages}`)
console.log(` 每頁限制: ${basicData.data.pagination.limit}`)
console.log(` 總結果數: ${basicData.data.pagination.totalResults}`)
console.log(`🏢 部門列表: ${basicData.data.departments.join(', ')}`)
console.log(`📋 結果數量: ${basicData.data.results.length}`)
} else {
console.log('❌ 基本 API 呼叫失敗:', basicData.message)
return
}
} else {
console.log('❌ 基本 API 呼叫失敗,狀態碼:', basicResponse.status)
return
}
// 測試搜尋功能
console.log('\n🔍 測試搜尋功能...')
const searchResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results?search=王', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (searchResponse.status === 200) {
const searchData = JSON.parse(searchResponse.data)
if (searchData.success) {
console.log(`✅ 搜尋功能正常,找到 ${searchData.data.pagination.totalResults} 筆結果`)
} else {
console.log('❌ 搜尋功能失敗:', searchData.message)
}
}
// 測試部門篩選
console.log('\n🏢 測試部門篩選...')
const deptResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results?department=人力資源部', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (deptResponse.status === 200) {
const deptData = JSON.parse(deptResponse.data)
if (deptData.success) {
console.log(`✅ 部門篩選正常,找到 ${deptData.data.pagination.totalResults} 筆結果`)
} else {
console.log('❌ 部門篩選失敗:', deptData.message)
}
}
// 測試測試類型篩選
console.log('\n🧠 測試測試類型篩選...')
const typeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results?testType=logic', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (typeResponse.status === 200) {
const typeData = JSON.parse(typeResponse.data)
if (typeData.success) {
console.log(`✅ 測試類型篩選正常,找到 ${typeData.data.pagination.totalResults} 筆結果`)
} else {
console.log('❌ 測試類型篩選失敗:', typeData.message)
}
}
// 測試分頁功能
console.log('\n📄 測試分頁功能...')
const pageResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results?page=1&limit=5', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (pageResponse.status === 200) {
const pageData = JSON.parse(pageResponse.data)
if (pageData.success) {
console.log(`✅ 分頁功能正常`)
console.log(` 每頁限制: ${pageData.data.pagination.limit}`)
console.log(` 當前頁結果數: ${pageData.data.results.length}`)
console.log(` 總頁數: ${pageData.data.pagination.totalPages}`)
} else {
console.log('❌ 分頁功能失敗:', pageData.message)
}
}
console.log('\n🎯 功能特點:')
console.log('✅ 從資料庫獲取所有測驗結果')
console.log('✅ 支援搜尋用戶姓名和郵箱')
console.log('✅ 支援部門篩選')
console.log('✅ 支援測試類型篩選')
console.log('✅ 支援分頁功能')
console.log('✅ 顯示詳細統計資料')
console.log('✅ 響應式設計(桌面版和手機版)')
console.log('✅ 載入狀態和錯誤處理')
console.log('\n📊 資料來源:')
console.log('✅ test_results 表(基本測試結果)')
console.log('✅ logic_test_answers 表(邏輯測試詳細答案)')
console.log('✅ creative_test_answers 表(創意測試詳細答案)')
console.log('✅ combined_test_results 表(綜合測試結果)')
console.log('✅ users 表(用戶資訊)')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 管理員測驗結果功能測試完成')
}
}
testAdminResults()

View File

@@ -1,73 +0,0 @@
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()

View File

@@ -1,122 +0,0 @@
const http = require('http')
const fs = require('fs')
const testChineseExport = async () => {
console.log('🔍 測試中文匯出功能')
console.log('=' .repeat(30))
try {
// 測試創意題目匯出(包含中文)
console.log('\n📊 測試創意題目匯出...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success) {
console.log('✅ 創意題目匯出成功')
// 解碼並檢查中文內容
const csvContent = Buffer.from(creativeData.data, 'base64').toString('utf8')
const lines = csvContent.split('\n')
console.log(`\n📋 匯出內容預覽:`)
console.log(`標題行: ${lines[0]}`)
console.log(`\n前3行資料:`)
for (let i = 1; i <= Math.min(3, lines.length - 1); i++) {
if (lines[i].trim()) {
console.log(`${i}行: ${lines[i]}`)
}
}
// 檢查是否包含正確的中文字符
const hasChinese = /[\u4e00-\u9fff]/.test(csvContent)
console.log(`\n🔤 中文字符檢測: ${hasChinese ? '✅ 包含中文字符' : '❌ 未檢測到中文字符'}`)
// 檢查 BOM
const hasBOM = csvContent.charCodeAt(0) === 0xFEFF
console.log(`📝 UTF-8 BOM: ${hasBOM ? '✅ 包含 BOM' : '❌ 未包含 BOM'}`)
// 保存到檔案進行測試
fs.writeFileSync('test-creative-export.csv', csvContent, 'utf8')
console.log(`💾 已保存測試檔案: test-creative-export.csv`)
} else {
console.log('❌ 創意題目匯出失敗:', creativeData.message)
}
} else {
console.log('❌ 創意題目匯出失敗,狀態碼:', creativeResponse.status)
}
// 測試邏輯題目匯出
console.log('\n📊 測試邏輯題目匯出...')
const logicResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=logic', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (logicResponse.status === 200) {
const logicData = JSON.parse(logicResponse.data)
if (logicData.success) {
console.log('✅ 邏輯題目匯出成功')
// 解碼並檢查中文內容
const csvContent = Buffer.from(logicData.data, 'base64').toString('utf8')
const lines = csvContent.split('\n')
console.log(`\n📋 匯出內容預覽:`)
console.log(`標題行: ${lines[0]}`)
console.log(`\n第1行資料:`)
if (lines[1]) {
console.log(`第1行: ${lines[1]}`)
}
// 檢查是否包含正確的中文字符
const hasChinese = /[\u4e00-\u9fff]/.test(csvContent)
console.log(`\n🔤 中文字符檢測: ${hasChinese ? '✅ 包含中文字符' : '❌ 未檢測到中文字符'}`)
// 檢查 BOM
const hasBOM = csvContent.charCodeAt(0) === 0xFEFF
console.log(`📝 UTF-8 BOM: ${hasBOM ? '✅ 包含 BOM' : '❌ 未包含 BOM'}`)
// 保存到檔案進行測試
fs.writeFileSync('test-logic-export.csv', csvContent, 'utf8')
console.log(`💾 已保存測試檔案: test-logic-export.csv`)
} else {
console.log('❌ 邏輯題目匯出失敗:', logicData.message)
}
} else {
console.log('❌ 邏輯題目匯出失敗,狀態碼:', logicResponse.status)
}
console.log('\n📝 修正說明:')
console.log('✅ 添加了 UTF-8 BOM (Byte Order Mark)')
console.log('✅ 確保 Excel 能正確識別中文編碼')
console.log('✅ 使用 Base64 編碼避免 API 路由字符限制')
console.log('✅ 前端正確解碼並生成 CSV 檔案')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 中文匯出功能測試完成')
}
}
testChineseExport()

View File

@@ -1,90 +0,0 @@
const testCombinedCreativityLevels = () => {
console.log('💡 綜合能力測試創意能力評語功能測試')
console.log('=' .repeat(50))
// 模擬創意能力評語函數
const getCreativityLevel = (score) => {
if (score >= 90) return {
level: "創意巔峰者",
color: "bg-purple-600",
description: "創意力近乎無窮,你是團隊裡的靈感源泉,總能帶來突破性的想法。",
suggestion: "你不只創造靈感,更能影響他人。如果能結合執行力,你將成為真正的創新領袖。"
}
if (score >= 75) return {
level: "創意引領者",
color: "bg-blue-500",
description: "你是靈感的推動者!總是能在團體中主動拋出新想法,激發別人跟進。",
suggestion: "持續累積學習,讓你的靈感不僅是點子,而能帶動真正的行動。"
}
if (score >= 55) return {
level: "創意實踐者",
color: "bg-green-500",
description: "靈感已經隨手可得,在團體中也常被認為是「有創意的人」。",
suggestion: "再給自己一點勇氣,不要害怕挑戰慣例,你的創意將更有力量。"
}
if (score >= 35) return {
level: "創意開拓者",
color: "bg-yellow-500",
description: "你其實有自己的想法,但有時習慣跟隨大多數人的步伐。",
suggestion: "試著勇敢說出腦中天馬行空的念頭,你會發現,這些點子或許就是團隊需要的突破口。"
}
return {
level: "創意萌芽者",
color: "bg-red-500",
description: "還在創意旅程的起點。雖然暫時表現平淡,但這正是無限潛力的開端!",
suggestion: "觀察生活小事,或閱讀不同領域的內容,讓靈感一點一滴積累。"
}
}
console.log('\n📊 測試案例:')
// 測試各個分數區間
const testScores = [0, 20, 30, 45, 60, 70, 80, 90, 95]
testScores.forEach(score => {
const level = getCreativityLevel(score)
console.log(`\n分數: ${score}`)
console.log(`等級: ${level.level}`)
console.log(`顏色: ${level.color}`)
console.log(`描述: ${level.description}`)
console.log(`建議: ${level.suggestion}`)
})
console.log('\n🎯 評語等級對應:')
console.log('90分以上: 創意巔峰者 (紫色)')
console.log('75-89分: 創意引領者 (藍色)')
console.log('55-74分: 創意實踐者 (綠色)')
console.log('35-54分: 創意開拓者 (黃色)')
console.log('0-34分: 創意萌芽者 (紅色)')
console.log('\n🎨 UI設計特色:')
console.log('- 等級標示: 彩色圓點 + 等級名稱')
console.log('- 描述文字: 生動有趣的比喻和描述')
console.log('- 建議區塊: 淺色背景,包含👉圖示')
console.log('- 響應式設計: 適配手機和桌面版')
console.log('\n📝 評語內容特色:')
console.log('- 使用生動的比喻 (靈感源泉、天馬行空、創新領袖)')
console.log('- 提供具體的改進建議')
console.log('- 鼓勵性的語言風格')
console.log('- 符合不同能力水平的描述')
console.log('\n🌟 創意能力評語亮點:')
console.log('- 創意巔峰者: 強調影響力和領導力')
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('5. UI佈局美觀整齊')
console.log('6. 與邏輯思維評語風格一致')
console.log('\n✅ 綜合能力測試創意能力評語功能測試完成')
}
testCombinedCreativityLevels()

View File

@@ -1,114 +0,0 @@
const https = require('https')
const http = require('http')
const testCombinedDBIntegration = async () => {
console.log('🧪 測試綜合測試結果資料庫整合功能')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 1. 測試綜合測試結果上傳 API
console.log('\n📊 1. 測試綜合測試結果上傳 API...')
const testData = {
userId: userId,
logicScore: 10,
creativityScore: 78,
overallScore: 48,
level: '待提升',
description: '綜合能力有待提升,建議系統性訓練邏輯思維和創意能力',
logicBreakdown: {
correct: 1,
total: 10,
answers: { 0: 'A', 1: 'B', 2: 'C' }
},
creativityBreakdown: {
total: 70,
maxScore: 90,
answers: { 0: 5, 1: 4, 2: 3 }
},
balanceScore: 66,
completedAt: new Date().toISOString().replace('Z', '').replace('T', ' ')
}
console.log('測試數據:', JSON.stringify(testData, null, 2))
const uploadResponse = await new Promise((resolve, reject) => {
const req = http.request({
hostname: 'localhost',
port: 3000,
path: '/api/test-results/combined',
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
}, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(JSON.stringify(testData))
req.end()
})
console.log('📊 上傳響應狀態:', uploadResponse.status)
if (uploadResponse.status === 200) {
const uploadResult = JSON.parse(uploadResponse.data)
console.log('✅ 上傳成功!')
console.log('📡 響應內容:', JSON.stringify(uploadResult, null, 2))
if (uploadResult.success) {
console.log('測試結果ID:', uploadResult.data.testResult.id)
}
} else {
console.log('❌ 上傳失敗,狀態碼:', uploadResponse.status)
console.log('響應內容:', uploadResponse.data)
}
// 2. 測試綜合測試結果獲取 API
console.log('\n📊 2. 測試綜合測試結果獲取 API...')
const getResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/combined?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
console.log('📊 獲取響應狀態:', getResponse.status)
if (getResponse.status === 200) {
const getResult = JSON.parse(getResponse.data)
console.log('✅ 獲取成功!')
console.log('📡 響應內容:', JSON.stringify(getResult, null, 2))
if (getResult.success && getResult.data.length > 0) {
console.log(`找到 ${getResult.data.length} 筆綜合測試結果`)
getResult.data.forEach((result, index) => {
console.log(`\n結果 ${index + 1}:`)
console.log(` ID: ${result.id}`)
console.log(` 邏輯分數: ${result.logic_score}`)
console.log(` 創意分數: ${result.creativity_score}`)
console.log(` 總分: ${result.overall_score}`)
console.log(` 等級: ${result.level}`)
console.log(` 完成時間: ${result.completed_at}`)
})
}
} else {
console.log('❌ 獲取失敗,狀態碼:', getResponse.status)
console.log('響應內容:', getResponse.data)
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 綜合測試結果資料庫整合功能測試完成')
}
}
testCombinedDBIntegration()

View File

@@ -1,80 +0,0 @@
const testCombinedIntegration = () => {
console.log('🔄 綜合能力測試資料庫整合測試')
console.log('=' .repeat(50))
console.log('\n📋 測試目標:')
console.log('- 整合 logic_questions 資料表')
console.log('- 整合 creative_questions 資料表')
console.log('- 移除硬編碼的題目資料')
console.log('- 確保題目、答案與資料庫一致')
console.log('\n🔧 主要修改:')
console.log('1. 移除硬編碼的題目匯入')
console.log(' - 移除: import { logicQuestions } from "@/lib/questions/logic-questions"')
console.log(' - 移除: import { creativeQuestions } from "@/lib/questions/creative-questions"')
console.log('\n2. 新增資料庫介面')
console.log(' - LogicQuestion 介面 (id, question, option_a-e, correct_answer, explanation)')
console.log(' - CreativeQuestion 介面 (id, statement, category, is_reverse)')
console.log('\n3. 新增狀態管理')
console.log(' - logicQuestions: LogicQuestion[]')
console.log(' - creativeQuestions: CreativeQuestion[]')
console.log(' - isLoading: boolean')
console.log('\n4. 新增資料載入邏輯')
console.log(' - useEffect 載入邏輯題目 (/api/logic-questions)')
console.log(' - useEffect 載入創意題目 (/api/creative-questions)')
console.log(' - 錯誤處理和載入狀態')
console.log('\n5. 修改題目渲染')
console.log(' - 邏輯題目: 使用 option_a 到 option_e 欄位')
console.log(' - 創意題目: 使用 statement 和 is_reverse 欄位')
console.log(' - 移除數值顯示 (5, 4, 3, 2, 1)')
console.log('\n6. 新增載入和錯誤狀態')
console.log(' - 載入中: 顯示載入動畫')
console.log(' - 載入失敗: 顯示錯誤訊息和重新載入按鈕')
console.log('\n📊 資料庫欄位對應:')
console.log('邏輯題目 (logic_questions):')
console.log(' - question -> 題目內容')
console.log(' - option_a, option_b, option_c, option_d, option_e -> 選項 A-E')
console.log(' - correct_answer -> 正確答案 (A-E)')
console.log(' - explanation -> 解釋說明')
console.log('\n創意題目 (creative_questions):')
console.log(' - statement -> 題目描述')
console.log(' - category -> 能力類別 (innovation, imagination, flexibility, originality)')
console.log(' - is_reverse -> 是否反向計分')
console.log('\n🎯 測試流程:')
console.log('1. 載入綜合能力測試頁面')
console.log('2. 檢查是否從資料庫載入題目')
console.log('3. 驗證邏輯題目選項顯示 (A-E)')
console.log('4. 驗證創意題目選項顯示 (無數值)')
console.log('5. 完成測試並檢查結果頁面')
console.log('\n✅ 預期結果:')
console.log('- 題目完全來自資料庫,無硬編碼')
console.log('- 邏輯題目顯示 A-E 選項')
console.log('- 創意題目不顯示數值')
console.log('- 載入狀態正常顯示')
console.log('- 錯誤處理完善')
console.log('\n🔍 驗證要點:')
console.log('- 檢查 Network 標籤中的 API 請求')
console.log('- 確認題目內容與資料庫一致')
console.log('- 測試載入失敗情況')
console.log('- 驗證計分邏輯正確性')
console.log('\n📝 注意事項:')
console.log('- 確保 API 路由正常運作')
console.log('- 檢查資料庫連線狀態')
console.log('- 驗證題目數量正確')
console.log('- 測試反向計分邏輯')
console.log('\n✅ 綜合能力測試資料庫整合測試完成')
}
testCombinedIntegration()

View File

@@ -1,89 +0,0 @@
const testCombinedLogicAnswers = () => {
console.log('🔍 綜合能力測試邏輯題目答案驗證')
console.log('=' .repeat(50))
// 模擬資料庫中的邏輯題目 (使用正確的欄位名稱)
const mockLogicQuestions = [
{
id: 1,
question: "如果所有的玫瑰都是花,所有的花都需要水,那麼可以得出什麼結論?",
option_a: "所有的玫瑰都需要水",
option_b: "所有需要水的都是玫瑰",
option_c: "有些花不是玫瑰",
option_d: "玫瑰不需要土壤",
option_e: "以上都不對",
correct_answer: "A", // 正確的欄位名稱
explanation: "根據邏輯推理,如果所有玫瑰都是花,所有花都需要水,那麼所有玫瑰都需要水。"
},
{
id: 2,
question: "在一個密碼中A=1, B=2, C=3...Z=26。如果「CAT」的數值和是24那麼「DOG」的數值和是",
option_a: "26",
option_b: "27",
option_c: "28",
option_d: "29",
option_e: "30",
correct_answer: "C", // 正確的欄位名稱
explanation: "C=3, A=1, T=20所以CAT=24。D=4, O=15, G=7所以DOG=4+15+7=26。"
},
{
id: 3,
question: "如果今天是星期三,那麼後天是星期幾?",
option_a: "星期四",
option_b: "星期五",
option_c: "星期六",
option_d: "星期日",
option_e: "星期一",
correct_answer: "B", // 正確的欄位名稱
explanation: "今天是星期三,明天是星期四,後天是星期五。"
}
]
console.log('\n📊 測試案例: 邏輯題目答案比較')
console.log('題目資料:')
mockLogicQuestions.forEach((q, i) => {
console.log(`\n題目 ${i+1}: ${q.question}`)
console.log(` 選項: A.${q.option_a}, B.${q.option_b}, C.${q.option_c}, D.${q.option_d}, E.${q.option_e}`)
console.log(` 正確答案: ${q.correct_answer}`)
})
// 模擬用戶答案
const userAnswers = ["A", "C", "B"] // 用戶選擇的答案
console.log('\n用戶答案:', userAnswers)
console.log('\n計分過程 (修正後):')
let logicCorrect = 0
mockLogicQuestions.forEach((question, index) => {
const userAnswer = userAnswers[index]
const correctAnswer = question.correct_answer // 使用正確的欄位名稱
const isCorrect = userAnswer === correctAnswer
console.log(`\n題目 ${index + 1}:`)
console.log(` 用戶答案: ${userAnswer}`)
console.log(` 正確答案: ${correctAnswer}`)
console.log(` 是否正確: ${isCorrect}`)
if (isCorrect) logicCorrect++
})
const logicScore = Math.round((logicCorrect / mockLogicQuestions.length) * 100)
console.log(`\n邏輯思維答對: ${logicCorrect} / ${mockLogicQuestions.length} = ${logicScore}%`)
console.log('\n🔧 修正內容:')
console.log('錯誤: logicAnswers[index] === question.correctAnswer')
console.log('正確: logicAnswers[index] === question.correct_answer')
console.log('\n原因: 資料庫欄位名稱是 correct_answer不是 correctAnswer')
console.log('\n📈 修正效果:')
console.log('- 現在會正確讀取資料庫中的正確答案')
console.log('- 邏輯題目計分會與單獨的邏輯測試一致')
console.log('- 用戶應該能獲得正確的分數')
console.log('\n✅ 綜合能力測試邏輯題目答案驗證完成')
console.log('\n🎯 結論:')
console.log('- 修正了欄位名稱錯誤')
console.log('- 現在使用資料庫中的正確答案進行比較')
console.log('- 計分邏輯與單獨測試頁面完全一致')
}
testCombinedLogicAnswers()

View File

@@ -1,79 +0,0 @@
const testCombinedLogicInstructions = () => {
console.log('📝 綜合能力測試邏輯題註記文字測試')
console.log('=' .repeat(50))
console.log('\n🎯 添加內容:')
console.log('位置: 綜合能力測試中邏輯題標題下方')
console.log('文字: "請仔細閱讀題目,選擇最正確的答案,每題均為單選。"')
console.log('條件: 僅在邏輯題階段顯示')
console.log('\n🎨 UI設計特色:')
console.log('邏輯題階段:')
console.log('- 標題: 題目內容')
console.log('- 說明: 請仔細閱讀題目,選擇最正確的答案,每題均為單選。')
console.log('- 樣式: text-sm text-muted-foreground mt-2')
console.log('\n創意題階段:')
console.log('- 標題: 題目描述')
console.log('- 說明: 請根據您的實際情況選擇最符合的選項5=非常符合1=完全不符合)。')
console.log('- 樣式: text-sm text-muted-foreground')
console.log('\n📊 條件渲染邏輯:')
console.log('1. phase === "logic": 顯示邏輯題說明')
console.log('2. phase === "creative": 顯示創意題說明')
console.log('3. 兩個階段都有各自的說明文字')
console.log('4. 樣式保持一致,但內容不同')
console.log('\n💡 設計理念:')
console.log('- 根據測試階段顯示相應說明')
console.log('- 邏輯題強調仔細閱讀和單選')
console.log('- 創意題強調根據實際情況選擇')
console.log('- 保持與單獨邏輯測試的一致性')
console.log('- 簡潔明瞭,不干擾主要內容')
console.log('\n📱 響應式設計:')
console.log('- 手機版: 文字大小適中,易於閱讀')
console.log('- 桌面版: 保持一致的視覺效果')
console.log('- 文字換行: 自動換行,保持可讀性')
console.log('- 間距: 與標題保持適當距離')
console.log('\n🎯 用戶體驗提升:')
console.log('- 清楚說明不同階段的答題規則')
console.log('- 邏輯題階段提醒仔細閱讀')
console.log('- 創意題階段說明評分標準')
console.log('- 視覺上不突兀,融入整體設計')
console.log('- 與單獨測試頁面保持一致')
console.log('\n🔍 與單獨邏輯測試對比:')
console.log('單獨邏輯測試:')
console.log('- 標題: 題目內容')
console.log('- 說明: 請仔細閱讀題目,選擇最正確的答案,每題均為單選。')
console.log('- 樣式: text-sm text-muted-foreground mt-2')
console.log('\n綜合能力測試邏輯題:')
console.log('- 標題: 題目內容')
console.log('- 說明: 請仔細閱讀題目,選擇最正確的答案,每題均為單選。')
console.log('- 樣式: text-sm text-muted-foreground mt-2')
console.log('\n✅ 一致性:')
console.log('- 文字內容完全一致 ✓')
console.log('- 樣式設計完全一致 ✓')
console.log('- 用戶體驗保持一致 ✓')
console.log('\n🔍 測試要點:')
console.log('1. 邏輯題階段是否顯示正確說明')
console.log('2. 創意題階段是否顯示正確說明')
console.log('3. 樣式是否與單獨測試一致')
console.log('4. 條件渲染是否正常工作')
console.log('5. 整體設計是否協調')
console.log('\n✅ 預期效果:')
console.log('- 用戶在邏輯題階段看到相應說明')
console.log('- 用戶在創意題階段看到相應說明')
console.log('- 與單獨測試頁面保持一致性')
console.log('- 整體用戶體驗更加完善')
console.log('\n✅ 綜合能力測試邏輯題註記文字測試完成')
}
testCombinedLogicInstructions()

View File

@@ -1,82 +0,0 @@
const testCombinedLogicLevels = () => {
console.log('🧠 綜合能力測試邏輯思維評語功能測試')
console.log('=' .repeat(50))
// 模擬邏輯思維評語函數
const getLogicLevel = (score) => {
if (score >= 100) return {
level: "邏輯巔峰者",
color: "bg-purple-600",
description: "近乎完美的邏輯典範!你像一台「推理引擎」,嚴謹又高效,幾乎不受陷阱干擾。",
suggestion: "多和他人分享你的思考路徑,能幫助團隊整體邏輯力提升。"
}
if (score >= 80) return {
level: "邏輯大師",
color: "bg-blue-500",
description: "你的思維如同精密儀器,能快速抓住題目關鍵,並做出有效推理。常常是團隊中「冷靜的分析者」。",
suggestion: "挑戰更高層次的難題,讓你的邏輯力更加精進。"
}
if (score >= 60) return {
level: "邏輯高手",
color: "bg-green-500",
description: "邏輯清晰穩定,大部分情境都能正確判斷。偶爾會因粗心錯過陷阱。",
suggestion: "在思維縝密之餘,更加留心細節,就能把錯誤率降到最低。"
}
if (score >= 30) return {
level: "邏輯學徒",
color: "bg-yellow-500",
description: "已經抓到一些邏輯規律,能解決中等難度的問題。遇到複雜情境時,仍可能卡關。",
suggestion: "嘗試將問題拆解成小步驟,就像組裝樂高,每一塊拼好,答案就自然浮現。"
}
return {
level: "邏輯探險新手",
color: "bg-red-500",
description: "還在邏輯森林的入口徘徊。思考時可能忽略細節,或被陷阱誤導。",
suggestion: "多練習經典邏輯題,像是在拼拼圖般,慢慢建立清晰的分析步驟。"
}
}
console.log('\n📊 測試案例:')
// 測試各個分數區間
const testScores = [0, 15, 25, 45, 65, 85, 95, 100]
testScores.forEach(score => {
const level = getLogicLevel(score)
console.log(`\n分數: ${score}`)
console.log(`等級: ${level.level}`)
console.log(`顏色: ${level.color}`)
console.log(`描述: ${level.description}`)
console.log(`建議: ${level.suggestion}`)
})
console.log('\n🎯 評語等級對應:')
console.log('100分: 邏輯巔峰者 (紫色)')
console.log('80-99分: 邏輯大師 (藍色)')
console.log('60-79分: 邏輯高手 (綠色)')
console.log('30-59分: 邏輯學徒 (黃色)')
console.log('0-29分: 邏輯探險新手 (紅色)')
console.log('\n🎨 UI設計特色:')
console.log('- 等級標示: 彩色圓點 + 等級名稱')
console.log('- 描述文字: 生動有趣的比喻和描述')
console.log('- 建議區塊: 淺色背景,包含👉圖示')
console.log('- 響應式設計: 適配手機和桌面版')
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('5. UI佈局美觀整齊')
console.log('\n✅ 綜合能力測試邏輯思維評語功能測試完成')
}
testCombinedLogicLevels()

View File

@@ -1,68 +0,0 @@
const testCombinedMobileButtons = () => {
console.log('📱 綜合能力測試結果頁面手機版按鈕修正測試')
console.log('=' .repeat(50))
console.log('\n🔍 問題分析:')
console.log('原始問題: 手機版「返回首頁」文字消失')
console.log('原因: 使用了 hidden sm:inline 類別,在手機版隱藏文字')
console.log('\n🔧 修正內容:')
console.log('舊代碼: <span className="hidden sm:inline">返回首頁</span>')
console.log('新代碼: <span>返回首頁</span>')
console.log('效果: 移除 hidden sm:inline讓文字在所有螢幕尺寸都顯示')
console.log('\n📊 按鈕區域分析:')
console.log('按鈕容器: flex flex-col sm:flex-row gap-4 justify-center')
console.log('- 手機版: 垂直排列 (flex-col)')
console.log('- 桌面版: 水平排列 (sm:flex-row)')
console.log('- 間距: 4 (16px)')
console.log('- 對齊: 置中')
console.log('\n🎯 三個按鈕:')
console.log('1. 返回首頁按鈕:')
console.log(' - 樣式: 主要按鈕 (solid blue)')
console.log(' - 圖示: Home 圖示')
console.log(' - 文字: 返回首頁 (現在所有螢幕都顯示)')
console.log(' - 連結: / (首頁)')
console.log('\n2. 重新測試按鈕:')
console.log(' - 樣式: 次要按鈕 (outline)')
console.log(' - 圖示: RotateCcw 圖示')
console.log(' - 文字: 重新測試')
console.log(' - 連結: /tests/combined')
console.log('\n3. 查看所有成績按鈕:')
console.log(' - 樣式: 次要按鈕 (outline)')
console.log(' - 圖示: 無')
console.log(' - 文字: 查看所有成績')
console.log(' - 連結: /results')
console.log('\n📱 手機版顯示效果:')
console.log('- 按鈕垂直堆疊')
console.log('- 每個按鈕全寬顯示')
console.log('- 圖示和文字都清晰可見')
console.log('- 間距適中,易於點擊')
console.log('\n🖥 桌面版顯示效果:')
console.log('- 按鈕水平排列')
console.log('- 按鈕寬度自動調整')
console.log('- 圖示和文字都清晰可見')
console.log('- 整體佈局平衡')
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('5. 響應式設計在不同螢幕尺寸都正常')
console.log('\n✅ 綜合能力測試結果頁面手機版按鈕修正測試完成')
}
testCombinedMobileButtons()

View File

@@ -1,74 +0,0 @@
const testCombinedMobileUI = () => {
console.log('📱 綜合能力測試結果頁面手機版UI優化')
console.log('=' .repeat(50))
console.log('\n🎯 優化目標:')
console.log('- 邏輯思維、創意能力、能力平衡在手機版並排顯示')
console.log('- 改善手機版UI感受')
console.log('- 保持桌面版的良好體驗')
console.log('\n🔧 主要修改:')
console.log('1. 網格佈局調整:')
console.log(' 舊: grid-cols-1 md:grid-cols-3 (手機版單欄)')
console.log(' 新: grid-cols-3 (手機版和桌面版都3欄)')
console.log('\n2. 間距優化:')
console.log(' 舊: gap-6 (固定間距)')
console.log(' 新: gap-4 md:gap-6 (手機版較小間距)')
console.log('\n3. 字體大小響應式:')
console.log(' 分數: text-2xl md:text-3xl (手機版較小)')
console.log(' 標籤: text-xs md:text-sm (手機版較小)')
console.log('\n4. 邊距優化:')
console.log(' 分數下方邊距: mb-1 md:mb-2 (手機版較小)')
console.log('\n📊 響應式設計:')
console.log('手機版 (< 768px):')
console.log(' - 3欄並排顯示')
console.log(' - 分數: 2xl (24px)')
console.log(' - 標籤: xs (12px)')
console.log(' - 間距: 4 (16px)')
console.log(' - 邊距: 1 (4px)')
console.log('\n桌面版 (≥ 768px):')
console.log(' - 3欄並排顯示')
console.log(' - 分數: 3xl (30px)')
console.log(' - 標籤: sm (14px)')
console.log(' - 間距: 6 (24px)')
console.log(' - 邊距: 2 (8px)')
console.log('\n🎨 視覺效果:')
console.log('- 手機版: 緊湊但清晰的3欄佈局')
console.log('- 桌面版: 寬鬆舒適的3欄佈局')
console.log('- 保持一致的視覺層次')
console.log('- 分數顏色根據表現動態變化')
console.log('\n📱 手機版優勢:')
console.log('- 三個分數一目了然')
console.log('- 節省垂直空間')
console.log('- 更好的視覺平衡')
console.log('- 與其他測試結果頁面保持一致')
console.log('\n🖥 桌面版保持:')
console.log('- 較大的字體和間距')
console.log('- 舒適的閱讀體驗')
console.log('- 清晰的視覺層次')
console.log('\n✅ 預期效果:')
console.log('- 手機版UI感受大幅改善')
console.log('- 三個分數並排顯示,易於比較')
console.log('- 響應式設計適配各種螢幕尺寸')
console.log('- 與創意測試結果頁面設計一致')
console.log('\n🔍 測試要點:')
console.log('1. 手機版 (< 768px) 檢查3欄並排')
console.log('2. 桌面版 (≥ 768px) 檢查字體和間距')
console.log('3. 分數顏色根據數值正確顯示')
console.log('4. 標籤文字完整顯示')
console.log('5. 整體佈局平衡美觀')
console.log('\n✅ 綜合能力測試結果頁面手機版UI優化完成')
}
testCombinedMobileUI()

View File

@@ -1,59 +0,0 @@
const testCombinedScoreDisplay = () => {
console.log('📊 綜合能力測試分數顯示修正測試')
console.log('=' .repeat(50))
console.log('\n🔍 問題分析:')
console.log('原始問題: 總得分 70 與上面 78 分不一致')
console.log('原因: 標籤誤導,實際上是不同的分數類型')
console.log('\n📈 分數類型說明:')
console.log('1. creativityScore (78分): 百分比分數')
console.log(' - 計算方式: (creativityTotal / creativityMaxScore) * 100')
console.log(' - 用途: 用於評語等級判斷和進度條顯示')
console.log(' - 顯示位置: 主要得分區域')
console.log('\n2. creativityTotal (70分): 原始總分')
console.log(' - 計算方式: 所有題目分數的總和')
console.log(' - 用途: 顯示實際獲得的原始分數')
console.log(' - 顯示位置: 詳細分數區域')
console.log('\n3. creativityMaxScore (90分): 滿分')
console.log(' - 計算方式: 題目數量 * 5 (每題最高5分)')
console.log(' - 用途: 作為原始分數的滿分基準')
console.log(' - 顯示位置: 詳細分數區域')
console.log('\n🔧 修正內容:')
console.log('舊標籤: "總得分" (容易誤解)')
console.log('新標籤: "原始得分" (更清楚)')
console.log('\n📊 修正後的顯示邏輯:')
console.log('主要得分區域:')
console.log(' - 得分: 78分 (百分比分數)')
console.log(' - 進度條: 78% 填充')
console.log('\n詳細分數區域:')
console.log(' - 原始得分: 70分 (實際獲得的分數)')
console.log(' - 滿分: 90分 (最高可能分數)')
console.log('\n🎯 修正效果:')
console.log('- 消除了分數不一致的誤解')
console.log('- 清楚區分百分比分數和原始分數')
console.log('- 用戶更容易理解分數含義')
console.log('\n📝 計算範例:')
console.log('假設有18題創意題目:')
console.log('- 每題最高5分滿分 = 18 * 5 = 90分')
console.log('- 用戶實際獲得70分')
console.log('- 百分比分數 = (70 / 90) * 100 = 77.78% ≈ 78分')
console.log('- 評語等級基於78分判斷')
console.log('\n✅ 修正要點:')
console.log('1. 主要得分顯示百分比分數 (用於評語)')
console.log('2. 詳細區域顯示原始分數 (用於參考)')
console.log('3. 標籤清楚區分兩種分數類型')
console.log('4. 保持計算邏輯的一致性')
console.log('\n✅ 綜合能力測試分數顯示修正測試完成')
}
testCombinedScoreDisplay()

View File

@@ -1,130 +0,0 @@
const testCombinedScoringLogic = () => {
console.log('🧮 綜合能力測試計分邏輯驗證')
console.log('=' .repeat(50))
// 模擬資料庫中的創意題目
const mockCreativeQuestions = [
{
id: 1,
statement: "我常能從不同角度看事情,接受多元觀點。",
category: "flexibility",
is_reverse: false
},
{
id: 2,
statement: "我習慣一次只做一件事,不輕易嘗試新方法。",
category: "flexibility",
is_reverse: true
},
{
id: 3,
statement: "當靈感枯竭時,我仍能找到突破的方法。",
category: "imagination",
is_reverse: false
},
{
id: 4,
statement: "我很少質疑現有的做法或流程。",
category: "innovation",
is_reverse: true
}
]
// 模擬資料庫中的邏輯題目
const mockLogicQuestions = [
{
id: 1,
question: "如果所有的玫瑰都是花,所有的花都需要水,那麼可以得出什麼結論?",
correct_answer: "A"
},
{
id: 2,
question: "在一個密碼中A=1, B=2, C=3...Z=26。如果「CAT」的數值和是24那麼「DOG」的數值和是",
correct_answer: "C"
}
]
console.log('\n📊 測試案例 1: 創意題目計分')
console.log('題目資料:')
mockCreativeQuestions.forEach((q, i) => {
console.log(` ${i+1}. ${q.statement}`)
console.log(` 類別: ${q.category}, 反向: ${q.is_reverse}`)
})
// 模擬用戶答案 (1-5 分)
const creativeAnswers = [5, 2, 4, 1] // 用戶選擇的分數
console.log('\n用戶答案:', creativeAnswers)
console.log('\n計分過程:')
let creativityTotal = 0
mockCreativeQuestions.forEach((question, index) => {
const answer = creativeAnswers[index] || 1
const originalScore = answer
const actualScore = question.is_reverse ? 6 - answer : answer
console.log(`\n題目 ${index + 1}:`)
console.log(` 原始分數: ${originalScore}`)
console.log(` 是否反向: ${question.is_reverse}`)
console.log(` 實際分數: ${actualScore}`)
console.log(` 計算: ${question.is_reverse ? `6 - ${answer} = ${actualScore}` : `直接使用 ${answer}`}`)
creativityTotal += actualScore
})
const creativityMaxScore = mockCreativeQuestions.length * 5
const creativityScore = Math.round((creativityTotal / creativityMaxScore) * 100)
console.log(`\n創意能力總分: ${creativityTotal} / ${creativityMaxScore} = ${creativityScore}%`)
console.log('\n📊 測試案例 2: 邏輯題目計分')
console.log('題目資料:')
mockLogicQuestions.forEach((q, i) => {
console.log(` ${i+1}. ${q.question}`)
console.log(` 正確答案: ${q.correct_answer}`)
})
// 模擬用戶答案
const logicAnswers = ["A", "B"] // 用戶選擇的答案
console.log('\n用戶答案:', logicAnswers)
console.log('\n計分過程:')
let logicCorrect = 0
mockLogicQuestions.forEach((question, index) => {
const userAnswer = logicAnswers[index]
const correctAnswer = question.correct_answer
const isCorrect = userAnswer === correctAnswer
console.log(`\n題目 ${index + 1}:`)
console.log(` 用戶答案: ${userAnswer}`)
console.log(` 正確答案: ${correctAnswer}`)
console.log(` 是否正確: ${isCorrect}`)
if (isCorrect) logicCorrect++
})
const logicScore = Math.round((logicCorrect / mockLogicQuestions.length) * 100)
console.log(`\n邏輯思維答對: ${logicCorrect} / ${mockLogicQuestions.length} = ${logicScore}%`)
console.log('\n🔍 問題檢查:')
console.log('1. 邏輯題目計分:')
console.log(' ✅ 使用 question.correctAnswer 與用戶答案比較')
console.log(' ✅ 計分邏輯正確')
console.log('\n2. 創意題目計分:')
console.log(' ✅ 使用 question.is_reverse 判斷是否反向計分')
console.log(' ✅ 反向計分: 6 - 用戶答案')
console.log(' ✅ 正向計分: 直接使用用戶答案')
console.log('\n📈 反向計分範例:')
console.log('題目: "我習慣一次只做一件事,不輕易嘗試新方法。" (is_reverse: true)')
console.log('用戶選擇: 2分 (不太符合)')
console.log('反向計分: 6 - 2 = 4分 (因為不習慣 = 靈活性高)')
console.log('\n✅ 綜合能力測試計分邏輯驗證完成')
console.log('\n🎯 結論:')
console.log('- 邏輯題目計分與資料庫正確答案一致')
console.log('- 創意題目反向計分邏輯正確')
console.log('- 計分方式與單獨測試頁面一致')
}
testCombinedScoringLogic()

View File

@@ -1,107 +0,0 @@
const testCombinedScoring = () => {
console.log('🧮 綜合能力計分邏輯測試')
console.log('=' .repeat(50))
// 模擬修正後的計分函數
const calculateCombinedScore = (logicScore, creativityScore) => {
const logicWeight = 0.4
const creativityWeight = 0.4
const balanceWeight = 0.2
// 修正後的平衡性計算
const scoreDiff = Math.abs(logicScore - creativityScore)
const balanceScore = Math.max(0, 100 - Math.min(scoreDiff * 0.5, 50))
const overallScore = Math.round(
logicScore * logicWeight + creativityScore * creativityWeight + balanceScore * balanceWeight,
)
let level, description, color
if (overallScore >= 90) {
level = "卓越"
color = "bg-gradient-to-r from-purple-500 to-blue-500"
description = "綜合能力卓越,邏輯思維與創意能力並重,是理想的複合型人才"
} else if (overallScore >= 80) {
level = "優秀"
color = "bg-gradient-to-r from-blue-500 to-green-500"
description = "綜合能力優秀,在邏輯思維和創意能力方面都有良好表現"
} else if (overallScore >= 70) {
level = "良好"
color = "bg-gradient-to-r from-green-500 to-yellow-500"
description = "綜合能力良好,具備一定的邏輯思維和創意能力"
} else if (overallScore >= 60) {
level = "中等"
color = "bg-gradient-to-r from-yellow-500 to-orange-500"
description = "綜合能力中等,建議針對性提升薄弱環節"
} else {
level = "待提升"
color = "bg-gradient-to-r from-orange-500 to-red-500"
description = "綜合能力有待提升,建議系統性訓練邏輯思維和創意能力"
}
return {
overallScore,
level,
description,
color,
breakdown: {
logic: logicScore,
creativity: creativityScore,
balance: Math.round(balanceScore),
},
}
}
console.log('\n📊 測試案例:')
// 測試案例 1: 用戶的情況 (邏輯 0, 創意 100)
const testCase1 = calculateCombinedScore(0, 100)
console.log('\n案例 1: 邏輯思維 0 分,創意能力 100 分')
console.log(` 分數差距: ${Math.abs(0 - 100)}`)
console.log(` 平衡性分數: ${testCase1.breakdown.balance}`)
console.log(` 綜合分數: ${testCase1.overallScore}`)
console.log(` 等級: ${testCase1.level}`)
console.log(` 描述: ${testCase1.description}`)
// 測試案例 2: 平衡的情況
const testCase2 = calculateCombinedScore(80, 80)
console.log('\n案例 2: 邏輯思維 80 分,創意能力 80 分')
console.log(` 分數差距: ${Math.abs(80 - 80)}`)
console.log(` 平衡性分數: ${testCase2.breakdown.balance}`)
console.log(` 綜合分數: ${testCase2.overallScore}`)
console.log(` 等級: ${testCase2.level}`)
// 測試案例 3: 中等差距
const testCase3 = calculateCombinedScore(60, 90)
console.log('\n案例 3: 邏輯思維 60 分,創意能力 90 分')
console.log(` 分數差距: ${Math.abs(60 - 90)}`)
console.log(` 平衡性分數: ${testCase3.breakdown.balance}`)
console.log(` 綜合分數: ${testCase3.overallScore}`)
console.log(` 等級: ${testCase3.level}`)
// 測試案例 4: 極端情況
const testCase4 = calculateCombinedScore(100, 0)
console.log('\n案例 4: 邏輯思維 100 分,創意能力 0 分')
console.log(` 分數差距: ${Math.abs(100 - 0)}`)
console.log(` 平衡性分數: ${testCase4.breakdown.balance}`)
console.log(` 綜合分數: ${testCase4.overallScore}`)
console.log(` 等級: ${testCase4.level}`)
console.log('\n🔧 修正內容:')
console.log('舊公式: balanceScore = Math.max(0, 100 - scoreDiff * 2)')
console.log('新公式: balanceScore = Math.max(0, 100 - Math.min(scoreDiff * 0.5, 50))')
console.log('\n修正說明:')
console.log('- 降低平衡性扣分比例 (從 2 倍改為 0.5 倍)')
console.log('- 設定最大扣分上限 (最多扣 50 分)')
console.log('- 避免極端情況下的平衡性為 0')
console.log('\n📈 修正效果:')
console.log('- 邏輯 0, 創意 100: 綜合分數從 40 提升到 60')
console.log('- 平衡性分數從 0 提升到 50')
console.log('- 更合理的綜合能力評估')
console.log('\n✅ 綜合能力計分邏輯測試完成')
}
testCombinedScoring()

View File

@@ -1,131 +0,0 @@
const http = require('http')
const testCompleteExcelFunctionality = async () => {
console.log('🔍 測試完整的 Excel 匯入匯出功能')
console.log('=' .repeat(50))
try {
// 1. 測試邏輯題目匯出
console.log('\n📊 1. 測試邏輯題目匯出...')
const logicExportResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=logic', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (logicExportResponse.status === 200) {
const logicData = JSON.parse(logicExportResponse.data)
if (logicData.success) {
console.log('✅ 邏輯題目匯出成功')
console.log(` 檔案名: ${logicData.filename}`)
console.log(` 內容類型: ${logicData.contentType}`)
console.log(` 資料大小: ${logicData.data.length} 字符`)
// 解碼並檢查內容
const csvContent = Buffer.from(logicData.data, 'base64').toString('utf8')
const lines = csvContent.split('\n')
console.log(` 總行數: ${lines.length}`)
console.log(` 標題行: ${lines[0]}`)
if (lines.length > 1) {
console.log(` 第一題: ${lines[1].substring(0, 100)}...`)
}
} else {
console.log('❌ 邏輯題目匯出失敗:', logicData.message)
}
} else {
console.log('❌ 邏輯題目匯出失敗,狀態碼:', logicExportResponse.status)
}
// 2. 測試創意題目匯出
console.log('\n📊 2. 測試創意題目匯出...')
const creativeExportResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (creativeExportResponse.status === 200) {
const creativeData = JSON.parse(creativeExportResponse.data)
if (creativeData.success) {
console.log('✅ 創意題目匯出成功')
console.log(` 檔案名: ${creativeData.filename}`)
console.log(` 內容類型: ${creativeData.contentType}`)
console.log(` 資料大小: ${creativeData.data.length} 字符`)
// 解碼並檢查內容
const csvContent = Buffer.from(creativeData.data, 'base64').toString('utf8')
const lines = csvContent.split('\n')
console.log(` 總行數: ${lines.length}`)
console.log(` 標題行: ${lines[0]}`)
if (lines.length > 1) {
console.log(` 第一題: ${lines[1].substring(0, 100)}...`)
}
} else {
console.log('❌ 創意題目匯出失敗:', creativeData.message)
}
} else {
console.log('❌ 創意題目匯出失敗,狀態碼:', creativeExportResponse.status)
}
// 3. 功能特點總結
console.log('\n📊 3. Excel 匯入匯出功能特點:')
console.log('✅ 根據資料庫格式匯出範本')
console.log('✅ 支援邏輯思維和創意能力兩種題目')
console.log('✅ 使用 Base64 編碼避免中文字符問題')
console.log('✅ 支援 A-E 選項(邏輯題目)')
console.log('✅ 支援反向計分標記(創意題目)')
console.log('✅ 匯入時覆蓋現有資料')
console.log('✅ 自動重新載入題目資料')
// 4. 資料庫整合
console.log('\n📊 4. 資料庫整合特點:')
console.log('✅ 匯出:從資料庫讀取現有題目')
console.log('✅ 匯入:清空現有資料後插入新資料')
console.log('✅ 格式:完全匹配資料庫欄位名稱')
console.log('✅ 驗證:匯入時進行資料驗證')
console.log('✅ 更新:匯入後自動刷新頁面資料')
// 5. 檔案格式
console.log('\n📊 5. 檔案格式支援:')
console.log('✅ 邏輯題目ID, 題目內容, 選項A-E, 正確答案, 解釋')
console.log('✅ 創意題目ID, 陳述內容, 類別, 反向計分')
console.log('✅ CSV 格式:.csv 檔案')
console.log('✅ 中文支援UTF-8 編碼')
console.log('✅ 資料完整性:包含所有必要欄位')
// 6. 用戶體驗
console.log('\n📊 6. 用戶體驗:')
console.log('✅ 一鍵下載:點擊按鈕直接下載範本')
console.log('✅ 格式一致:範本格式與資料庫完全一致')
console.log('✅ 即時更新:匯入後立即看到更新結果')
console.log('✅ 錯誤處理:詳細的錯誤訊息提示')
console.log('✅ 載入狀態:匯入過程顯示載入指示器')
console.log('\n📝 Excel 匯入匯出功能總結:')
console.log('✅ 完全基於資料庫格式設計')
console.log('✅ 支援覆蓋式更新現有題目')
console.log('✅ 提供完整的匯入匯出流程')
console.log('✅ 用戶友好的操作界面')
console.log('✅ 自動化的資料同步機制')
console.log('✅ 解決了中文字符編碼問題')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ Excel 匯入匯出功能測試完成')
}
}
testCompleteExcelFunctionality()

View File

@@ -1,157 +0,0 @@
const https = require('https')
const http = require('http')
const testCompleteProfileSystem = async () => {
console.log('🔍 測試完整的個人資訊系統')
console.log('=' .repeat(50))
const testUserId = 'user-1759073326705-m06y3wacd'
try {
// 1. 獲取初始用戶資料
console.log('\n📊 1. 獲取初始用戶資料...')
const initialResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/user/profile?userId=${testUserId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
let initialData = null
if (initialResponse.status === 200) {
const data = JSON.parse(initialResponse.data)
if (data.success) {
initialData = data.data
console.log('✅ 初始用戶資料:')
console.log(` 姓名: ${initialData.name}`)
console.log(` 電子郵件: ${initialData.email}`)
console.log(` 部門: ${initialData.department}`)
console.log(` 角色: ${initialData.role}`)
}
}
// 2. 測試個人資料更新
console.log('\n📊 2. 測試個人資料更新...')
const profileUpdateData = {
userId: testUserId,
name: '王測試',
email: 'test@company.com',
department: '測試部'
}
const profileResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(profileUpdateData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/user/profile',
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (profileResponse.status === 200) {
const profileResult = JSON.parse(profileResponse.data)
if (profileResult.success) {
console.log('✅ 個人資料更新成功')
} else {
console.log('❌ 個人資料更新失敗:', profileResult.error)
}
}
// 3. 測試密碼更新
console.log('\n📊 3. 測試密碼更新...')
const passwordUpdateData = {
userId: testUserId,
currentPassword: 'newpassword123',
newPassword: 'test123'
}
const passwordResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(passwordUpdateData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/user/profile',
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (passwordResponse.status === 200) {
const passwordResult = JSON.parse(passwordResponse.data)
if (passwordResult.success) {
console.log('✅ 密碼更新成功')
} else {
console.log('❌ 密碼更新失敗:', passwordResult.error)
}
}
// 4. 驗證最終狀態
console.log('\n📊 4. 驗證最終狀態...')
const finalResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/user/profile?userId=${testUserId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (finalResponse.status === 200) {
const finalData = JSON.parse(finalResponse.data)
if (finalData.success) {
console.log('✅ 最終用戶資料:')
console.log(` 姓名: ${finalData.data.name}`)
console.log(` 電子郵件: ${finalData.data.email}`)
console.log(` 部門: ${finalData.data.department}`)
console.log(` 角色: ${finalData.data.role}`)
// 檢查是否恢復到初始狀態
const isRestored = finalData.data.name === '王測試' &&
finalData.data.email === 'test@company.com' &&
finalData.data.department === '測試部'
console.log(`資料是否恢復: ${isRestored ? '✅' : '❌'}`)
}
}
console.log('\n📝 功能總結:')
console.log('✅ 個人資料更新功能正常')
console.log('✅ 密碼更新功能正常')
console.log('✅ 資料庫整合成功')
console.log('✅ API 端點運作正常')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 完整個人資訊系統測試完成')
}
}
testCompleteProfileSystem()

View File

@@ -1,57 +0,0 @@
const https = require('https')
const http = require('http')
const testCorrectedApiTime = async () => {
console.log('🔍 測試修正後的 API 時間處理')
console.log('=' .repeat(50))
try {
// 測試當前時間
console.log('\n📊 當前時間:')
const now = new Date()
const utcTime = now.toISOString()
const taiwanTime = now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(`UTC 時間: ${utcTime}`)
console.log(`台灣時間: ${taiwanTime}`)
// 測試修正後的 API 時間轉換
console.log('\n📊 修正後的 API 時間轉換:')
const apiInput = utcTime // 前端傳入的 UTC 時間
const utcDate = new Date(apiInput)
const apiOutput = utcDate.toISOString().replace('Z', '').replace('T', ' ')
console.log(`API 輸入 (前端): ${apiInput}`)
console.log(`API 輸出 (資料庫): ${apiOutput}`)
// 測試前端讀取
console.log('\n📊 前端讀取測試:')
const frontendRead = new Date(apiOutput + 'Z') // 重新添加 Z 來正確解析
const frontendDisplay = frontendRead.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(`前端讀取: ${frontendRead.toISOString()}`)
console.log(`前端顯示: ${frontendDisplay}`)
// 驗證轉換是否正確
const isCorrect = frontendRead.toISOString() === utcTime
console.log(`轉換是否正確: ${isCorrect ? '✅' : '❌'}`)
if (!isCorrect) {
console.log(`期望: ${utcTime}`)
console.log(`實際: ${frontendRead.toISOString()}`)
}
console.log('\n📝 修正說明:')
console.log('1. 前端傳入: UTC 時間 (2025-09-29T09:37:40.867Z)')
console.log('2. API 轉換: 先解析為 Date再轉換為 MySQL 格式')
console.log('3. 資料庫儲存: UTC 時間格式 (2025-09-29 09:37:40.867)')
console.log('4. 前端讀取: 添加 Z 後解析,正確轉換為台灣時間')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後的 API 時間處理測試完成')
}
}
testCorrectedApiTime()

View File

@@ -1,42 +0,0 @@
const https = require('https')
const http = require('http')
const testCorrectedMysqlFormat = async () => {
console.log('🔍 測試修正後的 MySQL 時間格式')
console.log('=' .repeat(50))
try {
// 測試時間格式轉換
console.log('\n📊 測試時間格式轉換:')
const now = new Date()
const isoTime = now.toISOString()
const mysqlTime = isoTime.replace('Z', '').replace('T', ' ')
console.log(`ISO 8601 格式: ${isoTime}`)
console.log(`MySQL 格式: ${mysqlTime}`)
// 測試轉換後的時間解析
const parsedTime = new Date(mysqlTime + 'Z') // 重新添加 Z 來正確解析
const taiwanTime = parsedTime.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(`轉換後解析: ${parsedTime.toISOString()}`)
console.log(`台灣時間: ${taiwanTime}`)
// 驗證轉換是否正確
const isCorrect = parsedTime.toISOString() === isoTime
console.log(`轉換是否正確: ${isCorrect ? '✅' : '❌'}`)
console.log('\n📝 修正說明:')
console.log('1. 前端使用 ISO 8601 格式 (2025-09-29T09:30:00.000Z)')
console.log('2. API 直接替換格式 (2025-09-29 09:30:00.000)')
console.log('3. 資料庫儲存 UTC 時間')
console.log('4. 前端讀取時正確轉換為台灣時間')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後的 MySQL 時間格式測試完成')
}
}
testCorrectedMysqlFormat()

View File

@@ -1,49 +0,0 @@
const https = require('https')
const http = require('http')
const testCorrectedTime = async () => {
console.log('🔍 測試修正後的時間格式')
console.log('=' .repeat(50))
try {
// 測試當前時間
console.log('\n📊 當前時間測試:')
const now = new Date()
const utcTime = now.toISOString()
const taiwanTime = now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(`當前 UTC 時間: ${utcTime}`)
console.log(`當前台灣時間: ${taiwanTime}`)
// 模擬舊格式和新格式的差異
console.log('\n📊 格式比較:')
const oldFormat = now.toISOString().replace('Z', '').replace('T', ' ')
const newFormat = now.toISOString()
console.log(`舊格式: ${oldFormat}`)
console.log(`新格式: ${newFormat}`)
// 測試兩種格式的轉換
const oldDate = new Date(oldFormat)
const newDate = new Date(newFormat)
console.log(`\n舊格式轉換:`)
console.log(` UTC: ${oldDate.toISOString()}`)
console.log(` 台灣時間: ${oldDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(`\n新格式轉換:`)
console.log(` UTC: ${newDate.toISOString()}`)
console.log(` 台灣時間: ${newDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
// 驗證新格式是否正確
const isCorrect = newDate.toISOString() === utcTime
console.log(`\n新格式是否正確: ${isCorrect ? '✅' : '❌'}`)
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後時間格式測試完成')
}
}
testCorrectedTime()

View File

@@ -1,72 +0,0 @@
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()

View File

@@ -1,61 +0,0 @@
const https = require('https')
const http = require('http')
const testCreativeAnswersAPI = async () => {
console.log('🧪 測試創意測驗答案 API')
console.log('=' .repeat(50))
const testResultId = 'test_1759086508812_xv2pof6lk' // 使用最新的測試結果ID
const url = `http://localhost:3000/api/creative-test-answers?testResultId=${testResultId}`
try {
console.log(`\n📊 測試結果ID: ${testResultId}`)
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('📡 響應內容:', JSON.stringify(result, null, 2))
if (result.success) {
console.log(`\n📈 答案記錄詳情:`)
console.log(`- 答案數量: ${result.data.length}`)
// 按維度分組統計
const dimensionStats = {
innovation: { total: 0, count: 0 },
imagination: { total: 0, count: 0 },
flexibility: { total: 0, count: 0 },
originality: { total: 0, count: 0 }
}
result.data.forEach((answer, index) => {
console.log(`${index + 1}. 題目ID: ${answer.question_id}, 用戶答案: ${answer.user_answer}, 計算分數: ${answer.score}`)
})
}
} else {
console.log('❌ API 響應失敗,狀態碼:', response.status)
console.log('響應內容:', response.data)
}
} catch (error) {
console.error('\n❌ 請求失敗:')
console.error('錯誤類型:', error.name)
console.error('錯誤訊息:', error.message)
} finally {
console.log('\n✅ 創意測驗答案 API 測試完成')
}
}
testCreativeAnswersAPI()

View File

@@ -1,89 +0,0 @@
// 測試創意能力分析圖表功能
const testCategoryResults = [
{ category: 'innovation', name: '創新能力', score: 73, rawScore: 22, maxRawScore: 30 },
{ category: 'imagination', name: '想像力', score: 100, rawScore: 30, maxRawScore: 30 },
{ category: 'flexibility', name: '靈活性', score: 68, rawScore: 20, maxRawScore: 30 },
{ category: 'originality', name: '原創性', score: 52, rawScore: 15, maxRawScore: 30 }
]
console.log('📊 創意能力分析圖表測試 (4維度修正版)')
console.log('=' .repeat(50))
console.log('\n🎯 圖表功能:')
console.log('- 雷達圖顯示四個能力維度 (正確的4維度)')
console.log('- 每個維度顯示分數百分比,使用文字陰影效果')
console.log('- 圖表大小響應式:手機 320x320px桌面 384x384px')
console.log('- 包含網格線、數據點、面積填充和圖例')
console.log('\n📈 測試數據 (4維度):')
testCategoryResults.forEach((category, index) => {
const angle = (index * 90 - 90) * Math.PI / 180
const radius = (category.score / 100) * 80
const x = 100 + radius * Math.cos(angle)
const y = 100 + radius * Math.sin(angle)
console.log(`\n${category.name}:`)
console.log(` 分數: ${category.score}%`)
console.log(` 角度: ${(index * 90 - 90)}°`)
console.log(` 半徑: ${radius.toFixed(1)}`)
console.log(` 座標: (${x.toFixed(1)}, ${y.toFixed(1)})`)
})
console.log('\n🎨 視覺元素 (4維度修正版):')
console.log('- 網格圓圈: 4個同心圓 (17, 35, 52, 70 半徑)')
console.log('- 網格線: 4條從中心放射的線 (0°, 90°, 180°, 270°)')
console.log('- 數據點: 藍色圓點半徑4px白色邊框2px')
console.log('- 分數標籤: 使用文字陰影效果,確保可讀性')
console.log('- 面積填充: 半透明藍色 (rgba(59, 130, 246, 0.2))')
console.log('- 邊框: 2px 藍色實線')
console.log('- 標籤: 灰色文字10px粗體 (縮小)')
console.log('- 分數: 藍色文字10px粗體白色陰影 (縮小)')
console.log('\n📱 響應式設計 (4維度最終版):')
console.log('- 手機版: w-56 h-56 (224x224px)')
console.log('- 桌面版: w-72 h-72 (288x288px)')
console.log('- 圖例: 手機2欄桌面4欄間距3')
console.log('\n🔧 修正內容 (4維度優化):')
console.log('- 修正為正確的4個維度 (0°, 90°, 180°, 270°)')
console.log('- 移除多餘的網格線只保留4條軸線')
console.log('- 使用文字陰影效果替代背景框,更簡潔')
console.log('- 縮小圖表尺寸,為文字留出更多空間')
console.log('- 維度標籤位置調整到圖表外圍')
console.log('- 根據位置調整文字對齊方式')
console.log('- 圖例置中顯示')
console.log('\n📝 文字對齊修正 (最終版):')
console.log('- 上方 (創新能力): dominantBaseline="hanging", 半徑75px')
console.log('- 右方 (想像力): textAnchor="start", 半徑70px (特殊調整)')
console.log('- 下方 (靈活性): dominantBaseline="alphabetic", 半徑75px')
console.log('- 左方 (原創性): textAnchor="end", 半徑70px (特殊調整)')
console.log('- 一般標籤半徑: 75px')
console.log('- 想像力/原創性半徑: 70px (更靠近圖表)')
console.log('\n📏 圖表尺寸優化 (最終版):')
console.log('- 圖表半徑: 60px (從70px進一步縮小)')
console.log('- 網格圓圈: 15, 30, 45, 60 半徑')
console.log('- 標籤位置: 75px 半徑 (一般), 70px (想像力/原創性)')
console.log('- 容器尺寸: 手機224px桌面288px')
console.log('\n🔤 文字大小優化:')
console.log('- 維度標籤: 從12px縮小到10px')
console.log('- 分數標籤: 從12px縮小到10px')
console.log('- 使用text-[10px]自定義大小')
console.log('- 保持粗體和陰影效果')
console.log('\n🎨 新增功能 (豐富化):')
console.log('- 百分比刻度標籤: 25%, 50%, 75%, 100%')
console.log('- 能力維度詳細說明: 每個維度的具體描述')
console.log('- 能力等級評定: 優秀(80+), 良好(60+), 一般(40+), 待提升(<40)')
console.log('- 響應式網格: 手機1欄桌面2欄')
console.log('- 視覺層次: 分數、等級、描述分層顯示')
console.log('\n📋 維度說明內容:')
console.log('- 創新能力: 善於提出新想法,勇於嘗試不同的解決方案')
console.log('- 想像力: 能夠從不同角度思考,具有豐富的創意思維')
console.log('- 靈活性: 適應變化能力強,能夠靈活調整思維方式')
console.log('- 原創性: 具有獨特的創見,能夠產生原創性想法')
console.log('\n✅ 圖表功能測試完成')

View File

@@ -1,79 +0,0 @@
const https = require('https')
const http = require('http')
const testCreativeDBUpload = async () => {
console.log('🧪 測試創意測驗資料庫上傳功能')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd' // 使用現有用戶ID
const url = 'http://localhost:3000/api/test-results/creative'
// 模擬創意測驗答案1-5分包含反向題
const testAnswers = [
5, 4, 3, 2, 1, // 前5題正常題
1, 2, 3, 4, 5, // 中間5題反向題會自動反轉
5, 4, 3, 2, 1, // 後8題正常題
1, 2, 3, 4, 5
]
const testData = {
userId: userId,
answers: testAnswers,
completedAt: new Date().toISOString().replace('Z', '').replace('T', ' ')
}
console.log('\n📝 測試數據:')
console.log('用戶ID:', testData.userId)
console.log('答案數量:', testData.answers.length)
console.log('答案內容:', testData.answers)
console.log('完成時間:', testData.completedAt)
try {
console.log('\n🔄 測試創意測驗 API...')
const response = await new Promise((resolve, reject) => {
const req = http.request(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
}, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(JSON.stringify(testData))
req.end()
})
console.log('📊 響應狀態:', response.status)
if (response.status === 200) {
const result = JSON.parse(response.data)
console.log('\n✅ API 測試成功!')
console.log('📡 響應內容:', JSON.stringify(result, null, 2))
if (result.success) {
console.log('\n📈 測試結果詳情:')
console.log('- 測試結果ID:', result.data.testResult.id)
console.log('- 分數:', result.data.testResult.score)
console.log('- 總題數:', result.data.testResult.total_questions)
console.log('- 總分數:', result.data.testResult.correct_answers)
console.log('- 答案記錄數量:', result.data.answerCount)
}
} else {
console.log('❌ API 響應失敗,狀態碼:', response.status)
console.log('響應內容:', response.data)
}
} catch (error) {
console.error('\n❌ 請求失敗:')
console.error('錯誤類型:', error.name)
console.error('錯誤訊息:', error.message)
} finally {
console.log('\n✅ 創意測驗資料庫上傳測試完成')
}
}
testCreativeDBUpload()

View File

@@ -1,71 +0,0 @@
// 測試創意測試流程
const mysql = require('mysql2/promise')
async function testCreativeFlow() {
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)
// 1. 檢查資料庫中的題目
const [questions] = await connection.execute('SELECT * FROM creative_questions ORDER BY id')
console.log(`✅ 資料庫中有 ${questions.length} 道題目`)
// 2. 模擬 API 回應
const apiResponse = {
success: true,
questions: questions
}
console.log('✅ API 回應格式正確')
// 3. 測試分數計算邏輯
const mockAnswers = {
0: 5, // 一般題目,選擇 5
1: 5, // 反向題目,選擇 5
2: 1, // 一般題目,選擇 1
3: 1 // 反向題目,選擇 1
}
let totalScore = 0
questions.slice(0, 4).forEach((question, index) => {
const answer = mockAnswers[index] || 1
const score = question.is_reverse ? 6 - answer : answer
totalScore += score
console.log(`題目 ${index + 1}: ${question.is_reverse ? '反向' : '一般'} - 選擇${answer} → 得分${score}`)
})
const maxScore = 4 * 5
const percentage = Math.round((totalScore / maxScore) * 100)
console.log(`\n📊 測試結果: ${totalScore}/${maxScore} (${percentage}%)`)
// 4. 檢查題目類別分布
const categoryCount = {}
questions.forEach(q => {
categoryCount[q.category] = (categoryCount[q.category] || 0) + 1
})
console.log('\n📋 題目類別分布:')
Object.entries(categoryCount).forEach(([category, count]) => {
console.log(`- ${category}: ${count}`)
})
await connection.end()
console.log('\n✅ 創意測試流程測試完成')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
}
}
testCreativeFlow()

View File

@@ -1,93 +0,0 @@
const https = require('https')
const http = require('http')
const testCreativePagination = async () => {
console.log('🔍 測試創意題目分頁功能')
console.log('=' .repeat(50))
try {
// 1. 獲取創意題目資料
console.log('\n📊 1. 獲取創意題目資料...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success) {
const questions = creativeData.data
const itemsPerPage = 10
const totalPages = Math.ceil(questions.length / itemsPerPage)
console.log('✅ 創意題目資料獲取成功')
console.log(` 總題目數量: ${questions.length}`)
console.log(` 每頁顯示: ${itemsPerPage}`)
console.log(` 總頁數: ${totalPages}`)
// 2. 模擬分頁計算
console.log('\n📊 2. 分頁計算模擬:')
for (let page = 1; page <= totalPages; page++) {
const startIndex = (page - 1) * itemsPerPage
const endIndex = startIndex + itemsPerPage
const currentQuestions = questions.slice(startIndex, endIndex)
console.log(`${page} 頁: 顯示第 ${startIndex + 1} - ${Math.min(endIndex, questions.length)}`)
console.log(` 題目ID: ${currentQuestions.map(q => q.id).join(', ')}`)
}
// 3. 分頁功能特點
console.log('\n📊 3. 分頁功能特點:')
console.log('✅ 每頁顯示 10 道題目')
console.log('✅ 支援桌面版和手機版響應式設計')
console.log('✅ 智能省略頁碼(手機版最多顯示 3 個頁碼)')
console.log('✅ 上一頁/下一頁按鈕')
console.log('✅ 顯示當前頁範圍和總筆數')
// 4. 響應式設計
console.log('\n📊 4. 響應式設計:')
console.log('✅ 桌面版: 完整頁碼顯示')
console.log('✅ 手機版: 智能省略頁碼')
console.log('✅ 按鈕大小適配不同螢幕')
console.log('✅ 佈局自動調整')
// 5. 用戶體驗
console.log('\n📊 5. 用戶體驗:')
console.log('✅ 清晰的頁面資訊顯示')
console.log('✅ 直觀的導航控制')
console.log('✅ 載入狀態和錯誤處理')
console.log('✅ 觸控友好的按鈕設計')
// 6. 技術實作
console.log('\n📊 6. 技術實作:')
console.log('✅ 使用 slice() 進行前端分頁')
console.log('✅ 狀態管理: currentPage, itemsPerPage')
console.log('✅ 計算邏輯: startIndex, endIndex, totalPages')
console.log('✅ 條件渲染: 只在題目數量 > itemsPerPage 時顯示分頁')
console.log('\n📝 分頁功能總結:')
console.log('✅ 創意題目現在支援分頁顯示')
console.log('✅ 每頁顯示 10 道題目')
console.log('✅ 18 道題目分為 2 頁顯示')
console.log('✅ 響應式設計適配不同設備')
console.log('✅ 用戶體驗優化')
} else {
console.log('❌ 創意題目 API 失敗:', creativeData.message)
}
} else {
console.log('❌ 創意題目 API 狀態碼:', creativeResponse.status)
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 創意題目分頁功能測試完成')
}
}
testCreativePagination()

View File

@@ -1,55 +0,0 @@
// 測試創意測試結果頁面的響應式設計
const responsiveClasses = {
// 統計數據區域
statsGrid: "grid grid-cols-3 gap-4 mb-6",
statsText: "text-xs text-muted-foreground",
// 能力維度分析區域
categoryGrid: "grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6",
categoryItem: "space-y-2 md:space-y-3",
categoryTitle: "text-sm md:text-base",
categoryBadge: "text-xs",
categoryScore: "text-xs md:text-sm",
// 詳細反饋區域
feedbackCard: "p-3 md:p-4",
feedbackTitle: "text-sm md:text-base",
feedbackText: "text-xs md:text-sm",
feedbackGrid: "grid grid-cols-1 md:grid-cols-2 gap-3 md:gap-4",
// 按鈕區域
buttonContainer: "flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center",
button: "w-full sm:w-auto"
}
console.log('📱 創意測試結果頁面響應式設計測試')
console.log('=' .repeat(60))
console.log('\n📊 統計數據區域:')
console.log(`網格佈局: ${responsiveClasses.statsGrid}`)
console.log(`標籤文字: ${responsiveClasses.statsText}`)
console.log('\n📋 能力維度分析區域:')
console.log(`網格佈局: ${responsiveClasses.categoryGrid}`)
console.log(`項目間距: ${responsiveClasses.categoryItem}`)
console.log(`標題大小: ${responsiveClasses.categoryTitle}`)
console.log(`徽章大小: ${responsiveClasses.categoryBadge}`)
console.log(`分數文字: ${responsiveClasses.categoryScore}`)
console.log('\n💬 詳細反饋區域:')
console.log(`卡片內邊距: ${responsiveClasses.feedbackCard}`)
console.log(`標題大小: ${responsiveClasses.feedbackTitle}`)
console.log(`文字大小: ${responsiveClasses.feedbackText}`)
console.log(`網格佈局: ${responsiveClasses.feedbackGrid}`)
console.log('\n🔘 按鈕區域:')
console.log(`按鈕容器: ${responsiveClasses.buttonContainer}`)
console.log(`按鈕樣式: ${responsiveClasses.button}`)
console.log('\n✅ 響應式設計配置完成')
console.log('\n📱 手機版特點:')
console.log('- 統計數據始終 3 欄並排顯示')
console.log('- 文字大小在手機上較小,桌面版較大')
console.log('- 能力維度分析在手機上單欄顯示,桌面版雙欄')
console.log('- 按鈕在手機上全寬顯示,桌面版自動寬度')
console.log('- 內邊距在手機上較小,桌面版較大')

View File

@@ -1,69 +0,0 @@
const https = require('https')
const http = require('http')
const testCreativeResultsPage = async () => {
console.log('🔍 測試創意測驗結果頁面數據')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查創意測試結果 API模擬創意測驗結果頁面的請求
console.log('\n📊 檢查創意測試結果 API...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.length > 0) {
console.log(`找到 ${data.data.length} 筆創意測試結果:`)
// 按創建時間排序,取最新的(模擬前端邏輯)
const sortedResults = data.data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
const latestResult = sortedResults[0]
console.log('\n📋 創意測驗結果頁面會使用的數據:')
console.log(`ID: ${latestResult.id}`)
console.log(`completed_at: ${latestResult.completed_at}`)
console.log(`created_at: ${latestResult.created_at}`)
// 測試時間解析(模擬前端顯示邏輯)
const parsedDate = new Date(latestResult.completed_at)
const isValid = !isNaN(parsedDate.getTime())
console.log(`\n📊 前端時間解析測試:`)
console.log(`解析是否有效: ${isValid ? '✅' : '❌'}`)
if (isValid) {
const taiwanTime = parsedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(`台灣時間: ${taiwanTime}`)
console.log(`顯示效果: 完成時間:${taiwanTime}`)
} else {
console.log(`❌ 會顯示: 完成時間Invalid Date`)
}
// 檢查是否為今天
const now = new Date()
const isToday = now.toDateString() === parsedDate.toDateString()
console.log(`是否為今天: ${isToday ? '✅' : '❌'}`)
if (!isToday) {
console.log(`⚠️ 這是舊數據,可能需要重新進行測試`)
}
}
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 創意測驗結果頁面數據測試完成')
}
}
testCreativeResultsPage()

View File

@@ -1,55 +0,0 @@
// 測試新的創意評分系統
const testScores = [0, 20, 40, 50, 60, 70, 80, 85, 90, 95, 100]
function getCreativityLevel(score) {
if (score >= 90) return {
level: "創意巔峰者",
color: "bg-purple-600",
description: "創意力近乎無窮,你是團隊裡的靈感源泉,總能帶來突破性的想法。",
suggestion: "你不只創造靈感,更能影響他人。如果能結合執行力,你將成為真正的創新領袖。"
}
if (score >= 75) return {
level: "創意引領者",
color: "bg-blue-500",
description: "你是靈感的推動者!總是能在團體中主動拋出新想法,激發別人跟進。",
suggestion: "持續累積學習,讓你的靈感不僅是點子,而能帶動真正的行動。"
}
if (score >= 55) return {
level: "創意實踐者",
color: "bg-green-500",
description: "靈感已經隨手可得,在團體中也常被認為是「有創意的人」。",
suggestion: "再給自己一點勇氣,不要害怕挑戰慣例,你的創意將更有力量。"
}
if (score >= 35) return {
level: "創意開拓者",
color: "bg-yellow-500",
description: "你其實有自己的想法,但有時習慣跟隨大多數人的步伐。",
suggestion: "試著勇敢說出腦中天馬行空的念頭,你會發現,這些點子或許就是團隊需要的突破口。"
}
return {
level: "創意萌芽者",
color: "bg-red-500",
description: "還在創意旅程的起點。雖然暫時表現平淡,但這正是無限潛力的開端!",
suggestion: "觀察生活小事,或閱讀不同領域的內容,讓靈感一點一滴積累。"
}
}
console.log('🎨 測試新的創意評分系統')
console.log('=' .repeat(80))
testScores.forEach(score => {
const level = getCreativityLevel(score)
console.log(`\n📊 分數: ${score}`)
console.log(`🏆 等級: ${level.level}`)
console.log(`📝 描述: ${level.description}`)
console.log(`💡 建議: ${level.suggestion}`)
console.log('-'.repeat(60))
})
console.log('\n✅ 創意評分系統測試完成')
console.log('\n📋 評分標準:')
console.log('- 90分以上: 創意巔峰者')
console.log('- 75-89分: 創意引領者')
console.log('- 55-74分: 創意實踐者')
console.log('- 35-54分: 創意開拓者')
console.log('- 35分以下: 創意萌芽者')

View File

@@ -1,71 +0,0 @@
const https = require('https')
const http = require('http')
const testCreativeTimeFix = async () => {
console.log('🔍 測試創意測驗時間修正')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查創意測試結果 API
console.log('\n📊 檢查創意測試結果 API...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.length > 0) {
console.log(`找到 ${data.data.length} 筆創意測試結果:`)
// 按創建時間排序
const sortedResults = data.data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
console.log('\n📋 排序後的創意測試結果:')
sortedResults.forEach((result, index) => {
console.log(`\n${index + 1}. 創意測試:`)
console.log(` ID: ${result.id}`)
console.log(` completed_at: ${result.completed_at}`)
console.log(` created_at: ${result.created_at}`)
const completedDate = new Date(result.completed_at)
const createdDate = new Date(result.created_at)
console.log(` completed_at 台灣時間: ${completedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
console.log(` created_at 台灣時間: ${createdDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
// 檢查是否是今天
const now = new Date()
const isToday = now.toDateString() === completedDate.toDateString()
console.log(` 是否為今天: ${isToday}`)
})
// 顯示最新結果
const latestResult = sortedResults[0]
console.log('\n🎯 最新結果 (創意測驗結果頁面會使用這個):')
console.log(`completed_at: ${latestResult.completed_at}`)
const latestDate = new Date(latestResult.completed_at)
console.log(`台灣時間: ${latestDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
}
}
// 檢查當前時間
console.log('\n📊 當前時間:')
const now = new Date()
console.log(`UTC 時間: ${now.toISOString()}`)
console.log(`台灣時間: ${now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`)
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 創意測驗時間修正測試完成')
}
}
testCreativeTimeFix()

View File

@@ -1,53 +0,0 @@
const { executeQuery } = require('../lib/database/connection');
async function testDbConnection() {
console.log('🔍 測試資料庫連接和表結構');
console.log('==============================');
try {
// 測試基本連接
console.log('1. 測試基本連接...');
const testQuery = await executeQuery('SELECT 1 as test');
console.log('✅ 資料庫連接成功:', testQuery);
// 檢查所有表
console.log('\n2. 檢查所有表...');
const tables = await executeQuery('SHOW TABLES');
console.log('📋 所有表:', tables.map(t => Object.values(t)[0]));
// 檢查 logic_test_answers 表是否存在
console.log('\n3. 檢查 logic_test_answers 表...');
const tableExists = await executeQuery(`
SELECT COUNT(*) as count
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'logic_test_answers'
`);
console.log('logic_test_answers 表存在:', tableExists[0].count > 0);
// 檢查表結構
console.log('\n4. 檢查 logic_test_answers 表結構...');
const tableStructure = await executeQuery('DESCRIBE logic_test_answers');
console.log('📋 表結構:', tableStructure);
// 檢查資料數量
console.log('\n5. 檢查資料數量...');
const count = await executeQuery('SELECT COUNT(*) as count FROM logic_test_answers');
console.log('📊 logic_test_answers 資料數量:', count[0].count);
// 檢查前幾筆資料
if (count[0].count > 0) {
console.log('\n6. 檢查前 3 筆資料...');
const sampleData = await executeQuery('SELECT * FROM logic_test_answers LIMIT 3');
console.log('📋 範例資料:', sampleData);
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
console.error('錯誤詳情:', error);
}
console.log('==============================\n');
}
testDbConnection();

View File

@@ -1,73 +0,0 @@
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()

View File

@@ -1,36 +0,0 @@
const mysql = require('mysql2/promise')
async function testDatabaseConnection() {
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('連接資訊:', {
host: config.host,
port: config.port,
user: config.user,
database: config.database
})
try {
const connection = await mysql.createConnection(config)
await connection.ping()
console.log('✅ 資料庫連接成功!')
// 測試查詢
const [rows] = await connection.execute('SELECT 1 as test')
console.log('✅ 查詢測試成功:', rows)
await connection.end()
} catch (error) {
console.error('❌ 資料庫連接失敗:', error.message)
process.exit(1)
}
}
testDatabaseConnection()

View File

@@ -1,151 +0,0 @@
const https = require('https')
const http = require('http')
const testDeleteConfirmation = async () => {
console.log('🔍 測試刪除確認對話框功能')
console.log('=' .repeat(50))
try {
// 1. 先創建一個測試用戶
console.log('\n📊 1. 創建測試用戶...')
const testUser = {
name: '刪除測試用戶',
email: 'delete.test@company.com',
password: 'password123',
department: '測試部',
role: 'user'
}
const createResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(testUser)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/admin/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
let testUserId = null
if (createResponse.status === 200) {
const createData = JSON.parse(createResponse.data)
if (createData.success) {
testUserId = createData.data.id
console.log('✅ 測試用戶創建成功:')
console.log(` ID: ${createData.data.id}`)
console.log(` 姓名: ${createData.data.name}`)
console.log(` 電子郵件: ${createData.data.email}`)
} else {
console.log('❌ 創建測試用戶失敗:', createData.error)
return
}
}
// 2. 驗證用戶存在
console.log('\n📊 2. 驗證用戶存在...')
const getResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/users', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (getResponse.status === 200) {
const getData = JSON.parse(getResponse.data)
if (getData.success) {
const userExists = getData.data.some(user => user.id === testUserId)
console.log(`✅ 用戶存在驗證: ${userExists ? '是' : '否'}`)
if (userExists) {
const user = getData.data.find(user => user.id === testUserId)
console.log(` 用戶資訊: ${user.name} (${user.email})`)
}
}
}
// 3. 模擬刪除用戶(這裡只是測試 API實際的確認對話框在前端
console.log('\n📊 3. 測試刪除用戶 API...')
if (testUserId) {
const deleteResponse = await new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 3000,
path: `/api/admin/users?id=${testUserId}`,
method: 'DELETE'
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.end()
})
if (deleteResponse.status === 200) {
const deleteResult = JSON.parse(deleteResponse.data)
if (deleteResult.success) {
console.log('✅ 刪除用戶 API 測試成功')
} else {
console.log('❌ 刪除用戶 API 測試失敗:', deleteResult.error)
}
}
}
// 4. 驗證用戶已被刪除
console.log('\n📊 4. 驗證用戶已被刪除...')
const finalResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/users', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (finalResponse.status === 200) {
const finalData = JSON.parse(finalResponse.data)
if (finalData.success) {
const userStillExists = finalData.data.some(user => user.id === testUserId)
console.log(`✅ 用戶刪除驗證: ${!userStillExists ? '成功' : '失敗'}`)
}
}
console.log('\n📝 功能總結:')
console.log('✅ 刪除確認對話框已實作')
console.log('✅ 對話框包含用戶詳細資訊顯示')
console.log('✅ 對話框包含警告訊息')
console.log('✅ 對話框包含取消和確認按鈕')
console.log('✅ 刪除 API 功能正常')
console.log('✅ 用戶資料完整性保護')
console.log('\n🎨 對話框設計特色:')
console.log('✅ 符合網頁整體風格')
console.log('✅ 清晰的視覺層次')
console.log('✅ 適當的警告色彩')
console.log('✅ 用戶友好的介面')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 刪除確認對話框功能測試完成')
}
}
testDeleteConfirmation()

View File

@@ -1,70 +0,0 @@
const fetch = require('node-fetch');
async function testDetailAPI() {
console.log('🔍 測試詳細結果 API');
console.log('==============================');
try {
// 先獲取測試結果列表
const listResponse = await fetch('http://localhost:3000/api/admin/test-results');
const listData = await listResponse.json();
if (listData.success && listData.data.results.length > 0) {
const firstResult = listData.data.results[0];
console.log(`📋 測試結果: ${firstResult.userName} - ${firstResult.type}`);
console.log(` 分數: ${firstResult.score}, 等級: ${firstResult.grade}`);
// 測試詳細結果 API
const detailResponse = await fetch(`http://localhost:3000/api/admin/test-results/detail?testResultId=${firstResult.id}&testType=${firstResult.type}`);
const detailData = await detailResponse.json();
if (detailData.success) {
console.log('✅ 詳細結果獲取成功');
console.log('📊 用戶資訊:', {
name: detailData.data.user.name,
email: detailData.data.user.email,
department: detailData.data.user.department
});
console.log('📈 測試結果:', {
type: detailData.data.result.type,
score: detailData.data.result.score,
completedAt: detailData.data.result.completedAt
});
console.log('📝 題目數量:', detailData.data.questions?.length || 0);
console.log('💡 答案數量:', detailData.data.answers?.length || 0);
if (detailData.data.questions && detailData.data.questions.length > 0) {
console.log('\n📋 第一題詳情:');
const firstQuestion = detailData.data.questions[0];
console.log(' 題目:', firstQuestion.question || firstQuestion.statement);
console.log(' 用戶答案:', firstQuestion.userAnswer);
if (firstQuestion.isCorrect !== undefined) {
console.log(' 是否正確:', firstQuestion.isCorrect ? '是' : '否');
}
if (firstQuestion.score !== undefined) {
console.log(' 得分:', firstQuestion.score);
}
}
if (detailData.data.result.type === 'combined' && detailData.data.result.details) {
console.log('\n🎯 綜合能力分析:');
console.log(' 邏輯思維:', detailData.data.result.details.logicScore);
console.log(' 創意能力:', detailData.data.result.details.creativeScore);
console.log(' 能力平衡:', detailData.data.result.details.abilityBalance);
}
} else {
console.error('❌ 詳細結果獲取失敗:', detailData.message);
}
} else {
console.log('⚠️ 沒有找到測試結果');
}
} catch (error) {
console.error('❌ 測試錯誤:', error.message);
}
console.log('==============================\n');
}
testDetailAPI();

View File

@@ -1,121 +0,0 @@
const fetch = require('node-fetch');
async function testDetailedAnswersFixed() {
console.log('🔍 測試修復後的詳細答題結果功能');
console.log('==============================');
try {
// 先獲取測試結果列表
const listResponse = await fetch('http://localhost:3000/api/admin/test-results');
const listData = await listResponse.json();
if (listData.success && listData.data.results.length > 0) {
// 測試綜合能力測試的詳細結果
const combinedResult = listData.data.results.find(r => r.type === 'combined');
if (combinedResult) {
console.log(`📋 測試綜合能力結果: ${combinedResult.userName}`);
console.log(` 分數: ${combinedResult.score}, 等級: ${combinedResult.grade}`);
console.log(` ID: ${combinedResult.id}`);
const detailResponse = await fetch(`http://localhost:3000/api/admin/test-results/detail?testResultId=${combinedResult.id}&testType=combined`);
const detailData = await detailResponse.json();
if (detailData.success) {
console.log('✅ 綜合能力詳細結果獲取成功');
console.log('📊 用戶資訊:', {
name: detailData.data.user.name,
email: detailData.data.user.email,
department: detailData.data.user.department
});
console.log('📈 測試結果:', {
type: detailData.data.result.type,
score: detailData.data.result.score,
completedAt: detailData.data.result.completedAt
});
console.log('🎯 能力分析:', {
logicScore: detailData.data.result.details.logicScore,
creativeScore: detailData.data.result.details.creativeScore,
abilityBalance: detailData.data.result.details.abilityBalance
});
console.log('📝 題目總數:', detailData.data.questions?.length || 0);
if (detailData.data.questions && detailData.data.questions.length > 0) {
const logicQuestions = detailData.data.questions.filter(q => q.type === 'logic');
const creativeQuestions = detailData.data.questions.filter(q => q.type === 'creative');
console.log(`\n🧠 邏輯思維題目: ${logicQuestions.length}`);
console.log(`💡 創意能力題目: ${creativeQuestions.length}`);
if (logicQuestions.length > 0) {
console.log('\n📋 邏輯題詳情:');
logicQuestions.forEach((q, index) => {
console.log(`${index + 1} 題:`, {
question: q.question?.substring(0, 50) + '...',
userAnswer: q.userAnswer,
correctAnswer: q.correctAnswer,
isCorrect: q.isCorrect
});
});
}
if (creativeQuestions.length > 0) {
console.log('\n📋 創意題詳情:');
creativeQuestions.forEach((q, index) => {
console.log(`${index + 1} 題:`, {
statement: q.statement?.substring(0, 50) + '...',
userAnswer: q.userAnswer,
score: q.score
});
});
}
} else {
console.log('⚠️ 沒有找到詳細答題資料');
}
} else {
console.error('❌ 綜合能力詳細結果獲取失敗:', detailData.message);
}
} else {
console.log('⚠️ 沒有找到綜合能力測試結果');
}
// 測試單一測試類型
const singleResult = listData.data.results.find(r => r.type !== 'combined');
if (singleResult) {
console.log(`\n📋 測試單一類型結果: ${singleResult.userName} - ${singleResult.type}`);
const detailResponse = await fetch(`http://localhost:3000/api/admin/test-results/detail?testResultId=${singleResult.id}&testType=${singleResult.type}`);
const detailData = await detailResponse.json();
if (detailData.success) {
console.log('✅ 單一類型詳細結果獲取成功');
console.log('📝 題目數量:', detailData.data.questions?.length || 0);
if (detailData.data.questions && detailData.data.questions.length > 0) {
console.log('\n📋 題目詳情:');
detailData.data.questions.forEach((q, index) => {
console.log(`${index + 1} 題:`, {
question: (q.question || q.statement)?.substring(0, 50) + '...',
userAnswer: q.userAnswer,
isCorrect: q.isCorrect,
score: q.score
});
});
}
} else {
console.error('❌ 單一類型詳細結果獲取失敗:', detailData.message);
}
}
} else {
console.log('⚠️ 沒有找到測試結果');
}
} catch (error) {
console.error('❌ 測試錯誤:', error.message);
}
console.log('==============================\n');
}
testDetailedAnswersFixed();

View File

@@ -1,113 +0,0 @@
const fetch = require('node-fetch');
async function testDetailedAnswers() {
console.log('🔍 測試詳細答題結果功能');
console.log('==============================');
try {
// 先獲取測試結果列表
const listResponse = await fetch('http://localhost:3000/api/admin/test-results');
const listData = await listResponse.json();
if (listData.success && listData.data.results.length > 0) {
// 測試綜合能力測試的詳細結果
const combinedResult = listData.data.results.find(r => r.type === 'combined');
if (combinedResult) {
console.log(`📋 測試綜合能力結果: ${combinedResult.userName}`);
console.log(` 分數: ${combinedResult.score}, 等級: ${combinedResult.grade}`);
const detailResponse = await fetch(`http://localhost:3000/api/admin/test-results/detail?testResultId=${combinedResult.id}&testType=combined`);
const detailData = await detailResponse.json();
if (detailData.success) {
console.log('✅ 綜合能力詳細結果獲取成功');
console.log('📊 用戶資訊:', {
name: detailData.data.user.name,
email: detailData.data.user.email,
department: detailData.data.user.department
});
console.log('📈 測試結果:', {
type: detailData.data.result.type,
score: detailData.data.result.score,
completedAt: detailData.data.result.completedAt
});
console.log('🎯 能力分析:', {
logicScore: detailData.data.result.details.logicScore,
creativeScore: detailData.data.result.details.creativeScore,
abilityBalance: detailData.data.result.details.abilityBalance
});
console.log('📝 題目總數:', detailData.data.questions?.length || 0);
if (detailData.data.questions && detailData.data.questions.length > 0) {
const logicQuestions = detailData.data.questions.filter(q => q.type === 'logic');
const creativeQuestions = detailData.data.questions.filter(q => q.type === 'creative');
console.log(`\n🧠 邏輯思維題目: ${logicQuestions.length}`);
console.log(`💡 創意能力題目: ${creativeQuestions.length}`);
if (logicQuestions.length > 0) {
console.log('\n📋 第一題邏輯題詳情:');
const firstLogic = logicQuestions[0];
console.log(' 題目:', firstLogic.question);
console.log(' 用戶答案:', firstLogic.userAnswer);
console.log(' 正確答案:', firstLogic.correctAnswer);
console.log(' 是否正確:', firstLogic.isCorrect ? '是' : '否');
}
if (creativeQuestions.length > 0) {
console.log('\n📋 第一題創意題詳情:');
const firstCreative = creativeQuestions[0];
console.log(' 題目:', firstCreative.statement);
console.log(' 用戶答案:', firstCreative.userAnswer);
console.log(' 得分:', firstCreative.score);
}
}
} else {
console.error('❌ 綜合能力詳細結果獲取失敗:', detailData.message);
}
} else {
console.log('⚠️ 沒有找到綜合能力測試結果');
}
// 測試單一測試類型的詳細結果
const singleResult = listData.data.results.find(r => r.type !== 'combined');
if (singleResult) {
console.log(`\n📋 測試單一類型結果: ${singleResult.userName} - ${singleResult.type}`);
const detailResponse = await fetch(`http://localhost:3000/api/admin/test-results/detail?testResultId=${singleResult.id}&testType=${singleResult.type}`);
const detailData = await detailResponse.json();
if (detailData.success) {
console.log('✅ 單一類型詳細結果獲取成功');
console.log('📝 題目數量:', detailData.data.questions?.length || 0);
if (detailData.data.questions && detailData.data.questions.length > 0) {
console.log('\n📋 第一題詳情:');
const firstQuestion = detailData.data.questions[0];
console.log(' 題目:', firstQuestion.question || firstQuestion.statement);
console.log(' 用戶答案:', firstQuestion.userAnswer);
if (firstQuestion.isCorrect !== undefined) {
console.log(' 是否正確:', firstQuestion.isCorrect ? '是' : '否');
}
if (firstQuestion.score !== undefined) {
console.log(' 得分:', firstQuestion.score);
}
}
} else {
console.error('❌ 單一類型詳細結果獲取失敗:', detailData.message);
}
}
} else {
console.log('⚠️ 沒有找到測試結果');
}
} catch (error) {
console.error('❌ 測試錯誤:', error.message);
}
console.log('==============================\n');
}
testDetailedAnswers();

View File

@@ -1,101 +0,0 @@
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()

View File

@@ -1,96 +0,0 @@
const https = require('https')
const http = require('http')
const fs = require('fs')
const path = require('path')
const testExcelImportExport = async () => {
console.log('🔍 測試 Excel 匯入匯出功能')
console.log('=' .repeat(50))
try {
// 1. 測試匯出邏輯題目範本
console.log('\n📊 1. 測試匯出邏輯題目範本...')
const logicResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=logic', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data, headers: res.headers }))
})
req.on('error', reject)
})
if (logicResponse.status === 200) {
console.log('✅ 邏輯題目範本匯出成功')
console.log(` Content-Type: ${logicResponse.headers['content-type']}`)
console.log(` Content-Disposition: ${logicResponse.headers['content-disposition']}`)
} else {
console.log('❌ 邏輯題目範本匯出失敗:', logicResponse.status)
}
// 2. 測試匯出創意題目範本
console.log('\n📊 2. 測試匯出創意題目範本...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data, headers: res.headers }))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
console.log('✅ 創意題目範本匯出成功')
console.log(` Content-Type: ${creativeResponse.headers['content-type']}`)
console.log(` Content-Disposition: ${creativeResponse.headers['content-disposition']}`)
} else {
console.log('❌ 創意題目範本匯出失敗:', creativeResponse.status)
}
// 3. 功能特點
console.log('\n📊 3. Excel 匯入匯出功能特點:')
console.log('✅ 根據資料庫格式匯出範本')
console.log('✅ 支援邏輯思維和創意能力兩種題目')
console.log('✅ 匯入時覆蓋現有資料')
console.log('✅ 支援 A-E 選項(邏輯題目)')
console.log('✅ 支援反向計分標記(創意題目)')
console.log('✅ 自動重新載入題目資料')
// 4. 資料庫整合
console.log('\n📊 4. 資料庫整合特點:')
console.log('✅ 匯出:從資料庫讀取現有題目')
console.log('✅ 匯入:清空現有資料後插入新資料')
console.log('✅ 格式:完全匹配資料庫欄位名稱')
console.log('✅ 驗證:匯入時進行資料驗證')
console.log('✅ 更新:匯入後自動刷新頁面資料')
// 5. 檔案格式
console.log('\n📊 5. 檔案格式支援:')
console.log('✅ 邏輯題目ID, 題目內容, 選項A-E, 正確答案, 解釋')
console.log('✅ 創意題目ID, 陳述內容, 類別, 反向計分')
console.log('✅ Excel 格式:.xlsx 檔案')
console.log('✅ 中文標題:便於理解和使用')
console.log('✅ 資料完整性:包含所有必要欄位')
// 6. 用戶體驗
console.log('\n📊 6. 用戶體驗:')
console.log('✅ 一鍵下載:點擊按鈕直接下載範本')
console.log('✅ 格式一致:範本格式與資料庫完全一致')
console.log('✅ 即時更新:匯入後立即看到更新結果')
console.log('✅ 錯誤處理:詳細的錯誤訊息提示')
console.log('✅ 載入狀態:匯入過程顯示載入指示器')
console.log('\n📝 Excel 匯入匯出功能總結:')
console.log('✅ 完全基於資料庫格式設計')
console.log('✅ 支援覆蓋式更新現有題目')
console.log('✅ 提供完整的匯入匯出流程')
console.log('✅ 用戶友好的操作界面')
console.log('✅ 自動化的資料同步機制')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ Excel 匯入匯出功能測試完成')
}
}
testExcelImportExport()

View File

@@ -1,39 +0,0 @@
const http = require('http')
const testExportAPI = async () => {
console.log('🔍 測試匯出 API')
console.log('=' .repeat(30))
try {
// 測試邏輯題目匯出
console.log('\n📊 測試邏輯題目匯出...')
const logicResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=logic', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
headers: res.headers,
data: data.substring(0, 200) // 只顯示前200字符
}))
})
req.on('error', reject)
})
console.log(`狀態碼: ${logicResponse.status}`)
console.log(`Content-Type: ${logicResponse.headers['content-type']}`)
console.log(`Content-Disposition: ${logicResponse.headers['content-disposition']}`)
console.log(`資料預覽: ${logicResponse.data}`)
if (logicResponse.status === 500) {
console.log('❌ 伺服器錯誤,可能是資料庫連接問題')
} else if (logicResponse.status === 200) {
console.log('✅ 匯出成功')
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
}
}
testExportAPI()

View File

@@ -1,89 +0,0 @@
const http = require('http')
const testExportDetails = async () => {
console.log('🔍 測試匯出詳細資料')
console.log('=' .repeat(40))
try {
// 測試匯出 API
const response = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results/export', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success) {
console.log('✅ 匯出成功')
// 解碼並檢查 CSV 內容
const binaryString = Buffer.from(data.data, 'base64').toString('binary')
const csvContent = Buffer.from(binaryString, 'binary').toString('utf-8')
const lines = csvContent.split('\n')
console.log('\n📋 所有綜合測試的詳細資料:')
lines.forEach((line, index) => {
if (index === 0) return // 跳過標題行
const columns = line.split(',')
if (columns.length >= 8) {
const testType = columns[3].replace(/"/g, '')
const details = columns[7].replace(/"/g, '')
if (testType === '綜合能力') {
console.log(`${index} 行: ${details}`)
}
}
})
// 檢查原始資料
console.log('\n🔍 檢查原始 API 資料...')
const apiResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (apiResponse.status === 200) {
const apiData = JSON.parse(apiResponse.data)
if (apiData.success) {
const combinedResults = apiData.data.results.filter(result => result.type === 'combined')
console.log(`\n📊 API 中的綜合測試結果 (${combinedResults.length} 筆):`)
combinedResults.forEach((result, index) => {
console.log(`\n 結果 ${index + 1}:`)
console.log(` 用戶: ${result.userName}`)
console.log(` 分數: ${result.score}`)
console.log(` 詳細資料:`, JSON.stringify(result.details, null, 2))
})
}
}
} else {
console.log('❌ 匯出失敗:', data.message)
}
} else {
console.log('❌ 匯出失敗,狀態碼:', response.status)
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 匯出詳細資料測試完成')
}
}
testExportDetails()

View File

@@ -1,154 +0,0 @@
const http = require('http')
const testExportResults = async () => {
console.log('🔍 測試測驗結果匯出功能')
console.log('=' .repeat(40))
try {
// 測試基本匯出
console.log('\n📊 測試基本匯出...')
const basicResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results/export', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (basicResponse.status === 200) {
const basicData = JSON.parse(basicResponse.data)
if (basicData.success) {
console.log('✅ 基本匯出成功')
console.log(`📄 檔案名稱: ${basicData.filename}`)
console.log(`📊 內容類型: ${basicData.contentType}`)
console.log(`📏 資料大小: ${basicData.data.length} 字元`)
// 解碼並檢查 CSV 內容
const binaryString = Buffer.from(basicData.data, 'base64').toString('binary')
const csvContent = Buffer.from(binaryString, 'binary').toString('utf-8')
console.log('\n📋 CSV 內容預覽:')
const lines = csvContent.split('\n')
console.log(`總行數: ${lines.length}`)
console.log('前 5 行內容:')
lines.slice(0, 5).forEach((line, index) => {
console.log(` ${index + 1}: ${line}`)
})
// 檢查是否包含中文
const hasChinese = /[\u4e00-\u9fff]/.test(csvContent)
console.log(`✅ 包含中文字符: ${hasChinese ? '是' : '否'}`)
// 檢查 BOM
const hasBOM = csvContent.startsWith('\uFEFF')
console.log(`✅ 包含 UTF-8 BOM: ${hasBOM ? '是' : '否'}`)
} else {
console.log('❌ 基本匯出失敗:', basicData.message)
return
}
} else {
console.log('❌ 基本匯出失敗,狀態碼:', basicResponse.status)
return
}
// 測試篩選匯出
console.log('\n🔍 測試篩選匯出...')
const filterResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results/export?testType=logic&department=人力資源部', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (filterResponse.status === 200) {
const filterData = JSON.parse(filterResponse.data)
if (filterData.success) {
console.log('✅ 篩選匯出成功')
// 解碼並檢查篩選結果
const binaryString = Buffer.from(filterData.data, 'base64').toString('binary')
const csvContent = Buffer.from(binaryString, 'binary').toString('utf-8')
const lines = csvContent.split('\n')
console.log(`📊 篩選後結果數量: ${lines.length - 1} 筆(扣除標題行)`)
// 檢查是否只包含邏輯測試
const logicLines = lines.filter(line => line.includes('邏輯思維'))
console.log(`🧠 邏輯思維測試數量: ${logicLines.length}`)
} else {
console.log('❌ 篩選匯出失敗:', filterData.message)
}
}
// 測試搜尋匯出
console.log('\n🔍 測試搜尋匯出...')
const searchResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results/export?search=王', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (searchResponse.status === 200) {
const searchData = JSON.parse(searchResponse.data)
if (searchData.success) {
console.log('✅ 搜尋匯出成功')
// 解碼並檢查搜尋結果
const binaryString = Buffer.from(searchData.data, 'base64').toString('binary')
const csvContent = Buffer.from(binaryString, 'binary').toString('utf-8')
const lines = csvContent.split('\n')
console.log(`📊 搜尋結果數量: ${lines.length - 1} 筆(扣除標題行)`)
// 檢查是否只包含包含「王」的結果
const wangLines = lines.filter(line => line.includes('王'))
console.log(`👤 包含「王」的結果數量: ${wangLines.length}`)
} else {
console.log('❌ 搜尋匯出失敗:', searchData.message)
}
}
console.log('\n🎯 匯出功能特點:')
console.log('✅ 支援 CSV 格式匯出')
console.log('✅ 包含 UTF-8 BOM確保中文正確顯示')
console.log('✅ 支援篩選條件匯出')
console.log('✅ 包含詳細的測試結果資料')
console.log('✅ 自動生成檔案名稱(包含日期)')
console.log('✅ 支援搜尋、部門、測試類型篩選')
console.log('\n📊 匯出欄位:')
console.log('✅ 用戶姓名')
console.log('✅ 用戶郵箱')
console.log('✅ 部門')
console.log('✅ 測試類型')
console.log('✅ 分數')
console.log('✅ 等級')
console.log('✅ 完成時間')
console.log('✅ 詳細資料(根據測試類型不同)')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 測驗結果匯出功能測試完成')
}
}
testExportResults()

View File

@@ -1,61 +0,0 @@
const http = require('http')
const testExportSimple = async () => {
console.log('🔍 簡單測試匯出功能')
console.log('=' .repeat(30))
try {
const response = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results/export', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success) {
console.log('✅ 匯出成功')
// 解碼並檢查 CSV 內容
const binaryString = Buffer.from(data.data, 'base64').toString('binary')
const csvContent = Buffer.from(binaryString, 'binary').toString('utf-8')
// 只顯示前幾行
const lines = csvContent.split('\n')
console.log('\n📋 CSV 前 10 行:')
lines.slice(0, 10).forEach((line, index) => {
console.log(`${index + 1}: ${line}`)
})
// 檢查是否有「創意」和「平衡」字樣
const hasCreative = csvContent.includes('創意')
const hasBalance = csvContent.includes('平衡')
console.log(`\n🔍 檢查結果:`)
console.log(` 包含「創意」: ${hasCreative ? '是' : '否'}`)
console.log(` 包含「平衡」: ${hasBalance ? '是' : '否'}`)
if (hasCreative && hasBalance) {
console.log('✅ 修復成功!')
} else {
console.log('❌ 仍有問題')
}
} else {
console.log('❌ 匯出失敗:', data.message)
}
} else {
console.log('❌ 匯出失敗,狀態碼:', response.status)
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
}
}
testExportSimple()

View File

@@ -1,135 +0,0 @@
const http = require('http')
const fs = require('fs')
const testFinalChineseExport = async () => {
console.log('🎉 最終中文匯出功能測試')
console.log('=' .repeat(40))
try {
// 測試創意題目匯出
console.log('\n📊 測試創意題目匯出...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success) {
console.log('✅ 創意題目匯出成功')
// 解碼 Base64 資料
const binaryString = Buffer.from(creativeData.data, 'base64').toString('binary')
const bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
// 檢查 BOM
const hasBOM = bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF
console.log(`📝 UTF-8 BOM: ${hasBOM ? '✅' : '❌'}`)
// 解碼為文字
const csvContent = new TextDecoder('utf-8').decode(bytes)
const hasChinese = /[\u4e00-\u9fff]/.test(csvContent)
console.log(`🔤 中文字符: ${hasChinese ? '✅' : '❌'}`)
// 顯示內容
const lines = csvContent.split('\n')
console.log(`📊 總行數: ${lines.length}`)
console.log(`📋 標題: ${lines[0]}`)
console.log(`📝 範例: ${lines[1]?.substring(0, 60)}...`)
// 保存測試檔案
fs.writeFileSync('test-final-creative.csv', csvContent, 'utf8')
console.log(`💾 已保存測試檔案: test-final-creative.csv`)
// 檢查檔案開頭
const fileContent = fs.readFileSync('test-final-creative.csv', 'utf8')
const fileHasBOM = fileContent.charCodeAt(0) === 0xFEFF
console.log(`📁 檔案 BOM: ${fileHasBOM ? '✅' : '❌'}`)
if (hasBOM && hasChinese && fileHasBOM) {
console.log('\n🎉 完美Excel 應該能正確顯示中文了!')
} else {
console.log('\n⚠ 還有問題需要修正')
}
}
}
// 測試邏輯題目匯出
console.log('\n📊 測試邏輯題目匯出...')
const logicResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=logic', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (logicResponse.status === 200) {
const logicData = JSON.parse(logicResponse.data)
if (logicData.success) {
console.log('✅ 邏輯題目匯出成功')
// 解碼 Base64 資料
const binaryString = Buffer.from(logicData.data, 'base64').toString('binary')
const bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
// 檢查 BOM
const hasBOM = bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF
console.log(`📝 UTF-8 BOM: ${hasBOM ? '✅' : '❌'}`)
// 解碼為文字
const csvContent = new TextDecoder('utf-8').decode(bytes)
const hasChinese = /[\u4e00-\u9fff]/.test(csvContent)
console.log(`🔤 中文字符: ${hasChinese ? '✅' : '❌'}`)
// 顯示內容
const lines = csvContent.split('\n')
console.log(`📊 總行數: ${lines.length}`)
console.log(`📋 標題: ${lines[0]}`)
console.log(`📝 範例: ${lines[1]?.substring(0, 60)}...`)
// 保存測試檔案
fs.writeFileSync('test-final-logic.csv', csvContent, 'utf8')
console.log(`💾 已保存測試檔案: test-final-logic.csv`)
}
}
console.log('\n🎯 解決方案總結:')
console.log('✅ 後端:使用 Uint8Array 處理 UTF-8 BOM')
console.log('✅ 後端:使用 TextEncoder 編碼中文內容')
console.log('✅ 後端:使用 Base64 編碼避免 API 路由限制')
console.log('✅ 前端:使用 atob() 解碼 Base64')
console.log('✅ 前端:使用 Uint8Array 保留原始字節')
console.log('✅ 前端:使用 Blob 創建檔案,保留 BOM')
console.log('\n📋 使用說明:')
console.log('1. 點擊「邏輯思維範本」或「創意能力範本」按鈕')
console.log('2. 下載的 CSV 檔案包含 UTF-8 BOM')
console.log('3. 在 Excel 中打開,中文字符會正確顯示')
console.log('4. 編輯後上傳,系統會覆蓋現有資料')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 最終中文匯出功能測試完成')
}
}
testFinalChineseExport()

View File

@@ -1,94 +0,0 @@
const http = require('http')
const testFinalExcelFunctionality = async () => {
console.log('🎉 最終 Excel 匯入匯出功能測試')
console.log('=' .repeat(50))
try {
// 測試創意題目匯出
console.log('\n📊 測試創意題目匯出...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success) {
console.log('✅ 創意題目匯出成功')
const csvContent = Buffer.from(creativeData.data, 'base64').toString('utf8')
const lines = csvContent.split('\n')
console.log(` 📁 檔案名: ${creativeData.filename}`)
console.log(` 📊 總行數: ${lines.length}`)
console.log(` 🔤 中文支援: ${/[\u4e00-\u9fff]/.test(csvContent) ? '✅' : '❌'}`)
console.log(` 📝 UTF-8 BOM: ${csvContent.charCodeAt(0) === 0xFEFF ? '✅' : '❌'}`)
console.log(` 📋 標題: ${lines[0]}`)
console.log(` 📝 範例: ${lines[1]?.substring(0, 50)}...`)
}
}
// 測試邏輯題目匯出
console.log('\n📊 測試邏輯題目匯出...')
const logicResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=logic', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (logicResponse.status === 200) {
const logicData = JSON.parse(logicResponse.data)
if (logicData.success) {
console.log('✅ 邏輯題目匯出成功')
const csvContent = Buffer.from(logicData.data, 'base64').toString('utf8')
const lines = csvContent.split('\n')
console.log(` 📁 檔案名: ${logicData.filename}`)
console.log(` 📊 總行數: ${lines.length}`)
console.log(` 🔤 中文支援: ${/[\u4e00-\u9fff]/.test(csvContent) ? '✅' : '❌'}`)
console.log(` 📝 UTF-8 BOM: ${csvContent.charCodeAt(0) === 0xFEFF ? '✅' : '❌'}`)
console.log(` 📋 標題: ${lines[0]}`)
console.log(` 📝 範例: ${lines[1]?.substring(0, 50)}...`)
}
}
console.log('\n🎯 功能特點總結:')
console.log('✅ 完全基於資料庫格式設計')
console.log('✅ 支援覆蓋式更新現有題目')
console.log('✅ 提供完整的匯入匯出流程')
console.log('✅ 用戶友好的操作界面')
console.log('✅ 自動化的資料同步機制')
console.log('✅ 解決了中文字符編碼問題')
console.log('✅ 添加 UTF-8 BOM 確保 Excel 正確顯示中文')
console.log('✅ 使用 Base64 編碼避免 API 路由限制')
console.log('\n📋 使用說明:')
console.log('1. 點擊「邏輯思維範本」或「創意能力範本」下載 CSV 檔案')
console.log('2. 在 Excel 中打開檔案,中文字符會正確顯示')
console.log('3. 編輯題目內容後保存')
console.log('4. 在網頁中選擇編輯後的檔案並點擊「開始匯入」')
console.log('5. 系統會清空舊資料並插入新資料')
console.log('\n🎉 Excel 匯入匯出功能完全正常!')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
}
}
testFinalExcelFunctionality()

View File

@@ -1,77 +0,0 @@
const http = require('http')
const testFixedDecoding = async () => {
console.log('🔍 測試修正後的解碼功能')
console.log('=' .repeat(30))
try {
// 獲取創意題目匯出資料
console.log('\n📊 獲取創意題目匯出資料...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success) {
console.log('✅ 創意題目資料獲取成功')
// 模擬修正後的前端解碼過程
const base64Data = creativeData.data
// 模擬 atob + TextDecoder 過程
const binaryString = Buffer.from(base64Data, 'base64').toString('binary')
const bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
// 使用 ignoreBOM: false 確保保留 BOM
const csvContent = new TextDecoder('utf-8', { ignoreBOM: false }).decode(bytes)
console.log('\n📋 修正後的解碼結果:')
console.log(`前100字符: ${csvContent.substring(0, 100)}`)
console.log(`包含中文: ${/[\u4e00-\u9fff]/.test(csvContent) ? '✅' : '❌'}`)
console.log(`BOM檢測: ${csvContent.charCodeAt(0) === 0xFEFF ? '✅' : '❌'}`)
// 顯示前幾行內容
const lines = csvContent.split('\n')
console.log('\n📋 匯出內容預覽:')
for (let i = 0; i < Math.min(3, lines.length); i++) {
if (lines[i].trim()) {
console.log(`${i + 1}行: ${lines[i]}`)
}
}
if (csvContent.charCodeAt(0) === 0xFEFF && /[\u4e00-\u9fff]/.test(csvContent)) {
console.log('\n🎉 修正成功!')
console.log('✅ UTF-8 BOM 保留完整')
console.log('✅ 中文字符顯示正常')
console.log('✅ Excel 應該能正確識別編碼')
} else {
console.log('\n⚠ 仍有問題需要進一步修正')
}
} else {
console.log('❌ 創意題目資料獲取失敗:', creativeData.message)
}
} else {
console.log('❌ 創意題目資料獲取失敗,狀態碼:', creativeResponse.status)
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後的解碼功能測試完成')
}
}
testFixedDecoding()

View File

@@ -1,156 +0,0 @@
const https = require('https')
const http = require('http')
const testFixedDimensionDisplay = async () => {
console.log('🧪 測試修正後的維度分數顯示')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
const testResultId = 'test_1759086508812_xv2pof6lk'
try {
// 1. 獲取測試結果
console.log('\n📊 1. 獲取測試結果...')
const resultResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
let testResult = null
if (resultResponse.status === 200) {
const resultData = JSON.parse(resultResponse.data)
if (resultData.success && resultData.data.length > 0) {
testResult = resultData.data[0]
console.log('測試結果:', {
id: testResult.id,
score: testResult.score,
total_questions: testResult.total_questions,
correct_answers: testResult.correct_answers
})
}
}
// 2. 獲取題目資料
console.log('\n📊 2. 獲取題目資料...')
const questionsResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/creative-questions', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
let questions = []
if (questionsResponse.status === 200) {
const questionsData = JSON.parse(questionsResponse.data)
if (questionsData.success) {
questions = questionsData.questions
console.log(`獲取到 ${questions.length} 個題目`)
}
}
// 3. 獲取詳細答案
console.log('\n📊 3. 獲取詳細答案...')
const answersResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/creative-test-answers?testResultId=${testResultId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (answersResponse.status === 200) {
const answersData = JSON.parse(answersResponse.data)
if (answersData.success) {
const answers = answersData.data
console.log(`獲取到 ${answers.length} 個答案`)
// 4. 模擬新的維度分數計算
console.log('\n📊 4. 模擬新的維度分數計算...')
const dimensionScores = {
innovation: { total: 0, count: 0 },
imagination: { total: 0, count: 0 },
flexibility: { total: 0, count: 0 },
originality: { total: 0, count: 0 }
}
answers.forEach((answer) => {
const question = questions.find(q => q.id === answer.question_id)
if (question && dimensionScores[question.category]) {
dimensionScores[question.category].total += answer.score
dimensionScores[question.category].count += 1
}
})
// 計算新的維度分數結構
const calculatedDimensionScores = {
innovation: { percentage: 0, rawScore: 0, maxScore: 0 },
imagination: { percentage: 0, rawScore: 0, maxScore: 0 },
flexibility: { percentage: 0, rawScore: 0, maxScore: 0 },
originality: { percentage: 0, rawScore: 0, maxScore: 0 }
}
Object.keys(dimensionScores).forEach(category => {
const { total, count } = dimensionScores[category]
const maxScore = count * 5
const percentage = count > 0 ? Math.round((total / maxScore) * 100) : 0
calculatedDimensionScores[category] = {
percentage: percentage,
rawScore: total,
maxScore: maxScore
}
})
console.log('\n📈 新的維度分數結構:')
Object.entries(calculatedDimensionScores).forEach(([category, data]) => {
console.log(`${category}:`)
console.log(` 百分比: ${data.percentage}%`)
console.log(` 原始分數: ${data.rawScore}`)
console.log(` 滿分: ${data.maxScore}`)
console.log(` 顯示: ${data.rawScore}/${data.maxScore}`)
})
// 5. 模擬 categoryResults 計算
console.log('\n📊 5. 模擬 categoryResults 計算...')
const dimensionNames = {
innovation: '創新能力',
imagination: '想像力',
flexibility: '靈活性',
originality: '原創性'
}
const categoryResults = Object.entries(calculatedDimensionScores).map(([key, data]) => ({
category: key,
name: dimensionNames[key],
score: data.percentage,
rawScore: data.rawScore,
maxRawScore: data.maxScore
}))
console.log('\n📈 categoryResults:')
categoryResults.forEach(category => {
console.log(`${category.name}:`)
console.log(` 分數: ${category.score}`)
console.log(` 顯示: ${category.rawScore}/${category.maxRawScore}`)
})
}
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後的維度分數顯示測試完成')
}
}
testFixedDimensionDisplay()

View File

@@ -1,158 +0,0 @@
const https = require('https')
const http = require('http')
const testFixedDimensionScoring = async () => {
console.log('🧪 測試修正後的維度分數計算')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
const testResultId = 'test_1759086508812_xv2pof6lk'
try {
// 1. 獲取測試結果
console.log('\n📊 1. 獲取測試結果...')
const resultResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
let testResult = null
if (resultResponse.status === 200) {
const resultData = JSON.parse(resultResponse.data)
if (resultData.success && resultData.data.length > 0) {
testResult = resultData.data[0]
console.log('測試結果:', {
id: testResult.id,
score: testResult.score,
total_questions: testResult.total_questions,
correct_answers: testResult.correct_answers
})
}
}
// 2. 獲取題目資料
console.log('\n📊 2. 獲取題目資料...')
const questionsResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/creative-questions', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
let questions = []
if (questionsResponse.status === 200) {
const questionsData = JSON.parse(questionsResponse.data)
if (questionsData.success) {
questions = questionsData.questions
console.log(`獲取到 ${questions.length} 個題目`)
}
}
// 3. 獲取詳細答案
console.log('\n📊 3. 獲取詳細答案...')
const answersResponse = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/creative-test-answers?testResultId=${testResultId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (answersResponse.status === 200) {
const answersData = JSON.parse(answersResponse.data)
if (answersData.success) {
const answers = answersData.data
console.log(`獲取到 ${answers.length} 個答案`)
// 4. 模擬結果頁面的維度分數計算
console.log('\n📊 4. 模擬結果頁面的維度分數計算...')
// 計算各維度分數(模擬資料庫計算)
const dimensionScores = {
innovation: { total: 0, count: 0 },
imagination: { total: 0, count: 0 },
flexibility: { total: 0, count: 0 },
originality: { total: 0, count: 0 }
}
answers.forEach((answer) => {
const question = questions.find(q => q.id === answer.question_id)
if (question && dimensionScores[question.category]) {
dimensionScores[question.category].total += answer.score
dimensionScores[question.category].count += 1
}
})
// 計算百分比分數
const calculatedDimensionScores = {
innovation: 0,
imagination: 0,
flexibility: 0,
originality: 0
}
Object.keys(dimensionScores).forEach(category => {
const { total, count } = dimensionScores[category]
calculatedDimensionScores[category] =
count > 0 ? Math.round((total / (count * 5)) * 100) : 0
})
console.log('\n📈 計算結果:')
console.log('創新能力:', calculatedDimensionScores.innovation + '%')
console.log('想像力:', calculatedDimensionScores.imagination + '%')
console.log('靈活性:', calculatedDimensionScores.flexibility + '%')
console.log('原創性:', calculatedDimensionScores.originality + '%')
// 5. 模擬結果頁面的 categoryResults 計算
console.log('\n📊 5. 模擬結果頁面的 categoryResults 計算...')
const dimensionNames = {
innovation: '創新能力',
imagination: '想像力',
flexibility: '靈活性',
originality: '原創性'
}
const categoryResults = Object.entries(calculatedDimensionScores).map(([key, score]) => ({
category: key,
name: dimensionNames[key],
score: score,
rawScore: 0,
maxRawScore: 0
}))
console.log('\n📈 categoryResults:')
categoryResults.forEach(category => {
console.log(`${category.name}: ${category.score}`)
})
// 6. 驗證總分一致性
console.log('\n📊 6. 驗證總分一致性...')
const totalScore = answers.reduce((sum, answer) => sum + answer.score, 0)
const maxTotalScore = answers.length * 5
const totalPercentage = Math.round((totalScore / maxTotalScore) * 100)
console.log(`資料庫總分數: ${testResult.correct_answers}`)
console.log(`計算總分數: ${totalScore}`)
console.log(`資料庫百分比: ${testResult.score}%`)
console.log(`計算百分比: ${totalPercentage}%`)
console.log(`一致性: ${testResult.correct_answers === totalScore && testResult.score === totalPercentage ? '✅ 一致' : '❌ 不一致'}`)
}
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後的維度分數計算測試完成')
}
}
testFixedDimensionScoring()

View File

@@ -1,106 +0,0 @@
const http = require('http')
const testFixedExport = async () => {
console.log('🔍 測試修復後的匯出功能')
console.log('=' .repeat(40))
try {
// 測試基本匯出
console.log('\n📊 測試修復後的匯出...')
const response = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/admin/test-results/export', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success) {
console.log('✅ 匯出成功')
// 解碼並檢查 CSV 內容
const binaryString = Buffer.from(data.data, 'base64').toString('binary')
const csvContent = Buffer.from(binaryString, 'binary').toString('utf-8')
const lines = csvContent.split('\n')
console.log(`📊 總行數: ${lines.length}`)
console.log('\n📋 檢查詳細資料欄位:')
let hasUndefined = false
let combinedCount = 0
let logicCount = 0
let creativeCount = 0
lines.forEach((line, index) => {
if (index === 0) return // 跳過標題行
const columns = line.split(',')
if (columns.length >= 8) {
const testType = columns[3].replace(/"/g, '')
const details = columns[7].replace(/"/g, '')
if (testType === '綜合能力') {
combinedCount++
console.log(` 綜合能力測試 ${combinedCount}: ${details}`)
if (details.includes('undefined')) {
hasUndefined = true
console.log(` ❌ 發現 undefined: ${details}`)
} else {
console.log(` ✅ 無 undefined`)
}
} else if (testType === '邏輯思維') {
logicCount++
console.log(` 邏輯思維測試 ${logicCount}: ${details}`)
} else if (testType === '創意能力') {
creativeCount++
console.log(` 創意能力測試 ${creativeCount}: ${details}`)
}
}
})
console.log('\n📊 統計:')
console.log(` 綜合能力測試: ${combinedCount}`)
console.log(` 邏輯思維測試: ${logicCount}`)
console.log(` 創意能力測試: ${creativeCount}`)
if (hasUndefined) {
console.log('\n❌ 仍然發現 undefined 值')
} else {
console.log('\n✅ 所有詳細資料欄位都沒有 undefined 值')
}
// 檢查特定修復
console.log('\n🔧 檢查修復項目:')
const hasUndefinedInCombined = csvContent.includes('undefined')
const hasNoDataPlaceholder = csvContent.includes('無資料')
console.log(` 包含 undefined: ${hasUndefinedInCombined ? '是' : '否'}`)
console.log(` 包含「無資料」: ${hasNoDataPlaceholder ? '是' : '否'}`)
if (!hasUndefinedInCombined && hasNoDataPlaceholder) {
console.log('✅ 修復成功undefined 已被替換為「無資料」')
} else if (hasUndefinedInCombined) {
console.log('❌ 修復失敗,仍有 undefined 值')
}
} else {
console.log('❌ 匯出失敗:', data.message)
}
} else {
console.log('❌ 匯出失敗,狀態碼:', response.status)
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修復後匯出功能測試完成')
}
}
testFixedExport()

View File

@@ -1,234 +0,0 @@
const https = require('https')
const http = require('http')
const testFixedLogin = async () => {
console.log('🔍 測試修正後的登入功能')
console.log('=' .repeat(50))
try {
// 1. 測試管理員新建用戶登入
console.log('\n📊 1. 測試管理員新建用戶登入...')
const adminCreatedUser = {
name: '管理員新建用戶',
email: 'admin.created@company.com',
password: 'password123',
department: '測試部',
role: 'user'
}
const createResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(adminCreatedUser)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/admin/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
let adminCreatedUserId = null
if (createResponse.status === 200) {
const createData = JSON.parse(createResponse.data)
if (createData.success) {
adminCreatedUserId = createData.data.id
console.log('✅ 管理員新建用戶成功')
console.log(' 用戶ID:', createData.data.id)
console.log(' 電子郵件:', createData.data.email)
} else {
console.log('❌ 管理員新建用戶失敗:', createData.error)
return
}
}
// 2. 測試管理員新建用戶登入
console.log('\n📊 2. 測試管理員新建用戶登入...')
const adminLoginData = {
email: 'admin.created@company.com',
password: 'password123'
}
const adminLoginResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(adminLoginData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (adminLoginResponse.status === 200) {
const adminLoginResult = JSON.parse(adminLoginResponse.data)
if (adminLoginResult.success) {
console.log('✅ 管理員新建用戶登入成功!')
console.log(' 用戶ID:', adminLoginResult.user.id)
console.log(' 姓名:', adminLoginResult.user.name)
console.log(' 電子郵件:', adminLoginResult.user.email)
console.log(' 角色:', adminLoginResult.user.role)
} else {
console.log('❌ 管理員新建用戶登入失敗:', adminLoginResult.error)
}
} else {
const errorData = JSON.parse(adminLoginResponse.data)
console.log('❌ 管理員新建用戶登入 API 錯誤:', errorData.error)
}
// 3. 測試註冊用戶登入(對照組)
console.log('\n📊 3. 測試註冊用戶登入(對照組)...')
const registerUser = {
name: '註冊用戶',
email: 'register.user@company.com',
password: 'password123',
department: '測試部',
role: 'user'
}
const registerResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(registerUser)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/register',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
let registerUserId = null
if (registerResponse.status === 200) {
const registerData = JSON.parse(registerResponse.data)
if (registerData.success) {
registerUserId = registerData.data.id
console.log('✅ 註冊用戶成功')
console.log(' 用戶ID:', registerData.data.id)
console.log(' 電子郵件:', registerData.data.email)
} else {
console.log('❌ 註冊用戶失敗:', registerData.error)
}
}
// 4. 測試註冊用戶登入
console.log('\n📊 4. 測試註冊用戶登入...')
const registerLoginData = {
email: 'register.user@company.com',
password: 'password123'
}
const registerLoginResponse = await new Promise((resolve, reject) => {
const postData = JSON.stringify(registerLoginData)
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.write(postData)
req.end()
})
if (registerLoginResponse.status === 200) {
const registerLoginResult = JSON.parse(registerLoginResponse.data)
if (registerLoginResult.success) {
console.log('✅ 註冊用戶登入成功!')
console.log(' 用戶ID:', registerLoginResult.user.id)
console.log(' 姓名:', registerLoginResult.user.name)
console.log(' 電子郵件:', registerLoginResult.user.email)
console.log(' 角色:', registerLoginResult.user.role)
} else {
console.log('❌ 註冊用戶登入失敗:', registerLoginResult.error)
}
} else {
const errorData = JSON.parse(registerLoginResponse.data)
console.log('❌ 註冊用戶登入 API 錯誤:', errorData.error)
}
// 5. 清理測試用戶
console.log('\n📊 5. 清理測試用戶...')
const userIdsToDelete = [adminCreatedUserId, registerUserId].filter(id => id)
for (const userId of userIdsToDelete) {
const deleteResponse = await new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 3000,
path: `/api/admin/users?id=${userId}`,
method: 'DELETE'
}
const req = http.request(options, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
req.end()
})
if (deleteResponse.status === 200) {
console.log(`✅ 已刪除測試用戶: ${userId}`)
}
}
console.log('\n📝 修正測試總結:')
console.log('✅ 密碼雙重加密問題已修正')
console.log('✅ 管理員新建用戶可以正常登入')
console.log('✅ 註冊用戶登入功能正常')
console.log('✅ 密碼雜湊邏輯統一')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後登入功能測試完成')
}
}
testFixedLogin()

View File

@@ -1,62 +0,0 @@
const https = require('https')
const http = require('http')
const testFixedTimeParsing = async () => {
console.log('🔍 測試修正後的時間解析')
console.log('=' .repeat(50))
const userId = 'user-1759073326705-m06y3wacd'
try {
// 檢查創意測試結果 API
console.log('\n📊 檢查創意測試結果 API...')
const response = await new Promise((resolve, reject) => {
const req = http.get(`http://localhost:3000/api/test-results/creative?userId=${userId}`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({ status: res.statusCode, data }))
})
req.on('error', reject)
})
if (response.status === 200) {
const data = JSON.parse(response.data)
if (data.success && data.data.length > 0) {
// 按創建時間排序,取最新的
const sortedResults = data.data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
const latestResult = sortedResults[0]
console.log('\n📋 最新創意測試結果:')
console.log(`completed_at: ${latestResult.completed_at}`)
// 測試時間解析
console.log('\n📊 測試時間解析:')
const parsedDate = new Date(latestResult.completed_at)
const isValid = !isNaN(parsedDate.getTime())
console.log(`解析結果: ${parsedDate.toISOString()}`)
console.log(`是否有效: ${isValid ? '✅' : '❌'}`)
if (isValid) {
const taiwanTime = parsedDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })
console.log(`台灣時間: ${taiwanTime}`)
}
// 檢查所有結果的時間格式
console.log('\n📊 所有結果的時間格式:')
data.data.forEach((result, index) => {
const date = new Date(result.completed_at)
const isValid = !isNaN(date.getTime())
console.log(`${index + 1}. ${result.completed_at}${isValid ? '✅' : '❌'}`)
})
}
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 修正後的時間解析測試完成')
}
}
testFixedTimeParsing()

View File

@@ -1,90 +0,0 @@
const http = require('http')
const testFrontendDecoding = async () => {
console.log('🔍 測試前端解碼功能')
console.log('=' .repeat(30))
try {
// 獲取創意題目匯出資料
console.log('\n📊 獲取創意題目匯出資料...')
const creativeResponse = await new Promise((resolve, reject) => {
const req = http.get('http://localhost:3000/api/questions/export?type=creative', (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve({
status: res.statusCode,
data: data
}))
})
req.on('error', reject)
})
if (creativeResponse.status === 200) {
const creativeData = JSON.parse(creativeResponse.data)
if (creativeData.success) {
console.log('✅ 創意題目資料獲取成功')
// 模擬前端解碼過程
const base64Data = creativeData.data
// 方法1: 直接使用 Buffer (Node.js 環境)
const buffer = Buffer.from(base64Data, 'base64')
const csvContent1 = buffer.toString('utf8')
// 方法2: 模擬前端 atob + TextDecoder
const binaryString = Buffer.from(base64Data, 'base64').toString('binary')
const bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
const csvContent2 = new TextDecoder('utf-8').decode(bytes)
console.log('\n📋 解碼結果比較:')
console.log('方法1 (Buffer):')
console.log(` 前100字符: ${csvContent1.substring(0, 100)}`)
console.log(` 包含中文: ${/[\u4e00-\u9fff]/.test(csvContent1) ? '✅' : '❌'}`)
console.log(` BOM檢測: ${csvContent1.charCodeAt(0) === 0xFEFF ? '✅' : '❌'}`)
console.log('\n方法2 (atob + TextDecoder):')
console.log(` 前100字符: ${csvContent2.substring(0, 100)}`)
console.log(` 包含中文: ${/[\u4e00-\u9fff]/.test(csvContent2) ? '✅' : '❌'}`)
console.log(` BOM檢測: ${csvContent2.charCodeAt(0) === 0xFEFF ? '✅' : '❌'}`)
// 檢查兩種方法是否一致
const isSame = csvContent1 === csvContent2
console.log(`\n兩種方法結果一致: ${isSame ? '✅' : '❌'}`)
if (isSame) {
console.log('\n🎉 前端解碼方法正確!')
console.log('✅ Base64 解碼正常')
console.log('✅ UTF-8 編碼處理正確')
console.log('✅ UTF-8 BOM 保留完整')
console.log('✅ 中文字符顯示正常')
} else {
console.log('\n⚠ 兩種解碼方法結果不同,需要檢查')
}
// 顯示前幾行內容
const lines = csvContent1.split('\n')
console.log('\n📋 匯出內容預覽:')
for (let i = 0; i < Math.min(3, lines.length); i++) {
if (lines[i].trim()) {
console.log(`${i + 1}行: ${lines[i]}`)
}
}
} else {
console.log('❌ 創意題目資料獲取失敗:', creativeData.message)
}
} else {
console.log('❌ 創意題目資料獲取失敗,狀態碼:', creativeResponse.status)
}
} catch (error) {
console.error('❌ 測試失敗:', error.message)
} finally {
console.log('\n✅ 前端解碼功能測試完成')
}
}
testFrontendDecoding()

Some files were not shown because too many files have changed in this diff Show More