實作所有測驗結果與資料庫整合
This commit is contained in:
38
scripts/check-combined-table-fields.js
Normal file
38
scripts/check-combined-table-fields.js
Normal file
@@ -0,0 +1,38 @@
|
||||
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()
|
38
scripts/check-combined-table-structure.js
Normal file
38
scripts/check-combined-table-structure.js
Normal file
@@ -0,0 +1,38 @@
|
||||
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()
|
52
scripts/check-combined-test-data.js
Normal file
52
scripts/check-combined-test-data.js
Normal file
@@ -0,0 +1,52 @@
|
||||
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()
|
41
scripts/check-db-fields.js
Normal file
41
scripts/check-db-fields.js
Normal file
@@ -0,0 +1,41 @@
|
||||
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()
|
170
scripts/test-admin-results.js
Normal file
170
scripts/test-admin-results.js
Normal file
@@ -0,0 +1,170 @@
|
||||
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()
|
89
scripts/test-export-details.js
Normal file
89
scripts/test-export-details.js
Normal file
@@ -0,0 +1,89 @@
|
||||
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()
|
154
scripts/test-export-results.js
Normal file
154
scripts/test-export-results.js
Normal file
@@ -0,0 +1,154 @@
|
||||
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()
|
@@ -1,14 +1,12 @@
|
||||
const http = require('http')
|
||||
|
||||
const testExportSimple = async () => {
|
||||
console.log('🔍 測試簡化匯出功能')
|
||||
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) => {
|
||||
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({
|
||||
@@ -19,50 +17,40 @@ const testExportSimple = async () => {
|
||||
req.on('error', reject)
|
||||
})
|
||||
|
||||
console.log(`狀態碼: ${logicResponse.status}`)
|
||||
|
||||
if (logicResponse.status === 200) {
|
||||
const logicData = JSON.parse(logicResponse.data)
|
||||
console.log(`成功獲取 ${logicData.data?.length || 0} 道邏輯題目`)
|
||||
|
||||
if (logicData.data && logicData.data.length > 0) {
|
||||
const firstQuestion = logicData.data[0]
|
||||
console.log(`第一題: ${firstQuestion.question?.substring(0, 50)}...`)
|
||||
console.log(`選項A: ${firstQuestion.option_a}`)
|
||||
console.log(`正確答案: ${firstQuestion.correct_answer}`)
|
||||
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('❌ 獲取邏輯題目失敗')
|
||||
}
|
||||
|
||||
// 測試創意題目
|
||||
console.log('\n📊 測試獲取創意題目資料...')
|
||||
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: data
|
||||
}))
|
||||
})
|
||||
req.on('error', reject)
|
||||
})
|
||||
|
||||
console.log(`狀態碼: ${creativeResponse.status}`)
|
||||
|
||||
if (creativeResponse.status === 200) {
|
||||
const creativeData = JSON.parse(creativeResponse.data)
|
||||
console.log(`成功獲取 ${creativeData.data?.length || 0} 道創意題目`)
|
||||
|
||||
if (creativeData.data && 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('❌ 獲取創意題目失敗')
|
||||
console.log('❌ 匯出失敗,狀態碼:', response.status)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
@@ -70,4 +58,4 @@ const testExportSimple = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
testExportSimple()
|
||||
testExportSimple()
|
106
scripts/test-fixed-export.js
Normal file
106
scripts/test-fixed-export.js
Normal file
@@ -0,0 +1,106 @@
|
||||
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()
|
Reference in New Issue
Block a user