- 월별 캘린더 UI로 작업 현황을 한눈에 확인 가능 - 미입력(빨강), 부분입력(주황), 확인필요(보라), 이상없음(초록) 상태 표시 - 범례 아이콘(●)을 사용한 직관적인 상태 표시 - 날짜 클릭 시 해당일 작업자별 상세 현황 모달 - 작업자 클릭 시 개별 작업 입력/수정 모달 - 휴가 처리 기능 (연차, 반차, 반반차, 조퇴) - 월별 집계 데이터 최적화로 API 호출 최소화 백엔드: - monthly_worker_status, monthly_summary 테이블 추가 - 자동 집계 stored procedure 및 trigger 구현 - 확인필요(12시간 초과) 상태 감지 로직 - 출석 관리 시스템 확장 프론트엔드: - 캘린더 그리드 UI 구현 - 상태별 색상 및 아이콘 표시 - 모달 기반 상세 정보 표시 - 반응형 디자인 적용
250 lines
9.7 KiB
SQL
250 lines
9.7 KiB
SQL
-- 007_create_monthly_worker_status.sql
|
|
-- 월별 작업자 상태 집계 테이블 생성
|
|
|
|
-- 월별 작업자 상태 집계 테이블
|
|
CREATE TABLE IF NOT EXISTS monthly_worker_status (
|
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
year INT NOT NULL COMMENT '연도',
|
|
month INT NOT NULL COMMENT '월 (1-12)',
|
|
worker_id INT NOT NULL COMMENT '작업자 ID',
|
|
date DATE NOT NULL COMMENT '날짜',
|
|
|
|
-- 작업 시간 정보
|
|
total_work_hours DECIMAL(5,2) DEFAULT 0.00 COMMENT '총 작업시간',
|
|
actual_work_hours DECIMAL(5,2) DEFAULT 0.00 COMMENT '실제 작업시간 (휴가 제외)',
|
|
vacation_hours DECIMAL(5,2) DEFAULT 0.00 COMMENT '휴가 시간',
|
|
|
|
-- 작업 건수
|
|
total_work_count INT DEFAULT 0 COMMENT '총 작업 건수',
|
|
regular_work_count INT DEFAULT 0 COMMENT '정규 작업 건수',
|
|
error_work_count INT DEFAULT 0 COMMENT '오류 작업 건수',
|
|
|
|
-- 상태 정보
|
|
work_status ENUM(
|
|
'incomplete', -- 미입력 (0시간)
|
|
'partial', -- 부분입력 (8시간 미만)
|
|
'complete', -- 정시근로 (8시간)
|
|
'overtime', -- 연장근로 (8시간 초과)
|
|
'vacation-full', -- 연차 (8시간)
|
|
'vacation-half', -- 반차 (4시간)
|
|
'vacation-quarter',-- 반반차 (2시간)
|
|
'vacation-half-half', -- 조퇴 (6시간)
|
|
'error', -- 오류 발생
|
|
'overtime-warning' -- 초과근무 확인필요 (12시간 초과)
|
|
) NOT NULL DEFAULT 'incomplete' COMMENT '작업 상태',
|
|
|
|
has_vacation BOOLEAN DEFAULT FALSE COMMENT '휴가 여부',
|
|
has_error BOOLEAN DEFAULT FALSE COMMENT '오류 여부',
|
|
has_issues BOOLEAN DEFAULT FALSE COMMENT '문제 여부 (미입력/부분입력)',
|
|
|
|
-- 메타 정보
|
|
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '마지막 업데이트 시간',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- 인덱스
|
|
UNIQUE KEY unique_worker_date (worker_id, date),
|
|
KEY idx_year_month (year, month),
|
|
KEY idx_worker_year_month (worker_id, year, month),
|
|
KEY idx_status (work_status),
|
|
KEY idx_has_issues (has_issues),
|
|
KEY idx_has_error (has_error),
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (worker_id) REFERENCES workers(worker_id) ON DELETE CASCADE
|
|
) COMMENT='월별 작업자 상태 집계 테이블';
|
|
|
|
-- 월별 집계 요약 테이블 (캘린더 최적화용)
|
|
CREATE TABLE IF NOT EXISTS monthly_summary (
|
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
year INT NOT NULL COMMENT '연도',
|
|
month INT NOT NULL COMMENT '월 (1-12)',
|
|
date DATE NOT NULL COMMENT '날짜',
|
|
|
|
-- 작업자 수
|
|
total_workers INT DEFAULT 0 COMMENT '총 작업자 수',
|
|
working_workers INT DEFAULT 0 COMMENT '작업한 작업자 수',
|
|
|
|
-- 상태별 작업자 수
|
|
incomplete_workers INT DEFAULT 0 COMMENT '미입력 작업자 수',
|
|
partial_workers INT DEFAULT 0 COMMENT '부분입력 작업자 수',
|
|
complete_workers INT DEFAULT 0 COMMENT '완료 작업자 수',
|
|
overtime_workers INT DEFAULT 0 COMMENT '연장근로 작업자 수',
|
|
vacation_workers INT DEFAULT 0 COMMENT '휴가 작업자 수',
|
|
error_workers INT DEFAULT 0 COMMENT '오류 작업자 수',
|
|
|
|
-- 집계 정보
|
|
total_work_hours DECIMAL(8,2) DEFAULT 0.00 COMMENT '총 작업시간',
|
|
total_work_count INT DEFAULT 0 COMMENT '총 작업 건수',
|
|
total_error_count INT DEFAULT 0 COMMENT '총 오류 건수',
|
|
|
|
-- 상태 플래그 (캘린더 표시용)
|
|
has_issues BOOLEAN DEFAULT FALSE COMMENT '문제 있음 (미입력/부분입력)',
|
|
has_errors BOOLEAN DEFAULT FALSE COMMENT '오류 있음',
|
|
|
|
-- 메타 정보
|
|
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- 인덱스
|
|
UNIQUE KEY unique_date (date),
|
|
KEY idx_year_month (year, month),
|
|
KEY idx_has_issues (has_issues),
|
|
KEY idx_has_errors (has_errors)
|
|
) COMMENT='월별 일자별 요약 테이블 (캘린더 최적화용)';
|
|
|
|
-- 집계 데이터 업데이트 함수
|
|
DELIMITER $$
|
|
|
|
CREATE OR REPLACE PROCEDURE UpdateMonthlyWorkerStatus(
|
|
IN p_date DATE,
|
|
IN p_worker_id INT
|
|
)
|
|
BEGIN
|
|
DECLARE v_year INT;
|
|
DECLARE v_month INT;
|
|
DECLARE v_total_hours DECIMAL(5,2);
|
|
DECLARE v_actual_hours DECIMAL(5,2);
|
|
DECLARE v_vacation_hours DECIMAL(5,2);
|
|
DECLARE v_total_count INT;
|
|
DECLARE v_regular_count INT;
|
|
DECLARE v_error_count INT;
|
|
DECLARE v_has_vacation BOOLEAN;
|
|
DECLARE v_has_error BOOLEAN;
|
|
DECLARE v_has_issues BOOLEAN;
|
|
DECLARE v_status VARCHAR(20);
|
|
|
|
-- 연도, 월 추출
|
|
SET v_year = YEAR(p_date);
|
|
SET v_month = MONTH(p_date);
|
|
|
|
-- 해당 날짜의 작업자 데이터 집계
|
|
SELECT
|
|
COALESCE(SUM(work_hours), 0),
|
|
COALESCE(SUM(CASE WHEN project_id != 13 THEN work_hours ELSE 0 END), 0),
|
|
COALESCE(SUM(CASE WHEN project_id = 13 THEN work_hours ELSE 0 END), 0),
|
|
COUNT(*),
|
|
COUNT(CASE WHEN project_id != 13 AND work_status_id != 2 THEN 1 END),
|
|
COUNT(CASE WHEN work_status_id = 2 THEN 1 END),
|
|
MAX(CASE WHEN project_id = 13 THEN 1 ELSE 0 END),
|
|
MAX(CASE WHEN work_status_id = 2 THEN 1 ELSE 0 END)
|
|
INTO
|
|
v_total_hours, v_actual_hours, v_vacation_hours,
|
|
v_total_count, v_regular_count, v_error_count,
|
|
v_has_vacation, v_has_error
|
|
FROM daily_work_reports
|
|
WHERE report_date = p_date AND worker_id = p_worker_id;
|
|
|
|
-- 상태 결정 로직
|
|
IF v_has_error THEN
|
|
SET v_status = 'error';
|
|
SET v_has_issues = FALSE;
|
|
ELSEIF v_total_hours > 12 THEN
|
|
SET v_status = 'overtime-warning';
|
|
SET v_has_issues = TRUE;
|
|
ELSEIF v_has_vacation AND v_vacation_hours > 0 THEN
|
|
-- 휴가 상태 결정
|
|
CASE v_vacation_hours
|
|
WHEN 8 THEN SET v_status = 'vacation-full';
|
|
WHEN 6 THEN SET v_status = 'vacation-half-half';
|
|
WHEN 4 THEN SET v_status = 'vacation-half';
|
|
WHEN 2 THEN SET v_status = 'vacation-quarter';
|
|
ELSE SET v_status = 'vacation-full';
|
|
END CASE;
|
|
SET v_has_issues = FALSE;
|
|
ELSEIF v_total_hours > 8 THEN
|
|
SET v_status = 'overtime';
|
|
SET v_has_issues = FALSE;
|
|
ELSEIF v_total_hours = 8 THEN
|
|
SET v_status = 'complete';
|
|
SET v_has_issues = FALSE;
|
|
ELSEIF v_total_hours > 0 THEN
|
|
SET v_status = 'partial';
|
|
SET v_has_issues = TRUE;
|
|
ELSE
|
|
SET v_status = 'incomplete';
|
|
SET v_has_issues = TRUE;
|
|
END IF;
|
|
|
|
-- 데이터 업서트
|
|
INSERT INTO monthly_worker_status (
|
|
year, month, worker_id, date,
|
|
total_work_hours, actual_work_hours, vacation_hours,
|
|
total_work_count, regular_work_count, error_work_count,
|
|
work_status, has_vacation, has_error, has_issues
|
|
) VALUES (
|
|
v_year, v_month, p_worker_id, p_date,
|
|
v_total_hours, v_actual_hours, v_vacation_hours,
|
|
v_total_count, v_regular_count, v_error_count,
|
|
v_status, v_has_vacation, v_has_error, v_has_issues
|
|
) ON DUPLICATE KEY UPDATE
|
|
total_work_hours = v_total_hours,
|
|
actual_work_hours = v_actual_hours,
|
|
vacation_hours = v_vacation_hours,
|
|
total_work_count = v_total_count,
|
|
regular_work_count = v_regular_count,
|
|
error_work_count = v_error_count,
|
|
work_status = v_status,
|
|
has_vacation = v_has_vacation,
|
|
has_error = v_has_error,
|
|
has_issues = v_has_issues,
|
|
last_updated = CURRENT_TIMESTAMP;
|
|
|
|
-- 일별 요약도 업데이트
|
|
CALL UpdateDailySummary(p_date);
|
|
END$$
|
|
|
|
-- 일별 요약 업데이트 함수
|
|
CREATE OR REPLACE PROCEDURE UpdateDailySummary(
|
|
IN p_date DATE
|
|
)
|
|
BEGIN
|
|
DECLARE v_year INT;
|
|
DECLARE v_month INT;
|
|
|
|
SET v_year = YEAR(p_date);
|
|
SET v_month = MONTH(p_date);
|
|
|
|
INSERT INTO monthly_summary (
|
|
year, month, date,
|
|
total_workers, working_workers,
|
|
incomplete_workers, partial_workers, complete_workers,
|
|
overtime_workers, vacation_workers, error_workers,
|
|
total_work_hours, total_work_count, total_error_count,
|
|
has_issues, has_errors
|
|
)
|
|
SELECT
|
|
v_year, v_month, p_date,
|
|
COUNT(*) as total_workers,
|
|
COUNT(CASE WHEN work_status != 'incomplete' THEN 1 END) as working_workers,
|
|
COUNT(CASE WHEN work_status = 'incomplete' THEN 1 END) as incomplete_workers,
|
|
COUNT(CASE WHEN work_status = 'partial' THEN 1 END) as partial_workers,
|
|
COUNT(CASE WHEN work_status IN ('complete') THEN 1 END) as complete_workers,
|
|
COUNT(CASE WHEN work_status = 'overtime' THEN 1 END) as overtime_workers,
|
|
COUNT(CASE WHEN work_status LIKE 'vacation%' THEN 1 END) as vacation_workers,
|
|
COUNT(CASE WHEN work_status = 'error' THEN 1 END) as error_workers,
|
|
SUM(total_work_hours) as total_work_hours,
|
|
SUM(total_work_count) as total_work_count,
|
|
SUM(error_work_count) as total_error_count,
|
|
MAX(has_issues) as has_issues,
|
|
MAX(has_error) as has_errors
|
|
FROM monthly_worker_status
|
|
WHERE date = p_date
|
|
ON DUPLICATE KEY UPDATE
|
|
total_workers = VALUES(total_workers),
|
|
working_workers = VALUES(working_workers),
|
|
incomplete_workers = VALUES(incomplete_workers),
|
|
partial_workers = VALUES(partial_workers),
|
|
complete_workers = VALUES(complete_workers),
|
|
overtime_workers = VALUES(overtime_workers),
|
|
vacation_workers = VALUES(vacation_workers),
|
|
error_workers = VALUES(error_workers),
|
|
total_work_hours = VALUES(total_work_hours),
|
|
total_work_count = VALUES(total_work_count),
|
|
total_error_count = VALUES(total_error_count),
|
|
has_issues = VALUES(has_issues),
|
|
has_errors = VALUES(has_errors),
|
|
last_updated = CURRENT_TIMESTAMP;
|
|
END$$
|
|
|
|
DELIMITER ;
|