import { query, queryOne, insertReturning, execute } from '../../utils/db' import { callOpenAI } from '../../utils/openai' import { getCurrentUserId } from '../../utils/user' interface GenerateBody { businessId: number reportYear: number reportWeek: number weekStartDate: string weekEndDate: string } /** * 사업 주간보고 취합 생성 * POST /api/business-report/generate */ export default defineEventHandler(async (event) => { const body = await readBody(event) const userId = await getCurrentUserId(event) if (!body.businessId || !body.reportYear || !body.reportWeek) { throw createError({ statusCode: 400, message: '필수 파라미터가 누락되었습니다.' }) } // 기존 보고서 확인 const existing = await queryOne(` SELECT * FROM wr_business_weekly_report WHERE business_id = $1 AND report_year = $2 AND report_week = $3 `, [body.businessId, body.reportYear, body.reportWeek]) // 사업에 속한 프로젝트 목록 const projects = await query(` SELECT project_id, project_name FROM wr_project_info WHERE business_id = $1 `, [body.businessId]) if (projects.length === 0) { throw createError({ statusCode: 400, message: '해당 사업에 속한 프로젝트가 없습니다.' }) } const projectIds = projects.map((p: any) => p.project_id) // 해당 주차 주간보고 실적 조회 const tasks = await query(` SELECT t.task_description, t.task_type, t.task_hours, p.project_name, e.employee_name FROM wr_weekly_report_task t JOIN wr_weekly_report r ON t.report_id = r.report_id JOIN wr_project_info p ON t.project_id = p.project_id JOIN wr_employee_info e ON r.author_id = e.employee_id WHERE t.project_id = ANY($1) AND r.report_year = $2 AND r.report_week = $3 ORDER BY p.project_name, e.employee_name `, [projectIds, body.reportYear, body.reportWeek]) if (tasks.length === 0) { throw createError({ statusCode: 400, message: '해당 주차에 등록된 실적이 없습니다.' }) } // 프로젝트별로 그룹화 const groupedTasks: Record = {} for (const task of tasks) { const key = task.project_name if (!groupedTasks[key]) groupedTasks[key] = [] groupedTasks[key].push(task) } // OpenAI 프롬프트 생성 let taskText = '' for (const [projectName, projectTasks] of Object.entries(groupedTasks)) { taskText += `\n[${projectName}]\n` for (const t of projectTasks) { taskText += `- ${t.employee_name}: ${t.task_description}\n` } } const prompt = `다음은 사업의 주간 실적입니다. 이를 경영진에게 보고하기 위한 간결한 요약문을 작성해주세요. ${taskText} 요약 작성 가이드: 1. 프로젝트별로 구분하여 작성 2. 핵심 성과와 진행 상황 중심 3. 한국어로 작성 4. 불릿 포인트 형식 5. 200자 이내로 간결하게 JSON 형식으로 응답해주세요: { "summary": "요약 내용" }` let aiSummary = '' try { const response = await callOpenAI([ { role: 'system', content: '당신은 프로젝트 관리 전문가입니다. 주간 실적을 간결하게 요약합니다.' }, { role: 'user', content: prompt } ], true) const parsed = JSON.parse(response) aiSummary = parsed.summary || response } catch (e) { console.error('OpenAI error:', e) aiSummary = '(AI 요약 생성 실패)' } let result if (existing) { // 업데이트 await execute(` UPDATE wr_business_weekly_report SET ai_summary = $1, updated_at = NOW() WHERE business_report_id = $2 `, [aiSummary, existing.business_report_id]) result = { ...existing, ai_summary: aiSummary } } else { // 신규 생성 result = await insertReturning(` INSERT INTO wr_business_weekly_report ( business_id, report_year, report_week, week_start_date, week_end_date, ai_summary, status, created_by ) VALUES ($1, $2, $3, $4, $5, $6, 'draft', $7) RETURNING * `, [ body.businessId, body.reportYear, body.reportWeek, body.weekStartDate, body.weekEndDate, aiSummary, userId ]) } return { success: true, report: { businessReportId: result.business_report_id, aiSummary: result.ai_summary || aiSummary, status: result.status || 'draft' } } })