import { query, queryOne, insertReturning, execute } from '../../utils/db' import { getClientIp } from '../../utils/ip' const ADMIN_EMAIL = 'coziny@gmail.com' interface ProjectInput { projectId: number | null // null이면 신규 생성 projectName: string workDescription: string | null planDescription: string | null } interface ReportInput { employeeId: number projects: ProjectInput[] issueDescription: string | null vacationDescription: string | null remarkDescription: string | null } interface BulkRegisterBody { reportYear: number reportWeek: number weekStartDate: string weekEndDate: string reports: ReportInput[] } /** * 주간보고 일괄 등록 * POST /api/admin/bulk-register */ export default defineEventHandler(async (event) => { // 관리자 권한 체크 const userId = getCookie(event, 'user_id') if (!userId) { throw createError({ statusCode: 401, message: '로그인이 필요합니다.' }) } const currentUser = await queryOne(` SELECT employee_email FROM wr_employee_info WHERE employee_id = $1 `, [userId]) if (!currentUser || currentUser.employee_email !== ADMIN_EMAIL) { throw createError({ statusCode: 403, message: '관리자만 사용할 수 있습니다.' }) } const body = await readBody(event) const clientIp = getClientIp(event) if (!body.reports || body.reports.length === 0) { throw createError({ statusCode: 400, message: '등록할 보고서가 없습니다.' }) } const results: any[] = [] for (const report of body.reports) { try { // 1. 프로젝트 처리 (신규 생성 또는 기존 사용) const projectIds: number[] = [] for (const proj of report.projects) { let projectId = proj.projectId if (!projectId) { // 신규 프로젝트 생성 const year = new Date().getFullYear() const lastProject = await queryOne(` SELECT project_code FROM wr_project_info WHERE project_code LIKE $1 ORDER BY project_code DESC LIMIT 1 `, [`${year}-%`]) let nextNum = 1 if (lastProject?.project_code) { const lastNum = parseInt(lastProject.project_code.split('-')[1]) || 0 nextNum = lastNum + 1 } const newCode = `${year}-${String(nextNum).padStart(3, '0')}` const newProject = await insertReturning(` INSERT INTO wr_project_info ( project_code, project_name, project_type, created_ip, created_email, updated_ip, updated_email ) VALUES ($1, $2, 'SI', $3, $4, $3, $4) RETURNING project_id `, [newCode, proj.projectName, clientIp, ADMIN_EMAIL]) projectId = newProject.project_id } projectIds.push(projectId) } // 2. 기존 주간보고 확인 (덮어쓰기) const existingReport = await queryOne(` SELECT report_id FROM wr_weekly_report WHERE author_id = $1 AND report_year = $2 AND report_week = $3 `, [report.employeeId, body.reportYear, body.reportWeek]) let reportId: number if (existingReport) { // 기존 보고서 업데이트 reportId = existingReport.report_id // 기존 프로젝트 실적 삭제 await execute(`DELETE FROM wr_weekly_report_project WHERE report_id = $1`, [reportId]) // 마스터 업데이트 await execute(` UPDATE wr_weekly_report SET issue_description = $1, vacation_description = $2, remark_description = $3, report_status = 'SUBMITTED', submitted_at = NOW(), updated_at = NOW(), updated_ip = $4, updated_email = $5 WHERE report_id = $6 `, [ report.issueDescription, report.vacationDescription, report.remarkDescription, clientIp, ADMIN_EMAIL, reportId ]) } else { // 신규 보고서 생성 const newReport = await insertReturning(` INSERT INTO wr_weekly_report ( author_id, report_year, report_week, week_start_date, week_end_date, issue_description, vacation_description, remark_description, report_status, submitted_at, created_ip, created_email, updated_ip, updated_email ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'SUBMITTED', NOW(), $9, $10, $9, $10) RETURNING report_id `, [ report.employeeId, body.reportYear, body.reportWeek, body.weekStartDate, body.weekEndDate, report.issueDescription, report.vacationDescription, report.remarkDescription, clientIp, ADMIN_EMAIL ]) reportId = newReport.report_id } // 3. 프로젝트별 실적 등록 for (let i = 0; i < report.projects.length; i++) { const proj = report.projects[i] const projectId = projectIds[i] await execute(` INSERT INTO wr_weekly_report_project ( report_id, project_id, work_description, plan_description, created_ip, created_email, updated_ip, updated_email ) VALUES ($1, $2, $3, $4, $5, $6, $5, $6) `, [ reportId, projectId, proj.workDescription, proj.planDescription, clientIp, ADMIN_EMAIL ]) } // 직원 정보 조회 const employee = await queryOne(` SELECT employee_name FROM wr_employee_info WHERE employee_id = $1 `, [report.employeeId]) results.push({ success: true, employeeId: report.employeeId, employeeName: employee?.employee_name, reportId, isUpdate: !!existingReport }) } catch (err: any) { results.push({ success: false, employeeId: report.employeeId, error: err.message }) } } return { success: true, totalCount: body.reports.length, successCount: results.filter(r => r.success).length, results } })