diff --git a/app/admin/users/page.tsx b/app/admin/users/page.tsx index fb35f39..23576b6 100644 --- a/app/admin/users/page.tsx +++ b/app/admin/users/page.tsx @@ -446,7 +446,7 @@ function UsersManagementContent() { {user.role === "admin" ? "管理員" : "一般用戶"} - {new Date(user.created_at).toLocaleDateString("zh-TW")} + {new Date(user.createdAt).toLocaleDateString("zh-TW")} handleEditUser(user)}> diff --git a/app/api/admin/test-results/detail/route.ts b/app/api/admin/test-results/detail/route.ts index d66df47..454bff0 100644 --- a/app/api/admin/test-results/detail/route.ts +++ b/app/api/admin/test-results/detail/route.ts @@ -94,14 +94,14 @@ export async function GET(request: NextRequest) { console.log('Debug: 所有創意題目數量:', allCreativeQuestions.length) 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)] // 使用索引獲取題目 if (question) { questions.push({ ...question, type: 'creative', userAnswer: score.toString(), // 創意題的答案就是分數 - score: score as number, + score: score, isReverse: question.is_reverse }) } diff --git a/app/api/admin/test-results/export/route.ts b/app/api/admin/test-results/export/route.ts index 718f716..b8cca00 100644 --- a/app/api/admin/test-results/export/route.ts +++ b/app/api/admin/test-results/export/route.ts @@ -35,21 +35,24 @@ export async function GET(request: NextRequest) { if (result.test_type === 'logic') { const logicAnswers = await getLogicTestAnswersByTestResultId(result.id) 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 = { - correctAnswers: logicAnswer.correct_answers, - totalQuestions: logicAnswer.total_questions, - accuracy: logicAnswer.accuracy + correctAnswers, + totalQuestions, + accuracy } } } else if (result.test_type === 'creative') { const creativeAnswers = await getCreativeTestAnswersByTestResultId(result.id) 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 = { - dimensionScores: creativeAnswer.dimension_scores, - totalScore: creativeAnswer.total_score, - maxScore: creativeAnswer.max_score + dimensionScores: {}, // This would need to be calculated based on question categories + totalScore, + maxScore } } } diff --git a/app/api/admin/test-results/route.ts b/app/api/admin/test-results/route.ts index e39037d..b5d207d 100644 --- a/app/api/admin/test-results/route.ts +++ b/app/api/admin/test-results/route.ts @@ -37,21 +37,24 @@ export async function GET(request: NextRequest) { if (result.test_type === 'logic') { const logicAnswers = await getLogicTestAnswersByTestResultId(result.id) 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 = { - correctAnswers: logicAnswer.correct_answers, - totalQuestions: logicAnswer.total_questions, - accuracy: logicAnswer.accuracy + correctAnswers, + totalQuestions, + accuracy } } } else if (result.test_type === 'creative') { const creativeAnswers = await getCreativeTestAnswersByTestResultId(result.id) 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 = { - dimensionScores: creativeAnswer.dimension_scores, - totalScore: creativeAnswer.total_score, - maxScore: creativeAnswer.max_score + dimensionScores: {}, // This would need to be calculated based on question categories + totalScore, + maxScore } } } diff --git a/app/api/questions/import/route.ts b/app/api/questions/import/route.ts index ab2978a..ad77e30 100644 --- a/app/api/questions/import/route.ts +++ b/app/api/questions/import/route.ts @@ -2,13 +2,11 @@ import { NextRequest, NextResponse } from "next/server" import * as XLSX from "xlsx" import { createLogicQuestion, - updateLogicQuestion, getAllLogicQuestions, clearLogicQuestions } from "@/lib/database/models/logic_question" import { createCreativeQuestion, - updateCreativeQuestion, getAllCreativeQuestions, clearCreativeQuestions } from "@/lib/database/models/creative_question" diff --git a/app/api/test-results/logic/route.ts b/app/api/test-results/logic/route.ts index ffbfad9..2e4a697 100644 --- a/app/api/test-results/logic/route.ts +++ b/app/api/test-results/logic/route.ts @@ -110,8 +110,7 @@ export async function POST(request: NextRequest) { console.error('上傳邏輯測驗結果失敗:', error) console.error('錯誤詳情:', { message: error instanceof Error ? error.message : '未知錯誤', - stack: error instanceof Error ? error.stack : undefined, - body: body + stack: error instanceof Error ? error.stack : undefined }) return NextResponse.json( { diff --git a/app/results/creative/page.tsx b/app/results/creative/page.tsx index 25cdae0..856218d 100644 --- a/app/results/creative/page.tsx +++ b/app/results/creative/page.tsx @@ -42,7 +42,7 @@ export default function CreativeResultsPage() { 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] // 獲取題目資料來計算各維度分數 diff --git a/lib/utils/jwt.ts b/lib/utils/jwt.ts index c55f7e5..2d99e46 100644 --- a/lib/utils/jwt.ts +++ b/lib/utils/jwt.ts @@ -12,7 +12,7 @@ export interface JWTPayload { // 生成 JWT Token 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 diff --git a/package.json b/package.json index 23d89c6..39d2679 100644 --- a/package.json +++ b/package.json @@ -6,48 +6,7 @@ "build": "next build", "dev": "next dev", "lint": "next lint", - "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" + "start": "next start" }, "dependencies": { "@hookform/resolvers": "^3.10.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72480ee..a3b4c4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,12 +92,18 @@ importers: '@radix-ui/react-tooltip': 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) + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 '@vercel/analytics': 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) autoprefixer: specifier: ^10.4.20 version: 10.4.21(postcss@8.5.6) + bcryptjs: + specifier: ^3.0.2 + version: 3.0.2 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -119,15 +125,24 @@ importers: input-otp: specifier: 1.4.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: specifier: ^0.454.0 version: 0.454.0(react@18.3.1) + mysql2: + specifier: ^3.15.1 + version: 3.15.1 next: specifier: 14.2.16 version: 14.2.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.4.6 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: specifier: ^18 version: 18.3.1 @@ -155,6 +170,9 @@ importers: tailwindcss-animate: specifier: ^1.0.7 version: 1.0.7(tailwindcss@4.1.13) + uuid: + specifier: ^13.0.0 + version: 13.0.0 vaul: 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) @@ -168,6 +186,12 @@ importers: '@tailwindcss/postcss': specifier: ^4.1.9 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': specifier: ^22 version: 22.18.6 @@ -1137,6 +1161,9 @@ packages: '@tailwindcss/postcss@4.1.13': resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==} + '@types/bcryptjs@2.4.6': + resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} + '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -1164,6 +1191,12 @@ packages: '@types/d3-timer@3.0.2': 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': resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} @@ -1178,6 +1211,9 @@ packages: '@types/react@18.3.24': resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==} + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@vercel/analytics@1.3.1': resolution: {integrity: sha512-xhSlYgAuJ6Q4WQGkzYTLmXwhYl39sWjoMA3nHxfkvG+WdBT25c563a7QhwwKivEOZtPJXifYHR1m2ihoisbWyA==} peerDependencies: @@ -1204,15 +1240,26 @@ packages: peerDependencies: 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: resolution: {integrity: sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==} hasBin: true + bcryptjs@3.0.2: + resolution: {integrity: sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==} + hasBin: true + browserslist@4.26.2: resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -1300,6 +1347,10 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} 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: resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} @@ -1309,6 +1360,10 @@ packages: decimal.js-light@2.5.1: 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: resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} engines: {node: '>=8'} @@ -1319,6 +1374,9 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + electron-to-chromium@1.5.227: resolution: {integrity: sha512-ITxuoPfJu3lsNWUi2lBM2PaBPYgH3uqmxut5vmBxgYvyI4AlJ6P3Cai1O76mOrkJCBzq0IxWg/NtqOrpu/0gKA==} @@ -1350,6 +1408,14 @@ packages: resolution: {integrity: sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ==} 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: resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} engines: {node: '>=0.8'} @@ -1362,6 +1428,9 @@ packages: peerDependencies: next: '>=13.2.0' + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} @@ -1369,6 +1438,10 @@ packages: graceful-fs@4.2.11: 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: resolution: {integrity: sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==} peerDependencies: @@ -1379,6 +1452,9 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + jiti@2.6.0: resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==} hasBin: true @@ -1386,6 +1462,16 @@ packages: js-tokens@4.0.0: 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: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} @@ -1450,13 +1536,45 @@ packages: resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} 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: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 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: resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==} peerDependencies: @@ -1473,6 +1591,17 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} 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: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1502,6 +1631,15 @@ packages: sass: 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: resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} @@ -1615,9 +1753,23 @@ packages: 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 + 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: 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: resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} @@ -1631,6 +1783,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + ssf@0.11.2: resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} engines: {node: '>=0.8'} @@ -1719,6 +1875,10 @@ packages: peerDependencies: 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: resolution: {integrity: sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ==} peerDependencies: @@ -1728,6 +1888,10 @@ packages: victory-vendor@36.9.2: 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: resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} engines: {node: '>=0.8'} @@ -2674,6 +2838,8 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.13 + '@types/bcryptjs@2.4.6': {} + '@types/d3-array@3.2.2': {} '@types/d3-color@3.1.3': {} @@ -2698,6 +2864,13 @@ snapshots: '@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': dependencies: undici-types: 6.21.0 @@ -2713,6 +2886,8 @@ snapshots: '@types/prop-types': 15.7.15 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)': dependencies: server-only: 0.0.1 @@ -2736,8 +2911,12 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 + aws-ssl-profiles@1.1.2: {} + baseline-browser-mapping@2.8.9: {} + bcryptjs@3.0.2: {} + browserslist@4.26.2: dependencies: baseline-browser-mapping: 2.8.9 @@ -2746,6 +2925,8 @@ snapshots: node-releases: 2.0.21 update-browserslist-db: 1.1.3(browserslist@4.26.2) + buffer-equal-constant-time@1.0.1: {} + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -2823,12 +3004,16 @@ snapshots: d3-timer@3.0.1: {} + data-uri-to-buffer@4.0.1: {} + date-fns-jalali@4.1.0-0: {} date-fns@4.1.0: {} decimal.js-light@2.5.1: {} + denque@2.1.0: {} + detect-libc@2.1.1: {} detect-node-es@1.1.0: {} @@ -2838,6 +3023,10 @@ snapshots: '@babel/runtime': 7.28.4 csstype: 3.1.3 + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + electron-to-chromium@1.5.227: {} embla-carousel-react@8.5.1(react@18.3.1): @@ -2863,6 +3052,15 @@ snapshots: 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: {} fraction.js@4.3.7: {} @@ -2871,10 +3069,18 @@ snapshots: dependencies: 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: {} 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): dependencies: react: 18.3.1 @@ -2882,10 +3088,36 @@ snapshots: internmap@2.0.3: {} + is-property@1.0.2: {} + jiti@2.6.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: optional: true @@ -2931,12 +3163,32 @@ snapshots: lightningcss-win32-arm64-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: {} + long@5.3.2: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + lru-cache@7.18.3: {} + + lru.min@1.1.2: {} + lucide-react@0.454.0(react@18.3.1): dependencies: react: 18.3.1 @@ -2951,6 +3203,24 @@ snapshots: dependencies: 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: {} 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-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: {} normalize-range@0.1.2: {} @@ -3102,10 +3380,18 @@ snapshots: tiny-invariant: 1.3.3 victory-vendor: 36.9.2 + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 + semver@7.7.2: {} + + seq-queue@0.0.5: {} + server-only@0.0.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: {} + sqlstring@2.3.3: {} + ssf@0.11.2: dependencies: frac: 1.1.2 @@ -3179,6 +3467,8 @@ snapshots: dependencies: 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): 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) @@ -3205,6 +3495,8 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + web-streams-polyfill@3.3.3: {} + wmf@1.0.2: {} word@0.3.0: {} diff --git a/scripts/check-actual-upload-times.js b/scripts/check-actual-upload-times.js deleted file mode 100644 index b9ebeed..0000000 --- a/scripts/check-actual-upload-times.js +++ /dev/null @@ -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() diff --git a/scripts/check-all-combined-times.js b/scripts/check-all-combined-times.js deleted file mode 100644 index 8ba086e..0000000 --- a/scripts/check-all-combined-times.js +++ /dev/null @@ -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() diff --git a/scripts/check-all-test-times.js b/scripts/check-all-test-times.js deleted file mode 100644 index d1e279a..0000000 --- a/scripts/check-all-test-times.js +++ /dev/null @@ -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() diff --git a/scripts/check-combined-breakdown.js b/scripts/check-combined-breakdown.js deleted file mode 100644 index b645bb9..0000000 --- a/scripts/check-combined-breakdown.js +++ /dev/null @@ -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(); diff --git a/scripts/check-combined-table-fields.js b/scripts/check-combined-table-fields.js deleted file mode 100644 index cdad775..0000000 --- a/scripts/check-combined-table-fields.js +++ /dev/null @@ -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() diff --git a/scripts/check-combined-table-structure.js b/scripts/check-combined-table-structure.js deleted file mode 100644 index 9404a3a..0000000 --- a/scripts/check-combined-table-structure.js +++ /dev/null @@ -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() diff --git a/scripts/check-combined-test-data.js b/scripts/check-combined-test-data.js deleted file mode 100644 index d989a94..0000000 --- a/scripts/check-combined-test-data.js +++ /dev/null @@ -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() diff --git a/scripts/check-combined-test-results-table.js b/scripts/check-combined-test-results-table.js deleted file mode 100644 index 450bacd..0000000 --- a/scripts/check-combined-test-results-table.js +++ /dev/null @@ -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() \ No newline at end of file diff --git a/scripts/check-combined-test-results-table.ts b/scripts/check-combined-test-results-table.ts deleted file mode 100644 index 4534b93..0000000 --- a/scripts/check-combined-test-results-table.ts +++ /dev/null @@ -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() diff --git a/scripts/check-combined-time.js b/scripts/check-combined-time.js deleted file mode 100644 index a5b1c78..0000000 --- a/scripts/check-combined-time.js +++ /dev/null @@ -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() diff --git a/scripts/check-creative-questions-table.js b/scripts/check-creative-questions-table.js deleted file mode 100644 index 7010490..0000000 --- a/scripts/check-creative-questions-table.js +++ /dev/null @@ -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() diff --git a/scripts/check-creative-questions.js b/scripts/check-creative-questions.js deleted file mode 100644 index d3843dc..0000000 --- a/scripts/check-creative-questions.js +++ /dev/null @@ -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() diff --git a/scripts/check-creative-table-structure.js b/scripts/check-creative-table-structure.js deleted file mode 100644 index bb8e1ef..0000000 --- a/scripts/check-creative-table-structure.js +++ /dev/null @@ -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() diff --git a/scripts/check-creative-test-answers-table.js b/scripts/check-creative-test-answers-table.js deleted file mode 100644 index 6afd151..0000000 --- a/scripts/check-creative-test-answers-table.js +++ /dev/null @@ -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() diff --git a/scripts/check-creative-test-results.js b/scripts/check-creative-test-results.js deleted file mode 100644 index 6a35431..0000000 --- a/scripts/check-creative-test-results.js +++ /dev/null @@ -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() diff --git a/scripts/check-database-password.js b/scripts/check-database-password.js deleted file mode 100644 index 8cdb8a8..0000000 --- a/scripts/check-database-password.js +++ /dev/null @@ -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() diff --git a/scripts/check-database-structure.js b/scripts/check-database-structure.js deleted file mode 100644 index bf81dcf..0000000 --- a/scripts/check-database-structure.js +++ /dev/null @@ -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(); diff --git a/scripts/check-db-fields.js b/scripts/check-db-fields.js deleted file mode 100644 index 5a2b255..0000000 --- a/scripts/check-db-fields.js +++ /dev/null @@ -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() diff --git a/scripts/check-db-tables.js b/scripts/check-db-tables.js deleted file mode 100644 index 47af833..0000000 --- a/scripts/check-db-tables.js +++ /dev/null @@ -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() diff --git a/scripts/check-db-time-format.js b/scripts/check-db-time-format.js deleted file mode 100644 index 96d2c98..0000000 --- a/scripts/check-db-time-format.js +++ /dev/null @@ -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() diff --git a/scripts/check-latest-creative-time.js b/scripts/check-latest-creative-time.js deleted file mode 100644 index 4411ec0..0000000 --- a/scripts/check-latest-creative-time.js +++ /dev/null @@ -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() diff --git a/scripts/check-latest-test-results.js b/scripts/check-latest-test-results.js deleted file mode 100644 index ab748d0..0000000 --- a/scripts/check-latest-test-results.js +++ /dev/null @@ -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() diff --git a/scripts/check-logic-answers.js b/scripts/check-logic-answers.js deleted file mode 100644 index ce6b5d6..0000000 --- a/scripts/check-logic-answers.js +++ /dev/null @@ -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(); diff --git a/scripts/check-logic-questions.js b/scripts/check-logic-questions.js deleted file mode 100644 index 3f0c87e..0000000 --- a/scripts/check-logic-questions.js +++ /dev/null @@ -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() diff --git a/scripts/check-passwords.js b/scripts/check-passwords.js deleted file mode 100644 index 013aaed..0000000 --- a/scripts/check-passwords.js +++ /dev/null @@ -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() diff --git a/scripts/check-raw-test-data.js b/scripts/check-raw-test-data.js deleted file mode 100644 index 2514237..0000000 --- a/scripts/check-raw-test-data.js +++ /dev/null @@ -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() diff --git a/scripts/check-single-test-answers.js b/scripts/check-single-test-answers.js deleted file mode 100644 index 06abf79..0000000 --- a/scripts/check-single-test-answers.js +++ /dev/null @@ -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(); diff --git a/scripts/check-table-structure.js b/scripts/check-table-structure.js deleted file mode 100644 index 5e6dd6e..0000000 --- a/scripts/check-table-structure.js +++ /dev/null @@ -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() diff --git a/scripts/check-test-results.js b/scripts/check-test-results.js deleted file mode 100644 index 9de0ba2..0000000 --- a/scripts/check-test-results.js +++ /dev/null @@ -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() diff --git a/scripts/check-timezone-issue.js b/scripts/check-timezone-issue.js deleted file mode 100644 index 2162662..0000000 --- a/scripts/check-timezone-issue.js +++ /dev/null @@ -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() diff --git a/scripts/check-user-auth.js b/scripts/check-user-auth.js deleted file mode 100644 index 275cf84..0000000 --- a/scripts/check-user-auth.js +++ /dev/null @@ -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() diff --git a/scripts/check-user-exists.js b/scripts/check-user-exists.js deleted file mode 100644 index bb522ce..0000000 --- a/scripts/check-user-exists.js +++ /dev/null @@ -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() diff --git a/scripts/check-user-password.js b/scripts/check-user-password.js deleted file mode 100644 index a770dec..0000000 --- a/scripts/check-user-password.js +++ /dev/null @@ -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() diff --git a/scripts/debug-dimension-scoring.js b/scripts/debug-dimension-scoring.js deleted file mode 100644 index 0b2ef4d..0000000 --- a/scripts/debug-dimension-scoring.js +++ /dev/null @@ -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() diff --git a/scripts/debug-invalid-date.js b/scripts/debug-invalid-date.js deleted file mode 100644 index dfa2cd0..0000000 --- a/scripts/debug-invalid-date.js +++ /dev/null @@ -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() diff --git a/scripts/debug-password-hash.js b/scripts/debug-password-hash.js deleted file mode 100644 index dbee465..0000000 --- a/scripts/debug-password-hash.js +++ /dev/null @@ -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() diff --git a/scripts/debug-password-verification.js b/scripts/debug-password-verification.js deleted file mode 100644 index 84ad8ee..0000000 --- a/scripts/debug-password-verification.js +++ /dev/null @@ -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() diff --git a/scripts/fix-existing-times.js b/scripts/fix-existing-times.js deleted file mode 100644 index 6eb8b9a..0000000 --- a/scripts/fix-existing-times.js +++ /dev/null @@ -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() diff --git a/scripts/fix-logic-answers-table.js b/scripts/fix-logic-answers-table.js deleted file mode 100644 index 361d204..0000000 --- a/scripts/fix-logic-answers-table.js +++ /dev/null @@ -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() diff --git a/scripts/test-admin-results.js b/scripts/test-admin-results.js deleted file mode 100644 index 4202896..0000000 --- a/scripts/test-admin-results.js +++ /dev/null @@ -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() diff --git a/scripts/test-api-direct.js b/scripts/test-api-direct.js deleted file mode 100644 index e5865c2..0000000 --- a/scripts/test-api-direct.js +++ /dev/null @@ -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() diff --git a/scripts/test-chinese-export.js b/scripts/test-chinese-export.js deleted file mode 100644 index f3bc038..0000000 --- a/scripts/test-chinese-export.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-creativity-levels.js b/scripts/test-combined-creativity-levels.js deleted file mode 100644 index f2a42c4..0000000 --- a/scripts/test-combined-creativity-levels.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-db-integration.js b/scripts/test-combined-db-integration.js deleted file mode 100644 index 2ba9f5c..0000000 --- a/scripts/test-combined-db-integration.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-integration.js b/scripts/test-combined-integration.js deleted file mode 100644 index 5befaf7..0000000 --- a/scripts/test-combined-integration.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-logic-answers.js b/scripts/test-combined-logic-answers.js deleted file mode 100644 index 6c5429d..0000000 --- a/scripts/test-combined-logic-answers.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-logic-instructions.js b/scripts/test-combined-logic-instructions.js deleted file mode 100644 index 8ffbf5b..0000000 --- a/scripts/test-combined-logic-instructions.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-logic-levels.js b/scripts/test-combined-logic-levels.js deleted file mode 100644 index c62279e..0000000 --- a/scripts/test-combined-logic-levels.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-mobile-buttons.js b/scripts/test-combined-mobile-buttons.js deleted file mode 100644 index 27516bf..0000000 --- a/scripts/test-combined-mobile-buttons.js +++ /dev/null @@ -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('舊代碼: 返回首頁') - console.log('新代碼: 返回首頁') - 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() diff --git a/scripts/test-combined-mobile-ui.js b/scripts/test-combined-mobile-ui.js deleted file mode 100644 index 5df389d..0000000 --- a/scripts/test-combined-mobile-ui.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-score-display.js b/scripts/test-combined-score-display.js deleted file mode 100644 index ce93bca..0000000 --- a/scripts/test-combined-score-display.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-scoring-logic.js b/scripts/test-combined-scoring-logic.js deleted file mode 100644 index e30e09d..0000000 --- a/scripts/test-combined-scoring-logic.js +++ /dev/null @@ -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() diff --git a/scripts/test-combined-scoring.js b/scripts/test-combined-scoring.js deleted file mode 100644 index ad36fee..0000000 --- a/scripts/test-combined-scoring.js +++ /dev/null @@ -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() diff --git a/scripts/test-complete-excel-functionality.js b/scripts/test-complete-excel-functionality.js deleted file mode 100644 index 43b9b43..0000000 --- a/scripts/test-complete-excel-functionality.js +++ /dev/null @@ -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() diff --git a/scripts/test-complete-profile-system.js b/scripts/test-complete-profile-system.js deleted file mode 100644 index 08ccf99..0000000 --- a/scripts/test-complete-profile-system.js +++ /dev/null @@ -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() diff --git a/scripts/test-corrected-api-time.js b/scripts/test-corrected-api-time.js deleted file mode 100644 index 3335e9d..0000000 --- a/scripts/test-corrected-api-time.js +++ /dev/null @@ -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() diff --git a/scripts/test-corrected-mysql-format.js b/scripts/test-corrected-mysql-format.js deleted file mode 100644 index 302bb1b..0000000 --- a/scripts/test-corrected-mysql-format.js +++ /dev/null @@ -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() diff --git a/scripts/test-corrected-time.js b/scripts/test-corrected-time.js deleted file mode 100644 index cd8f518..0000000 --- a/scripts/test-corrected-time.js +++ /dev/null @@ -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() diff --git a/scripts/test-create-result.js b/scripts/test-create-result.js deleted file mode 100644 index 475cb7f..0000000 --- a/scripts/test-create-result.js +++ /dev/null @@ -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() diff --git a/scripts/test-creative-answers-api.js b/scripts/test-creative-answers-api.js deleted file mode 100644 index 9196509..0000000 --- a/scripts/test-creative-answers-api.js +++ /dev/null @@ -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() diff --git a/scripts/test-creative-chart.js b/scripts/test-creative-chart.js deleted file mode 100644 index 1aafa51..0000000 --- a/scripts/test-creative-chart.js +++ /dev/null @@ -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✅ 圖表功能測試完成') diff --git a/scripts/test-creative-db-upload.js b/scripts/test-creative-db-upload.js deleted file mode 100644 index 92515f2..0000000 --- a/scripts/test-creative-db-upload.js +++ /dev/null @@ -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() diff --git a/scripts/test-creative-flow.js b/scripts/test-creative-flow.js deleted file mode 100644 index bb8c597..0000000 --- a/scripts/test-creative-flow.js +++ /dev/null @@ -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() diff --git a/scripts/test-creative-pagination.js b/scripts/test-creative-pagination.js deleted file mode 100644 index ac69261..0000000 --- a/scripts/test-creative-pagination.js +++ /dev/null @@ -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() diff --git a/scripts/test-creative-responsive-design.js b/scripts/test-creative-responsive-design.js deleted file mode 100644 index c02cb27..0000000 --- a/scripts/test-creative-responsive-design.js +++ /dev/null @@ -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('- 內邊距在手機上較小,桌面版較大') diff --git a/scripts/test-creative-results-page.js b/scripts/test-creative-results-page.js deleted file mode 100644 index 097931a..0000000 --- a/scripts/test-creative-results-page.js +++ /dev/null @@ -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() \ No newline at end of file diff --git a/scripts/test-creative-score-levels.js b/scripts/test-creative-score-levels.js deleted file mode 100644 index 5d813d6..0000000 --- a/scripts/test-creative-score-levels.js +++ /dev/null @@ -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分以下: 創意萌芽者') diff --git a/scripts/test-creative-time-fix.js b/scripts/test-creative-time-fix.js deleted file mode 100644 index e2f4c7d..0000000 --- a/scripts/test-creative-time-fix.js +++ /dev/null @@ -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() diff --git a/scripts/test-db-connection.js b/scripts/test-db-connection.js deleted file mode 100644 index 55a4fec..0000000 --- a/scripts/test-db-connection.js +++ /dev/null @@ -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(); diff --git a/scripts/test-db-models.js b/scripts/test-db-models.js deleted file mode 100644 index cb9f575..0000000 --- a/scripts/test-db-models.js +++ /dev/null @@ -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() diff --git a/scripts/test-db.js b/scripts/test-db.js deleted file mode 100644 index 4052452..0000000 --- a/scripts/test-db.js +++ /dev/null @@ -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() diff --git a/scripts/test-delete-confirmation.js b/scripts/test-delete-confirmation.js deleted file mode 100644 index 39ee214..0000000 --- a/scripts/test-delete-confirmation.js +++ /dev/null @@ -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() diff --git a/scripts/test-detail-api.js b/scripts/test-detail-api.js deleted file mode 100644 index c4d32e4..0000000 --- a/scripts/test-detail-api.js +++ /dev/null @@ -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(); diff --git a/scripts/test-detailed-answers-fixed.js b/scripts/test-detailed-answers-fixed.js deleted file mode 100644 index bc48248..0000000 --- a/scripts/test-detailed-answers-fixed.js +++ /dev/null @@ -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(); diff --git a/scripts/test-detailed-answers.js b/scripts/test-detailed-answers.js deleted file mode 100644 index 6098b45..0000000 --- a/scripts/test-detailed-answers.js +++ /dev/null @@ -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(); diff --git a/scripts/test-direct-insert.js b/scripts/test-direct-insert.js deleted file mode 100644 index dc0c7c9..0000000 --- a/scripts/test-direct-insert.js +++ /dev/null @@ -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() diff --git a/scripts/test-excel-import-export.js b/scripts/test-excel-import-export.js deleted file mode 100644 index cabb1ca..0000000 --- a/scripts/test-excel-import-export.js +++ /dev/null @@ -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() diff --git a/scripts/test-export-api.js b/scripts/test-export-api.js deleted file mode 100644 index 575ce2f..0000000 --- a/scripts/test-export-api.js +++ /dev/null @@ -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() diff --git a/scripts/test-export-details.js b/scripts/test-export-details.js deleted file mode 100644 index d9706e8..0000000 --- a/scripts/test-export-details.js +++ /dev/null @@ -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() diff --git a/scripts/test-export-results.js b/scripts/test-export-results.js deleted file mode 100644 index b71813f..0000000 --- a/scripts/test-export-results.js +++ /dev/null @@ -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() diff --git a/scripts/test-export-simple.js b/scripts/test-export-simple.js deleted file mode 100644 index af4545d..0000000 --- a/scripts/test-export-simple.js +++ /dev/null @@ -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() \ No newline at end of file diff --git a/scripts/test-final-chinese-export.js b/scripts/test-final-chinese-export.js deleted file mode 100644 index 80ec42e..0000000 --- a/scripts/test-final-chinese-export.js +++ /dev/null @@ -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() diff --git a/scripts/test-final-excel-functionality.js b/scripts/test-final-excel-functionality.js deleted file mode 100644 index aab0a23..0000000 --- a/scripts/test-final-excel-functionality.js +++ /dev/null @@ -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() diff --git a/scripts/test-fixed-decoding.js b/scripts/test-fixed-decoding.js deleted file mode 100644 index bfafd2c..0000000 --- a/scripts/test-fixed-decoding.js +++ /dev/null @@ -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() diff --git a/scripts/test-fixed-dimension-display.js b/scripts/test-fixed-dimension-display.js deleted file mode 100644 index 442bd95..0000000 --- a/scripts/test-fixed-dimension-display.js +++ /dev/null @@ -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() diff --git a/scripts/test-fixed-dimension-scoring.js b/scripts/test-fixed-dimension-scoring.js deleted file mode 100644 index 02e746c..0000000 --- a/scripts/test-fixed-dimension-scoring.js +++ /dev/null @@ -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() diff --git a/scripts/test-fixed-export.js b/scripts/test-fixed-export.js deleted file mode 100644 index e9a8f57..0000000 --- a/scripts/test-fixed-export.js +++ /dev/null @@ -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() diff --git a/scripts/test-fixed-login.js b/scripts/test-fixed-login.js deleted file mode 100644 index 7feb931..0000000 --- a/scripts/test-fixed-login.js +++ /dev/null @@ -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() diff --git a/scripts/test-fixed-time-parsing.js b/scripts/test-fixed-time-parsing.js deleted file mode 100644 index 25ed495..0000000 --- a/scripts/test-fixed-time-parsing.js +++ /dev/null @@ -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() diff --git a/scripts/test-frontend-decoding.js b/scripts/test-frontend-decoding.js deleted file mode 100644 index f2973b2..0000000 --- a/scripts/test-frontend-decoding.js +++ /dev/null @@ -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() diff --git a/scripts/test-frontend-time-fix.js b/scripts/test-frontend-time-fix.js deleted file mode 100644 index 653be12..0000000 --- a/scripts/test-frontend-time-fix.js +++ /dev/null @@ -1,49 +0,0 @@ -const https = require('https') -const http = require('http') - -const testFrontendTimeFix = async () => { - console.log('🔍 測試前端時間顯示修正') - console.log('=' .repeat(50)) - - try { - // 測試時間格式轉換 - console.log('\n📊 測試前端時間轉換:') - - // 模擬資料庫中的時間格式 - const dbTime = '2025-09-29 17:34:08' - console.log(`資料庫時間: ${dbTime}`) - - // 舊的轉換方式(錯誤) - const oldWay = new Date(dbTime) - const oldTaiwanTime = oldWay.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }) - console.log(`舊方式轉換: ${oldTaiwanTime}`) - - // 新的轉換方式(正確) - const newWay = new Date(dbTime + 'Z') - const newTaiwanTime = newWay.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }) - console.log(`新方式轉換: ${newTaiwanTime}`) - - // 驗證轉換是否正確 - const expectedTime = '2025/9/29 下午5:34:08' - const isCorrect = newTaiwanTime === expectedTime - console.log(`轉換是否正確: ${isCorrect ? '✅' : '❌'}`) - - if (!isCorrect) { - console.log(`期望時間: ${expectedTime}`) - console.log(`實際時間: ${newTaiwanTime}`) - } - - console.log('\n📝 修正說明:') - console.log('1. 資料庫儲存: 2025-09-29 17:34:08 (UTC 時間)') - console.log('2. 舊方式: new Date("2025-09-29 17:34:08") → 當作本地時間') - console.log('3. 新方式: new Date("2025-09-29 17:34:08Z") → 當作 UTC 時間') - console.log('4. 前端顯示: 正確轉換為台灣時間 (UTC+8)') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 前端時間顯示修正測試完成') - } -} - -testFrontendTimeFix() diff --git a/scripts/test-import-fix.js b/scripts/test-import-fix.js deleted file mode 100644 index a0c68a0..0000000 --- a/scripts/test-import-fix.js +++ /dev/null @@ -1,102 +0,0 @@ -const http = require('http') -const fs = require('fs') - -const testImportFix = async () => { - console.log('🔍 測試修正後的匯入功能') - console.log('=' .repeat(30)) - - try { - // 創建測試 CSV 檔案 - console.log('\n📊 創建測試 CSV 檔案...') - - const testLogicCSV = `"題目ID","題目內容","選項A","選項B","選項C","選項D","選項E","正確答案","解釋" -"1","測試邏輯題目:如果 A > B 且 B > C,那麼?","A > C","A < C","A = C","無法確定","A = B","A","根據傳遞性,A > C"` - - const testCreativeCSV = `"題目ID","陳述內容","類別","反向計分" -"1","我喜歡嘗試新的解決方案","innovation","否" -"2","我習慣按照既定規則工作","flexibility","是"` - - // 保存測試檔案 - fs.writeFileSync('test-logic-import.csv', testLogicCSV, 'utf8') - fs.writeFileSync('test-creative-import.csv', testCreativeCSV, 'utf8') - - console.log('✅ 測試檔案創建成功') - console.log(' test-logic-import.csv') - console.log(' test-creative-import.csv') - - // 測試匯入 API 端點 - console.log('\n📊 測試匯入 API 端點...') - - // 模擬 FormData 請求(簡化測試) - const testData = { - type: 'logic', - test: true - } - - const postData = JSON.stringify(testData) - - const options = { - hostname: 'localhost', - port: 3000, - path: '/api/questions/import', - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(postData) - } - } - - const response = await new Promise((resolve, reject) => { - const req = http.request(options, (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ - status: res.statusCode, - data: data - })) - }) - req.on('error', reject) - req.write(postData) - req.end() - }) - - console.log(`狀態碼: ${response.status}`) - console.log(`回應: ${response.data}`) - - if (response.status === 400) { - console.log('✅ API 端點正常運作(預期缺少檔案參數)') - } else if (response.status === 500) { - console.log('❌ 仍有伺服器錯誤') - } else { - console.log('⚠️ 意外的回應狀態') - } - - console.log('\n🎯 修正說明:') - console.log('✅ 移除了 FileReader 依賴') - console.log('✅ 使用 XLSX 庫直接處理檔案') - console.log('✅ 在伺服器端定義解析函數') - console.log('✅ 支援 CSV 和 Excel 格式') - - console.log('\n📋 使用方式:') - console.log('1. 下載範本檔案(CSV 格式)') - console.log('2. 在 Excel 中編輯內容') - console.log('3. 保存為 CSV 或 Excel 格式') - console.log('4. 在網頁中選擇檔案並上傳') - console.log('5. 系統會清空舊資料並插入新資料') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - // 清理測試檔案 - try { - fs.unlinkSync('test-logic-import.csv') - fs.unlinkSync('test-creative-import.csv') - console.log('\n🧹 測試檔案已清理') - } catch (e) { - // 忽略清理錯誤 - } - console.log('\n✅ 匯入功能修正測試完成') - } -} - -testImportFix() diff --git a/scripts/test-logic-api.js b/scripts/test-logic-api.js deleted file mode 100644 index da1906f..0000000 --- a/scripts/test-logic-api.js +++ /dev/null @@ -1,66 +0,0 @@ -const testLogicAPI = async () => { - console.log('🧪 測試邏輯測驗 API') - console.log('=' .repeat(50)) - - // 模擬測試數據 - const testData = { - userId: 'test_user_123', - answers: ['A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E'], // 10個答案 - completedAt: new Date().toISOString() - } - - console.log('\n📝 測試數據:') - console.log('用戶ID:', testData.userId) - console.log('答案數量:', testData.answers.length) - console.log('完成時間:', testData.completedAt) - - try { - console.log('\n🔄 發送 POST 請求到 /api/test-results/logic...') - - const response = await fetch('http://localhost:3000/api/test-results/logic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(testData) - }) - - console.log('📊 響應狀態:', response.status) - console.log('📊 響應狀態文字:', response.statusText) - - const result = await response.json() - console.log('📊 響應內容:', JSON.stringify(result, null, 2)) - - if (result.success) { - console.log('\n✅ API 測試成功!') - console.log('測試結果ID:', result.data.testResult.id) - console.log('答案記錄數量:', result.data.answerCount) - } else { - console.log('\n❌ API 測試失敗!') - console.log('錯誤訊息:', result.error) - } - - } catch (error) { - console.log('\n❌ 請求失敗:') - console.log('錯誤類型:', error.name) - console.log('錯誤訊息:', error.message) - - if (error.code === 'ECONNREFUSED') { - console.log('\n💡 建議:') - console.log('1. 確保開發伺服器正在運行 (npm run dev)') - console.log('2. 檢查端口 3000 是否可用') - console.log('3. 檢查防火牆設定') - } - } - - console.log('\n🔍 檢查要點:') - console.log('1. 開發伺服器是否運行') - console.log('2. API 路由是否正確') - console.log('3. 資料庫連接是否正常') - console.log('4. 用戶認證是否有效') - console.log('5. 資料庫表是否存在') - - console.log('\n✅ 邏輯測驗 API 測試完成') -} - -testLogicAPI() diff --git a/scripts/test-logic-db-upload.js b/scripts/test-logic-db-upload.js deleted file mode 100644 index 7754cf4..0000000 --- a/scripts/test-logic-db-upload.js +++ /dev/null @@ -1,100 +0,0 @@ -const testLogicDbUpload = () => { - console.log('🧠 邏輯測驗資料庫上傳功能測試') - console.log('=' .repeat(50)) - - console.log('\n📊 資料庫表結構分析:') - console.log('test_results 表:') - console.log('- id: varchar(50) PRIMARY KEY') - console.log('- user_id: varchar(50) NOT NULL') - console.log('- test_type: enum("logic","creative","combined") NOT NULL') - console.log('- score: int NOT NULL') - console.log('- total_questions: int NOT NULL') - console.log('- correct_answers: int NOT NULL') - console.log('- completed_at: timestamp NOT NULL') - console.log('- created_at: timestamp DEFAULT CURRENT_TIMESTAMP') - - console.log('\nlogic_test_answers 表:') - console.log('- id: varchar(50) PRIMARY KEY') - console.log('- test_result_id: varchar(50) NOT NULL (FK to test_results)') - console.log('- question_id: int NOT NULL (FK to logic_questions)') - console.log('- user_answer: enum("A","B","C","D","E") NOT NULL') - console.log('- is_correct: tinyint(1) NOT NULL') - console.log('- created_at: timestamp DEFAULT CURRENT_TIMESTAMP') - - console.log('\n🔧 已實現的功能:') - console.log('1. ✅ 資料庫模型檔案:') - console.log(' - lib/database/models/test_result.ts') - console.log(' - lib/database/models/logic_test_answer.ts') - console.log(' - 包含 CRUD 操作和關聯查詢') - - console.log('\n2. ✅ API 路由:') - console.log(' - app/api/test-results/logic/route.ts') - console.log(' - POST: 上傳邏輯測驗結果') - console.log(' - GET: 獲取用戶邏輯測驗結果') - - console.log('\n3. ✅ 前端整合:') - console.log(' - 修改 app/tests/logic/page.tsx') - console.log(' - 添加用戶認證檢查') - console.log(' - 添加資料庫上傳功能') - console.log(' - 保持 localStorage 向後兼容') - - console.log('\n📝 上傳流程:') - console.log('1. 用戶完成邏輯測驗') - console.log('2. 計算分數和正確答案數') - console.log('3. 儲存到 localStorage (向後兼容)') - console.log('4. 上傳到資料庫:') - console.log(' - 建立 test_results 記錄') - console.log(' - 建立 logic_test_answers 記錄') - console.log('5. 跳轉到結果頁面') - - console.log('\n🎯 資料庫上傳內容:') - console.log('test_results 記錄:') - console.log('- user_id: 用戶ID') - console.log('- test_type: "logic"') - console.log('- score: 分數 (0-100)') - console.log('- total_questions: 總題數') - console.log('- correct_answers: 答對題數') - console.log('- completed_at: 完成時間') - - console.log('\nlogic_test_answers 記錄:') - console.log('- test_result_id: 測試結果ID') - console.log('- question_id: 題目ID') - console.log('- user_answer: 用戶答案 (A-E)') - console.log('- is_correct: 是否正確 (0/1)') - - console.log('\n🔍 錯誤處理:') - console.log('- 用戶未登入: 顯示提示並停止') - console.log('- 上傳失敗: 記錄錯誤但繼續顯示結果') - console.log('- 網路錯誤: 顯示錯誤訊息') - console.log('- 資料庫錯誤: 記錄到控制台') - - console.log('\n📱 用戶體驗:') - console.log('- 提交按鈕顯示載入狀態') - console.log('- 防止重複提交') - console.log('- 保持原有功能不變') - console.log('- 向後兼容 localStorage') - - console.log('\n🧪 測試要點:') - console.log('1. 用戶登入狀態檢查') - console.log('2. 測驗結果計算正確性') - console.log('3. 資料庫記錄建立') - console.log('4. 答案記錄關聯') - console.log('5. 錯誤處理機制') - console.log('6. 向後兼容性') - - console.log('\n✅ 預期結果:') - console.log('- 用戶完成測驗後,結果自動上傳到資料庫') - console.log('- 管理員可以在後台查看所有測試結果') - console.log('- 支援詳細的答案分析') - console.log('- 保持現有功能正常運作') - - console.log('\n🚀 下一步:') - console.log('1. 測試實際的資料庫上傳功能') - console.log('2. 驗證資料完整性和正確性') - console.log('3. 檢查管理員後台顯示') - console.log('4. 考慮添加創意測驗和綜合測驗上傳') - - console.log('\n✅ 邏輯測驗資料庫上傳功能測試完成') -} - -testLogicDbUpload() diff --git a/scripts/test-logic-instructions.js b/scripts/test-logic-instructions.js deleted file mode 100644 index 03f3631..0000000 --- a/scripts/test-logic-instructions.js +++ /dev/null @@ -1,66 +0,0 @@ -const testLogicInstructions = () => { - console.log('📝 邏輯測驗註記文字添加測試') - console.log('=' .repeat(50)) - - console.log('\n🎯 添加內容:') - console.log('位置: 邏輯測驗題目卡片下方') - console.log('文字: "請仔細閱讀題目,選擇最正確的答案,每題均為單選。"') - console.log('樣式: 帶有圖示和邊框的說明區塊') - - console.log('\n🎨 UI設計特色:') - console.log('容器樣式:') - console.log('- 背景: bg-muted/30 (淺灰色背景)') - console.log('- 圓角: rounded-lg (圓角邊框)') - console.log('- 左邊框: border-l-4 border-primary (藍色左邊框)') - console.log('- 內邊距: p-4 (16px內邊距)') - console.log('- 上邊距: mt-6 (24px上邊距)') - - console.log('\n文字樣式:') - console.log('- 大小: text-sm (14px)') - console.log('- 顏色: text-muted-foreground (次要文字顏色)') - console.log('- 行高: leading-relaxed (放鬆行高)') - console.log('- 圖示: 📝 答題說明:') - console.log('- 重點文字: font-medium text-primary (粗體藍色)') - - console.log('\n📊 視覺層次:') - console.log('1. 題目內容 (主要)') - console.log('2. 選項列表 (主要)') - 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('\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✅ 邏輯測驗註記文字添加測試完成') -} - -testLogicInstructions() diff --git a/scripts/test-logic-pagination.js b/scripts/test-logic-pagination.js deleted file mode 100644 index 534a44c..0000000 --- a/scripts/test-logic-pagination.js +++ /dev/null @@ -1,88 +0,0 @@ -const http = require('http') - -const testLogicPagination = async () => { - console.log('🔍 測試邏輯題目分頁功能') - console.log('=' .repeat(30)) - - try { - // 獲取邏輯題目資料 - console.log('\n📊 獲取邏輯題目資料...') - const logicResponse = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/questions/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) { - const questions = logicData.data - console.log(`✅ 成功獲取 ${questions.length} 道邏輯題目`) - - // 模擬分頁計算 - const itemsPerPage = 10 - const totalPages = Math.ceil(questions.length / itemsPerPage) - - console.log(`\n📊 分頁計算結果:`) - console.log(`每頁顯示: ${itemsPerPage} 道題目`) - console.log(`總頁數: ${totalPages}`) - - // 顯示每頁的題目範圍 - for (let page = 1; page <= totalPages; page++) { - const startIndex = (page - 1) * itemsPerPage - const endIndex = startIndex + itemsPerPage - const currentQuestions = questions.slice(startIndex, endIndex) - - console.log(`\n第 ${page} 頁:`) - console.log(` 顯示第 ${startIndex + 1} - ${Math.min(endIndex, questions.length)} 筆`) - console.log(` 題目數量: ${currentQuestions.length}`) - console.log(` 題目ID範圍: ${currentQuestions[0]?.id} - ${currentQuestions[currentQuestions.length - 1]?.id}`) - } - - console.log('\n🎯 分頁功能特點:') - console.log('✅ 每頁顯示 10 道題目') - console.log('✅ 支援桌面版和手機版分頁') - console.log('✅ 顯示當前頁範圍和總數') - console.log('✅ 上一頁/下一頁按鈕') - console.log('✅ 頁碼按鈕(桌面版顯示全部,手機版顯示3個)') - console.log('✅ 省略號顯示(手機版)') - - console.log('\n📱 手機版分頁邏輯:') - console.log('✅ 最多顯示 3 個頁碼') - console.log('✅ 當前頁居中顯示') - console.log('✅ 首頁和末頁按需顯示') - console.log('✅ 省略號表示跳過的頁碼') - - console.log('\n💻 桌面版分頁邏輯:') - console.log('✅ 顯示所有頁碼') - console.log('✅ 當前頁高亮顯示') - console.log('✅ 上一頁/下一頁按鈕') - - if (questions.length > itemsPerPage) { - console.log('\n🎉 分頁功能已啟用!') - console.log(`目前有 ${questions.length} 道題目,分為 ${totalPages} 頁顯示`) - } else { - console.log('\n📝 題目數量少於一頁,分頁功能未顯示') - } - - } else { - console.log('❌ 獲取邏輯題目失敗:', logicData.message) - } - } else { - console.log('❌ 獲取邏輯題目失敗,狀態碼:', logicResponse.status) - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 邏輯題目分頁功能測試完成') - } -} - -testLogicPagination() diff --git a/scripts/test-logic-simple-instructions.js b/scripts/test-logic-simple-instructions.js deleted file mode 100644 index 963d9c2..0000000 --- a/scripts/test-logic-simple-instructions.js +++ /dev/null @@ -1,72 +0,0 @@ -const testLogicSimpleInstructions = () => { - console.log('📝 邏輯測驗簡潔註記文字測試') - console.log('=' .repeat(50)) - - console.log('\n🎯 修正後的設計:') - console.log('位置: 標題下方,CardHeader內') - console.log('文字: "請仔細閱讀題目,選擇最正確的答案,每題均為單選。"') - console.log('樣式: 簡潔無邊框,無emoji符號') - - console.log('\n🎨 UI設計特色:') - console.log('文字樣式:') - console.log('- 大小: text-sm (14px)') - console.log('- 顏色: text-muted-foreground (次要文字顏色)') - console.log('- 上邊距: mt-2 (8px上邊距)') - console.log('- 無邊框、無背景、無emoji') - - console.log('\n📊 視覺層次:') - console.log('1. 題目標題 (主要,大號粗體)') - console.log('2. 答題說明 (次要,小號灰色)') - 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('- 簡潔風格,符合現代UI趨勢') - - console.log('\n🔍 與圖二風格對比:') - console.log('圖二特色:') - console.log('- 標題: 大號粗體黑色文字') - console.log('- 說明: 小號灰色文字') - console.log('- 無邊框、無背景、無emoji') - console.log('- 簡潔乾淨的設計') - - console.log('\n我們的設計:') - console.log('- 標題: text-xl text-balance (大號粗體)') - console.log('- 說明: text-sm text-muted-foreground (小號灰色)') - console.log('- 無邊框、無背景、無emoji') - console.log('- 簡潔乾淨的設計') - - console.log('\n✅ 符合要求:') - console.log('- 位置: 標題下方 ✓') - console.log('- 風格: 簡潔無邊框 ✓') - console.log('- 無emoji符號 ✓') - console.log('- 符合圖二設計風格 ✓') - - console.log('\n🔍 測試要點:') - console.log('1. 註記文字是否在標題下方') - console.log('2. 樣式是否簡潔無邊框') - console.log('3. 無emoji符號') - console.log('4. 文字顏色和大小是否合適') - console.log('5. 整體設計是否協調') - - console.log('\n✅ 邏輯測驗簡潔註記文字測試完成') -} - -testLogicSimpleInstructions() diff --git a/scripts/test-login-with-debug.js b/scripts/test-login-with-debug.js deleted file mode 100644 index 23a4e78..0000000 --- a/scripts/test-login-with-debug.js +++ /dev/null @@ -1,143 +0,0 @@ -const https = require('https') -const http = require('http') - -const testLoginWithDebug = async () => { - console.log('🔍 測試登入並查看調試資訊') - console.log('=' .repeat(50)) - - try { - // 1. 創建一個測試用戶 - console.log('\n📊 1. 創建測試用戶...') - const testUser = { - name: '調試登入用戶', - email: 'debug.login@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.email) - } else { - console.log('❌ 創建測試用戶失敗:', createData.error) - return - } - } - - // 2. 等待一下讓資料庫更新 - console.log('\n⏳ 等待資料庫更新...') - await new Promise(resolve => setTimeout(resolve, 1000)) - - // 3. 嘗試登入 - console.log('\n📊 2. 嘗試登入(查看調試資訊)...') - const loginData = { - email: 'debug.login@company.com', - password: 'password123' - } - - console.log(' 登入資料:', loginData) - - 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('✅ 登入成功!') - console.log(' 用戶資料:', loginResult.user) - } else { - console.log('❌ 登入失敗:', loginResult.error) - } - } else { - const errorData = JSON.parse(loginResponse.data) - console.log('❌ 登入 API 錯誤:', errorData.error) - } - - // 4. 清理測試用戶 - console.log('\n📊 3. 清理測試用戶...') - 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✅ 登入調試測試完成') - } -} - -testLoginWithDebug() diff --git a/scripts/test-login.js b/scripts/test-login.js deleted file mode 100644 index 7b58433..0000000 --- a/scripts/test-login.js +++ /dev/null @@ -1,43 +0,0 @@ -const fetch = require('node-fetch') - -async function testLogin() { - console.log('🔄 正在測試登入功能...') - - const testUsers = [ - { email: 'admin@company.com', password: 'admin123' }, - { email: 'user@company.com', password: 'user123' }, - { email: 'manager@company.com', password: 'manager123' }, - { email: 'test@company.com', password: 'test123' } - ] - - for (const user of testUsers) { - try { - console.log(`\n測試用戶: ${user.email}`) - - const response = await fetch('http://localhost:3000/api/auth/login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(user), - }) - - const data = await response.json() - - if (data.success) { - console.log(`✅ 登入成功: ${data.user.name}`) - console.log(` Role: ${data.user.role}`) - console.log(` Token: ${data.accessToken ? '已生成' : '未生成'}`) - } else { - console.log(`❌ 登入失敗: ${data.error}`) - } - } catch (error) { - console.log(`❌ 請求失敗: ${error.message}`) - } - } -} - -// 如果直接執行此檔案,則執行測試 -if (require.main === module) { - testLogin().catch(console.error) -} diff --git a/scripts/test-mobile-pagination.js b/scripts/test-mobile-pagination.js deleted file mode 100644 index 89bd7d4..0000000 --- a/scripts/test-mobile-pagination.js +++ /dev/null @@ -1,128 +0,0 @@ -const https = require('https') -const http = require('http') - -const testMobilePagination = async () => { - console.log('🔍 測試手機版分頁響應式設計') - console.log('=' .repeat(50)) - - try { - // 1. 測試不同頁數的分頁顯示 - console.log('\n📊 1. 測試分頁顯示邏輯...') - - const testPages = [1, 2, 3, 4, 5] - - for (const page of testPages) { - console.log(`\n 測試第 ${page} 頁:`) - - const response = await new Promise((resolve, reject) => { - const req = http.get(`http://localhost:3000/api/admin/users?page=${page}&limit=5`, (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) { - const totalPages = data.data.totalPages - const currentPage = data.data.currentPage - - console.log(` 總頁數: ${totalPages}`) - console.log(` 當前頁: ${currentPage}`) - - // 模擬手機版分頁邏輯 - const maxVisiblePages = 3 - const startPage = Math.max(1, currentPage - 1) - const endPage = Math.min(totalPages, startPage + maxVisiblePages - 1) - - console.log(` 手機版顯示頁碼範圍: ${startPage} - ${endPage}`) - - // 顯示頁碼陣列 - const pages = [] - if (startPage > 1) { - pages.push('1') - if (startPage > 2) pages.push('...') - } - - for (let i = startPage; i <= endPage; i++) { - pages.push(i.toString()) - } - - if (endPage < totalPages) { - if (endPage < totalPages - 1) pages.push('...') - pages.push(totalPages.toString()) - } - - console.log(` 手機版頁碼: [${pages.join(', ')}]`) - } - } - } - - // 2. 測試響應式設計特點 - console.log('\n📊 2. 響應式設計特點:') - console.log('✅ 桌面版 (sm:flex): 顯示完整頁碼') - console.log('✅ 手機版 (sm:hidden): 智能省略頁碼') - console.log('✅ 最多顯示 3 個頁碼按鈕') - console.log('✅ 自動顯示第一頁和最後一頁') - console.log('✅ 使用省略號 (...) 表示跳過的頁碼') - console.log('✅ 上一頁/下一頁按鈕自適應寬度') - - // 3. 測試不同總頁數的情況 - console.log('\n📊 3. 測試不同總頁數情況:') - - const testScenarios = [ - { totalPages: 2, currentPage: 1, description: '2頁,第1頁' }, - { totalPages: 3, currentPage: 2, description: '3頁,第2頁' }, - { totalPages: 5, currentPage: 3, description: '5頁,第3頁' }, - { totalPages: 10, currentPage: 5, description: '10頁,第5頁' }, - { totalPages: 20, currentPage: 10, description: '20頁,第10頁' } - ] - - testScenarios.forEach(scenario => { - const { totalPages, currentPage, description } = scenario - const maxVisiblePages = 3 - const startPage = Math.max(1, currentPage - 1) - const endPage = Math.min(totalPages, startPage + maxVisiblePages - 1) - - const pages = [] - if (startPage > 1) { - pages.push('1') - if (startPage > 2) pages.push('...') - } - - for (let i = startPage; i <= endPage; i++) { - pages.push(i.toString()) - } - - if (endPage < totalPages) { - if (endPage < totalPages - 1) pages.push('...') - pages.push(totalPages.toString()) - } - - console.log(` ${description}: [${pages.join(', ')}]`) - }) - - 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('✅ 間距優化:適當的間距避免誤觸') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 手機版分頁響應式設計測試完成') - } -} - -testMobilePagination() diff --git a/scripts/test-multi-type-results.js b/scripts/test-multi-type-results.js deleted file mode 100644 index 5c43be8..0000000 --- a/scripts/test-multi-type-results.js +++ /dev/null @@ -1,73 +0,0 @@ -const https = require('https') -const http = require('http') - -const testMultiTypeResults = async () => { - console.log('🧪 測試多種類型測試結果的計算邏輯') - console.log('=' .repeat(50)) - - // 測試用戶 user-1759073650899-9c5yx0gjn (目前只有邏輯題) - const userId = 'user-1759073650899-9c5yx0gjn' - const url = `http://localhost:3000/api/user/test-results?userId=${userId}` - - try { - console.log(`\n📊 測試用戶ID: ${userId}`) - console.log(`🔗 API URL: ${url}`) - - const response = await new Promise((resolve, reject) => { - const req = http.get(url, (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - console.log('📊 響應狀態:', response.status) - - if (response.status === 200) { - const result = JSON.parse(response.data) - console.log('\n✅ API 測試成功!') - - console.log(`\n📈 統計數據:`) - console.log(`- 總測試次數: ${result.data.stats.totalTests}`) - console.log(`- 平均分數: ${result.data.stats.averageScore}`) - console.log(`- 最高分數: ${result.data.stats.bestScore}`) - console.log(`- 最近測試: ${result.data.stats.lastTestDate}`) - console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`) - console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`) - console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`) - - console.log(`\n📋 測試結果 (${result.data.results.length} 個):`) - result.data.results.forEach((testResult, index) => { - console.log(`${index + 1}. ${testResult.type} - 分數: ${testResult.score}, 測驗次數: ${testResult.testCount || 1}`) - console.log(` 完成時間: ${testResult.completedAt}`) - }) - - // 驗證計算邏輯 - console.log(`\n🧮 驗證計算邏輯:`) - console.log(`目前只有邏輯題有最新結果: 70分`) - console.log(`- 完成測試: 1次 (只有邏輯題有最新結果)`) - console.log(`- 平均分數: 70分 (70/1)`) - console.log(`- 最高分數: 70分 (70)`) - - console.log(`\n💡 假設有多種類型測試:`) - console.log(`- 邏輯題最新: 70分`) - console.log(`- 創意題最新: 80分`) - console.log(`- 綜合題最新: 60分`) - console.log(`- 完成測試: 3次 (3種類型都有最新結果)`) - console.log(`- 平均分數: 70分 ((70+80+60)/3)`) - console.log(`- 最高分數: 80分 (創意題)`) - } else { - console.log('❌ API 響應失敗,狀態碼:', response.status) - } - - } catch (error) { - console.error('\n❌ 請求失敗:') - console.error('錯誤類型:', error.name) - console.error('錯誤訊息:', error.message) - } finally { - console.log('\n✅ 多種類型測試結果計算邏輯測試完成') - } -} - -testMultiTypeResults() diff --git a/scripts/test-mysql-time-format.js b/scripts/test-mysql-time-format.js deleted file mode 100644 index c0dc5ed..0000000 --- a/scripts/test-mysql-time-format.js +++ /dev/null @@ -1,42 +0,0 @@ -const https = require('https') -const http = require('http') - -const testMysqlTimeFormat = async () => { - console.log('🔍 測試 MySQL 時間格式修正') - console.log('=' .repeat(50)) - - try { - // 測試時間格式轉換 - console.log('\n📊 測試時間格式轉換:') - const now = new Date() - const isoTime = now.toISOString() - const mysqlTime = now.toISOString().replace('Z', '').replace('T', ' ') - - console.log(`ISO 8601 格式: ${isoTime}`) - console.log(`MySQL 格式: ${mysqlTime}`) - - // 測試轉換後的時間解析 - const parsedTime = new Date(mysqlTime) - 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 轉換為 MySQL 格式 (2025-09-29 09:30:00.000)') - console.log('3. 資料庫正確儲存時間') - console.log('4. 前端讀取時正確轉換為台灣時間') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ MySQL 時間格式修正測試完成') - } -} - -testMysqlTimeFormat() diff --git a/scripts/test-new-creative-upload.js b/scripts/test-new-creative-upload.js deleted file mode 100644 index 71b4fc8..0000000 --- a/scripts/test-new-creative-upload.js +++ /dev/null @@ -1,58 +0,0 @@ -const https = require('https') -const http = require('http') - -const testNewCreativeUpload = async () => { - console.log('🔍 測試新的創意測驗上傳時間格式') - console.log('=' .repeat(50)) - - const userId = 'user-1759073326705-m06y3wacd' - - try { - // 模擬新的創意測驗上傳 - console.log('\n📊 模擬新的創意測驗上傳...') - - // 生成測試答案 - const testAnswers = [] - for (let i = 1; i <= 18; i++) { - testAnswers.push({ - questionId: i, - answer: Math.floor(Math.random() * 5) + 1 // 1-5 隨機答案 - }) - } - - const uploadData = { - userId: userId, - answers: testAnswers, - completedAt: new Date().toISOString() // 使用修正後的格式 - } - - console.log('上傳數據:', { - userId: uploadData.userId, - answersCount: uploadData.answers.length, - completedAt: uploadData.completedAt - }) - - // 測試時間轉換 - const testDate = new Date(uploadData.completedAt) - console.log(`\n時間轉換測試:`) - console.log(`UTC 時間: ${testDate.toISOString()}`) - console.log(`台灣時間: ${testDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`) - - // 檢查是否為今天 - const now = new Date() - const isToday = now.toDateString() === testDate.toDateString() - console.log(`是否為今天: ${isToday}`) - - console.log('\n📝 建議:') - console.log('1. 前端時間格式已修正,現在使用正確的 UTC 時間格式') - console.log('2. 建議重新進行一次創意測驗來驗證修正效果') - console.log('3. 新的測試結果應該會顯示正確的台灣時間') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 新創意測驗上傳時間格式測試完成') - } -} - -testNewCreativeUpload() diff --git a/scripts/test-new-time-format.js b/scripts/test-new-time-format.js deleted file mode 100644 index 844e2f9..0000000 --- a/scripts/test-new-time-format.js +++ /dev/null @@ -1,49 +0,0 @@ -const https = require('https') -const http = require('http') - -const testNewTimeFormat = 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 testDate = new Date(utcTime) - const convertedTaiwanTime = testDate.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }) - console.log(`轉換後的台灣時間: ${convertedTaiwanTime}`) - - // 驗證轉換是否正確 - const isCorrect = taiwanTime === convertedTaiwanTime - console.log(`轉換是否正確: ${isCorrect ? '✅' : '❌'}`) - - // 測試不同的時間格式 - console.log('\n📊 測試不同時間格式:') - const formats = [ - { name: 'UTC 格式 (修正後)', time: now.toISOString() }, - { name: '舊格式 (有問題)', time: now.toISOString().replace('Z', '').replace('T', ' ') } - ] - - formats.forEach(format => { - console.log(`\n${format.name}: ${format.time}`) - const date = new Date(format.time) - const taiwan = date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }) - console.log(` 轉換為台灣時間: ${taiwan}`) - }) - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 新時間格式測試完成') - } -} - -testNewTimeFormat() diff --git a/scripts/test-new-user-login.js b/scripts/test-new-user-login.js deleted file mode 100644 index 9077042..0000000 --- a/scripts/test-new-user-login.js +++ /dev/null @@ -1,178 +0,0 @@ -const https = require('https') -const http = require('http') - -const testNewUserLogin = async () => { - console.log('🔍 測試新建立用戶的登入功能') - console.log('=' .repeat(50)) - - try { - // 1. 創建一個測試用戶 - console.log('\n📊 1. 創建測試用戶...') - const testUser = { - name: '登入測試用戶', - email: 'login.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}`) - console.log(` 密碼: password123`) - } else { - console.log('❌ 創建測試用戶失敗:', createData.error) - return - } - } else { - console.log('❌ 創建用戶 API 回應錯誤:', createResponse.status) - return - } - - // 2. 嘗試用新用戶登入 - console.log('\n📊 2. 嘗試用新用戶登入...') - const loginData = { - email: 'login.test@company.com', - password: 'password123' - } - - 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('✅ 新用戶登入成功:') - console.log(` 用戶ID: ${loginResult.user.id}`) - console.log(` 姓名: ${loginResult.user.name}`) - console.log(` 電子郵件: ${loginResult.user.email}`) - console.log(` 角色: ${loginResult.user.role}`) - console.log(` 存取權杖: ${loginResult.accessToken ? '已生成' : '未生成'}`) - } else { - console.log('❌ 登入失敗:', loginResult.error) - } - } else { - const errorData = JSON.parse(loginResponse.data) - console.log('❌ 登入 API 回應錯誤:') - console.log(` 狀態碼: ${loginResponse.status}`) - console.log(` 錯誤訊息: ${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}`) - } else { - console.log('❌ 在資料庫中找不到測試用戶') - } - } - } - - // 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 = 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('✅ 用戶創建功能正常') - console.log('✅ 密碼加密儲存正常') - console.log('✅ 登入驗證功能正常') - console.log('✅ 資料庫整合正常') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 新用戶登入測試完成') - } -} - -testNewUserLogin() diff --git a/scripts/test-other-user-results.js b/scripts/test-other-user-results.js deleted file mode 100644 index 09ddb65..0000000 --- a/scripts/test-other-user-results.js +++ /dev/null @@ -1,64 +0,0 @@ -const https = require('https') -const http = require('http') - -const testOtherUserResults = async () => { - console.log('🧪 測試其他用戶的測試結果') - console.log('=' .repeat(50)) - - // 測試用戶 user-1759073650899-9c5yx0gjn (有70分和50分的測試) - const userId = 'user-1759073650899-9c5yx0gjn' - const url = `http://localhost:3000/api/user/test-results?userId=${userId}` - - try { - console.log(`\n📊 測試用戶ID: ${userId}`) - console.log(`🔗 API URL: ${url}`) - - const response = await new Promise((resolve, reject) => { - const req = http.get(url, (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - console.log('📊 響應狀態:', response.status) - - if (response.status === 200) { - const result = JSON.parse(response.data) - console.log('\n✅ API 測試成功!') - - console.log(`\n📈 統計數據:`) - console.log(`- 總測試次數: ${result.data.stats.totalTests}`) - console.log(`- 平均分數: ${result.data.stats.averageScore}`) - console.log(`- 最高分數: ${result.data.stats.bestScore}`) - console.log(`- 最近測試: ${result.data.stats.lastTestDate}`) - console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`) - console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`) - console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`) - - console.log(`\n📋 測試結果 (${result.data.results.length} 個):`) - result.data.results.forEach((testResult, index) => { - console.log(`${index + 1}. ${testResult.type} - 分數: ${testResult.score}, 測驗次數: ${testResult.testCount || 1}`) - console.log(` 完成時間: ${testResult.completedAt}`) - }) - - // 手動驗證平均分數計算 - console.log(`\n🧮 手動驗證平均分數計算:`) - console.log(`用戶 ${userId} 的測試分數: 70, 50`) - console.log(`手動計算平均: (70 + 50) / 2 = ${(70 + 50) / 2}`) - console.log(`API 返回平均: ${result.data.stats.averageScore}`) - } else { - console.log('❌ API 響應失敗,狀態碼:', response.status) - } - - } catch (error) { - console.error('\n❌ 請求失敗:') - console.error('錯誤類型:', error.name) - console.error('錯誤訊息:', error.message) - } finally { - console.log('\n✅ 其他用戶測試結果 API 測試完成') - } -} - -testOtherUserResults() diff --git a/scripts/test-pagination.js b/scripts/test-pagination.js deleted file mode 100644 index bc61b7c..0000000 --- a/scripts/test-pagination.js +++ /dev/null @@ -1,143 +0,0 @@ -const https = require('https') -const http = require('http') - -const testPagination = async () => { - console.log('🔍 測試用戶管理分頁功能') - console.log('=' .repeat(50)) - - try { - // 1. 測試第一頁 - console.log('\n📊 1. 測試第一頁 (page=1, limit=5)...') - const page1Response = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/admin/users?page=1&limit=5', (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - if (page1Response.status === 200) { - const page1Data = JSON.parse(page1Response.data) - if (page1Data.success) { - console.log('✅ 第一頁載入成功:') - console.log(` 用戶數量: ${page1Data.data.users.length}`) - console.log(` 總用戶數: ${page1Data.data.totalUsers}`) - console.log(` 總頁數: ${page1Data.data.totalPages}`) - console.log(` 當前頁: ${page1Data.data.currentPage}`) - console.log(` 每頁數量: ${page1Data.data.usersPerPage}`) - - console.log(' 用戶列表:') - page1Data.data.users.forEach((user, index) => { - console.log(` ${index + 1}. ${user.name} (${user.email})`) - }) - } else { - console.log('❌ 第一頁載入失敗:', page1Data.error) - } - } - - // 2. 測試第二頁 - console.log('\n📊 2. 測試第二頁 (page=2, limit=5)...') - const page2Response = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/admin/users?page=2&limit=5', (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - if (page2Response.status === 200) { - const page2Data = JSON.parse(page2Response.data) - if (page2Data.success) { - console.log('✅ 第二頁載入成功:') - console.log(` 用戶數量: ${page2Data.data.users.length}`) - console.log(` 總用戶數: ${page2Data.data.totalUsers}`) - console.log(` 總頁數: ${page2Data.data.totalPages}`) - console.log(` 當前頁: ${page2Data.data.currentPage}`) - - console.log(' 用戶列表:') - page2Data.data.users.forEach((user, index) => { - console.log(` ${index + 1}. ${user.name} (${user.email})`) - }) - } else { - console.log('❌ 第二頁載入失敗:', page2Data.error) - } - } - - // 3. 測試第三頁 - console.log('\n📊 3. 測試第三頁 (page=3, limit=5)...') - const page3Response = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/admin/users?page=3&limit=5', (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - if (page3Response.status === 200) { - const page3Data = JSON.parse(page3Response.data) - if (page3Data.success) { - console.log('✅ 第三頁載入成功:') - console.log(` 用戶數量: ${page3Data.data.users.length}`) - console.log(` 總用戶數: ${page3Data.data.totalUsers}`) - console.log(` 總頁數: ${page3Data.data.totalPages}`) - console.log(` 當前頁: ${page3Data.data.currentPage}`) - - console.log(' 用戶列表:') - page3Data.data.users.forEach((user, index) => { - console.log(` ${index + 1}. ${user.name} (${user.email})`) - }) - } else { - console.log('❌ 第三頁載入失敗:', page3Data.error) - } - } - - // 4. 測試預設參數 - console.log('\n📊 4. 測試預設參數 (無分頁參數)...') - const defaultResponse = 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 (defaultResponse.status === 200) { - const defaultData = JSON.parse(defaultResponse.data) - if (defaultData.success) { - console.log('✅ 預設參數載入成功:') - console.log(` 用戶數量: ${defaultData.data.users.length}`) - console.log(` 總用戶數: ${defaultData.data.totalUsers}`) - console.log(` 總頁數: ${defaultData.data.totalPages}`) - console.log(` 當前頁: ${defaultData.data.currentPage}`) - console.log(` 每頁數量: ${defaultData.data.usersPerPage}`) - } else { - console.log('❌ 預設參數載入失敗:', defaultData.error) - } - } - - console.log('\n📝 分頁功能測試總結:') - console.log('✅ API 分頁參數處理正常') - console.log('✅ 分頁數據計算正確') - console.log('✅ 總用戶數統計正確') - console.log('✅ 總頁數計算正確') - console.log('✅ 預設參數處理正常') - - console.log('\n🎨 前端分頁功能:') - console.log('✅ 分頁控制按鈕') - console.log('✅ 頁碼顯示') - console.log('✅ 上一頁/下一頁按鈕') - console.log('✅ 分頁資訊顯示') - console.log('✅ 響應式設計') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 分頁功能測試完成') - } -} - -testPagination() diff --git a/scripts/test-password-hash-direct.js b/scripts/test-password-hash-direct.js deleted file mode 100644 index cc43286..0000000 --- a/scripts/test-password-hash-direct.js +++ /dev/null @@ -1,58 +0,0 @@ -const bcrypt = require('bcryptjs') - -const testPasswordHashDirect = async () => { - console.log('🔍 直接測試密碼雜湊函數') - console.log('=' .repeat(50)) - - try { - const password = 'password123' - const SALT_ROUNDS = 12 - - console.log('\n📊 1. 測試密碼雜湊...') - console.log(' 原始密碼:', password) - console.log(' 鹽輪數:', SALT_ROUNDS) - - // 雜湊密碼 - const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS) - console.log(' 雜湊後密碼:', hashedPassword) - console.log(' 雜湊長度:', hashedPassword.length) - - // 驗證密碼 - console.log('\n📊 2. 測試密碼驗證...') - const isValid1 = await bcrypt.compare(password, hashedPassword) - console.log(' 驗證原始密碼:', isValid1 ? '✅ 成功' : '❌ 失敗') - - const isValid2 = await bcrypt.compare('wrongpassword', hashedPassword) - console.log(' 驗證錯誤密碼:', isValid2 ? '✅ 成功' : '❌ 失敗') - - const isValid3 = await bcrypt.compare('Password123', hashedPassword) - console.log(' 驗證大小寫不同密碼:', isValid3 ? '✅ 成功' : '❌ 失敗') - - // 測試多次雜湊 - console.log('\n📊 3. 測試多次雜湊...') - const hash1 = await bcrypt.hash(password, SALT_ROUNDS) - const hash2 = await bcrypt.hash(password, SALT_ROUNDS) - console.log(' 第一次雜湊:', hash1) - console.log(' 第二次雜湊:', hash2) - console.log(' 兩次雜湊相同:', hash1 === hash2 ? '是' : '否') - - // 驗證兩次雜湊 - const verify1 = await bcrypt.compare(password, hash1) - const verify2 = await bcrypt.compare(password, hash2) - console.log(' 第一次雜湊驗證:', verify1 ? '✅ 成功' : '❌ 失敗') - console.log(' 第二次雜湊驗證:', verify2 ? '✅ 成功' : '❌ 失敗') - - console.log('\n📝 密碼雜湊測試總結:') - console.log('✅ bcrypt 函數運作正常') - console.log('✅ 密碼雜湊和驗證功能正常') - console.log('✅ 每次雜湊結果不同(這是正常的)') - console.log('✅ 相同密碼的不同雜湊都可以正確驗證') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 密碼雜湊直接測試完成') - } -} - -testPasswordHashDirect() diff --git a/scripts/test-password-options.js b/scripts/test-password-options.js deleted file mode 100644 index 918b2bf..0000000 --- a/scripts/test-password-options.js +++ /dev/null @@ -1,192 +0,0 @@ -const https = require('https') -const http = require('http') - -const testPasswordOptions = async () => { - console.log('🔍 測試新增用戶密碼選項') - console.log('=' .repeat(50)) - - try { - // 1. 測試使用預設密碼創建用戶 - console.log('\n📊 1. 測試使用預設密碼創建用戶...') - const defaultPasswordUser = { - name: '預設密碼測試用戶', - email: 'default.password@company.com', - password: 'password123', // 預設密碼 - department: '測試部', - role: 'user' - } - - const createResponse1 = await new Promise((resolve, reject) => { - const postData = JSON.stringify(defaultPasswordUser) - 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 defaultPasswordUserId = null - if (createResponse1.status === 200) { - const createData = JSON.parse(createResponse1.data) - if (createData.success) { - defaultPasswordUserId = createData.data.id - console.log('✅ 使用預設密碼創建用戶成功:') - console.log(` ID: ${createData.data.id}`) - console.log(` 姓名: ${createData.data.name}`) - console.log(` 電子郵件: ${createData.data.email}`) - console.log(` 密碼: password123 (已加密儲存)`) - } else { - console.log('❌ 使用預設密碼創建用戶失敗:', createData.error) - } - } - - // 2. 測試使用自定義密碼創建用戶 - console.log('\n📊 2. 測試使用自定義密碼創建用戶...') - const customPasswordUser = { - name: '自定義密碼測試用戶', - email: 'custom.password@company.com', - password: 'MyCustomPassword2024!', // 自定義密碼 - department: '測試部', - role: 'user' - } - - const createResponse2 = await new Promise((resolve, reject) => { - const postData = JSON.stringify(customPasswordUser) - 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 customPasswordUserId = null - if (createResponse2.status === 200) { - const createData = JSON.parse(createResponse2.data) - if (createData.success) { - customPasswordUserId = createData.data.id - console.log('✅ 使用自定義密碼創建用戶成功:') - console.log(` ID: ${createData.data.id}`) - console.log(` 姓名: ${createData.data.name}`) - console.log(` 電子郵件: ${createData.data.email}`) - console.log(` 密碼: MyCustomPassword2024! (已加密儲存)`) - } else { - console.log('❌ 使用自定義密碼創建用戶失敗:', createData.error) - } - } - - // 3. 測試密碼驗證規則 - console.log('\n📊 3. 測試密碼驗證規則...') - const shortPasswordUser = { - name: '短密碼測試用戶', - email: 'short.password@company.com', - password: '123', // 太短的密碼 - department: '測試部', - role: 'user' - } - - const createResponse3 = await new Promise((resolve, reject) => { - const postData = JSON.stringify(shortPasswordUser) - 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() - }) - - if (createResponse3.status === 400) { - const errorData = JSON.parse(createResponse3.data) - console.log('✅ 密碼長度驗證正常:') - console.log(` 錯誤訊息: ${errorData.error}`) - } else { - console.log('❌ 密碼長度驗證失敗,應該拒絕短密碼') - } - - // 4. 清理測試用戶 - console.log('\n📊 4. 清理測試用戶...') - const userIdsToDelete = [defaultPasswordUserId, customPasswordUserId].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('✅ 支援預設密碼選項 (password123)') - console.log('✅ 支援自定義密碼輸入') - console.log('✅ 密碼長度驗證 (至少6個字元)') - console.log('✅ 密碼加密儲存') - console.log('✅ 用戶友好的介面設計') - - console.log('\n🎨 介面改進:') - console.log('✅ 預設密碼按鈕') - console.log('✅ 密碼提示文字') - console.log('✅ 靈活的密碼輸入方式') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 密碼選項功能測試完成') - } -} - -testPasswordOptions() diff --git a/scripts/test-password-update.js b/scripts/test-password-update.js deleted file mode 100644 index a4c46a9..0000000 --- a/scripts/test-password-update.js +++ /dev/null @@ -1,101 +0,0 @@ -const https = require('https') -const http = require('http') - -const testPasswordUpdate = async () => { - console.log('🔍 測試密碼更新功能') - console.log('=' .repeat(50)) - - const testUserId = 'user-1759073326705-m06y3wacd' - const testPassword = 'newpassword123' - - try { - // 1. 測試密碼更新 - console.log('\n📊 1. 測試密碼更新...') - const updateData = { - userId: testUserId, - currentPassword: 'password123', // 假設當前密碼 - newPassword: testPassword - } - - 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('✅ 密碼更新成功') - } else { - console.log('❌ 密碼更新失敗:', updateResult.error) - } - } else { - console.log('❌ API 請求失敗:', updateResponse.status) - } - - // 2. 測試錯誤的當前密碼 - console.log('\n📊 2. 測試錯誤的當前密碼...') - const wrongPasswordData = { - userId: testUserId, - currentPassword: 'wrongpassword', - newPassword: 'anotherpassword123' - } - - const wrongResponse = await new Promise((resolve, reject) => { - const postData = JSON.stringify(wrongPasswordData) - 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 (wrongResponse.status === 200) { - const wrongResult = JSON.parse(wrongResponse.data) - if (!wrongResult.success) { - console.log('✅ 錯誤密碼驗證成功:', wrongResult.error) - } else { - console.log('❌ 錯誤密碼驗證失敗,應該被拒絕') - } - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 密碼更新功能測試完成') - } -} - -testPasswordUpdate() diff --git a/scripts/test-password-visibility.js b/scripts/test-password-visibility.js deleted file mode 100644 index 0b96fb5..0000000 --- a/scripts/test-password-visibility.js +++ /dev/null @@ -1,118 +0,0 @@ -const https = require('https') -const http = require('http') - -const testPasswordVisibility = async () => { - console.log('🔍 測試密碼可見性切換功能') - console.log('=' .repeat(50)) - - try { - // 1. 測試使用預設密碼創建用戶 - console.log('\n📊 1. 測試密碼可見性功能...') - const testUser = { - name: '密碼可見性測試用戶', - email: 'password.visibility@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}`) - console.log(` 密碼: password123 (已加密儲存)`) - } else { - console.log('❌ 創建測試用戶失敗:', createData.error) - return - } - } - - // 2. 驗證密碼功能 - console.log('\n📊 2. 驗證密碼功能...') - console.log('✅ 密碼欄位支援以下功能:') - console.log(' - 眼睛圖標切換密碼可見性') - console.log(' - 預設密碼按鈕一鍵填入') - console.log(' - 手動輸入自定義密碼') - console.log(' - 密碼長度驗證 (至少6個字元)') - console.log(' - 密碼加密儲存') - - // 3. 清理測試用戶 - console.log('\n📊 3. 清理測試用戶...') - 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('✅ 眼睛圖標按鈕已添加') - console.log('✅ 支援密碼顯示/隱藏切換') - console.log('✅ 圖標狀態正確切換 (Eye/EyeOff)') - console.log('✅ 按鈕位置適當 (密碼欄位右側)') - console.log('✅ 保持原有功能完整性') - - console.log('\n🎨 介面改進:') - console.log('✅ 相對定位的按鈕設計') - console.log('✅ 適當的圖標大小和顏色') - console.log('✅ 無縫的用戶體驗') - console.log('✅ 響應式設計') - - console.log('\n💡 使用方式:') - console.log('1. 點擊眼睛圖標可以切換密碼可見性') - console.log('2. 顯示狀態:顯示 EyeOff 圖標') - console.log('3. 隱藏狀態:顯示 Eye 圖標') - console.log('4. 與預設密碼按鈕完美配合') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 密碼可見性功能測試完成') - } -} - -testPasswordVisibility() diff --git a/scripts/test-questions-display.js b/scripts/test-questions-display.js deleted file mode 100644 index 4eaebcc..0000000 --- a/scripts/test-questions-display.js +++ /dev/null @@ -1,98 +0,0 @@ -const https = require('https') -const http = require('http') - -const testQuestionsDisplay = async () => { - console.log('🔍 測試題目顯示修正') - 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/logic', (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) { - console.log('✅ 邏輯題目 API 成功') - console.log(` 總題目數量: ${logicData.data.length}`) - console.log(` 顯示狀態: 全部顯示 (移除 .slice(0, 10) 限制)`) - - if (logicData.data.length > 0) { - console.log(' 前 3 題預覽:') - logicData.data.slice(0, 3).forEach((question, index) => { - console.log(` ${index + 1}. ID: ${question.id}, 內容: ${question.question.substring(0, 30)}...`) - }) - } - } - } - - // 2. 測試創意題目顯示 - console.log('\n📊 2. 測試創意題目顯示...') - 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) { - console.log('✅ 創意題目 API 成功') - console.log(` 總題目數量: ${creativeData.data.length}`) - console.log(` 顯示狀態: 全部顯示 (移除 .slice(0, 10) 限制)`) - - if (creativeData.data.length > 0) { - console.log(' 前 3 題預覽:') - creativeData.data.slice(0, 3).forEach((question, index) => { - console.log(` ${index + 1}. ID: ${question.id}, 內容: ${question.statement.substring(0, 30)}...`) - }) - } - } - } - - // 3. 修正內容總結 - console.log('\n📊 3. 修正內容總結:') - console.log('✅ 移除邏輯題目 .slice(0, 10) 限制') - console.log('✅ 移除創意題目 .slice(0, 10) 限制') - console.log('✅ 現在顯示所有題目,不再限制為 10 道') - console.log('✅ 保持原有的載入狀態和錯誤處理') - - // 4. 用戶體驗改善 - console.log('\n📊 4. 用戶體驗改善:') - console.log('✅ 管理員可以看到所有題目') - console.log('✅ 題目數量統計準確') - console.log('✅ 完整的題目管理功能') - console.log('✅ 無需分頁即可查看全部內容') - - // 5. 技術細節 - console.log('\n📊 5. 技術修正細節:') - console.log(' 之前: logicQuestions.slice(0, 10).map(...)') - console.log(' 現在: logicQuestions.map(...)') - console.log('') - console.log(' 之前: creativeQuestions.slice(0, 10).map(...)') - console.log(' 現在: creativeQuestions.map(...)') - - console.log('\n📝 修正總結:') - console.log('✅ 創意題目現在顯示全部 18 道題目') - console.log('✅ 邏輯題目現在顯示全部 10 道題目') - console.log('✅ 移除了不必要的顯示限制') - console.log('✅ 保持所有原有功能正常運作') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 題目顯示修正測試完成') - } -} - -testQuestionsDisplay() diff --git a/scripts/test-questions-management.js b/scripts/test-questions-management.js deleted file mode 100644 index 1872f4f..0000000 --- a/scripts/test-questions-management.js +++ /dev/null @@ -1,105 +0,0 @@ -const https = require('https') -const http = require('http') - -const testQuestionsManagement = async () => { - console.log('🔍 測試題目管理頁面資料庫整合') - console.log('=' .repeat(50)) - - try { - // 1. 測試邏輯題目 API - console.log('\n📊 1. 測試邏輯題目 API...') - const logicResponse = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/questions/logic', (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) { - console.log('✅ 邏輯題目 API 成功') - console.log(` 題目數量: ${logicData.data.length}`) - if (logicData.data.length > 0) { - const firstQuestion = logicData.data[0] - console.log(` 第一題: ${firstQuestion.question.substring(0, 50)}...`) - console.log(` 選項數量: ${firstQuestion.option_e ? 5 : 4}`) - console.log(` 正確答案: ${firstQuestion.correct_answer}`) - } - } else { - console.log('❌ 邏輯題目 API 失敗:', logicData.message) - } - } else { - console.log('❌ 邏輯題目 API 狀態碼:', logicResponse.status) - } - - // 2. 測試創意題目 API - console.log('\n📊 2. 測試創意題目 API...') - 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) { - console.log('✅ 創意題目 API 成功') - console.log(` 題目數量: ${creativeData.data.length}`) - if (creativeData.data.length > 0) { - const firstQuestion = creativeData.data[0] - console.log(` 第一題: ${firstQuestion.statement.substring(0, 50)}...`) - console.log(` 類別: ${firstQuestion.category}`) - console.log(` 反向計分: ${firstQuestion.is_reverse ? '是' : '否'}`) - } - } else { - console.log('❌ 創意題目 API 失敗:', creativeData.message) - } - } else { - console.log('❌ 創意題目 API 狀態碼:', creativeResponse.status) - } - - // 3. 測試題目管理頁面功能 - console.log('\n📊 3. 題目管理頁面功能:') - console.log('✅ 從資料庫獲取題目而非硬編碼') - console.log('✅ 支援邏輯思維和創意能力兩種題目類型') - console.log('✅ 顯示載入狀態和錯誤處理') - console.log('✅ 響應式表格顯示題目資訊') - console.log('✅ 支援 Excel 檔案匯入功能') - - // 4. 資料庫整合特點 - console.log('\n📊 4. 資料庫整合特點:') - console.log('✅ 邏輯題目: 支援 A-E 選項,正確答案,解釋') - console.log('✅ 創意題目: 支援類別分類,反向計分標記') - console.log('✅ 即時更新: 題目數量動態顯示') - console.log('✅ 錯誤處理: 網路錯誤和資料錯誤處理') - console.log('✅ 載入狀態: 用戶友好的載入提示') - - // 5. 前端功能 - console.log('\n📊 5. 前端功能:') - console.log('✅ 分頁顯示: 每頁顯示 10 道題目') - console.log('✅ 標籤切換: 邏輯思維和創意能力切換') - console.log('✅ 統計資訊: 顯示各類型題目數量') - console.log('✅ 範本下載: 支援 CSV 範本下載') - console.log('✅ 檔案匯入: 支援 Excel 檔案匯入') - - console.log('\n📝 整合總結:') - console.log('✅ 完全移除硬編碼題目') - console.log('✅ 與資料庫完全整合') - console.log('✅ 支援即時資料更新') - console.log('✅ 提供完整的題目管理功能') - console.log('✅ 用戶體驗優化') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 題目管理頁面資料庫整合測試完成') - } -} - -testQuestionsManagement() diff --git a/scripts/test-responsive-design.js b/scripts/test-responsive-design.js deleted file mode 100644 index af56244..0000000 --- a/scripts/test-responsive-design.js +++ /dev/null @@ -1,47 +0,0 @@ -// 測試響應式設計的 CSS 類別 -const responsiveClasses = { - // 統計數據區域 - statsGrid: "grid grid-cols-3 gap-4 mb-6", - statsText: "text-xs text-muted-foreground", - - // 詳細結果區域 - questionCard: "border rounded-lg p-3 sm:p-4", - questionIcon: "w-4 h-4 sm:w-5 sm:h-5", - questionTitle: "text-sm sm:text-base", - questionContent: "text-xs sm:text-sm", - answerRow: "flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2", - badge: "text-xs w-fit", - explanation: "p-2 sm:p-3 text-xs sm:text-sm", - - // 按鈕區域 - 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(50)) - -console.log('\n📊 統計數據區域:') -console.log(`網格佈局: ${responsiveClasses.statsGrid}`) -console.log(`標籤文字: ${responsiveClasses.statsText}`) - -console.log('\n📋 詳細結果區域:') -console.log(`題目卡片: ${responsiveClasses.questionCard}`) -console.log(`圖示大小: ${responsiveClasses.questionIcon}`) -console.log(`題目標題: ${responsiveClasses.questionTitle}`) -console.log(`內容文字: ${responsiveClasses.questionContent}`) -console.log(`答案行: ${responsiveClasses.answerRow}`) -console.log(`徽章: ${responsiveClasses.badge}`) -console.log(`解析: ${responsiveClasses.explanation}`) - -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('- 內邊距在手機上較小,桌面版較大') diff --git a/scripts/test-results-responsive.js b/scripts/test-results-responsive.js deleted file mode 100644 index fb0a5c5..0000000 --- a/scripts/test-results-responsive.js +++ /dev/null @@ -1,73 +0,0 @@ -const https = require('https') -const http = require('http') - -const testResultsResponsive = async () => { - console.log('🔍 測試個人測驗結果頁面響應式設計') - console.log('=' .repeat(50)) - - try { - // 1. 測試統計卡片響應式設計 - console.log('\n📊 1. 統計卡片響應式設計:') - console.log('✅ 手機版 (grid-cols-2): 2x2 網格佈局') - console.log('✅ 桌面版 (md:grid-cols-4): 1x4 橫向佈局') - console.log('✅ 間距優化: 手機版 gap-3,桌面版 gap-6') - console.log('✅ 內邊距優化: 手機版 p-3,桌面版 p-6') - - console.log('\n🎨 2. 視覺元素響應式:') - console.log('✅ 圖標大小: 手機版 w-8 h-8,桌面版 w-12 h-12') - console.log('✅ 圖標內圖: 手機版 w-4 h-4,桌面版 w-6 h-6') - console.log('✅ 數字大小: 手機版 text-lg,桌面版 text-2xl') - console.log('✅ 標題大小: 手機版 text-xs,桌面版 text-sm') - console.log('✅ 間距調整: 手機版 mb-2,桌面版 mb-3') - - console.log('\n📱 3. 手機版佈局 (2x2):') - console.log('┌─────────┬─────────┐') - console.log('│完成測試 │平均分數 │') - console.log('│ 3 │ 45 │') - console.log('├─────────┼─────────┤') - console.log('│最高分數 │最近測試 │') - console.log('│ 78 │2025/9/29│') - console.log('└─────────┴─────────┘') - - console.log('\n💻 4. 桌面版佈局 (1x4):') - console.log('┌─────┬─────┬─────┬─────────┐') - console.log('│完成 │平均 │最高 │ 最近 │') - console.log('│測試 │分數 │分數 │ 測試 │') - console.log('│ 3 │ 45 │ 78 │2025/9/29│') - console.log('└─────┴─────┴─────┴─────────┘') - - console.log('\n📐 5. 響應式特點:') - console.log('✅ 空間效率: 手機版節省約 50% 垂直空間') - console.log('✅ 視覺平衡: 2x2 網格在手機版更易閱讀') - console.log('✅ 觸控友好: 卡片大小適合手指操作') - console.log('✅ 內容清晰: 文字大小適中,保持可讀性') - console.log('✅ 一致性: 保持桌面版的視覺風格') - - console.log('\n🎯 6. 用戶體驗改善:') - console.log('✅ 減少滾動: 統計資訊更緊湊顯示') - console.log('✅ 快速瀏覽: 四個指標一目了然') - console.log('✅ 視覺層次: 清晰的圖標和數字對比') - console.log('✅ 響應式: 適配不同螢幕尺寸') - - console.log('\n📝 7. 設計優化總結:') - console.log('✅ 佈局: 手機版 2x2,桌面版 1x4') - console.log('✅ 尺寸: 響應式圖標和文字大小') - console.log('✅ 間距: 適配不同螢幕的間距') - console.log('✅ 可讀性: 保持清晰的視覺層次') - console.log('✅ 一致性: 統一的設計語言') - - console.log('\n🔧 8. 技術實作:') - console.log('✅ Grid 佈局: grid-cols-2 md:grid-cols-4') - console.log('✅ 響應式間距: gap-3 md:gap-6') - console.log('✅ 響應式內邊距: p-3 md:p-6') - console.log('✅ 響應式圖標: w-8 h-8 md:w-12 md:h-12') - console.log('✅ 響應式文字: text-xs md:text-sm') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 個人測驗結果頁面響應式設計測試完成') - } -} - -testResultsResponsive() diff --git a/scripts/test-reverse-scoring.js b/scripts/test-reverse-scoring.js deleted file mode 100644 index 8af6140..0000000 --- a/scripts/test-reverse-scoring.js +++ /dev/null @@ -1,63 +0,0 @@ -// 測試反向題分數計算邏輯 -function testReverseScoring() { - console.log('🧮 測試反向題分數計算邏輯') - console.log('=' .repeat(50)) - - // 模擬題目數據 - const questions = [ - { id: 1, statement: "一般題目", is_reverse: false }, - { id: 2, statement: "反向題目", is_reverse: true }, - { id: 3, statement: "一般題目", is_reverse: false }, - { id: 4, statement: "反向題目", is_reverse: true } - ] - - // 模擬用戶答案 - const answers = { - 0: 5, // 一般題目,選擇 5 - 1: 5, // 反向題目,選擇 5 - 2: 1, // 一般題目,選擇 1 - 3: 1 // 反向題目,選擇 1 - } - - console.log('\n📋 題目和答案:') - questions.forEach((question, index) => { - const answer = answers[index] - const reverseText = question.is_reverse ? ' (反向題)' : '' - console.log(`${index + 1}. ${question.statement}${reverseText} - 用戶選擇: ${answer}`) - }) - - console.log('\n🧮 分數計算:') - let totalScore = 0 - - questions.forEach((question, index) => { - const answer = answers[index] || 1 - let score - - if (question.is_reverse) { - // 反向題:選擇 5 得 1 分,選擇 1 得 5 分 - score = 6 - answer - } else { - // 一般題:選擇多少得多少分 - score = answer - } - - totalScore += score - - console.log(`第${index + 1}題: ${question.is_reverse ? '反向' : '一般'} - 選擇${answer} → 得分${score}`) - }) - - const maxScore = questions.length * 5 - const percentage = Math.round((totalScore / maxScore) * 100) - - console.log('\n📊 結果:') - console.log(`總分: ${totalScore} / ${maxScore}`) - console.log(`百分比: ${percentage}%`) - - console.log('\n✅ 反向題分數計算邏輯測試完成') - console.log('\n📝 說明:') - console.log('- 一般題目:選擇 1-5 得 1-5 分') - console.log('- 反向題目:選擇 1-5 得 5-1 分(分數相反)') - console.log('- 這樣設計是為了確保高分代表高創意能力') -} - -testReverseScoring() diff --git a/scripts/test-score-levels.js b/scripts/test-score-levels.js deleted file mode 100644 index a6a730a..0000000 --- a/scripts/test-score-levels.js +++ /dev/null @@ -1,49 +0,0 @@ -// 測試新的評分系統 -const testScores = [0, 15, 25, 40, 55, 65, 75, 85, 95, 100] - -function getScoreLevel(score) { - if (score === 100) return { - level: "邏輯巔峰者", - color: "bg-purple-600", - description: "近乎完美的邏輯典範!你像一台「推理引擎」,嚴謹又高效,幾乎不受陷阱干擾。", - suggestion: "多和他人分享你的思考路徑,能幫助團隊整體邏輯力提升。" - } - if (score >= 80) return { - level: "邏輯大師", - color: "bg-green-500", - description: "你的思維如同精密儀器,能快速抓住題目關鍵,並做出有效推理。常常是團隊中「冷靜的分析者」。", - suggestion: "挑戰更高層次的難題,讓你的邏輯力更加精進。" - } - if (score >= 60) return { - level: "邏輯高手", - color: "bg-blue-500", - description: "邏輯清晰穩定,大部分情境都能正確判斷。偶爾會因粗心錯過陷阱。", - suggestion: "在思維縝密之餘,更加留心細節,就能把錯誤率降到最低。" - } - if (score >= 30) 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 = getScoreLevel(score) - console.log(`\n📊 分數: ${score}`) - console.log(`🏆 等級: ${level.level}`) - console.log(`📝 描述: ${level.description}`) - console.log(`💡 建議: ${level.suggestion}`) - console.log('-'.repeat(60)) -}) - -console.log('\n✅ 評分系統測試完成') diff --git a/scripts/test-simple-export.js b/scripts/test-simple-export.js deleted file mode 100644 index 2a5d85a..0000000 --- a/scripts/test-simple-export.js +++ /dev/null @@ -1,65 +0,0 @@ -const http = require('http') - -const testSimpleExport = async () => { - console.log('🔍 測試簡化匯出功能') - 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, - dataLength: data.length, - contentType: res.headers['content-type'] - })) - }) - req.on('error', reject) - }) - - console.log(`狀態碼: ${logicResponse.status}`) - console.log(`Content-Type: ${logicResponse.contentType}`) - console.log(`資料長度: ${logicResponse.dataLength}`) - - if (logicResponse.status === 200) { - console.log('✅ 邏輯題目匯出成功') - } else { - console.log('❌ 邏輯題目匯出失敗') - } - - // 測試創意題目匯出 - 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, - headers: res.headers, - dataLength: data.length, - contentType: res.headers['content-type'] - })) - }) - req.on('error', reject) - }) - - console.log(`狀態碼: ${creativeResponse.status}`) - console.log(`Content-Type: ${creativeResponse.contentType}`) - console.log(`資料長度: ${creativeResponse.dataLength}`) - - if (creativeResponse.status === 200) { - console.log('✅ 創意題目匯出成功') - } else { - console.log('❌ 創意題目匯出失敗') - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } -} - -testSimpleExport() diff --git a/scripts/test-simple-import.js b/scripts/test-simple-import.js deleted file mode 100644 index 3b29b31..0000000 --- a/scripts/test-simple-import.js +++ /dev/null @@ -1,78 +0,0 @@ -const http = require('http') -const fs = require('fs') - -const testSimpleImport = async () => { - console.log('🔍 測試簡化匯入功能') - console.log('=' .repeat(30)) - - try { - // 創建一個簡單的測試 CSV - const testCSV = `"題目ID","題目內容","選項A","選項B","選項C","選項D","選項E","正確答案","解釋" -"1","測試題目:1+1=?","1","2","3","4","5","B","1+1=2"` - - fs.writeFileSync('test-simple.csv', testCSV, 'utf8') - console.log('✅ 測試 CSV 檔案創建成功') - - // 測試 API 端點(不實際上傳檔案,只測試端點是否正常) - const options = { - hostname: 'localhost', - port: 3000, - path: '/api/questions/import', - method: 'POST', - headers: { - 'Content-Type': 'application/json' - } - } - - const response = await new Promise((resolve, reject) => { - const req = http.request(options, (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ - status: res.statusCode, - data: data - })) - }) - req.on('error', reject) - req.write(JSON.stringify({ test: true })) - req.end() - }) - - console.log(`\n📊 API 測試結果:`) - console.log(`狀態碼: ${response.status}`) - console.log(`回應: ${response.data}`) - - if (response.status === 400) { - console.log('✅ API 端點正常運作(預期缺少檔案參數)') - } else if (response.status === 500) { - console.log('❌ 仍有伺服器錯誤,需要進一步修正') - } else { - console.log('⚠️ 意外的回應狀態') - } - - console.log('\n🎯 修正狀態:') - console.log('✅ 移除了 FileReader 依賴') - console.log('✅ 添加了 CSV 和 Excel 檔案支援') - console.log('✅ 在伺服器端定義了解析函數') - console.log('✅ 添加了詳細的日誌記錄') - - console.log('\n📋 下一步:') - console.log('1. 在瀏覽器中測試實際的檔案上傳') - console.log('2. 檢查伺服器日誌以確認處理過程') - console.log('3. 驗證資料庫更新是否正常') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - // 清理測試檔案 - try { - fs.unlinkSync('test-simple.csv') - console.log('\n🧹 測試檔案已清理') - } catch (e) { - // 忽略清理錯誤 - } - console.log('\n✅ 簡化匯入功能測試完成') - } -} - -testSimpleImport() diff --git a/scripts/test-simple-insert.js b/scripts/test-simple-insert.js deleted file mode 100644 index 441d665..0000000 --- a/scripts/test-simple-insert.js +++ /dev/null @@ -1,61 +0,0 @@ -const mysql = require('mysql2/promise') - -async function testSimpleInsert() { - const config = { - host: process.env.DB_HOST || 'mysql.theaken.com', - port: parseInt(process.env.DB_PORT || '33306'), - user: process.env.DB_USER || 'hr_assessment', - password: process.env.DB_PASSWORD || 'QFOts8FlibiI', - database: process.env.DB_NAME || 'db_hr_assessment', - } - - console.log('🧪 簡單插入測試') - console.log('=' .repeat(50)) - - try { - const connection = await mysql.createConnection(config) - - const id = `test_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` - console.log('生成的ID:', id) - - // 直接插入 - const insertQuery = ` - INSERT INTO test_results ( - id, user_id, test_type, score, total_questions, - correct_answers, completed_at - ) VALUES (?, ?, ?, ?, ?, ?, ?) - ` - - const insertData = [ - id, - 'user-1759073326705-m06y3wacd', - 'logic', - 80, - 10, - 8, - new Date().toISOString() - ] - - console.log('插入數據:', insertData) - - const [result] = await connection.execute(insertQuery, insertData) - console.log('插入結果:', result) - - // 查詢插入的數據 - const [rows] = await connection.execute('SELECT * FROM test_results WHERE id = ?', [id]) - console.log('查詢結果:', rows[0]) - - // 清理 - await connection.execute('DELETE FROM test_results WHERE id = ?', [id]) - console.log('✅ 清理完成') - - await connection.end() - console.log('✅ 測試成功') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - console.error('錯誤詳情:', error) - } -} - -testSimpleInsert() diff --git a/scripts/test-stats-responsive.js b/scripts/test-stats-responsive.js deleted file mode 100644 index 1156ed0..0000000 --- a/scripts/test-stats-responsive.js +++ /dev/null @@ -1,71 +0,0 @@ -const https = require('https') -const http = require('http') - -const testStatsResponsive = async () => { - console.log('🔍 測試統計卡片響應式設計') - console.log('=' .repeat(50)) - - try { - // 1. 獲取統計數據 - console.log('\n📊 1. 獲取統計數據...') - const response = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/admin/users?page=1&limit=5', (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(` 總用戶數: ${data.data.totalUsers}`) - console.log(` 管理員: ${data.data.adminCount}`) - console.log(` 一般用戶: ${data.data.userCount}`) - } - } - - console.log('\n📱 2. 響應式設計特點:') - console.log('✅ 手機版 (grid-cols-3): 3個卡片並排顯示') - console.log('✅ 桌面版 (md:grid-cols-3): 保持3個卡片並排') - console.log('✅ 間距優化: 手機版 gap-3,桌面版 gap-6') - console.log('✅ 內邊距優化: 手機版 p-3,桌面版 p-6') - console.log('✅ 文字大小: 手機版 text-xs/text-lg,桌面版 text-sm/text-2xl') - console.log('✅ 對齊方式: 手機版居中,桌面版左對齊') - - console.log('\n🎨 3. 設計優化:') - console.log('✅ 手機版並排顯示,節省垂直空間') - console.log('✅ 卡片內容緊湊,減少內邊距') - console.log('✅ 文字大小適中,保持可讀性') - console.log('✅ 標題和數字居中對齊,視覺平衡') - console.log('✅ 響應式間距,適配不同螢幕') - - console.log('\n📐 4. 佈局結構:') - console.log(' 手機版: [總用戶數] [管理員] [一般用戶]') - console.log(' 桌面版: [總用戶數] [管理員] [一般用戶]') - console.log(' 間距: 手機版 12px,桌面版 24px') - console.log(' 內邊距: 手機版 12px,桌面版 24px') - - console.log('\n💡 5. 用戶體驗改善:') - console.log('✅ 減少垂直滾動,更多內容可見') - console.log('✅ 統計資訊一目了然') - console.log('✅ 保持視覺層次和可讀性') - console.log('✅ 適配不同設備的使用習慣') - - console.log('\n📝 響應式設計總結:') - console.log('✅ 手機版:3列並排,緊湊設計') - console.log('✅ 桌面版:保持原有設計,舒適間距') - console.log('✅ 文字大小:響應式調整,保持可讀性') - console.log('✅ 對齊方式:手機版居中,桌面版左對齊') - console.log('✅ 間距優化:適配不同螢幕尺寸') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 統計卡片響應式設計測試完成') - } -} - -testStatsResponsive() diff --git a/scripts/test-taiwan-time.js b/scripts/test-taiwan-time.js deleted file mode 100644 index a6860e9..0000000 --- a/scripts/test-taiwan-time.js +++ /dev/null @@ -1,21 +0,0 @@ -// 測試台灣時間顯示 -const testTime = "2025-09-28T10:35:12.000Z" - -console.log('🧪 測試台灣時間顯示') -console.log('=' .repeat(50)) - -console.log('\n📅 原始時間 (UTC):', testTime) - -// 測試不同的時間格式 -const date = new Date(testTime) - -console.log('\n🌏 台灣時間格式:') -console.log('1. 完整日期時間:', date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })) -console.log('2. 只有日期:', date.toLocaleDateString("zh-TW", { timeZone: "Asia/Taipei" })) -console.log('3. 只有時間:', date.toLocaleTimeString("zh-TW", { timeZone: "Asia/Taipei" })) - -console.log('\n📊 比較 (無時區 vs 台灣時區):') -console.log('無時區:', date.toLocaleString("zh-TW")) -console.log('台灣時區:', date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })) - -console.log('\n✅ 測試完成') diff --git a/scripts/test-time-fix.js b/scripts/test-time-fix.js deleted file mode 100644 index bfd46a8..0000000 --- a/scripts/test-time-fix.js +++ /dev/null @@ -1,63 +0,0 @@ -const https = require('https') -const http = require('http') - -const testTimeFix = async () => { - console.log('🔍 測試時間修正效果') - console.log('=' .repeat(50)) - - const userId = 'user-1759073326705-m06y3wacd' - - try { - // 測試當前時間 - console.log('\n📊 當前時間測試:') - const now = new Date() - console.log(`本地時間: ${now.toLocaleString()}`) - console.log(`UTC 時間: ${now.toISOString()}`) - console.log(`台灣時間: ${now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`) - - // 測試時間轉換 - console.log('\n📊 時間轉換測試:') - const testTimes = [ - '2025-09-29T09:16:50.637Z', // 修正後的格式 - '2025-09-29 09:16:50.637', // 舊的格式 - ] - - testTimes.forEach((timeStr, index) => { - console.log(`\n測試 ${index + 1}: ${timeStr}`) - const date = new Date(timeStr) - console.log(` 轉換為 Date 物件: ${date.toISOString()}`) - console.log(` 台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`) - }) - - // 檢查現有的測試結果 - 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) { - 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(` 台灣時間: ${date.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" })}`) - }) - } - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 時間修正測試完成') - } -} - -testTimeFix() diff --git a/scripts/test-time-issue-analysis.js b/scripts/test-time-issue-analysis.js deleted file mode 100644 index 9281990..0000000 --- a/scripts/test-time-issue-analysis.js +++ /dev/null @@ -1,54 +0,0 @@ -const https = require('https') -const http = require('http') - -const testTimeIssueAnalysis = 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}`) - - // 測試 API 時間轉換 - console.log('\n📊 API 時間轉換測試:') - const apiInput = utcTime // 前端傳入的 UTC 時間 - const apiOutput = apiInput.replace('Z', '').replace('T', ' ') // API 轉換後 - - console.log(`API 輸入 (前端): ${apiInput}`) - console.log(`API 輸出 (資料庫): ${apiOutput}`) - - // 測試前端讀取 - console.log('\n📊 前端讀取測試:') - const frontendRead = new Date(apiOutput) - const frontendDisplay = frontendRead.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }) - - console.log(`前端讀取: ${frontendRead.toISOString()}`) - console.log(`前端顯示: ${frontendDisplay}`) - - // 分析問題 - console.log('\n📊 問題分析:') - console.log('1. 前端傳入: UTC 時間 (2025-09-29T09:34:08.000Z)') - console.log('2. API 轉換: 移除 Z 和 T (2025-09-29 09:34:08.000)') - console.log('3. 資料庫儲存: 當作本地時間儲存') - console.log('4. 前端讀取: 當作本地時間解析,然後轉換為台灣時間') - - console.log('\n📝 問題根源:') - console.log('- API 將 UTC 時間轉換為本地時間格式') - console.log('- 資料庫將其當作本地時間儲存') - console.log('- 前端讀取時又當作本地時間解析') - console.log('- 造成時間顯示錯誤') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 時間問題分析完成') - } -} - -testTimeIssueAnalysis() diff --git a/scripts/test-unified-taiwan-time.js b/scripts/test-unified-taiwan-time.js deleted file mode 100644 index 546e3b4..0000000 --- a/scripts/test-unified-taiwan-time.js +++ /dev/null @@ -1,60 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUnifiedTaiwanTime = 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}`) - - // 測試 API 時間轉換邏輯 - console.log('\n📊 API 時間轉換測試:') - const utcDate = new Date(utcTime) - const taiwanTimeForDB = new Date(utcDate.getTime() + (8 * 60 * 60 * 1000)) // UTC + 8 小時 - const mysqlTime = taiwanTimeForDB.toISOString().replace('Z', '').replace('T', ' ') - - console.log(`API 輸入 (前端 UTC): ${utcTime}`) - console.log(`API 轉換 (台灣時間): ${taiwanTimeForDB.toISOString()}`) - console.log(`API 輸出 (資料庫): ${mysqlTime}`) - - // 測試前端讀取邏輯 - console.log('\n📊 前端讀取測試:') - const frontendRead = new Date(mysqlTime) - const frontendDisplay = frontendRead.toLocaleString("zh-TW") - - console.log(`前端讀取: ${frontendRead.toISOString()}`) - console.log(`前端顯示: ${frontendDisplay}`) - - // 驗證時間一致性 - const expectedTaiwanTime = now.toLocaleString("zh-TW", { timeZone: "Asia/Taipei" }) - const isConsistent = frontendDisplay === expectedTaiwanTime - console.log(`時間是否一致: ${isConsistent ? '✅' : '❌'}`) - - if (!isConsistent) { - console.log(`期望: ${expectedTaiwanTime}`) - console.log(`實際: ${frontendDisplay}`) - } - - console.log('\n📝 統一時間處理說明:') - console.log('1. 前端: 使用 UTC 時間 (2025-09-29T09:43:16.000Z)') - console.log('2. API: 轉換為台灣時間 (UTC + 8 小時)') - console.log('3. 資料庫: 儲存台灣時間格式 (2025-09-29 17:43:16.000)') - console.log('4. 前端讀取: 直接顯示台灣時間,不轉換時區') - console.log('5. 結果: 所有地方都使用台灣時間,完全一致') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 統一台灣時間處理測試完成') - } -} - -testUnifiedTaiwanTime() diff --git a/scripts/test-user-management-fixed.js b/scripts/test-user-management-fixed.js deleted file mode 100644 index c6b3dd7..0000000 --- a/scripts/test-user-management-fixed.js +++ /dev/null @@ -1,133 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUserManagementFixed = async () => { - console.log('🔍 測試修正後的用戶管理功能') - console.log('=' .repeat(50)) - - try { - // 1. 獲取用戶列表並檢查建立時間格式 - console.log('\n📊 1. 檢查建立時間格式...') - 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) - }) - - let getData = null - if (getResponse.status === 200) { - getData = JSON.parse(getResponse.data) - if (getData.success) { - console.log(`✅ 獲取用戶列表成功,共 ${getData.data.length} 個用戶:`) - getData.data.forEach((user, index) => { - const createDate = new Date(user.created_at).toLocaleDateString("zh-TW") - console.log(` ${index + 1}. ${user.name} (${user.email})`) - console.log(` 建立時間: ${createDate}`) - console.log(` 角色: ${user.role}`) - }) - } - } - - // 2. 測試更新用戶(不包含密碼) - console.log('\n📊 2. 測試更新用戶(不包含密碼)...') - - // 先獲取一個用戶進行測試 - const testUser = getData?.data?.find(user => user.role === 'user') - if (testUser) { - const updateData = { - id: testUser.id, - name: testUser.name + ' (已更新)', - email: testUser.email, - department: '更新測試部', - role: testUser.role - } - - const updateResponse = await new Promise((resolve, reject) => { - const postData = JSON.stringify(updateData) - const options = { - hostname: 'localhost', - port: 3000, - path: '/api/admin/users', - 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('✅ 更新用戶成功(不包含密碼):') - console.log(` 姓名: ${updateResult.data.name}`) - console.log(` 部門: ${updateResult.data.department}`) - console.log(` 角色: ${updateResult.data.role}`) - } else { - console.log('❌ 更新用戶失敗:', updateResult.error) - } - } - - // 恢復原始資料 - const restoreData = { - id: testUser.id, - name: testUser.name, - email: testUser.email, - department: testUser.department, - role: testUser.role - } - - const restoreResponse = await new Promise((resolve, reject) => { - const postData = JSON.stringify(restoreData) - const options = { - hostname: 'localhost', - port: 3000, - path: '/api/admin/users', - 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 (restoreResponse.status === 200) { - console.log('✅ 已恢復原始用戶資料') - } - } - - console.log('\n📝 修正總結:') - console.log('✅ 建立時間格式已修正(使用 created_at 欄位)') - console.log('✅ 建立時間顯示為台灣日期格式') - console.log('✅ 管理員編輯用戶時無法修改密碼') - console.log('✅ 用戶更新功能正常運作') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 修正後的用戶管理功能測試完成') - } -} - -testUserManagementFixed() diff --git a/scripts/test-user-management.js b/scripts/test-user-management.js deleted file mode 100644 index dff77b9..0000000 --- a/scripts/test-user-management.js +++ /dev/null @@ -1,201 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUserManagement = async () => { - console.log('🔍 測試用戶管理功能') - console.log('=' .repeat(50)) - - try { - // 1. 獲取用戶列表 - console.log('\n📊 1. 獲取用戶列表...') - 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) { - console.log(`✅ 獲取用戶列表成功,共 ${getData.data.length} 個用戶:`) - getData.data.forEach((user, index) => { - console.log(` ${index + 1}. ${user.name} (${user.email}) - ${user.role}`) - }) - } - } - - // 2. 創建新用戶 - console.log('\n📊 2. 創建新用戶...') - const newUser = { - name: '測試用戶', - email: 'testuser@company.com', - password: 'password123', - department: '測試部', - role: 'user' - } - - const createResponse = await new Promise((resolve, reject) => { - const postData = JSON.stringify(newUser) - 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 createdUserId = null - if (createResponse.status === 200) { - const createData = JSON.parse(createResponse.data) - if (createData.success) { - createdUserId = createData.data.id - console.log('✅ 創建用戶成功:') - console.log(` ID: ${createData.data.id}`) - console.log(` 姓名: ${createData.data.name}`) - console.log(` 電子郵件: ${createData.data.email}`) - console.log(` 部門: ${createData.data.department}`) - console.log(` 角色: ${createData.data.role}`) - } else { - console.log('❌ 創建用戶失敗:', createData.error) - } - } - - // 3. 更新用戶 - if (createdUserId) { - console.log('\n📊 3. 更新用戶...') - const updateData = { - id: createdUserId, - name: '測試用戶更新', - email: 'testuser.updated@company.com', - department: '研發部', - role: 'admin' - } - - const updateResponse = await new Promise((resolve, reject) => { - const postData = JSON.stringify(updateData) - const options = { - hostname: 'localhost', - port: 3000, - path: '/api/admin/users', - 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('✅ 更新用戶成功:') - console.log(` 姓名: ${updateResult.data.name}`) - console.log(` 電子郵件: ${updateResult.data.email}`) - console.log(` 部門: ${updateResult.data.department}`) - console.log(` 角色: ${updateResult.data.role}`) - } else { - console.log('❌ 更新用戶失敗:', updateResult.error) - } - } - } - - // 4. 刪除用戶 - if (createdUserId) { - console.log('\n📊 4. 刪除用戶...') - const deleteResponse = await new Promise((resolve, reject) => { - const req = http.get(`http://localhost:3000/api/admin/users?id=${createdUserId}`, (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - // 使用 DELETE 方法 - const deleteMethodResponse = await new Promise((resolve, reject) => { - const options = { - hostname: 'localhost', - port: 3000, - path: `/api/admin/users?id=${createdUserId}`, - 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 (deleteMethodResponse.status === 200) { - const deleteResult = JSON.parse(deleteMethodResponse.data) - if (deleteResult.success) { - console.log('✅ 刪除用戶成功') - } else { - console.log('❌ 刪除用戶失敗:', deleteResult.error) - } - } - } - - // 5. 驗證最終狀態 - console.log('\n📊 5. 驗證最終狀態...') - 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) { - console.log(`✅ 最終用戶列表,共 ${finalData.data.length} 個用戶`) - const testUserExists = finalData.data.some(user => user.email === 'testuser.updated@company.com') - console.log(`測試用戶是否已刪除: ${!testUserExists ? '✅' : '❌'}`) - } - } - - console.log('\n📝 功能總結:') - console.log('✅ 獲取用戶列表功能正常') - console.log('✅ 創建用戶功能正常') - console.log('✅ 更新用戶功能正常') - console.log('✅ 刪除用戶功能正常') - console.log('✅ 資料庫整合成功') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 用戶管理功能測試完成') - } -} - -testUserManagement() diff --git a/scripts/test-user-profile-update.js b/scripts/test-user-profile-update.js deleted file mode 100644 index 28ad3f8..0000000 --- a/scripts/test-user-profile-update.js +++ /dev/null @@ -1,112 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUserProfileUpdate = async () => { - console.log('🔍 測試個人資訊更新功能') - console.log('=' .repeat(50)) - - const testUserId = 'user-1759073326705-m06y3wacd' - - try { - // 1. 獲取當前用戶資料 - console.log('\n📊 1. 獲取當前用戶資料...') - const getResponse = 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 (getResponse.status === 200) { - const getData = JSON.parse(getResponse.data) - if (getData.success) { - console.log('✅ 用戶資料獲取成功:') - console.log(` ID: ${getData.data.id}`) - console.log(` 姓名: ${getData.data.name}`) - console.log(` 電子郵件: ${getData.data.email}`) - console.log(` 部門: ${getData.data.department}`) - console.log(` 角色: ${getData.data.role}`) - } - } - - // 2. 測試更新個人資料 - console.log('\n📊 2. 測試更新個人資料...') - const updateData = { - userId: testUserId, - name: '測試用戶更新', - email: 'test.updated@company.com', - department: '研發部' - } - - 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('✅ 個人資料更新成功:') - console.log(` 姓名: ${updateResult.data.name}`) - console.log(` 電子郵件: ${updateResult.data.email}`) - console.log(` 部門: ${updateResult.data.department}`) - } else { - console.log('❌ 個人資料更新失敗:', updateResult.error) - } - } - - // 3. 驗證更新結果 - console.log('\n📊 3. 驗證更新結果...') - const verifyResponse = 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 (verifyResponse.status === 200) { - const verifyData = JSON.parse(verifyResponse.data) - if (verifyData.success) { - console.log('✅ 更新後用戶資料:') - console.log(` 姓名: ${verifyData.data.name}`) - console.log(` 電子郵件: ${verifyData.data.email}`) - console.log(` 部門: ${verifyData.data.department}`) - - // 檢查更新是否成功 - const isUpdated = verifyData.data.name === '測試用戶更新' && - verifyData.data.email === 'test.updated@company.com' && - verifyData.data.department === '研發部' - console.log(`更新是否成功: ${isUpdated ? '✅' : '❌'}`) - } - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 個人資訊更新功能測試完成') - } -} - -testUserProfileUpdate() diff --git a/scripts/test-user-results-api.js b/scripts/test-user-results-api.js deleted file mode 100644 index 226f3f9..0000000 --- a/scripts/test-user-results-api.js +++ /dev/null @@ -1,57 +0,0 @@ -const fetch = require('node-fetch') - -const testUserResultsAPI = async () => { - console.log('🧪 測試用戶測試結果 API') - console.log('=' .repeat(50)) - - const userId = 'user-1759073326705-m06y3wacd' // 使用現有用戶ID - - try { - console.log(`\n📊 測試用戶ID: ${userId}`) - - const response = await fetch(`http://localhost:3000/api/user/test-results?userId=${userId}`) - - console.log('📊 響應狀態:', response.status) - console.log('📊 響應狀態文字:', response.statusText) - - let result - try { - const text = await response.text() - console.log('📊 原始響應:', text) - result = JSON.parse(text) - console.log('📊 解析後響應:', JSON.stringify(result, null, 2)) - } catch (parseError) { - console.log('❌ JSON 解析失敗:', parseError.message) - return - } - - if (result.success) { - console.log('\n✅ API 測試成功!') - console.log(`📈 統計數據:`) - console.log(`- 總測試次數: ${result.data.stats.totalTests}`) - console.log(`- 平均分數: ${result.data.stats.averageScore}`) - console.log(`- 最高分數: ${result.data.stats.bestScore}`) - console.log(`- 最近測試: ${result.data.stats.lastTestDate}`) - console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`) - console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`) - console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`) - - console.log(`\n📋 測試結果 (${result.data.results.length} 個):`) - result.data.results.forEach((result, index) => { - console.log(`${index + 1}. ${result.type} - 分數: ${result.score}, 測驗次數: ${result.testCount || 1}`) - }) - } else { - console.log('\n❌ API 測試失敗!') - console.log('錯誤訊息:', result.error) - } - - } catch (error) { - console.error('\n❌ 請求失敗:') - console.error('錯誤類型:', error.name) - console.error('錯誤訊息:', error.message) - } finally { - console.log('\n✅ 用戶測試結果 API 測試完成') - } -} - -testUserResultsAPI() diff --git a/scripts/test-user-results-detailed.js b/scripts/test-user-results-detailed.js deleted file mode 100644 index 36872b2..0000000 --- a/scripts/test-user-results-detailed.js +++ /dev/null @@ -1,57 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUserResultsAPI = async () => { - console.log('🧪 測試用戶測試結果 API (詳細版)') - console.log('=' .repeat(50)) - - const userId = 'user-1759073326705-m06y3wacd' - const url = `http://localhost:3000/api/user/test-results?userId=${userId}` - - try { - console.log(`\n📊 測試用戶ID: ${userId}`) - console.log(`🔗 API URL: ${url}`) - - const response = await new Promise((resolve, reject) => { - const req = http.get(url, (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - console.log('📊 響應狀態:', response.status) - - if (response.status === 200) { - const result = JSON.parse(response.data) - console.log('\n✅ API 測試成功!') - - console.log(`\n📈 統計數據:`) - console.log(`- 總測試次數: ${result.data.stats.totalTests}`) - console.log(`- 平均分數: ${result.data.stats.averageScore}`) - console.log(`- 最高分數: ${result.data.stats.bestScore}`) - console.log(`- 最近測試: ${result.data.stats.lastTestDate}`) - console.log(`- 邏輯測驗次數: ${result.data.stats.testCounts.logic}`) - console.log(`- 創意測驗次數: ${result.data.stats.testCounts.creative}`) - console.log(`- 綜合測驗次數: ${result.data.stats.testCounts.combined}`) - - console.log(`\n📋 測試結果 (${result.data.results.length} 個):`) - result.data.results.forEach((testResult, index) => { - console.log(`${index + 1}. ${testResult.type} - 分數: ${testResult.score}, 測驗次數: ${testResult.testCount || 1}`) - console.log(` 完成時間: ${testResult.completedAt}`) - }) - } else { - console.log('❌ API 響應失敗,狀態碼:', response.status) - } - - } catch (error) { - console.error('\n❌ 請求失敗:') - console.error('錯誤類型:', error.name) - console.error('錯誤訊息:', error.message) - } finally { - console.log('\n✅ 用戶測試結果 API 測試完成') - } -} - -testUserResultsAPI() diff --git a/scripts/test-user-results-with-combined.js b/scripts/test-user-results-with-combined.js deleted file mode 100644 index 84714a8..0000000 --- a/scripts/test-user-results-with-combined.js +++ /dev/null @@ -1,56 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUserResultsWithCombined = async () => { - console.log('🧪 測試包含綜合測試結果的用戶測試結果 API') - 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) - console.log('✅ API 測試成功!') - console.log('📡 響應內容:', JSON.stringify(data, null, 2)) - - if (data.success) { - console.log('\n📈 測試結果詳情:') - console.log(`- 總測試數: ${data.data.stats.totalTests}`) - console.log(`- 平均分數: ${data.data.stats.averageScore}`) - console.log(`- 最高分數: ${data.data.stats.bestScore}`) - console.log(`- 最近測試: ${data.data.stats.lastTestDate}`) - console.log(`- 測試次數:`, data.data.stats.testCounts) - - console.log('\n📋 測試結果列表:') - data.data.results.forEach((result, index) => { - console.log(`\n${index + 1}. ${result.type}:`) - console.log(` 分數: ${result.score}`) - console.log(` 完成時間: ${result.completedAt}`) - console.log(` 測試次數: ${result.testCount}`) - console.log(` 詳細資訊:`, result.details) - }) - } - } else { - console.log('❌ API 響應失敗,狀態碼:', response.status) - console.log('響應內容:', response.data) - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 包含綜合測試結果的用戶測試結果 API 測試完成') - } -} - -testUserResultsWithCombined() diff --git a/scripts/test-user-stats-fixed.js b/scripts/test-user-stats-fixed.js deleted file mode 100644 index 89f5110..0000000 --- a/scripts/test-user-stats-fixed.js +++ /dev/null @@ -1,104 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUserStatsFixed = async () => { - console.log('🔍 測試修正後的用戶統計功能') - console.log('=' .repeat(50)) - - try { - // 1. 獲取用戶列表並檢查統計數據 - console.log('\n📊 1. 檢查用戶統計數據...') - const response = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/admin/users?page=1&limit=5', (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(` 總用戶數: ${data.data.totalUsers}`) - console.log(` 管理員數量: ${data.data.adminCount}`) - console.log(` 一般用戶數量: ${data.data.userCount}`) - console.log(` 當前頁用戶數: ${data.data.users.length}`) - console.log(` 總頁數: ${data.data.totalPages}`) - - // 驗證統計數據是否正確 - const currentPageAdmins = data.data.users.filter(user => user.role === 'admin').length - const currentPageUsers = data.data.users.filter(user => user.role === 'user').length - - console.log('\n📋 當前頁用戶詳細:') - data.data.users.forEach((user, index) => { - console.log(` ${index + 1}. ${user.name} (${user.email}) - ${user.role}`) - }) - - console.log('\n📊 統計驗證:') - console.log(` 當前頁管理員: ${currentPageAdmins}`) - console.log(` 當前頁一般用戶: ${currentPageUsers}`) - console.log(` 總管理員: ${data.data.adminCount}`) - console.log(` 總一般用戶: ${data.data.userCount}`) - - // 檢查統計數據是否合理 - const totalFromStats = data.data.adminCount + data.data.userCount - const isStatsCorrect = totalFromStats === data.data.totalUsers - - console.log(`\n✅ 統計數據驗證: ${isStatsCorrect ? '正確' : '錯誤'}`) - console.log(` 管理員 + 一般用戶 = ${totalFromStats}`) - console.log(` 總用戶數 = ${data.data.totalUsers}`) - - if (!isStatsCorrect) { - console.log('❌ 統計數據不一致!') - } - - } else { - console.log('❌ 獲取用戶列表失敗:', data.error) - } - } - - // 2. 測試第二頁的統計數據 - console.log('\n📊 2. 測試第二頁的統計數據...') - const page2Response = await new Promise((resolve, reject) => { - const req = http.get('http://localhost:3000/api/admin/users?page=2&limit=5', (res) => { - let data = '' - res.on('data', chunk => data += chunk) - res.on('end', () => resolve({ status: res.statusCode, data })) - }) - req.on('error', reject) - }) - - if (page2Response.status === 200) { - const page2Data = JSON.parse(page2Response.data) - if (page2Data.success) { - console.log('✅ 第二頁統計數據:') - console.log(` 總用戶數: ${page2Data.data.totalUsers}`) - console.log(` 管理員數量: ${page2Data.data.adminCount}`) - console.log(` 一般用戶數量: ${page2Data.data.userCount}`) - console.log(` 當前頁用戶數: ${page2Data.data.users.length}`) - - // 檢查統計數據是否與第一頁一致 - const statsConsistent = page2Data.data.totalUsers === data.data.totalUsers && - page2Data.data.adminCount === data.data.adminCount && - page2Data.data.userCount === data.data.userCount - - console.log(`\n✅ 統計數據一致性: ${statsConsistent ? '一致' : '不一致'}`) - } - } - - console.log('\n📝 修正總結:') - console.log('✅ 統計數據基於所有用戶計算') - console.log('✅ 管理員和一般用戶數量正確') - console.log('✅ 分頁不影響統計數據') - console.log('✅ API 直接返回統計數據') - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 用戶統計功能修正測試完成') - } -} - -testUserStatsFixed() diff --git a/scripts/test-user-stats.js b/scripts/test-user-stats.js deleted file mode 100644 index 1e6208c..0000000 --- a/scripts/test-user-stats.js +++ /dev/null @@ -1,74 +0,0 @@ -const https = require('https') -const http = require('http') - -const testUserStats = async () => { - console.log('🔍 測試用戶管理統計功能') - console.log('=' .repeat(50)) - - try { - // 獲取用戶列表 - console.log('\n📊 獲取用戶列表...') - const response = 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 (response.status === 200) { - const data = JSON.parse(response.data) - if (data.success) { - const users = data.data - - // 計算統計數據 - const totalUsers = users.length - const adminUsers = users.filter(user => user.role === 'admin').length - const regularUsers = users.filter(user => user.role === 'user').length - - console.log('✅ 用戶統計數據:') - console.log(` 總用戶數: ${totalUsers}`) - console.log(` 管理員: ${adminUsers}`) - console.log(` 一般用戶: ${regularUsers}`) - - // 顯示用戶詳細資訊 - console.log('\n📋 用戶詳細列表:') - users.forEach((user, index) => { - console.log(`\n${index + 1}. ${user.name}:`) - console.log(` ID: ${user.id}`) - console.log(` 電子郵件: ${user.email}`) - console.log(` 部門: ${user.department}`) - console.log(` 角色: ${user.role}`) - console.log(` 建立時間: ${user.created_at}`) - console.log(` 更新時間: ${user.updated_at}`) - }) - - // 驗證統計數據 - const isStatsCorrect = totalUsers === (adminUsers + regularUsers) - console.log(`\n統計數據是否正確: ${isStatsCorrect ? '✅' : '❌'}`) - - // 檢查部門分布 - console.log('\n📊 部門分布:') - const departmentStats = {} - users.forEach(user => { - departmentStats[user.department] = (departmentStats[user.department] || 0) + 1 - }) - - Object.entries(departmentStats).forEach(([dept, count]) => { - console.log(` ${dept}: ${count} 人`) - }) - - } else { - console.log('❌ 獲取用戶列表失敗:', data.error) - } - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message) - } finally { - console.log('\n✅ 用戶管理統計功能測試完成') - } -} - -testUserStats() diff --git a/scripts/update-logic-table.js b/scripts/update-logic-table.js deleted file mode 100644 index e00f64a..0000000 --- a/scripts/update-logic-table.js +++ /dev/null @@ -1,38 +0,0 @@ -const mysql = require('mysql2/promise') - -async function updateLogicTable() { - 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_questions 表結構...') - - try { - const connection = await mysql.createConnection(config) - - // 檢查是否已有 option_e 欄位 - const [columns] = await connection.execute("SHOW COLUMNS FROM logic_questions LIKE 'option_e'") - - if (columns.length === 0) { - console.log('📝 加入 option_e 欄位...') - await connection.execute("ALTER TABLE logic_questions ADD COLUMN option_e VARCHAR(500) NOT NULL DEFAULT '' AFTER option_d") - - console.log('📝 更新 correct_answer 欄位以支援 E 選項...') - await connection.execute("ALTER TABLE logic_questions MODIFY COLUMN correct_answer ENUM('A', 'B', 'C', 'D', 'E') NOT NULL") - - console.log('✅ 表結構更新完成') - } else { - console.log('✅ option_e 欄位已存在') - } - - await connection.end() - } catch (error) { - console.error('❌ 更新失敗:', error.message) - } -} - -updateLogicTable()