Files
TK-FB-Project/web-ui/pages.backup.20260202/admin/workplaces.html
Hyungi Ahn 74d3a78aa3 feat: 페이지 구조 재구성 및 사이드바 네비게이션 구현
- 페이지 폴더 재구성: safety/, attendance/ 폴더 신규 생성
  - work/ → safety/: 이슈 신고, 출입 신청 관련 페이지 이동
  - common/ → attendance/: 근태/휴가 관련 페이지 이동
  - admin/ 정리: safety-* 파일들을 safety/로 이동

- 사이드바 네비게이션 메뉴 구현
  - 카테고리별 메뉴: 작업관리, 안전관리, 근태관리, 시스템관리
  - 접기/펼치기 기능 및 상태 저장
  - 관리자 전용 메뉴 자동 표시/숨김

- 날씨 API 연동 (기상청 단기예보)
  - TBM 및 navbar에 현재 날씨 표시
  - weatherService.js 추가

- 안전 체크리스트 확장
  - 기본/날씨별/작업별 체크 유형 추가
  - checklist-manage.html 페이지 추가

- 이슈 신고 시스템 구현
  - workIssueController, workIssueModel, workIssueRoutes 추가

- DB 마이그레이션 파일 추가 (실행 대기)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:27:22 +09:00

415 lines
20 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/admin-pages.css?v=7">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js?v=1" defer></script>
<script type="module" src="/js/api-config.js?v=3"></script>
</head>
<body>
<!-- 네비게이션 바 -->
<div id="navbar-container"></div>
<!-- 메인 레이아웃: 사이드바 + 콘텐츠 -->
<div class="page-container">
<!-- 사이드바 -->
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="sidebar-header">
<h3 class="sidebar-title">관리 메뉴</h3>
</div>
<ul class="sidebar-menu">
<li class="menu-item">
<a href="/pages/admin/projects.html">
<span class="menu-icon">📁</span>
<span class="menu-text">프로젝트 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workers.html">
<span class="menu-icon">👥</span>
<span class="menu-text">작업자 관리</span>
</a>
</li>
<li class="menu-item active">
<a href="/pages/admin/workplaces.html">
<span class="menu-icon">🏗️</span>
<span class="menu-text">작업장 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/equipments.html">
<span class="menu-icon">⚙️</span>
<span class="menu-text">설비 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/tasks.html">
<span class="menu-icon">📋</span>
<span class="menu-text">작업 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/codes.html">
<span class="menu-icon">🏷️</span>
<span class="menu-text">코드 관리</span>
</a>
</li>
<li class="menu-divider"></li>
<li class="menu-item">
<a href="/pages/dashboard.html">
<span class="menu-icon">🏠</span>
<span class="menu-text">대시보드로</span>
</a>
</li>
</ul>
</nav>
</aside>
<!-- 메인 콘텐츠 -->
<main class="main-content">
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🏗️</span>
작업장 관리
</h1>
<p class="page-description">공장 및 작업장을 등록하고 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="openCategoryModal()">
<span class="btn-icon"></span>
공장 추가
</button>
<button class="btn btn-primary" onclick="openWorkplaceModal()">
<span class="btn-icon"></span>
작업장 추가
</button>
<button class="btn btn-secondary" onclick="refreshWorkplaces()">
<span class="btn-icon">🔄</span>
새로고침
</button>
</div>
</div>
<!-- 공장(카테고리) 탭 -->
<div class="code-tabs" id="categoryTabs">
<button class="tab-btn active" data-category="" onclick="switchCategory('')">
<span class="tab-icon">🏗️</span>
전체
</button>
<!-- 공장 탭들이 여기에 동적으로 생성됩니다 -->
</div>
<!-- 공장 레이아웃 지도 관리 섹션 (카테고리가 선택된 경우에만 표시) -->
<div class="code-section" id="layoutMapSection" style="display: none;">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">🗺️</span>
<span id="selectedCategoryName"></span> 레이아웃 지도
</h2>
<button class="btn btn-secondary" onclick="openLayoutMapModal()">
<span class="btn-icon">⚙️</span>
지도 설정
</button>
</div>
<div id="layoutMapPreview" style="padding: 20px; background: #f9fafb; border-radius: 8px; text-align: center;">
<!-- 레이아웃 이미지 미리보기가 여기에 표시됩니다 -->
</div>
</div>
<!-- 작업장 목록 -->
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">🏭</span>
작업장 목록
</h2>
</div>
<div class="code-stats" id="workplaceStats">
<span class="stat-item">
<span class="stat-icon">🏗️</span>
전체 <span id="totalCount">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
활성 <span id="activeCount">0</span>
</span>
</div>
<div class="code-grid" id="workplaceGrid">
<!-- 작업장 카드들이 여기에 동적으로 생성됩니다 -->
</div>
</div>
</div>
</main>
<!-- 공장(카테고리) 추가/수정 모달 -->
<div id="categoryModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h2 id="categoryModalTitle">공장 추가</h2>
<button class="modal-close-btn" onclick="closeCategoryModal()">×</button>
</div>
<div class="modal-body">
<form id="categoryForm" onsubmit="event.preventDefault(); saveCategory();">
<input type="hidden" id="categoryId">
<div class="form-group">
<label class="form-label">공장명 *</label>
<input type="text" id="categoryName" class="form-control" placeholder="예: 제 1공장" required>
</div>
<div class="form-group">
<label class="form-label">설명</label>
<textarea id="categoryDescription" class="form-control" rows="3" placeholder="공장에 대한 설명을 입력하세요"></textarea>
</div>
<div class="form-group">
<label class="form-label">표시 순서</label>
<input type="number" id="categoryOrder" class="form-control" value="0" min="0">
<small class="form-help">작은 숫자가 먼저 표시됩니다</small>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeCategoryModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteCategoryBtn" onclick="deleteCategory()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveCategory()">
💾 저장
</button>
</div>
</div>
</div>
<!-- 작업장 추가/수정 모달 -->
<div id="workplaceModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h2 id="workplaceModalTitle">작업장 추가</h2>
<button class="modal-close-btn" onclick="closeWorkplaceModal()">×</button>
</div>
<div class="modal-body">
<form id="workplaceForm" onsubmit="event.preventDefault(); saveWorkplace();">
<input type="hidden" id="workplaceId">
<div class="form-group">
<label class="form-label">소속 공장</label>
<select id="workplaceCategoryId" class="form-control">
<option value="">공장 선택</option>
<!-- 공장 목록이 동적으로 생성됩니다 -->
</select>
</div>
<div class="form-group">
<label class="form-label">작업장명 *</label>
<input type="text" id="workplaceName" class="form-control" placeholder="예: 서스작업장, 조립구역" required>
</div>
<div class="form-group">
<label class="form-label">작업장 용도</label>
<select id="workplacePurpose" class="form-control">
<option value="">선택 안 함</option>
<option value="작업구역">작업구역</option>
<option value="설비">설비</option>
<option value="휴게시설">휴게시설</option>
<option value="회의실">회의실</option>
<option value="창고">창고</option>
<option value="기타">기타</option>
</select>
<small class="form-help">작업장의 주요 용도를 선택하세요</small>
</div>
<div class="form-group">
<label class="form-label">표시 순서</label>
<input type="number" id="displayPriority" class="form-control" value="0" min="0">
<small class="form-help">숫자가 작을수록 먼저 표시됩니다</small>
</div>
<div class="form-group">
<label class="form-label">설명</label>
<textarea id="workplaceDescription" class="form-control" rows="4" placeholder="작업장에 대한 설명을 입력하세요"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkplaceModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteWorkplaceBtn" onclick="deleteWorkplace()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveWorkplace()">
💾 저장
</button>
</div>
</div>
</div>
<!-- 작업장 지도 관리 모달 -->
<div id="workplaceMapModal" class="modal-overlay" style="display: none;">
<div class="modal-container" style="max-width: 90vw; max-height: 90vh;">
<div class="modal-header">
<h2 id="workplaceMapModalTitle">작업장 지도 관리</h2>
<button class="modal-close-btn" onclick="closeWorkplaceMapModal()">×</button>
</div>
<div class="modal-body" style="overflow-y: auto;">
<!-- Step 1: 이미지 업로드 -->
<div class="form-section" style="border-bottom: 2px solid #e5e7eb; padding-bottom: 20px; margin-bottom: 20px;">
<h3 style="font-size: 16px; font-weight: 600; margin-bottom: 12px;">Step 1. 작업장 레이아웃 이미지 업로드</h3>
<p style="color: #64748b; font-size: 14px; margin-bottom: 16px;">
작업장의 상세 레이아웃 이미지를 업로드하세요
</p>
<div class="form-group">
<label class="form-label">현재 이미지</label>
<div id="workplaceLayoutPreview" style="background: #f9fafb; border: 2px dashed #cbd5e1; padding: 20px; border-radius: 8px; text-align: center; min-height: 200px;">
<span style="color: #94a3b8;">업로드된 이미지가 없습니다</span>
</div>
</div>
<div class="form-group">
<label class="form-label">새 이미지 업로드</label>
<input type="file" id="workplaceLayoutFile" accept="image/*" class="form-control" onchange="previewWorkplaceLayoutImage(event)">
<small class="form-help">JPG, PNG, GIF 형식 지원 (최대 5MB)</small>
</div>
<button type="button" class="btn btn-primary" onclick="uploadWorkplaceLayout()">
📤 이미지 업로드
</button>
</div>
<!-- Step 2: 설비/영역 정의 -->
<div class="form-section">
<h3 style="font-size: 16px; font-weight: 600; margin-bottom: 12px;">Step 2. 설비 위치 정의 (선택사항)</h3>
<p style="color: #64748b; font-size: 14px; margin-bottom: 16px;">
작업장 이미지 위에 마우스로 드래그하여 각 설비의 위치를 지정하세요
</p>
<!-- 영역 그리기 캔버스 -->
<div style="position: relative; display: inline-block; margin-bottom: 20px;" id="workplaceCanvasContainer">
<canvas id="workplaceRegionCanvas" style="border: 2px solid #cbd5e1; cursor: crosshair; max-width: 100%;"></canvas>
</div>
<!-- 설비 선택 및 영역 목록 -->
<div class="form-group">
<label class="form-label">설비 이름 입력</label>
<input type="text" id="equipmentNameInput" class="form-control" placeholder="예: CNC-01, 선반기-A" style="margin-bottom: 12px;">
<small class="form-help">드래그로 영역을 선택한 후 설비 이름을 입력하고 저장하세요</small>
<div style="display: flex; gap: 8px; margin-top: 12px;">
<button type="button" class="btn btn-secondary" onclick="clearWorkplaceCurrentRegion()">
🗑️ 현재 영역 지우기
</button>
<button type="button" class="btn btn-primary" onclick="saveWorkplaceEquipmentRegion()">
💾 설비 위치 저장
</button>
</div>
</div>
<!-- 정의된 영역 목록 -->
<div class="form-group">
<label class="form-label">정의된 설비 목록</label>
<div id="workplaceEquipmentList" style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; min-height: 100px;">
<p style="color: #94a3b8; text-align: center;">아직 정의된 설비가 없습니다</p>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkplaceMapModal()">닫기</button>
</div>
</div>
</div>
<!-- 레이아웃 지도 설정 모달 -->
<div id="layoutMapModal" class="modal-overlay" style="display: none;">
<div class="modal-container" style="max-width: 90vw; max-height: 90vh;">
<div class="modal-header">
<h2>🗺️ 공장 레이아웃 지도 설정</h2>
<button class="modal-close-btn" onclick="closeLayoutMapModal()">×</button>
</div>
<div class="modal-body" style="overflow-y: auto;">
<!-- Step 1: 이미지 업로드 -->
<div class="form-section" style="border-bottom: 2px solid #e5e7eb; padding-bottom: 20px; margin-bottom: 20px;">
<h3 style="font-size: 16px; font-weight: 600; margin-bottom: 12px;">Step 1. 공장 레이아웃 이미지 업로드</h3>
<div class="form-group">
<label class="form-label">현재 이미지</label>
<div id="currentLayoutImage" style="background: #f9fafb; border: 2px dashed #cbd5e1; padding: 20px; border-radius: 8px; text-align: center;">
<span style="color: #94a3b8;">업로드된 이미지가 없습니다</span>
</div>
</div>
<div class="form-group">
<label class="form-label">새 이미지 업로드</label>
<input type="file" id="layoutImageFile" accept="image/*" class="form-control" onchange="previewLayoutImage(event)">
<small class="form-help">JPG, PNG, GIF 형식 지원 (최대 5MB)</small>
</div>
<button type="button" class="btn btn-primary" onclick="uploadLayoutImage()">
📤 이미지 업로드
</button>
</div>
<!-- Step 2: 작업장 영역 정의 -->
<div class="form-section">
<h3 style="font-size: 16px; font-weight: 600; margin-bottom: 12px;">Step 2. 작업장 영역 정의</h3>
<p style="color: #64748b; font-size: 14px; margin-bottom: 16px;">
이미지 위에 마우스로 드래그하여 각 작업장의 위치를 지정하세요
</p>
<!-- 영역 그리기 캔버스 -->
<div style="position: relative; display: inline-block; margin-bottom: 20px;" id="canvasContainer">
<canvas id="regionCanvas" style="border: 2px solid #cbd5e1; cursor: crosshair; max-width: 100%;"></canvas>
</div>
<!-- 작업장 선택 및 영역 목록 -->
<div class="form-group">
<label class="form-label">작업장 선택</label>
<select id="regionWorkplaceSelect" class="form-control" style="margin-bottom: 12px;">
<option value="">작업장을 선택하세요</option>
</select>
<div style="display: flex; gap: 8px;">
<button type="button" class="btn btn-secondary" onclick="clearCurrentRegion()">
🗑️ 현재 영역 지우기
</button>
<button type="button" class="btn btn-primary" onclick="saveRegion()">
💾 선택 영역 저장
</button>
</div>
</div>
<!-- 정의된 영역 목록 -->
<div class="form-group">
<label class="form-label">정의된 영역 목록</label>
<div id="regionList" style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; min-height: 100px;">
<!-- 영역 목록이 여기에 표시됩니다 -->
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeLayoutMapModal()">닫기</button>
</div>
</div>
</div>
</div>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/workplace-management.js?v=3"></script>
<script type="module" src="/js/workplace-layout-map.js?v=1"></script>
</body>
</html>