import { query } from '../../../utils/db' const ADMIN_EMAIL = 'coziny@gmail.com' /** * 주간보고 목록 조회 (필터링 지원) * GET /api/report/weekly/list * * Query params: * - authorId: 작성자 ID * - projectId: 프로젝트 ID * - year: 연도 * - weekFrom: 시작 주차 * - weekTo: 종료 주차 * - startDate: 시작일 (YYYY-MM-DD) * - endDate: 종료일 (YYYY-MM-DD) * - status: 상태 (DRAFT, SUBMITTED, AGGREGATED) * - viewAll: 전체 조회 (관리자만) * - limit: 조회 개수 (기본 100) */ 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]) const isAdmin = currentUser[0]?.employee_email === ADMIN_EMAIL const q = getQuery(event) const limit = parseInt(q.limit as string) || 100 const viewAll = q.viewAll === 'true' // 필터 조건 구성 const conditions: string[] = [] const params: any[] = [] let paramIndex = 1 // 관리자가 viewAll이면 전체 조회, 아니면 본인 것만 if (!isAdmin || !viewAll) { // 작성자 필터 (본인 또는 지정된 작성자) if (q.authorId) { conditions.push(`r.author_id = $${paramIndex++}`) params.push(q.authorId) } else if (!isAdmin) { // 관리자가 아니면 본인 것만 conditions.push(`r.author_id = $${paramIndex++}`) params.push(userId) } } else if (q.authorId) { // 관리자가 viewAll이어도 작성자 필터가 있으면 적용 conditions.push(`r.author_id = $${paramIndex++}`) params.push(q.authorId) } // 프로젝트 필터 if (q.projectId) { conditions.push(`EXISTS ( SELECT 1 FROM wr_weekly_report_project wrp WHERE wrp.report_id = r.report_id AND wrp.project_id = $${paramIndex++} )`) params.push(q.projectId) } // 연도 필터 if (q.year) { conditions.push(`r.report_year = $${paramIndex++}`) params.push(q.year) } // 주차 필터 (단일) if (q.week) { conditions.push(`r.report_week = $${paramIndex++}`) params.push(q.week) } // 주차 범위 필터 if (q.weekFrom) { conditions.push(`r.report_week >= $${paramIndex++}`) params.push(q.weekFrom) } if (q.weekTo) { conditions.push(`r.report_week <= $${paramIndex++}`) params.push(q.weekTo) } // 날짜 범위 필터 if (q.startDate) { conditions.push(`r.week_start_date >= $${paramIndex++}`) params.push(q.startDate) } if (q.endDate) { conditions.push(`r.week_end_date <= $${paramIndex++}`) params.push(q.endDate) } // 상태 필터 if (q.status) { conditions.push(`r.report_status = $${paramIndex++}`) params.push(q.status) } const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '' params.push(limit) const reports = await query(` SELECT r.report_id, r.author_id, e.employee_name as author_name, e.employee_email as author_email, r.report_year, r.report_week, r.week_start_date, r.week_end_date, r.issue_description, r.vacation_description, r.report_status, r.submitted_at, r.created_at, (SELECT COUNT(DISTINCT project_id) FROM wr_weekly_report_task WHERE report_id = r.report_id) as project_count, (SELECT string_agg(DISTINCT p.project_name, ', ') FROM wr_weekly_report_task t JOIN wr_project_info p ON t.project_id = p.project_id WHERE t.report_id = r.report_id) as project_names, (SELECT COALESCE(SUM(task_hours), 0) FROM wr_weekly_report_task WHERE report_id = r.report_id AND task_type = 'WORK') as total_work_hours, (SELECT COALESCE(SUM(task_hours), 0) FROM wr_weekly_report_task WHERE report_id = r.report_id AND task_type = 'PLAN') as total_plan_hours FROM wr_weekly_report r JOIN wr_employee_info e ON r.author_id = e.employee_id ${whereClause} ORDER BY r.report_year DESC, r.report_week DESC, e.employee_name LIMIT $${paramIndex} `, params) return { isAdmin, reports: reports.map((r: any) => ({ reportId: r.report_id, authorId: r.author_id, authorName: r.author_name, authorEmail: r.author_email, reportYear: r.report_year, reportWeek: r.report_week, weekStartDate: formatDateOnly(r.week_start_date), weekEndDate: formatDateOnly(r.week_end_date), issueDescription: r.issue_description, vacationDescription: r.vacation_description, reportStatus: r.report_status, submittedAt: r.submitted_at, createdAt: r.created_at, projectCount: parseInt(r.project_count), projectNames: r.project_names, totalWorkHours: parseFloat(r.total_work_hours) || 0, totalPlanHours: parseFloat(r.total_plan_hours) || 0 })) } }) // 날짜를 YYYY-MM-DD 형식으로 변환 (타임존 보정) function formatDateOnly(date: Date | string | null): string { if (!date) return '' const d = new Date(date) // 한국 시간 기준으로 날짜만 추출 const kstOffset = 9 * 60 * 60 * 1000 const kstDate = new Date(d.getTime() + kstOffset) return kstDate.toISOString().split('T')[0] }