import { NextRequest, NextResponse } from 'next/server'; import { EvaluationService } from '@/lib/services/database'; import { generateHTMLPDFReport, type PDFReportData } from '@/lib/utils/html-pdf-generator'; export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { try { const evaluationId = parseInt(params.id); if (isNaN(evaluationId)) { return NextResponse.json( { success: false, error: '無效的評審ID' }, { status: 400 } ); } console.log(`📄 開始生成 PDF 報告: ID=${evaluationId}`); // 獲取評審詳細數據 const evaluationWithDetails = await EvaluationService.findWithDetails(evaluationId); if (!evaluationWithDetails) { return NextResponse.json( { success: false, error: '找不到指定的評審記錄' }, { status: 404 } ); } console.log(`✅ 成功獲取評審數據: 專案=${evaluationWithDetails.project?.title}`); // 處理反饋數據,按類型分組 const feedbackByType = { criteria: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'criteria') || [], strength: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'strength') || [], improvement: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'improvement') || [], overall: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'overall') || [] }; // 為每個評分標準獲取對應的 AI 評語、優點和改進建議 const criteriaWithFeedback = evaluationWithDetails.scores?.map(score => { const criteriaId = score.criteria_item_id; const criteriaName = score.criteria_item_name || '未知項目'; // 獲取該評分標準的 AI 評語 const criteriaFeedback = feedbackByType.criteria .filter(f => f.criteria_item_id === criteriaId) .map(f => f.content) .filter((content, index, arr) => arr.indexOf(content) === index)[0] || '無評語'; // 獲取該評分標準的優點 const strengths = feedbackByType.strength .filter(f => f.criteria_item_id === criteriaId) .map(f => f.content) .filter((content, index, arr) => arr.indexOf(content) === index); // 獲取該評分標準的改進建議 const improvements = feedbackByType.improvement .filter(f => f.criteria_item_id === criteriaId) .map(f => f.content) .filter((content, index, arr) => arr.indexOf(content) === index); return { name: criteriaName, score: Number(score.score) || 0, maxScore: Number(score.max_score) || 10, weight: Number(score.weight) || 1, weightedScore: Number(score.weighted_score) || 0, percentage: Number(score.percentage) || 0, feedback: criteriaFeedback, strengths: strengths, improvements: improvements }; }) || []; // 構建 PDF 報告數據 const pdfData: PDFReportData = { projectTitle: evaluationWithDetails.project?.title || '未知專案', overallScore: Number(evaluationWithDetails.overall_score) || 0, totalPossible: Number(evaluationWithDetails.max_possible_score) || 100, grade: evaluationWithDetails.grade || 'N/A', analysisDate: evaluationWithDetails.created_at ? new Date(evaluationWithDetails.created_at).toISOString().split('T')[0] : new Date().toISOString().split('T')[0], criteria: criteriaWithFeedback, overview: { excellentItems: evaluationWithDetails.excellent_items || 0, improvementItems: evaluationWithDetails.improvement_items || 0, overallPerformance: Math.round(Number(evaluationWithDetails.overall_score) || 0) }, improvementSuggestions: { overallSuggestions: feedbackByType.overall[0]?.content || '無詳細分析', maintainStrengths: feedbackByType.strength .filter(f => f.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 }; }), keyImprovements: (() => { const allImprovementData = feedbackByType.improvement .filter(f => f.criteria_item_id === null); const improvementData = allImprovementData.length >= 5 ? allImprovementData.slice(1, -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) { 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('•')) { if (currentGroup) { const suggestion = remainingContent.substring(1).trim(); currentGroup.suggestions.push(suggestion); } } else { if (currentGroup) { tempGroups.push(currentGroup); } currentGroup = { title: title, subtitle: '', suggestions: [remainingContent] }; } } else { if (currentGroup) { tempGroups.push(currentGroup); } if (content.startsWith('•')) { if (currentGroup) { const suggestion = content.substring(1).trim(); currentGroup.suggestions.push(suggestion); } else { currentGroup = { title: '改進方向:', subtitle: '', suggestions: [content.substring(1).trim()] }; } } else { currentGroup = { title: '改進方向:', subtitle: '', description: content, suggestions: [] }; } } } if (currentGroup) { tempGroups.push(currentGroup); } return tempGroups; })(), actionPlan: feedbackByType.improvement .filter(f => f.criteria_item_id === null) .slice(-3) .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 }; }) } }; console.log(`📋 開始生成 PDF 報告: 專案=${pdfData.projectTitle}`); // 生成 PDF const pdfBlob = await generateHTMLPDFReport(pdfData); console.log(`✅ PDF 報告生成完成: 大小=${pdfBlob.size} bytes`); // 返回 PDF 文件 const fileName = `評審報告_${pdfData.projectTitle}_${pdfData.analysisDate}.pdf`; return new NextResponse(pdfBlob, { status: 200, headers: { 'Content-Type': 'application/pdf', 'Content-Disposition': `attachment; filename="${encodeURIComponent(fileName)}"`, 'Content-Length': pdfBlob.size.toString(), }, }); } catch (error) { console.error('❌ 生成 PDF 報告失敗:', error); return NextResponse.json( { success: false, error: '生成 PDF 報告失敗' }, { status: 500 } ); } }