Files
TK-FB-Project/web-ui/pages/dashboard.html
Hyungi Ahn b6485e3140 feat: 대시보드 작업장 현황 지도 구현
- 실시간 작업장 현황을 지도로 시각화
- 작업장 관리 페이지에서 정의한 구역 정보 활용
- TBM 작업자 및 방문자 현황 표시

주요 변경사항:
- dashboard.html: 작업장 현황 섹션 추가 (기존 작업 현황 테이블 제거)
- workplace-status.js: 지도 렌더링 및 데이터 통합 로직 구현
- modern-dashboard.js: 삭제된 DOM 요소 조건부 체크 추가

시각화 방식:
- 인원 없음: 회색 테두리 + 작업장 이름
- 내부 작업자: 파란색 영역 + 인원 수
- 외부 방문자: 보라색 영역 + 인원 수
- 둘 다: 초록색 영역 + 총 인원 수

기술 구현:
- Canvas API 기반 사각형 영역 렌더링
- map-regions API를 통한 데이터 일관성 보장
- 클릭 이벤트로 상세 정보 모달 표시

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-29 15:46:47 +09:00

253 lines
12 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>작업 현황판 | 테크니컬코리아</title>
<!-- 모던 디자인 시스템 적용 -->
<link rel="stylesheet" href="/css/design-system.css">
<link rel="stylesheet" href="/css/modern-dashboard.css?v=2">
<link rel="icon" type="image/png" href="/img/favicon.png">
<!-- 스크립트 (순서 중요: api-config.js가 먼저 로드되어야 함) -->
<script type="module" src="/js/api-config.js"></script>
<script type="module" src="/js/auth-check.js" defer></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/modern-dashboard.js?v=10" defer></script>
<script type="module" src="/js/group-leader-dashboard.js?v=1" defer></script>
<script src="/js/workplace-status.js" defer></script>
</head>
<body>
<!-- 메인 컨테이너 -->
<div class="dashboard-container">
<!-- 네비게이션 헤더 -->
<div id="navbar-container"></div>
<!-- 메인 콘텐츠 -->
<main class="dashboard-main">
<!-- 빠른 작업 섹션 -->
<section class="quick-actions-section">
<div class="card">
<div class="card-header">
<h2 class="card-title">빠른 작업</h2>
</div>
<div class="card-body">
<div class="quick-actions-grid-full">
<!-- TBM 관리 (페이지 권한 체크) -->
<a href="/pages/work/tbm.html" class="quick-action-card" id="tbmQuickAction" style="display: none; background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); color: white;">
<div class="action-content">
<h3 style="color: white;">🛠️ TBM 관리</h3>
<p style="color: rgba(255, 255, 255, 0.9);">아침 안전 회의 및 팀 구성을 관리합니다</p>
</div>
<div class="action-arrow" style="color: white;"></div>
</a>
<a href="/pages/work/visit-request.html" class="quick-action-card" style="background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); color: white;">
<div class="action-content">
<h3 style="color: white;">🚪 출입 신청</h3>
<p style="color: rgba(255, 255, 255, 0.9);">작업장 출입 및 안전교육을 신청합니다</p>
</div>
<div class="action-arrow" style="color: white;"></div>
</a>
<a href="/pages/admin/safety-management.html" class="quick-action-card admin-only" style="background: linear-gradient(135deg, #ec4899 0%, #db2777 100%); color: white;">
<div class="action-content">
<h3 style="color: white;">🛡️ 안전관리</h3>
<p style="color: rgba(255, 255, 255, 0.9);">출입 신청 승인 및 안전교육 관리</p>
</div>
<div class="action-arrow" style="color: white;"></div>
</a>
<a href="/pages/work/report-create.html" class="quick-action-card">
<div class="action-content">
<h3>작업 보고서 작성</h3>
<p>오늘의 작업 내용을 입력하고 관리합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/work/report-view.html" class="quick-action-card">
<div class="action-content">
<h3>작업 현황 확인</h3>
<p>팀원들의 작업 현황을 실시간으로 조회합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/work/analysis.html" class="quick-action-card admin-only">
<div class="action-content">
<h3>작업 분석</h3>
<p>작업 효율성 및 통계를 분석합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/admin/projects.html" class="quick-action-card admin-only">
<div class="action-content">
<h3>기본 정보 관리</h3>
<p>프로젝트, 작업자, 코드를 관리합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/common/daily-attendance.html" class="quick-action-card" style="background: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%); color: white;">
<div class="action-content">
<h3 style="color: white;">📅 일일 출퇴근 입력</h3>
<p style="color: rgba(255, 255, 255, 0.9);">오늘의 출퇴근 기록을 입력합니다</p>
</div>
<div class="action-arrow" style="color: white;"></div>
</a>
<a href="/pages/common/monthly-attendance.html" class="quick-action-card">
<div class="action-content">
<h3>📆 월별 출퇴근 현황</h3>
<p>이번 달 출퇴근 현황을 조회합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/common/vacation-request.html" class="quick-action-card">
<div class="action-content">
<h3>📝 휴가 신청</h3>
<p>휴가를 신청하고 신청 내역을 확인합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/common/vacation-management.html" class="quick-action-card admin-only">
<div class="action-content">
<h3>🏖️ 휴가 관리</h3>
<p>휴가 승인, 직접 입력, 전체 내역을 관리합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/common/annual-vacation-overview.html" class="quick-action-card admin-only">
<div class="action-content">
<h3>📊 연간 연차 현황</h3>
<p>모든 작업자의 연간 휴가 현황을 차트로 확인합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/common/vacation-allocation.html" class="quick-action-card admin-only">
<div class="action-content">
<h3> 휴가 발생 입력</h3>
<p>작업자별 휴가를 입력하고 특별 휴가를 관리합니다</p>
</div>
<div class="action-arrow"></div>
</a>
<a href="/pages/admin/attendance-report-comparison.html" class="quick-action-card admin-only">
<div class="action-content">
<h3>🔍 출퇴근-작업보고서 대조</h3>
<p>출퇴근 기록과 작업보고서를 비교 분석합니다</p>
</div>
<div class="action-arrow"></div>
</a>
</div>
</div>
</div>
</section>
<!-- 작업장 현황 -->
<section class="workplace-status-section">
<div class="card">
<div class="card-header">
<div class="flex justify-between items-center">
<h2 class="card-title">작업장 현황</h2>
<div class="flex items-center" style="gap: 12px;">
<select id="categorySelect" class="form-select" style="width: 200px;">
<option value="">공장을 선택하세요</option>
</select>
<button class="btn btn-primary btn-sm" id="refreshMapBtn">
새로고침
</button>
</div>
</div>
</div>
<div class="card-body">
<!-- 지도 영역 -->
<div id="workplaceMapContainer" style="position: relative; min-height: 500px; display: none;">
<canvas id="workplaceMapCanvas" style="width: 100%; max-width: 100%; cursor: pointer; border: 2px solid var(--gray-300); border-radius: var(--radius-md);"></canvas>
<div id="mapLegend" style="position: absolute; top: 16px; right: 16px; background: white; padding: 16px; border-radius: var(--radius-md); box-shadow: var(--shadow-md);">
<h4 style="font-size: var(--text-sm); font-weight: 700; margin-bottom: 12px;">범례</h4>
<div style="display: flex; flex-direction: column; gap: 8px;">
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 16px; height: 16px; background: rgba(59, 130, 246, 0.3); border: 2px solid rgb(59, 130, 246); border-radius: 4px;"></div>
<span style="font-size: var(--text-sm);">작업 중 (내부 작업자)</span>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 16px; height: 16px; background: rgba(168, 85, 247, 0.3); border: 2px solid rgb(168, 85, 247); border-radius: 4px;"></div>
<span style="font-size: var(--text-sm);">방문 예정 (외부 인원)</span>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 16px; height: 16px; background: rgba(34, 197, 94, 0.3); border: 2px solid rgb(34, 197, 94); border-radius: 4px;"></div>
<span style="font-size: var(--text-sm);">작업 + 방문</span>
</div>
</div>
</div>
</div>
<!-- 안내 메시지 -->
<div id="mapPlaceholder" style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 400px; color: var(--gray-500);">
<div style="font-size: 48px; margin-bottom: 16px;">🏭</div>
<h3 style="margin-bottom: 8px;">공장을 선택하세요</h3>
<p style="font-size: var(--text-sm);">위에서 공장을 선택하면 작업장 현황을 확인할 수 있습니다.</p>
</div>
</div>
</div>
</section>
</main>
<!-- 푸터 -->
<footer class="dashboard-footer">
<div class="footer-content">
<p class="footer-text">
© 2025 (주)테크니컬코리아. 모든 권리 보유.
</p>
<div class="footer-links">
<a href="#" class="footer-link">도움말</a>
<a href="#" class="footer-link">문의하기</a>
<a href="#" class="footer-link">개인정보처리방침</a>
</div>
</div>
</footer>
</div>
<!-- 알림 토스트 -->
<div class="toast-container" id="toastContainer"></div>
<!-- 작업장 상세 정보 모달 -->
<div id="workplaceDetailModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 1000; align-items: center; justify-content: center;">
<div style="background: white; border-radius: var(--radius-lg); padding: 32px; max-width: 800px; width: 90%; max-height: 80vh; overflow-y: auto; box-shadow: var(--shadow-2xl);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px;">
<h2 id="modalWorkplaceName" style="margin: 0; font-size: var(--text-2xl); font-weight: 700;"></h2>
<button class="btn btn-secondary btn-sm" onclick="closeWorkplaceModal()">닫기</button>
</div>
<!-- 내부 작업자 -->
<div id="internalWorkersSection" style="margin-bottom: 24px;">
<h3 style="font-size: var(--text-lg); font-weight: 600; margin-bottom: 16px; color: var(--primary-600);">👷 내부 작업자</h3>
<div id="internalWorkersList"></div>
</div>
<!-- 외부 방문자 -->
<div id="externalVisitorsSection">
<h3 style="font-size: var(--text-lg); font-weight: 600; margin-bottom: 16px; color: var(--purple-600);">🚪 외부 방문자</h3>
<div id="externalVisitorsList"></div>
</div>
</div>
</div>
</body>
</html>