import { query } from '../../utils/db' import { callOpenAI, buildParseReportPrompt } from '../../utils/openai' const ADMIN_EMAIL = 'coziny@gmail.com' interface ParsedTask { description: string hours: number } interface ParsedProject { projectName: string workTasks: ParsedTask[] planTasks: ParsedTask[] } interface ParsedReport { employeeName: string employeeEmail: string | null projects: ParsedProject[] issueDescription: string | null vacationDescription: string | null remarkDescription: string | null } interface ParsedResult { reportYear: number reportWeek: number weekStartDate: string weekEndDate: string reports: ParsedReport[] } /** * 주간보고 텍스트 분석 (OpenAI) * POST /api/admin/parse-report */ export default defineEventHandler(async (event) => { // 관리자 권한 체크 const userId = getCookie(event, 'user_id') if (!userId) { throw createError({ statusCode: 401, message: '로그인이 필요합니다.' }) } const currentUser = await query(` SELECT employee_email FROM wr_employee_info WHERE employee_id = $1 `, [userId]) if (!currentUser[0] || currentUser[0].employee_email !== ADMIN_EMAIL) { throw createError({ statusCode: 403, message: '관리자만 사용할 수 있습니다.' }) } const body = await readBody<{ rawText: string }>(event) if (!body.rawText || body.rawText.trim().length < 10) { throw createError({ statusCode: 400, message: '분석할 텍스트를 입력해주세요.' }) } // OpenAI 분석 const messages = buildParseReportPrompt(body.rawText) const aiResponse = await callOpenAI(messages, true) let parsed: ParsedResult try { parsed = JSON.parse(aiResponse) } catch (e) { throw createError({ statusCode: 500, message: 'AI 응답 파싱 실패' }) } // 주차 정보 기본값 설정 (AI가 파싱 못한 경우) const now = new Date() if (!parsed.reportYear) { parsed.reportYear = now.getFullYear() } if (!parsed.reportWeek) { // ISO 주차 계산 const startOfYear = new Date(now.getFullYear(), 0, 1) const days = Math.floor((now.getTime() - startOfYear.getTime()) / (24 * 60 * 60 * 1000)) parsed.reportWeek = Math.ceil((days + startOfYear.getDay() + 1) / 7) } if (!parsed.weekStartDate || !parsed.weekEndDate) { // 현재 주의 월요일~일요일 계산 const day = now.getDay() const monday = new Date(now) monday.setDate(now.getDate() - (day === 0 ? 6 : day - 1)) const sunday = new Date(monday) sunday.setDate(monday.getDate() + 6) parsed.weekStartDate = monday.toISOString().split('T')[0] parsed.weekEndDate = sunday.toISOString().split('T')[0] } // 기존 직원 목록 조회 const employees = await query(` SELECT employee_id, employee_name, employee_email FROM wr_employee_info WHERE is_active = true `) // 기존 프로젝트 목록 조회 const projects = await query(` SELECT project_id, project_code, project_name FROM wr_project_info WHERE project_status != 'COMPLETED' `) // 직원 및 프로젝트 매칭 const matchedReports = parsed.reports.map(report => { // 이메일로 정확 매칭 시도 let matchedEmployee = null if (report.employeeEmail) { matchedEmployee = employees.find( (e: any) => e.employee_email.toLowerCase() === report.employeeEmail?.toLowerCase() ) } // 이메일 매칭 실패시 이름으로 매칭 if (!matchedEmployee) { matchedEmployee = employees.find( (e: any) => e.employee_name === report.employeeName ) } // 프로젝트 매칭 const matchedProjects = report.projects.map(proj => { const existingProject = projects.find((p: any) => p.project_name.includes(proj.projectName) || proj.projectName.includes(p.project_name) ) return { ...proj, matchedProjectId: existingProject?.project_id || null, matchedProjectCode: existingProject?.project_code || null, matchedProjectName: existingProject?.project_name || null, isNewProject: !existingProject } }) return { ...report, matchedEmployeeId: matchedEmployee?.employee_id || null, matchedEmployeeName: matchedEmployee?.employee_name || null, matchedEmployeeEmail: matchedEmployee?.employee_email || null, isEmployeeMatched: !!matchedEmployee, isNewEmployee: !matchedEmployee && !!report.employeeEmail, projects: matchedProjects } }) return { success: true, parsed: { reportYear: parsed.reportYear, reportWeek: parsed.reportWeek, weekStartDate: parsed.weekStartDate, weekEndDate: parsed.weekEndDate, reports: matchedReports }, employees: employees.map((e: any) => ({ employeeId: e.employee_id, employeeName: e.employee_name, employeeEmail: e.employee_email })), projects: projects.map((p: any) => ({ projectId: p.project_id, projectCode: p.project_code, projectName: p.project_name })) } })