sso_users.user_id를 단일 식별자로 통합. JWT에서 worker_id 제거, department_id/is_production 추가. 백엔드 15개 모델, 11개 컨트롤러, 4개 서비스, 7개 라우트, 프론트엔드 32+ JS/11+ HTML 변환. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
115 lines
3.7 KiB
JavaScript
115 lines
3.7 KiB
JavaScript
// /models/analysisModel.js
|
|
const { getDb } = require('../dbPool');
|
|
|
|
/**
|
|
* 지정된 기간 동안의 작업 보고서 데이터를 집계하여 분석합니다.
|
|
* 이 함수는 여러 개의 SQL 쿼리를 병렬로 실행하여 효율성을 높입니다.
|
|
* @param {string} startDate - 시작일 (YYYY-MM-DD)
|
|
* @param {string} endDate - 종료일 (YYYY-MM-DD)
|
|
* @returns {Promise<object>} - 요약, 프로젝트별, 작업자별, 작업별 집계 데이터 및 상세 내역
|
|
*/
|
|
const getAnalysis = async (startDate, endDate) => {
|
|
try {
|
|
const db = await getDb();
|
|
|
|
// SQL 쿼리에서 반복적으로 사용될 WHERE 조건과 실제 투입 시간 계산 로직
|
|
const whereClause = `WHERE dwr.report_date BETWEEN ? AND ?`;
|
|
const workHoursCalc = `
|
|
CASE dwr.work_details
|
|
WHEN '연차' THEN 0 WHEN '반차' THEN 4 WHEN '반반차' THEN 6
|
|
WHEN '조퇴' THEN 2 WHEN '휴무' THEN 0 WHEN '유급' THEN 0
|
|
ELSE 8
|
|
END + (COALESCE(dwr.overtime_hours, 0) * 1.5)
|
|
`;
|
|
|
|
// 1. 요약 정보 쿼리
|
|
const summarySql = `
|
|
SELECT
|
|
COUNT(DISTINCT dwr.project_id) as totalProjects,
|
|
COUNT(DISTINCT dwr.user_id) as totalworkers,
|
|
COUNT(DISTINCT dwr.task_id) as totalTasks,
|
|
SUM(${workHoursCalc}) as totalHours
|
|
FROM DailyWorkReports dwr
|
|
${whereClause} AND (${workHoursCalc}) > 0
|
|
`;
|
|
|
|
// 2. 프로젝트별 집계 쿼리
|
|
const byProjectSql = `
|
|
SELECT p.project_name as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.user_id) as participants
|
|
FROM DailyWorkReports dwr
|
|
JOIN projects p ON dwr.project_id = p.project_id
|
|
${whereClause}
|
|
GROUP BY p.project_name
|
|
HAVING hours > 0
|
|
ORDER BY hours DESC;
|
|
`;
|
|
|
|
// 3. 작업자별 집계 쿼리
|
|
const byWorkerSql = `
|
|
SELECT w.worker_name as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.project_id) as participants
|
|
FROM DailyWorkReports dwr
|
|
JOIN workers w ON dwr.user_id = w.user_id
|
|
${whereClause}
|
|
GROUP BY w.worker_name
|
|
HAVING hours > 0
|
|
ORDER BY hours DESC;
|
|
`;
|
|
|
|
// 4. 작업별 집계 쿼리
|
|
const byTaskSql = `
|
|
SELECT t.category as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.user_id) as participants
|
|
FROM DailyWorkReports dwr
|
|
JOIN Tasks t ON dwr.task_id = t.task_id
|
|
${whereClause}
|
|
GROUP BY t.category
|
|
HAVING hours > 0
|
|
ORDER BY hours DESC;
|
|
`;
|
|
|
|
// 5. 상세 내역 쿼리
|
|
const detailsSql = `
|
|
SELECT
|
|
dwr.report_date as date, p.project_name, w.worker_name,
|
|
t.category as task_category, dwr.work_details,
|
|
(${workHoursCalc}) as work_hours, dwr.memo
|
|
FROM DailyWorkReports dwr
|
|
JOIN projects p ON dwr.project_id = p.project_id
|
|
JOIN workers w ON dwr.user_id = w.user_id
|
|
JOIN Tasks t ON dwr.task_id = t.task_id
|
|
${whereClause}
|
|
HAVING work_hours > 0
|
|
ORDER BY dwr.report_date DESC;
|
|
`;
|
|
|
|
// 모든 쿼리를 병렬로 실행
|
|
const [
|
|
[summaryResult],
|
|
[byProject],
|
|
[byWorker],
|
|
[byTask],
|
|
[details]
|
|
] = await Promise.all([
|
|
db.query(summarySql, [startDate, endDate]),
|
|
db.query(byProjectSql, [startDate, endDate]),
|
|
db.query(byWorkerSql, [startDate, endDate]),
|
|
db.query(byTaskSql, [startDate, endDate]),
|
|
db.query(detailsSql, [startDate, endDate])
|
|
]);
|
|
|
|
return {
|
|
summary: summaryResult[0],
|
|
byProject,
|
|
byWorker,
|
|
byTask,
|
|
details
|
|
};
|
|
|
|
} catch (err) {
|
|
console.error('[Model] 분석 데이터 조회 오류:', err);
|
|
throw new Error('데이터베이스에서 분석 데이터를 조회하는 중 오류가 발생했습니다.');
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
getAnalysis
|
|
};
|