Files
TK-FB-Project/web-ui/pages/common/daily-work-report-viewer.html
Hyungi Ahn 746e09420b feat: 캘린더 기반 작업 현황 확인 시스템 구현
- 월별 캘린더 UI로 작업 현황을 한눈에 확인 가능
- 미입력(빨강), 부분입력(주황), 확인필요(보라), 이상없음(초록) 상태 표시
- 범례 아이콘(●)을 사용한 직관적인 상태 표시
- 날짜 클릭 시 해당일 작업자별 상세 현황 모달
- 작업자 클릭 시 개별 작업 입력/수정 모달
- 휴가 처리 기능 (연차, 반차, 반반차, 조퇴)
- 월별 집계 데이터 최적화로 API 호출 최소화

백엔드:
- monthly_worker_status, monthly_summary 테이블 추가
- 자동 집계 stored procedure 및 trigger 구현
- 확인필요(12시간 초과) 상태 감지 로직
- 출석 관리 시스템 확장

프론트엔드:
- 캘린더 그리드 UI 구현
- 상태별 색상 및 아이콘 표시
- 모달 기반 상세 정보 표시
- 반응형 디자인 적용
2025-11-04 10:12:07 +09:00

286 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>작업 현황 확인 - TK 건설</title>
<link rel="stylesheet" href="/css/common.css?v=13">
<link rel="stylesheet" href="/css/modern-dashboard.css?v=13">
<link rel="stylesheet" href="/css/work-report-calendar.css?v=22">
</head>
<body>
<!-- 대시보드 헤더 -->
<header class="dashboard-header">
<div class="header-content">
<div class="header-left">
<div class="brand">
<img src="/img/logo.png" alt="테크니컬코리아" class="brand-logo">
<div class="brand-text">
<h1 class="brand-title">테크니컬코리아</h1>
<p class="brand-subtitle">작업 현황 확인</p>
</div>
</div>
</div>
<div class="header-center">
<div class="current-time" id="currentTime">
<span class="time-label">현재 시각</span>
<span class="time-value" id="timeValue">--:--:--</span>
</div>
</div>
<div class="header-right">
<div class="user-profile" id="userProfile">
<div class="user-avatar">
<span class="avatar-text" id="userInitial"></span>
</div>
<div class="user-info">
<span class="user-name" id="userName">사용자</span>
<span class="user-role" id="userRole">작업자</span>
</div>
<div class="profile-menu" id="profileMenu">
<a href="/pages/profile/my-profile.html" class="menu-item">
<span class="menu-icon">👤</span>
내 프로필
</a>
<a href="/pages/profile/change-password.html" class="menu-item">
<span class="menu-icon">🔐</span>
비밀번호 변경
</a>
<a href="/pages/dashboard/group-leader.html" class="menu-item">
<span class="menu-icon">📊</span>
대시보드
</a>
<button class="menu-item logout-btn" id="logoutBtn">
<span class="menu-icon">🚪</span>
로그아웃
</button>
</div>
</div>
</div>
</div>
</header>
<!-- 메인 콘텐츠 -->
<main class="dashboard-main">
<div class="calendar-page-container">
<!-- 페이지 제목 -->
<div class="page-title-section">
<h2 class="page-title">📅 작업 현황 확인</h2>
<p class="page-subtitle">월별 작업자 현황을 한눈에 확인하세요</p>
</div>
<!-- 캘린더 카드 -->
<div class="calendar-card">
<!-- 월 네비게이션 -->
<div class="calendar-nav">
<button id="prevMonthBtn" class="nav-btn prev-btn">
<span class="nav-icon"></span>
<span class="nav-text">이전</span>
</button>
<div class="calendar-title">
<h3 id="monthYearTitle">2025년 11월</h3>
<button id="todayBtn" class="today-btn">오늘</button>
</div>
<button id="nextMonthBtn" class="nav-btn next-btn">
<span class="nav-text">다음</span>
<span class="nav-icon"></span>
</button>
</div>
<!-- 범례 -->
<div class="calendar-legend">
<div class="legend-item">
<div class="legend-dot has-overtime-warning"></div>
<span>확인필요</span>
</div>
<div class="legend-item">
<div class="legend-dot has-errors"></div>
<span>미입력</span>
</div>
<div class="legend-item">
<div class="legend-dot has-issues"></div>
<span>부분입력</span>
</div>
<div class="legend-item">
<div class="legend-dot has-normal"></div>
<span>이상 없음</span>
</div>
</div>
<!-- 캘린더 -->
<div class="calendar-grid">
<div class="calendar-header">
<div class="day-header sunday"></div>
<div class="day-header"></div>
<div class="day-header"></div>
<div class="day-header"></div>
<div class="day-header"></div>
<div class="day-header"></div>
<div class="day-header saturday"></div>
</div>
<div class="calendar-days" id="calendarDays">
<!-- 캘린더 날짜들이 여기에 동적으로 생성됩니다 -->
</div>
</div>
</div>
</div>
</main>
<!-- 로딩 스피너 -->
<div id="loadingSpinner" class="loading-overlay" style="display: none;">
<div class="loading-content">
<div class="spinner"></div>
<p>데이터를 불러오는 중...</p>
</div>
</div>
<!-- 일일 작업 현황 모달 -->
<div id="dailyWorkModal" class="modal-overlay" style="display: none;">
<div class="modal-container large-modal">
<div class="modal-header">
<h2 id="modalTitle">2025년 11월 3일 작업 현황</h2>
<button class="modal-close-btn" onclick="closeDailyWorkModal()">×</button>
</div>
<div class="modal-body">
<!-- 요약 정보 -->
<div class="daily-summary">
<div class="summary-card">
<div class="summary-icon success">👥</div>
<div class="summary-content">
<div class="summary-label">총 작업자</div>
<div class="summary-value" id="modalTotalWorkers">0명</div>
</div>
</div>
<div class="summary-card">
<div class="summary-icon primary"></div>
<div class="summary-content">
<div class="summary-label">총 작업시간</div>
<div class="summary-value" id="modalTotalHours">0.0h</div>
</div>
</div>
<div class="summary-card">
<div class="summary-icon warning">📝</div>
<div class="summary-content">
<div class="summary-label">작업 건수</div>
<div class="summary-value" id="modalTotalTasks">0건</div>
</div>
</div>
<div class="summary-card">
<div class="summary-icon error">⚠️</div>
<div class="summary-content">
<div class="summary-label">오류 건수</div>
<div class="summary-value" id="modalErrorCount">0건</div>
</div>
</div>
</div>
<!-- 작업자 현황 리스트 -->
<div class="modal-work-status">
<div class="work-status-header">
<h3>작업자별 현황</h3>
<div class="status-filter">
<select id="statusFilter">
<option value="all">전체</option>
<option value="incomplete">미입력</option>
<option value="partial">부분입력</option>
<option value="complete">완료</option>
<option value="overtime">연장근로</option>
<option value="error">오류</option>
</select>
</div>
</div>
<div id="modalWorkersList" class="worker-status-list">
<!-- 작업자 리스트가 여기에 동적으로 생성됩니다 -->
</div>
<div id="modalNoData" class="empty-state" style="display: none;">
<div class="empty-icon">📭</div>
<h3>해당 날짜의 작업 보고서가 없습니다</h3>
<p>다른 날짜를 선택해 주세요.</p>
</div>
</div>
</div>
</div>
</div>
<!-- 작업 입력 모달 -->
<div id="workEntryModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h2 id="workEntryModalTitle">작업 입력</h2>
<button class="modal-close-btn" onclick="closeWorkEntryModal()">×</button>
</div>
<div class="modal-body">
<form id="workEntryForm">
<!-- 작업자 정보 -->
<div class="form-section">
<h3>작업자 정보</h3>
<div class="form-group">
<label class="form-label">작업자</label>
<input type="text" id="workerNameDisplay" class="form-control" readonly>
<input type="hidden" id="workerId">
</div>
<div class="form-group">
<label class="form-label">작업 날짜</label>
<input type="date" id="workDate" class="form-control" readonly>
</div>
</div>
<!-- 작업 내용 -->
<div class="form-section">
<h3>작업 내용</h3>
<div class="form-group">
<label class="form-label">프로젝트 *</label>
<select id="projectSelect" class="form-control" required>
<option value="">프로젝트를 선택하세요</option>
</select>
</div>
<div class="form-group">
<label class="form-label">작업 시간 (시간) *</label>
<input type="number" id="workHours" class="form-control" min="0" max="24" step="0.5" required>
</div>
<div class="form-group">
<label class="form-label">작업 상태 *</label>
<select id="workStatusSelect" class="form-control" required>
<option value="">상태를 선택하세요</option>
</select>
</div>
<div class="form-group">
<label class="form-label">작업 설명</label>
<textarea id="workDescription" class="form-control" rows="3" placeholder="작업 내용을 상세히 입력하세요"></textarea>
</div>
</div>
<!-- 휴가 처리 -->
<div class="form-section">
<h3>휴가 처리</h3>
<div class="vacation-buttons">
<button type="button" class="btn-vacation" onclick="handleVacation('full')">연차 (8시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('half')">반차 (4시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('quarter')">반반차 (2시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('early')">조퇴 (6시간)</button>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkEntryModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="saveWorkEntry()">저장</button>
</div>
</div>
</div>
<!-- JavaScript -->
<script src="/js/api-config.js?v=13"></script>
<script src="/js/auth-check.js?v=13"></script>
<script src="/js/load-navbar.js?v=13"></script>
<script src="/js/work-report-calendar.js?v=27"></script>
</body>
</html>