diff --git a/app/api/evaluation/[id]/route.ts b/app/api/evaluation/[id]/route.ts index b55bec2..62023b5 100644 --- a/app/api/evaluation/[id]/route.ts +++ b/app/api/evaluation/[id]/route.ts @@ -119,34 +119,167 @@ export async function GET( // 整體改進建議 - evaluation_feedback 的第一筆 overall overallSuggestions: feedbackByType.overall[0]?.content || '無改進建議', - // 繼續保持的優勢 - evaluation_feedback 的 strength + // 繼續保持的優勢 - evaluation_feedback 的 feedback_type = strength 且 criteria_item_id 是 null 的全部資料 maintainStrengths: feedbackByType.strength - .filter(f => f.criteria_item_id) // 只取有 criteria_item_id 的 - .map(f => ({ - title: f.criteria_item_name || '優勢', - description: f.content || '無描述' - })) - .filter((item, index, arr) => arr.findIndex(i => i.title === item.title) === index), // 去重 + .filter(f => f.criteria_item_id === null) // 只取 criteria_item_id 是 null 的 + .map(f => { + const content = f.content || '無描述'; + const colonIndex = content.indexOf(':'); + const title = colonIndex > -1 ? content.substring(0, colonIndex + 1) : '系統優勢:'; + const description = colonIndex > -1 ? content.substring(colonIndex + 1).trim() : content; + + return { + title: title, + description: description + }; + }), - // 重點改進方向 - evaluation_feedback 的 improvement (除了最後3筆) - keyImprovements: feedbackByType.improvement - .filter(f => f.criteria_item_id) // 只取有 criteria_item_id 的 - .slice(0, -3) // 排除最後3筆 - .map(f => ({ - title: f.criteria_item_name || '改進項目', - description: f.content || '無描述', - suggestions: [f.content || '無建議'] - })) - .filter((item, index, arr) => arr.findIndex(i => i.title === item.title) === index), // 去重 + // 重點改進方向 - evaluation_feedback 的 feedback_type = improvement 且 criteria_item_id 是 null 的全部資料,但不能有最後 3 筆數據,也不能是第一筆 + keyImprovements: (() => { + const allImprovementData = feedbackByType.improvement + .filter(f => f.criteria_item_id === null); // 只取 criteria_item_id 是 null 的 + + // 如果數據不足5筆,則不進行過濾,直接使用所有數據 + const improvementData = allImprovementData.length >= 5 + ? allImprovementData.slice(1, -3) // 排除第一筆和最後3筆 + : allImprovementData; // 數據不足時使用所有數據 + + // 分組處理 - 先收集所有組,然後合併相同標題的組 + const tempGroups = []; + let currentGroup = null; + + for (const item of improvementData) { + const content = item.content || ''; + const colonIndex = content.indexOf(':'); + + if (colonIndex > -1) { + // 有冒號的情況 + const title = content.substring(0, colonIndex + 1); + const remainingContent = content.substring(colonIndex + 1).trim(); + + // 檢查是否包含小標題 "建議:" + const suggestionIndex = remainingContent.indexOf('建議:'); + + if (suggestionIndex > -1) { + // 如果有小標題,開始新的 group + if (currentGroup) { + tempGroups.push(currentGroup); + } + + currentGroup = { + title: title, + subtitle: '建議:', + suggestions: [] + }; + + // 處理建議後面的內容 + const suggestionsText = remainingContent.substring(suggestionIndex + 3).trim(); + const suggestions = suggestionsText.split('\n') + .map(s => s.trim()) + .filter(s => s.startsWith('•')) + .map(s => s.substring(1).trim()); + + currentGroup.suggestions = suggestions; + } else if (remainingContent.startsWith('•')) { + // 如果是條列資料,添加到當前 group + if (currentGroup) { + const suggestion = remainingContent.substring(1).trim(); + currentGroup.suggestions.push(suggestion); + } + } else { + // 如果是普通描述,創建簡單的 group + if (currentGroup) { + tempGroups.push(currentGroup); + } + + currentGroup = { + title: title, + subtitle: '', + suggestions: [remainingContent] + }; + } + } else { + // 沒有冒號的情況,創建簡單的 group + if (currentGroup) { + tempGroups.push(currentGroup); + } + + // 檢查內容是否以 • 開頭 + if (content.startsWith('•')) { + // 如果是條列資料,添加到當前 group + if (currentGroup) { + const suggestion = content.substring(1).trim(); + currentGroup.suggestions.push(suggestion); + } else { + // 如果沒有當前 group,創建一個 + currentGroup = { + title: '改進方向:', + subtitle: '', + suggestions: [content.substring(1).trim()] + }; + } + } else { + // 如果是普通描述,創建新的 group,將內容作為描述而不是條列建議 + currentGroup = { + title: '改進方向:', + subtitle: '', + description: content, + suggestions: [] + }; + } + } + } + + // 添加最後一個 group + if (currentGroup) { + tempGroups.push(currentGroup); + } + + // 合併相同標題的組 + const groups = []; + const groupMap = new Map(); + + for (const group of tempGroups) { + if (groupMap.has(group.title)) { + // 合併到現有組 + const existingGroup = groupMap.get(group.title); + if (group.suggestions && group.suggestions.length > 0) { + // 合併建議並去重 + const allSuggestions = [...(existingGroup.suggestions || []), ...group.suggestions]; + existingGroup.suggestions = [...new Set(allSuggestions)]; // 使用 Set 去重 + } + if (group.description) { + existingGroup.description = group.description; + } + } else { + // 創建新組 + groupMap.set(group.title, { ...group }); + } + } + + // 將合併後的組添加到結果數組 + for (const group of groupMap.values()) { + groups.push(group); + } + + return groups; + })(), - // 下一步行動計劃 - evaluation_feedback 的 improvement 最後3筆 + // 下一步行動計劃 - evaluation_feedback 的 feedback_type = improvement 且 criteria_item_id 是 null 的最後 3 筆數據 actionPlan: feedbackByType.improvement - .filter(f => f.criteria_item_id) // 只取有 criteria_item_id 的 + .filter(f => f.criteria_item_id === null) // 只取 criteria_item_id 是 null 的 .slice(-3) // 取最後3筆 - .map((f, index) => ({ - phase: `階段 ${index + 1}`, - description: f.content || '無描述' - })) + .map((f, index) => { + const content = f.content || '無描述'; + const colonIndex = content.indexOf(':'); + const phase = colonIndex > -1 ? content.substring(0, colonIndex + 1) : `階段 ${index + 1}:`; + const description = colonIndex > -1 ? content.substring(colonIndex + 1).trim() : content; + + return { + phase: phase, + description: description + }; + }) }, chartData: chartData }; @@ -165,4 +298,4 @@ export async function GET( { status: 500 } ); } -} +} \ No newline at end of file diff --git a/check-feedback-data.js b/check-feedback-data.js deleted file mode 100644 index 4a0013a..0000000 --- a/check-feedback-data.js +++ /dev/null @@ -1,66 +0,0 @@ -const mysql = require('mysql2/promise'); - -const dbConfig = { - host: 'mysql.theaken.com', - port: 33306, - user: 'root', - password: 'zh6161168', - database: 'db_AI_scoring' -}; - -async function checkFeedbackData() { - let connection; - try { - console.log('🔗 連接到資料庫...'); - connection = await mysql.createConnection(dbConfig); - console.log('✅ 資料庫連接成功'); - - // 檢查 evaluation_feedback 表結構 - console.log('📋 檢查 evaluation_feedback 表結構...'); - const [columns] = await connection.execute(` - SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT - FROM INFORMATION_SCHEMA.COLUMNS - WHERE TABLE_NAME = 'evaluation_feedback' - ORDER BY ORDINAL_POSITION - `); - console.log('表結構:', columns); - - // 檢查 evaluation_feedback 數據 - console.log('📊 檢查 evaluation_feedback 數據...'); - const [feedbackData] = await connection.execute(` - SELECT id, evaluation_id, criteria_item_id, feedback_type, content, sort_order - FROM evaluation_feedback - WHERE evaluation_id = 2 - ORDER BY sort_order - `); - console.log('評審 ID 2 的反饋數據:', feedbackData); - - // 檢查不同 feedback_type 的數據 - console.log('🔍 檢查不同 feedback_type 的數據...'); - const [typeStats] = await connection.execute(` - SELECT feedback_type, COUNT(*) as count - FROM evaluation_feedback - GROUP BY feedback_type - `); - console.log('feedback_type 統計:', typeStats); - - // 檢查 criteria_items 表 - console.log('📝 檢查 criteria_items 表...'); - const [criteriaItems] = await connection.execute(` - SELECT id, name, description - FROM criteria_items - ORDER BY id - `); - console.log('評分標準項目:', criteriaItems); - - } catch (error) { - console.error('❌ 錯誤:', error.message); - } finally { - if (connection) { - await connection.end(); - console.log('🔌 資料庫連接已關閉'); - } - } -} - -checkFeedbackData(); diff --git a/check-strength-improvement.js b/check-strength-improvement.js deleted file mode 100644 index 26fa975..0000000 --- a/check-strength-improvement.js +++ /dev/null @@ -1,61 +0,0 @@ -const mysql = require('mysql2/promise'); - -const dbConfig = { - host: 'mysql.theaken.com', - port: 33306, - user: 'root', - password: 'zh6161168', - database: 'db_AI_scoring' -}; - -async function checkStrengthImprovement() { - let connection; - try { - console.log('🔗 連接到資料庫...'); - connection = await mysql.createConnection(dbConfig); - console.log('✅ 資料庫連接成功'); - - // 檢查 strength 類型的數據 - console.log('💪 檢查 strength 類型的數據...'); - const [strengthData] = await connection.execute(` - SELECT ef.id, ef.evaluation_id, ef.criteria_item_id, ef.content, ci.name as criteria_name - FROM evaluation_feedback ef - LEFT JOIN criteria_items ci ON ef.criteria_item_id = ci.id - WHERE ef.evaluation_id = 2 AND ef.feedback_type = 'strength' - ORDER BY ef.criteria_item_id, ef.sort_order - `); - console.log('優點數據:', strengthData); - - // 檢查 improvement 類型的數據 - console.log('🔧 檢查 improvement 類型的數據...'); - const [improvementData] = await connection.execute(` - SELECT ef.id, ef.evaluation_id, ef.criteria_item_id, ef.content, ci.name as criteria_name - FROM evaluation_feedback ef - LEFT JOIN criteria_items ci ON ef.criteria_item_id = ci.id - WHERE ef.evaluation_id = 2 AND ef.feedback_type = 'improvement' - ORDER BY ef.criteria_item_id, ef.sort_order - `); - console.log('改進建議數據:', improvementData); - - // 檢查 criteria 類型的數據(AI 評語) - console.log('💬 檢查 criteria 類型的數據(AI 評語)...'); - const [criteriaData] = await connection.execute(` - SELECT ef.id, ef.evaluation_id, ef.criteria_item_id, ef.content, ci.name as criteria_name - FROM evaluation_feedback ef - LEFT JOIN criteria_items ci ON ef.criteria_item_id = ci.id - WHERE ef.evaluation_id = 2 AND ef.feedback_type = 'criteria' - ORDER BY ef.criteria_item_id, ef.sort_order - `); - console.log('AI 評語數據:', criteriaData); - - } catch (error) { - console.error('❌ 錯誤:', error.message); - } finally { - if (connection) { - await connection.end(); - console.log('🔌 資料庫連接已關閉'); - } - } -} - -checkStrengthImprovement(); diff --git a/test-chart-data.js b/test-chart-data.js deleted file mode 100644 index c5d9ae8..0000000 --- a/test-chart-data.js +++ /dev/null @@ -1,74 +0,0 @@ -const http = require('http'); - -function makeRequest(url) { - return new Promise((resolve, reject) => { - const req = http.get(url, (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - try { - const jsonData = JSON.parse(data); - resolve(jsonData); - } catch (error) { - reject(error); - } - }); - }); - req.on('error', reject); - }); -} - -async function testChartData() { - try { - console.log('🧪 測試圖表數據生成...'); - - // 測試評審詳細API - console.log('📋 測試評審詳細API (ID=2)...'); - const detailData = await makeRequest('http://localhost:3000/api/evaluation/2'); - - if (detailData.success) { - console.log('✅ API 調用成功'); - console.log('📊 專案標題:', detailData.data.projectTitle); - console.log('📊 總分:', detailData.data.overallScore); - - // 檢查圖表數據 - console.log('\n📊 圖表數據檢查:'); - - console.log('\n📈 各項目得分 (Bar Chart):'); - detailData.data.chartData.barChart.forEach((item, index) => { - console.log(` ${index + 1}. ${item.name}: ${item.score}分`); - }); - - console.log('\n🥧 權重分布 (Pie Chart):'); - detailData.data.chartData.pieChart.forEach((item, index) => { - console.log(` ${index + 1}. ${item.name}: 權重=${item.weight}%, 加權分數=${item.value}`); - }); - - console.log('\n🎯 能力雷達圖 (Radar Chart):'); - detailData.data.chartData.radarChart.forEach((item, index) => { - console.log(` ${index + 1}. ${item.subject}: ${item.score}/${item.fullMark}`); - }); - - // 檢查評分標準詳情 - console.log('\n📝 評分標準詳情:'); - detailData.data.criteria.forEach((criteria, index) => { - console.log(` ${index + 1}. ${criteria.name}: ${criteria.score}/${criteria.maxScore}`); - console.log(` AI 評語: ${criteria.feedback}`); - console.log(` 優點: ${criteria.strengths.length > 0 ? criteria.strengths.join(', ') : '無'}`); - console.log(` 改進建議: ${criteria.improvements.length > 0 ? criteria.improvements.join(', ') : '無'}`); - console.log(''); - }); - - } else { - console.log('❌ API 調用失敗:', detailData.error); - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message); - } -} - -// 等待一下讓服務器啟動 -setTimeout(testChartData, 2000); diff --git a/test-database.js b/test-database.js deleted file mode 100644 index 902755c..0000000 --- a/test-database.js +++ /dev/null @@ -1,40 +0,0 @@ -const mysql = require('mysql2/promise'); - -const dbConfig = { - host: 'mysql.theaken.com', - port: 33306, - user: 'root', - password: 'zh6161168', - database: 'db_AI_scoring' -}; - -async function checkData() { - let connection; - try { - console.log('🔗 連接到資料庫...'); - connection = await mysql.createConnection(dbConfig); - console.log('✅ 資料庫連接成功'); - - // 檢查評審記錄 - const [evaluations] = await connection.execute('SELECT id, project_id, overall_score, grade FROM evaluations LIMIT 5'); - console.log('📊 評審記錄:', evaluations); - - // 檢查專案記錄 - const [projects] = await connection.execute('SELECT id, title, status FROM projects LIMIT 5'); - console.log('📋 專案記錄:', projects); - - // 檢查評分記錄 - const [scores] = await connection.execute('SELECT id, evaluation_id, criteria_item_id, score FROM evaluation_scores LIMIT 5'); - console.log('🎯 評分記錄:', scores); - - } catch (error) { - console.error('❌ 錯誤:', error.message); - } finally { - if (connection) { - await connection.end(); - console.log('🔌 資料庫連接已關閉'); - } - } -} - -checkData(); diff --git a/test-fixed-api.js b/test-fixed-api.js deleted file mode 100644 index 0898d5d..0000000 --- a/test-fixed-api.js +++ /dev/null @@ -1,66 +0,0 @@ -const http = require('http'); - -function makeRequest(url) { - return new Promise((resolve, reject) => { - const req = http.get(url, (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - try { - const jsonData = JSON.parse(data); - resolve(jsonData); - } catch (error) { - reject(error); - } - }); - }); - req.on('error', reject); - }); -} - -async function testFixedAPI() { - try { - console.log('🧪 測試修正後的 API...'); - - // 測試評審詳細API - console.log('📋 測試評審詳細API (ID=2)...'); - const detailData = await makeRequest('http://localhost:3000/api/evaluation/2'); - - if (detailData.success) { - console.log('✅ API 調用成功'); - console.log('📊 專案標題:', detailData.data.projectTitle); - console.log('📊 總分:', detailData.data.overallScore); - console.log('📊 等級:', detailData.data.grade); - - console.log('\n📝 評分標準詳情:'); - detailData.data.criteria.forEach((criteria, index) => { - console.log(` ${index + 1}. ${criteria.name}: ${criteria.score}/${criteria.maxScore}`); - console.log(` AI 評語: ${criteria.feedback}`); - console.log(` 優點: ${criteria.strengths.length > 0 ? criteria.strengths.join(', ') : '無'}`); - console.log(` 改進建議: ${criteria.improvements.length > 0 ? criteria.improvements.join(', ') : '無'}`); - console.log(''); - }); - - console.log('📋 詳細分析:'); - console.log(' 摘要:', detailData.data.detailedAnalysis.summary); - console.log(' 關鍵發現:', detailData.data.detailedAnalysis.keyFindings); - - console.log('\n💡 改進建議:'); - console.log(' 整體建議:', detailData.data.improvementSuggestions.overallSuggestions); - console.log(' 保持優勢:', detailData.data.improvementSuggestions.maintainStrengths); - console.log(' 關鍵改進:', detailData.data.improvementSuggestions.keyImprovements); - console.log(' 行動計劃:', detailData.data.improvementSuggestions.actionPlan); - - } else { - console.log('❌ API 調用失敗:', detailData.error); - } - - } catch (error) { - console.error('❌ 測試失敗:', error.message); - } -} - -// 等待一下讓服務器啟動 -setTimeout(testFixedAPI, 2000);