fix: 캘린더 모달 중복 카드 문제 및 삭제 권한 개선
- monthly_worker_status 조회 시 GROUP BY로 중복 데이터 합산 - 작업보고서 삭제 권한을 그룹장 이상으로 제한 (admin, system, group_leader) - 중복 데이터 정리를 위한 마이그레이션 SQL 추가 (009_fix_duplicate_monthly_status.sql) - synology_deployment 버전에도 동일 수정 적용
This commit is contained in:
172
synology_deployment/api/models/monthlyStatusModel.js
Normal file
172
synology_deployment/api/models/monthlyStatusModel.js
Normal file
@@ -0,0 +1,172 @@
|
||||
// models/monthlyStatusModel.js
|
||||
// 월별 작업자 상태 집계 모델
|
||||
|
||||
const { getDb } = require('../dbPool');
|
||||
|
||||
class MonthlyStatusModel {
|
||||
// 월별 일자별 요약 조회 (캘린더용)
|
||||
static async getMonthlySummary(year, month) {
|
||||
const db = await getDb();
|
||||
|
||||
try {
|
||||
const [rows] = await db.execute(`
|
||||
SELECT
|
||||
date,
|
||||
total_workers,
|
||||
working_workers,
|
||||
incomplete_workers,
|
||||
partial_workers,
|
||||
complete_workers,
|
||||
overtime_workers,
|
||||
vacation_workers,
|
||||
error_workers,
|
||||
overtime_warning_workers,
|
||||
total_work_hours,
|
||||
total_work_count,
|
||||
total_error_count,
|
||||
has_issues,
|
||||
has_errors,
|
||||
has_overtime_warning,
|
||||
last_updated
|
||||
FROM monthly_summary
|
||||
WHERE year = ? AND month = ?
|
||||
ORDER BY date ASC
|
||||
`, [year, month]);
|
||||
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('월별 요약 조회 오류:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 특정 날짜의 작업자별 상태 조회 (모달용)
|
||||
static async getDailyWorkerStatus(date) {
|
||||
const db = await getDb();
|
||||
|
||||
try {
|
||||
// 중복 방지: worker_id와 date로 그룹화하고 최신 데이터만 조회
|
||||
const [rows] = await db.execute(`
|
||||
SELECT
|
||||
mws.worker_id,
|
||||
w.worker_name,
|
||||
w.job_type,
|
||||
MAX(mws.year) as year,
|
||||
MAX(mws.month) as month,
|
||||
mws.date,
|
||||
SUM(mws.total_work_hours) as total_work_hours,
|
||||
SUM(mws.actual_work_hours) as actual_work_hours,
|
||||
SUM(mws.vacation_hours) as vacation_hours,
|
||||
SUM(mws.total_work_count) as total_work_count,
|
||||
SUM(mws.regular_work_count) as regular_work_count,
|
||||
SUM(mws.error_work_count) as error_work_count,
|
||||
MAX(mws.work_status) as work_status,
|
||||
MAX(mws.has_vacation) as has_vacation,
|
||||
MAX(mws.has_error) as has_error,
|
||||
MAX(mws.has_issues) as has_issues,
|
||||
MAX(mws.last_updated) as last_updated
|
||||
FROM monthly_worker_status mws
|
||||
JOIN workers w ON mws.worker_id = w.worker_id
|
||||
WHERE mws.date = ?
|
||||
GROUP BY mws.worker_id, mws.date, w.worker_name, w.job_type
|
||||
ORDER BY w.worker_name ASC
|
||||
`, [date]);
|
||||
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('일별 작업자 상태 조회 오류:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 월별 집계 데이터 강제 재계산 (관리용)
|
||||
static async recalculateMonth(year, month) {
|
||||
const db = await getDb();
|
||||
|
||||
try {
|
||||
// 해당 월의 모든 날짜와 작업자 조합을 찾아서 재계산
|
||||
const [workDates] = await db.execute(`
|
||||
SELECT DISTINCT report_date, worker_id
|
||||
FROM daily_work_reports
|
||||
WHERE YEAR(report_date) = ? AND MONTH(report_date) = ?
|
||||
`, [year, month]);
|
||||
|
||||
let updatedCount = 0;
|
||||
|
||||
for (const { report_date, worker_id } of workDates) {
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [report_date, worker_id]);
|
||||
updatedCount++;
|
||||
}
|
||||
|
||||
console.log(`✅ ${year}년 ${month}월 집계 재계산 완료: ${updatedCount}건`);
|
||||
return { success: true, updatedCount };
|
||||
|
||||
} catch (error) {
|
||||
console.error('월별 집계 재계산 오류:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 특정 날짜 집계 강제 업데이트
|
||||
static async updateDateSummary(date, workerId = null) {
|
||||
const db = await getDb();
|
||||
|
||||
try {
|
||||
if (workerId) {
|
||||
// 특정 작업자만 업데이트
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [date, workerId]);
|
||||
} else {
|
||||
// 해당 날짜의 모든 작업자 업데이트
|
||||
const [workers] = await db.execute(`
|
||||
SELECT DISTINCT worker_id
|
||||
FROM daily_work_reports
|
||||
WHERE report_date = ?
|
||||
`, [date]);
|
||||
|
||||
for (const { worker_id } of workers) {
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [date, worker_id]);
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('날짜별 집계 업데이트 오류:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 집계 테이블 상태 확인
|
||||
static async getStatusInfo() {
|
||||
const db = await getDb();
|
||||
|
||||
try {
|
||||
const [summaryCount] = await db.execute(`
|
||||
SELECT
|
||||
COUNT(*) as total_days,
|
||||
MIN(date) as earliest_date,
|
||||
MAX(date) as latest_date,
|
||||
MAX(last_updated) as last_update
|
||||
FROM monthly_summary
|
||||
`);
|
||||
|
||||
const [workerStatusCount] = await db.execute(`
|
||||
SELECT
|
||||
COUNT(*) as total_records,
|
||||
COUNT(DISTINCT worker_id) as unique_workers,
|
||||
COUNT(DISTINCT date) as unique_dates,
|
||||
MAX(last_updated) as last_update
|
||||
FROM monthly_worker_status
|
||||
`);
|
||||
|
||||
return {
|
||||
summary: summaryCount[0],
|
||||
workerStatus: workerStatusCount[0]
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('집계 테이블 상태 확인 오류:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MonthlyStatusModel;
|
||||
Reference in New Issue
Block a user