feat: 캘린더 기반 작업 현황 확인 시스템 구현
- 월별 캘린더 UI로 작업 현황을 한눈에 확인 가능 - 미입력(빨강), 부분입력(주황), 확인필요(보라), 이상없음(초록) 상태 표시 - 범례 아이콘(●)을 사용한 직관적인 상태 표시 - 날짜 클릭 시 해당일 작업자별 상세 현황 모달 - 작업자 클릭 시 개별 작업 입력/수정 모달 - 휴가 처리 기능 (연차, 반차, 반반차, 조퇴) - 월별 집계 데이터 최적화로 API 호출 최소화 백엔드: - monthly_worker_status, monthly_summary 테이블 추가 - 자동 집계 stored procedure 및 trigger 구현 - 확인필요(12시간 초과) 상태 감지 로직 - 출석 관리 시스템 확장 프론트엔드: - 캘린더 그리드 UI 구현 - 상태별 색상 및 아이콘 표시 - 모달 기반 상세 정보 표시 - 반응형 디자인 적용
This commit is contained in:
@@ -3,98 +3,284 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>일일 작업보고서 조회</title>
|
||||
<link rel="stylesheet" href="/css/daily-report-viewer.css">
|
||||
<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>
|
||||
<div class="container">
|
||||
<header class="page-header">
|
||||
<h1>📊 일일 작업보고서 조회</h1>
|
||||
<p class="subtitle">날짜를 선택하여 해당일의 작업 현황을 확인하세요</p>
|
||||
</header>
|
||||
|
||||
<div class="date-selector">
|
||||
<div class="date-input-group">
|
||||
<label for="reportDate">📅 조회 날짜:</label>
|
||||
<input type="date" id="reportDate" class="date-input">
|
||||
<button id="searchBtn" class="search-btn">조회</button>
|
||||
<button id="todayBtn" class="today-btn">오늘</button>
|
||||
<!-- 대시보드 헤더 -->
|
||||
<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>
|
||||
|
||||
<div id="loadingSpinner" class="loading-spinner" style="display: none;">
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<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="errorMessage" class="error-message" style="display: none;">
|
||||
<div class="error-content">
|
||||
<span class="error-icon">⚠️</span>
|
||||
<span class="error-text"></span>
|
||||
<!-- 일일 작업 현황 모달 -->
|
||||
<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>
|
||||
|
||||
<div id="noDataMessage" class="no-data-message" style="display: none;">
|
||||
<div class="no-data-content">
|
||||
<span class="no-data-icon">📭</span>
|
||||
<h3>해당 날짜의 작업보고서가 없습니다</h3>
|
||||
<p>다른 날짜를 선택해 주세요.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="reportSummary" class="report-summary" style="display: none;">
|
||||
<div class="summary-cards">
|
||||
<div class="summary-card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon">👥</span>
|
||||
<span class="card-title">작업자 수</span>
|
||||
|
||||
<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="card-value" id="totalWorkers">0</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon">⏰</span>
|
||||
<span class="card-title">총 작업시간</span>
|
||||
<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="card-value" id="totalHours">0시간</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon">📝</span>
|
||||
<span class="card-title">작업 항목</span>
|
||||
<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="card-value" id="totalEntries">0개</div>
|
||||
</div>
|
||||
<div class="summary-card error-card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon">⚠️</span>
|
||||
<span class="card-title">에러 항목</span>
|
||||
<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 class="card-value" id="errorCount">0개</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="workersReport" class="workers-report" style="display: none;">
|
||||
<h2 class="section-title">👥 작업자별 상세 현황</h2>
|
||||
<div id="workersList" class="workers-list">
|
||||
<!-- 작업자별 데이터가 여기에 표시됩니다 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="exportSection" class="export-section" style="display: none;">
|
||||
<h3>📤 데이터 내보내기</h3>
|
||||
<div class="export-buttons">
|
||||
<button id="exportExcelBtn" class="export-btn excel-btn">
|
||||
📊 Excel로 내보내기
|
||||
</button>
|
||||
<button id="printBtn" class="export-btn print-btn">
|
||||
🖨️ 인쇄
|
||||
</button>
|
||||
<!-- 작업자 현황 리스트 -->
|
||||
<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>
|
||||
|
||||
<script src="/js/daily-report-viewer.js"></script>
|
||||
<!-- 작업 입력 모달 -->
|
||||
<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>
|
||||
Reference in New Issue
Block a user