Files
weeklyreport/backend/api/report/weekly/list.get.ts
2026-01-05 02:00:13 +09:00

166 lines
5.2 KiB
TypeScript

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<any>(`
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.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<any>(`
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]
}