166 lines
5.2 KiB
TypeScript
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]
|
|
}
|