feat: 안전 코드 tksafety 이관 + 사용자 관리 정리 + UI Tailwind 전환
Phase 1: tksafety에 출입신청/체크리스트 API·웹 추가, tkfb 안전 코드 삭제
Phase 2: 사용자 관리 페이지 삭제, API 축소, 알림 수신자 tkuser 이관
Phase 3: tkuser 권한 페이지 정의 업데이트
Phase 4: 전체 34개 페이지 Tailwind CSS + tkfb-core.js 전환,
미사용 CSS 20개·인프라 JS 10개·템플릿·컴포넌트 삭제
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,286 +0,0 @@
|
||||
<!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/common.css?v=1">
|
||||
<link rel="stylesheet" href="/css/admin-settings.css?v=2">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="work-report-main">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">관리자 설정</h1>
|
||||
<p class="page-description">시스템 사용자 계정 및 권한을 관리합니다</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 사용자 관리 섹션 -->
|
||||
<div class="settings-section">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">사용자 계정 관리</h2>
|
||||
<button class="btn btn-primary" id="addUserBtn">새 사용자 추가</button>
|
||||
</div>
|
||||
|
||||
<div class="users-container">
|
||||
<div class="users-header">
|
||||
<div class="search-box">
|
||||
<input type="text" id="userSearch" placeholder="사용자 검색..." class="search-input">
|
||||
<span class="search-icon"></span>
|
||||
</div>
|
||||
<div class="filter-buttons">
|
||||
<button class="filter-btn active" data-filter="all">전체</button>
|
||||
<button class="filter-btn" data-filter="admin">관리자</button>
|
||||
<button class="filter-btn" data-filter="leader">그룹장</button>
|
||||
<button class="filter-btn" data-filter="user">작업자</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="users-table-container">
|
||||
<table class="users-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>사용자명</th>
|
||||
<th>아이디</th>
|
||||
<th>역할</th>
|
||||
<th>상태</th>
|
||||
<th>최종 로그인</th>
|
||||
<th>관리</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="usersTableBody">
|
||||
<!-- 사용자 목록이 여기에 동적으로 생성됩니다 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" id="emptyState" style="display: none;">
|
||||
<h3>등록된 사용자가 없습니다</h3>
|
||||
<p>새 사용자를 추가해보세요.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 알림 수신자 설정 섹션 -->
|
||||
<div class="settings-section" id="notificationRecipientsSection">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">알림 수신자 설정</h2>
|
||||
<p class="section-description">알림 유형별 수신자를 지정합니다. 지정된 사용자에게만 알림이 전송됩니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="notification-recipients-container">
|
||||
<div class="notification-type-cards" id="notificationTypeCards">
|
||||
<!-- 동적으로 생성됨 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 사용자 추가/수정 모달 -->
|
||||
<div id="userModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<h2 id="modalTitle">새 사용자 추가</h2>
|
||||
<button class="modal-close-btn" onclick="closeUserModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form id="userForm">
|
||||
<div class="form-group">
|
||||
<label class="form-label">사용자명 *</label>
|
||||
<input type="text" id="userName" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">아이디 *</label>
|
||||
<input type="text" id="userId" class="form-control" required>
|
||||
<small class="form-help">영문, 숫자, 한글, 특수문자(._-) 사용 가능 (3-20자)</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="passwordGroup">
|
||||
<label class="form-label">비밀번호 *</label>
|
||||
<input type="password" id="userPassword" class="form-control" required>
|
||||
<small class="form-help">최소 6자 이상</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">역할 *</label>
|
||||
<select id="userRole" class="form-control" required>
|
||||
<option value="">역할 선택</option>
|
||||
<option value="admin">관리자</option>
|
||||
<option value="user">사용자</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">이메일</label>
|
||||
<input type="email" id="userEmail" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">전화번호</label>
|
||||
<input type="tel" id="userPhone" class="form-control">
|
||||
</div>
|
||||
|
||||
<!-- 작업자 연결 (수정 시에만 표시) -->
|
||||
<div class="form-group" id="workerLinkGroup" style="display: none;">
|
||||
<label class="form-label">작업자 연결</label>
|
||||
<div class="worker-link-container">
|
||||
<div class="linked-worker-info" id="linkedWorkerInfo">
|
||||
<span class="no-worker">연결된 작업자 없음</span>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary btn-sm" onclick="openWorkerSelectModal()">
|
||||
작업자 선택
|
||||
</button>
|
||||
</div>
|
||||
<small class="form-help">계정과 작업자를 연결하면 출퇴근, 작업보고서 등의 기록이 연동됩니다</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeUserModal()">취소</button>
|
||||
<button type="button" class="btn btn-primary" id="saveUserBtn">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 사용자 삭제 확인 모달 -->
|
||||
<div id="deleteModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container small">
|
||||
<div class="modal-header">
|
||||
<h2>사용자 삭제</h2>
|
||||
<button class="modal-close-btn" onclick="closeDeleteModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="delete-warning">
|
||||
<div class="warning-icon"></div>
|
||||
<p>정말로 이 사용자를 삭제하시겠습니까?</p>
|
||||
<p class="warning-text">삭제된 사용자는 복구할 수 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeDeleteModal()">취소</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmDeleteBtn">삭제</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 페이지 권한 관리 모달 -->
|
||||
<div id="pageAccessModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<h2 id="pageAccessModalTitle">페이지 권한 관리</h2>
|
||||
<button class="modal-close-btn" onclick="closePageAccessModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="page-access-user-info">
|
||||
<div class="user-avatar-small" id="pageAccessUserAvatar">U</div>
|
||||
<div>
|
||||
<h3 id="pageAccessUserName">사용자</h3>
|
||||
<p id="pageAccessUserRole">역할</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">접근 가능한 페이지</label>
|
||||
<small class="form-help">체크된 페이지에만 접근할 수 있습니다</small>
|
||||
<div id="pageAccessModalList" class="page-access-list">
|
||||
<!-- 페이지 체크박스 목록 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closePageAccessModal()">취소</button>
|
||||
<button type="button" class="btn btn-primary" id="savePageAccessBtn">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업자 선택 모달 -->
|
||||
<div id="workerSelectModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<h2>작업자 선택</h2>
|
||||
<button class="modal-close-btn" onclick="closeWorkerSelectModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="worker-select-layout">
|
||||
<!-- 부서 목록 -->
|
||||
<div class="department-list-panel">
|
||||
<h3 class="panel-title">부서</h3>
|
||||
<div class="department-list" id="departmentList">
|
||||
<!-- 부서 목록이 동적으로 생성됩니다 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업자 목록 -->
|
||||
<div class="worker-list-panel">
|
||||
<h3 class="panel-title">작업자</h3>
|
||||
<div class="worker-list" id="workerListForSelect">
|
||||
<div class="empty-message">부서를 선택하세요</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeWorkerSelectModal()">취소</button>
|
||||
<button type="button" class="btn btn-danger" onclick="unlinkWorker()">연결 해제</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 알림 수신자 편집 모달 -->
|
||||
<div id="notificationRecipientModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<h2 id="recipientModalTitle">알림 수신자 설정</h2>
|
||||
<button class="modal-close-btn" onclick="closeRecipientModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="modal-description" id="recipientModalDesc">이 알림을 받을 사용자를 선택하세요.</p>
|
||||
|
||||
<div class="recipient-search-box">
|
||||
<input type="text" id="recipientSearchInput" placeholder="사용자 검색..." class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="recipient-user-list" id="recipientUserList">
|
||||
<!-- 사용자 체크박스 목록 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeRecipientModal()">취소</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveNotificationRecipients()">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 토스트 알림 -->
|
||||
<div class="toast-container" id="toastContainer"></div>
|
||||
|
||||
<!-- JavaScript -->
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<script src="/js/admin-settings.js?v=9"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,13 +3,10 @@
|
||||
<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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>출퇴근-작업보고서 대조 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.comparison-grid {
|
||||
display: grid;
|
||||
@@ -98,13 +95,28 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">출퇴근-작업보고서 대조</h1>
|
||||
@@ -174,9 +186,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
@@ -482,5 +497,6 @@
|
||||
container.innerHTML = tableHTML;
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
<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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>부서 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.department-grid {
|
||||
display: grid;
|
||||
@@ -215,12 +212,28 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<div class="page-container">
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">부서 관리</h1>
|
||||
@@ -266,9 +279,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 부서 등록/수정 모달 -->
|
||||
<div class="modal-backdrop" id="departmentModal">
|
||||
@@ -311,6 +324,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/department-management.js"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,23 +3,34 @@
|
||||
<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=8">
|
||||
<title>설비 상세 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/equipment-detail.css?v=1">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 레이아웃 -->
|
||||
<div class="page-container">
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 뒤로가기 & 제목 -->
|
||||
<div class="page-header eq-detail-header">
|
||||
<div class="page-title-section">
|
||||
@@ -118,9 +129,9 @@
|
||||
<div class="eq-history-empty">이동 이력이 없습니다</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 사진 추가 모달 -->
|
||||
<div id="photoModal" class="modal-overlay" style="display: none;">
|
||||
@@ -303,6 +314,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
@@ -340,5 +353,6 @@
|
||||
})();
|
||||
</script>
|
||||
<script src="/js/equipment-detail.js?v=1"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,23 +3,34 @@
|
||||
<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=8">
|
||||
<title>설비 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/equipment-management.css?v=1">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 레이아웃 -->
|
||||
<div class="page-container">
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">설비 관리</h1>
|
||||
@@ -71,9 +82,9 @@
|
||||
<div id="equipmentList" class="eq-table-container">
|
||||
<!-- 설비 목록이 여기에 동적으로 렌더링됩니다 -->
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비 추가/수정 모달 -->
|
||||
<div id="equipmentModal" class="modal-overlay" style="display: none;">
|
||||
@@ -179,6 +190,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
@@ -216,5 +229,6 @@
|
||||
})();
|
||||
</script>
|
||||
<script src="/js/equipment-management.js?v=8"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
<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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>신고 카테고리 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.type-tabs {
|
||||
display: flex;
|
||||
@@ -211,12 +208,28 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<div class="page-container">
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">신고 카테고리 관리</h1>
|
||||
@@ -237,9 +250,9 @@
|
||||
<div id="categoryList">
|
||||
<div class="empty-state">카테고리를 불러오는 중...</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 카테고리 추가/수정 모달 -->
|
||||
<div id="categoryModal" class="modal-overlay" style="display: none;">
|
||||
@@ -316,6 +329,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script type="module" src="/js/issue-category-manage.js"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,18 +3,14 @@
|
||||
<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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>알림 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.notification-page-container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.notification-header {
|
||||
@@ -308,11 +304,28 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar-placeholder"></div>
|
||||
<div id="sidebar-placeholder"></div>
|
||||
|
||||
<main class="main-content">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="notification-page-container">
|
||||
<div class="notification-header">
|
||||
<h1>알림 관리</h1>
|
||||
@@ -358,9 +371,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/load-sidebar.js"></script>
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script>
|
||||
let currentPage = 1;
|
||||
let totalPages = 1;
|
||||
@@ -550,5 +566,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
<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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<title>프로젝트 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1rem 1.5rem;
|
||||
max-width: 1600px;
|
||||
}
|
||||
.page-header {
|
||||
@@ -226,11 +225,28 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="has-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
<div id="sidebar-container"></div>
|
||||
|
||||
<main class="main-content">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="page-wrapper">
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">프로젝트 관리</h1>
|
||||
@@ -280,7 +296,9 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 프로젝트 모달 -->
|
||||
<div id="projectModal" class="modal-overlay" style="display: none;">
|
||||
@@ -366,8 +384,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script>
|
||||
let allProjects = [];
|
||||
let filteredProjects = [];
|
||||
@@ -683,5 +701,6 @@
|
||||
window.refreshProjectList = refreshProjectList;
|
||||
window.filterByStatus = filterByStatus;
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,17 +3,14 @@
|
||||
<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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<title>시설설비 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.repair-page {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
@@ -358,11 +355,28 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar-container"></div>
|
||||
<div id="sidebar-container"></div>
|
||||
|
||||
<main class="main-content">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="repair-page">
|
||||
<div class="page-header">
|
||||
<h1>시설설비 관리</h1>
|
||||
@@ -408,7 +422,9 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 접수 모달 -->
|
||||
<div class="modal-overlay" id="receiveModal">
|
||||
@@ -471,6 +487,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script>
|
||||
let currentReportId = null;
|
||||
let allRepairs = [];
|
||||
@@ -848,5 +866,6 @@
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
<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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<title>작업 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.page-wrapper { padding: 1rem 1.5rem; max-width: 1400px; }
|
||||
.page-wrapper { max-width: 1400px; }
|
||||
.page-header {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
@@ -140,11 +138,28 @@
|
||||
.form-hint { font-size: 0.7rem; color: #6b7280; margin-top: 0.25rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="has-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
<div id="sidebar-container"></div>
|
||||
|
||||
<main class="main-content">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="page-wrapper">
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">작업 관리</h1>
|
||||
@@ -193,7 +208,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업 모달 -->
|
||||
<div id="taskModal" class="modal-overlay" style="display:none;">
|
||||
@@ -268,6 +285,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script>
|
||||
let workTypes = [];
|
||||
let tasks = [];
|
||||
@@ -592,5 +611,6 @@
|
||||
window.deleteWorkType = deleteWorkType;
|
||||
window.refreshData = refreshData;
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,495 +0,0 @@
|
||||
<!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=8">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<!-- 최적화된 로딩: API 설정 → 앱 초기화 (병렬 컴포넌트 로딩) -->
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<!-- instant.page: 링크 호버 시 페이지 프리로딩 -->
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<style>
|
||||
.department-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 280px 1fr;
|
||||
gap: 1.5rem;
|
||||
min-height: calc(100vh - 200px);
|
||||
}
|
||||
|
||||
/* 부서 패널 */
|
||||
.department-panel {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.department-panel-header {
|
||||
padding: 1rem 1.25rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.department-panel-header h3 {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.department-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.department-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.department-item:hover {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
.department-item.active {
|
||||
background: #dbeafe;
|
||||
border-left: 3px solid #3b82f6;
|
||||
}
|
||||
|
||||
.department-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.department-name {
|
||||
font-weight: 500;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.department-count {
|
||||
font-size: 0.75rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.department-actions {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.department-item:hover .department-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
padding: 0.375rem;
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
color: #6b7280;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.btn-icon:hover {
|
||||
background: #e5e7eb;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.btn-icon.danger:hover {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
/* 작업자 패널 */
|
||||
.worker-panel {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.worker-panel-header {
|
||||
padding: 1rem 1.25rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.worker-panel-header h3 {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.worker-toolbar {
|
||||
padding: 1rem 1.25rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.worker-toolbar .search-input {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.worker-toolbar .filter-select {
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.875rem;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.worker-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* 작업자 테이블 스타일 */
|
||||
.workers-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.workers-table th,
|
||||
.workers-table td {
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.workers-table th {
|
||||
background: #f9fafb;
|
||||
font-weight: 600;
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.workers-table tr:hover {
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.worker-name-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.worker-avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-badge.active {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.status-badge.inactive {
|
||||
background: #f3f4f6;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.status-badge.resigned {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.account-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.account-badge.has-account {
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.account-badge.no-account {
|
||||
background: #f3f4f6;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
/* 빈 상태 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.empty-state h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 1024px) {
|
||||
.department-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.department-panel {
|
||||
max-height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 부서 모달 스타일 */
|
||||
.form-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-check input[type="checkbox"] {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 레이아웃 -->
|
||||
<div class="page-container">
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">작업자 관리</h1>
|
||||
<p class="page-description">부서별 작업자를 관리합니다. 부서를 선택하면 해당 부서의 작업자를 확인하고 관리할 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 부서 기반 레이아웃 -->
|
||||
<div class="department-layout">
|
||||
<!-- 왼쪽: 부서 목록 -->
|
||||
<div class="department-panel">
|
||||
<div class="department-panel-header">
|
||||
<h3>부서 목록</h3>
|
||||
<button class="btn btn-sm btn-primary" onclick="openDepartmentModal()">+ 부서 추가</button>
|
||||
</div>
|
||||
<div class="department-list" id="departmentList">
|
||||
<!-- 부서 목록이 여기에 렌더링됩니다 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 오른쪽: 작업자 목록 -->
|
||||
<div class="worker-panel">
|
||||
<div class="worker-panel-header">
|
||||
<h3 id="workerListTitle">부서를 선택하세요</h3>
|
||||
<button class="btn btn-sm btn-primary" id="addWorkerBtn" onclick="openWorkerModal()" style="display: none;">+ 작업자 추가</button>
|
||||
</div>
|
||||
<div class="worker-toolbar" id="workerToolbar" style="display: none;">
|
||||
<input type="text" class="search-input" id="workerSearch" placeholder="작업자 검색..." oninput="filterWorkers()">
|
||||
<select class="filter-select" id="statusFilter" onchange="filterWorkers()">
|
||||
<option value="">모든 상태</option>
|
||||
<option value="active">활성</option>
|
||||
<option value="inactive">비활성</option>
|
||||
<option value="resigned">퇴사</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="worker-list" id="workerList">
|
||||
<div class="empty-state">
|
||||
<h4>부서를 선택해주세요</h4>
|
||||
<p>왼쪽에서 부서를 선택하면 해당 부서의 작업자가 표시됩니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 부서 추가/수정 모달 -->
|
||||
<div id="departmentModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container" style="max-width: 500px;">
|
||||
<div class="modal-header">
|
||||
<h2 id="departmentModalTitle">새 부서 등록</h2>
|
||||
<button class="modal-close-btn" onclick="closeDepartmentModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="departmentForm" onsubmit="event.preventDefault(); saveDepartment();">
|
||||
<input type="hidden" id="departmentId">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">부서명 *</label>
|
||||
<input type="text" id="departmentName" class="form-control" placeholder="예: 생산팀, 품질관리팀" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">상위 부서</label>
|
||||
<select id="parentDepartment" class="form-control">
|
||||
<option value="">없음 (최상위 부서)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">설명</label>
|
||||
<textarea id="departmentDescription" class="form-control" rows="2" placeholder="부서에 대한 설명"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">표시 순서</label>
|
||||
<input type="number" id="displayOrder" class="form-control" value="0" min="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label"> </label>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="isActiveDept" checked>
|
||||
<label for="isActiveDept">활성화</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeDepartmentModal()">취소</button>
|
||||
<button type="button" class="btn btn-danger" id="deleteDeptBtn" onclick="deleteDepartment()" style="display: none;">삭제</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveDepartment()">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업자 추가/수정 모달 -->
|
||||
<div id="workerModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<h2 id="workerModalTitle">새 작업자 등록</h2>
|
||||
<button class="modal-close-btn" onclick="closeWorkerModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form id="workerForm" onsubmit="event.preventDefault(); saveWorker();">
|
||||
<input type="hidden" id="workerId">
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">작업자명 *</label>
|
||||
<input type="text" id="workerName" class="form-control" placeholder="작업자 이름을 입력하세요" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">직책</label>
|
||||
<select id="jobType" class="form-control">
|
||||
<option value="worker">작업자</option>
|
||||
<option value="leader">그룹장</option>
|
||||
<option value="admin">관리자</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">입사일</label>
|
||||
<input type="date" id="joinDate" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">급여</label>
|
||||
<input type="number" id="salary" class="form-control" placeholder="월급여">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">연차</label>
|
||||
<input type="number" id="annualLeave" class="form-control" placeholder="연차 일수" value="0">
|
||||
</div>
|
||||
|
||||
<!-- 상태 관리 섹션 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" style="font-weight: 600; margin-bottom: 0.75rem; display: block;">상태 관리</label>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
||||
<!-- 계정 생성/연동 -->
|
||||
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
|
||||
<input type="checkbox" id="createAccount" style="margin: 0; cursor: pointer;">
|
||||
<span>계정 생성/연동</span>
|
||||
</label>
|
||||
<small style="color: #6b7280; font-size: 0.75rem; margin-top: -0.5rem; margin-left: 1.5rem;">
|
||||
체크 시 로그인 계정이 자동 생성됩니다 (ID: 이름 로마자 변환, 초기 비밀번호: 1234)
|
||||
</small>
|
||||
|
||||
<!-- 현장직/사무직 구분 -->
|
||||
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
|
||||
<input type="checkbox" id="isActiveWorker" checked style="margin: 0; cursor: pointer;">
|
||||
<span>현장직 (활성화)</span>
|
||||
</label>
|
||||
<small style="color: #6b7280; font-size: 0.75rem; margin-top: -0.5rem; margin-left: 1.5rem;">
|
||||
체크: 현장직 (TBM, 작업보고서에 표시) / 체크 해제: 사무직
|
||||
</small>
|
||||
|
||||
<!-- 퇴사 처리 -->
|
||||
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
|
||||
<input type="checkbox" id="isResigned" style="margin: 0; cursor: pointer;">
|
||||
<span style="color: #ef4444;">퇴사 처리</span>
|
||||
</label>
|
||||
<small style="color: #ef4444; font-size: 0.75rem; margin-top: -0.5rem; margin-left: 1.5rem;">
|
||||
퇴사한 작업자로 표시됩니다. TBM/작업 보고서에서 제외됩니다
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeWorkerModal()">취소</button>
|
||||
<button type="button" class="btn btn-danger" id="deleteWorkerBtn" onclick="deleteWorker()" style="display: none;">삭제</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveWorker()">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- worker-management.js만 로드 (navbar/sidebar는 app-init.js에서 처리) -->
|
||||
<script type="module" src="/js/worker-management.js?v=8"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,22 +3,34 @@
|
||||
<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=8">
|
||||
<title>작업장 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/workplace-management.css?v=7">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 레이아웃 (기존 admin 레이아웃과 호환) -->
|
||||
<div class="page-container">
|
||||
<main class="main-content">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="wp-content">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="wp-page-header">
|
||||
@@ -128,8 +140,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 공장(카테고리) 추가/수정 모달 -->
|
||||
<div id="categoryModal" class="wp-modal-overlay" style="display: none;">
|
||||
@@ -418,6 +431,8 @@
|
||||
</div>
|
||||
|
||||
<!-- 작업장 관리 모듈 (리팩토링된 구조) -->
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/workplace-management/state.js?v=1"></script>
|
||||
<script src="/js/workplace-management/utils.js?v=1"></script>
|
||||
<script src="/js/workplace-management/api.js?v=1"></script>
|
||||
@@ -425,5 +440,6 @@
|
||||
<!-- 기존 UI 로직 (점진적 마이그레이션) -->
|
||||
<script type="module" src="/js/workplace-management.js?v=9"></script>
|
||||
<script type="module" src="/js/workplace-layout-map.js?v=2"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<title>연간 연차 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
@@ -234,12 +232,29 @@
|
||||
.loading { text-align: center; padding: 2rem; color: #6b7280; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="has-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
<div id="sidebar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<main class="main-content">
|
||||
<div class="page-wrapper">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">연간 연차 현황</h1>
|
||||
@@ -289,8 +304,10 @@
|
||||
<span class="save-status" id="saveStatus">변경사항이 있으면 저장 버튼을 눌러주세요</span>
|
||||
<button class="btn btn-success" onclick="saveAll()">저장</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 경조사 모달 -->
|
||||
<div class="modal-overlay" id="specialModal">
|
||||
@@ -311,6 +328,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script>
|
||||
// axios 설정
|
||||
@@ -758,5 +777,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,14 +3,10 @@
|
||||
<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="stylesheet" href="/css/mobile.css?v=1">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>출근 체크 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
@@ -162,12 +158,29 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="has-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
<div id="sidebar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<main class="main-content">
|
||||
<div class="page-wrapper">
|
||||
<h1 class="page-title">출근 체크</h1>
|
||||
<p class="page-desc">클릭하여 출근/결근 상태를 변경하세요</p>
|
||||
|
||||
@@ -204,12 +217,14 @@
|
||||
<div id="saveStatus" style="margin-bottom: 1rem;"></div>
|
||||
<button id="saveBtn" class="btn-save" onclick="saveCheckin()">출근 체크 저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script type="module">
|
||||
</script>
|
||||
<script>
|
||||
(function() {
|
||||
const checkApiConfig = setInterval(() => {
|
||||
@@ -395,19 +410,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 모바일 하단 네비게이션 -->
|
||||
<div id="mobile-nav-container"></div>
|
||||
<script>
|
||||
if (window.innerWidth <= 768) {
|
||||
fetch('/components/mobile-nav.html')
|
||||
.then(r => r.text())
|
||||
.then(html => {
|
||||
document.getElementById('mobile-nav-container').innerHTML = html;
|
||||
const scripts = document.getElementById('mobile-nav-container').querySelectorAll('script');
|
||||
scripts.forEach(s => eval(s.textContent));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,21 +3,34 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>일일 출퇴근 입력 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">일일 출퇴근 입력</h1>
|
||||
@@ -52,13 +65,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
</script>
|
||||
<script>
|
||||
// axios 기본 설정
|
||||
(function() {
|
||||
@@ -388,5 +402,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>월별 출근부 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
/* 테이블 컨테이너 */
|
||||
.table-container {
|
||||
@@ -354,13 +351,29 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">월별 출근부</h1>
|
||||
@@ -433,8 +446,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 휴무일 설정 모달 -->
|
||||
<div class="modal-overlay" id="holidayModal">
|
||||
@@ -459,10 +474,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
</script>
|
||||
<script>
|
||||
// axios 기본 설정
|
||||
(function() {
|
||||
@@ -1157,5 +1171,6 @@
|
||||
link.click();
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<title>내 연차 정보 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
@@ -197,12 +195,29 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="has-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
<div id="sidebar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<main class="main-content">
|
||||
<div class="page-wrapper">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">내 연차 정보</h1>
|
||||
@@ -245,9 +260,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script>
|
||||
// axios 설정
|
||||
@@ -550,5 +569,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,30 +4,35 @@
|
||||
<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">
|
||||
<title>휴가 발생 입력 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/vacation-allocation.css">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
|
||||
<!-- 스크립트 -->
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<script type="module" src="/js/vacation-allocation.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- 메인 컨테이너 -->
|
||||
<div class="page-container">
|
||||
|
||||
<!-- 네비게이션 헤더 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="content-wrapper">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="page-header">
|
||||
@@ -255,10 +260,9 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 알림 토스트 -->
|
||||
<div class="toast-container" id="toastContainer"></div>
|
||||
@@ -349,6 +353,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script type="module" src="/js/vacation-allocation.js" defer></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>휴가 승인 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.tabs {
|
||||
display: flex;
|
||||
@@ -42,13 +39,29 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">휴가 승인 관리</h1>
|
||||
@@ -105,14 +118,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script src="/js/vacation-common.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
</script>
|
||||
<script>
|
||||
// axios 기본 설정
|
||||
(function() {
|
||||
@@ -260,5 +274,6 @@
|
||||
renderVacationRequests(allRequestsData, 'allRequestsList', false);
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,21 +3,34 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>휴가 직접 입력 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">휴가 직접 입력</h1>
|
||||
@@ -105,14 +118,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script src="/js/vacation-common.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
</script>
|
||||
<script>
|
||||
// axios 기본 설정
|
||||
(function() {
|
||||
@@ -287,5 +301,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>휴가 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.tabs {
|
||||
display: flex;
|
||||
@@ -42,13 +39,29 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">휴가 관리</h1>
|
||||
@@ -187,14 +200,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script src="/js/vacation-common.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
</script>
|
||||
<script>
|
||||
// axios 기본 설정
|
||||
(function() {
|
||||
@@ -454,5 +468,6 @@
|
||||
renderVacationRequests(allRequestsData, 'allRequestsList', false);
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,21 +3,34 @@
|
||||
<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/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<title>휴가 신청 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">휴가 신청</h1>
|
||||
@@ -99,14 +112,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script src="/js/vacation-common.js"></script>
|
||||
<script type="module">
|
||||
import '/js/api-config.js?v=3';
|
||||
</script>
|
||||
<script>
|
||||
// axios 기본 설정
|
||||
(function() {
|
||||
@@ -265,5 +279,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
<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="stylesheet" href="/css/mobile.css?v=1">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<title>근무 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
@@ -204,12 +201,33 @@
|
||||
.warning-box a { color: #92400e; font-weight: 500; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="has-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
<div id="sidebar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<main class="main-content">
|
||||
<div class="page-wrapper">
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">근무 현황</h1>
|
||||
<div class="controls">
|
||||
@@ -253,9 +271,13 @@
|
||||
<span id="saveStatus" class="save-status"></span>
|
||||
<button id="saveBtn" class="btn-save" onclick="saveWorkStatus()">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
@@ -695,19 +717,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 모바일 하단 네비게이션 -->
|
||||
<div id="mobile-nav-container"></div>
|
||||
<script>
|
||||
if (window.innerWidth <= 768) {
|
||||
fetch('/components/mobile-nav.html')
|
||||
.then(r => r.text())
|
||||
.then(html => {
|
||||
document.getElementById('mobile-nav-container').innerHTML = html;
|
||||
const scripts = document.getElementById('mobile-nav-container').querySelectorAll('script');
|
||||
scripts.forEach(s => eval(s.textContent));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
144
system1-factory/web/pages/dashboard-new.html
Normal file
144
system1-factory/web/pages/dashboard-new.html
Normal file
@@ -0,0 +1,144 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>대시보드 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Mobile overlay -->
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<!-- Sidebar Nav -->
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 날짜/시간 헤더 -->
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-gray-800">대시보드</h2>
|
||||
<p class="text-sm text-gray-500 mt-0.5" id="dateTimeDisplay">-</p>
|
||||
</div>
|
||||
<button onclick="loadDashboard()" class="text-sm text-gray-500 hover:text-orange-600 border border-gray-200 px-3 py-1.5 rounded-lg hover:bg-orange-50">
|
||||
<i class="fas fa-sync-alt mr-1"></i>새로고침
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 요약 카드 -->
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-3 mb-5">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-orange-600" id="statTbm">-</div>
|
||||
<div class="stat-label">금일 TBM</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-blue-600" id="statWorkers">-</div>
|
||||
<div class="stat-label">출근 인원</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-red-600" id="statRepairs">-</div>
|
||||
<div class="stat-label">수리 요청</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-purple-600" id="statNotifications">-</div>
|
||||
<div class="stat-label">미확인 알림</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
||||
<!-- 금일 TBM 현황 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5">
|
||||
<h3 class="text-base font-semibold text-gray-800 mb-4">
|
||||
<i class="fas fa-clipboard-list text-orange-500 mr-2"></i>금일 TBM
|
||||
</h3>
|
||||
<div id="tbmList" class="space-y-2">
|
||||
<p class="text-gray-400 text-sm text-center py-4">로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 최근 알림 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5">
|
||||
<h3 class="text-base font-semibold text-gray-800 mb-4">
|
||||
<i class="fas fa-bell text-orange-500 mr-2"></i>최근 알림
|
||||
</h3>
|
||||
<div id="notificationList" class="space-y-2">
|
||||
<p class="text-gray-400 text-sm text-center py-4">로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 미완료 수리 요청 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5">
|
||||
<h3 class="text-base font-semibold text-gray-800 mb-4">
|
||||
<i class="fas fa-tools text-orange-500 mr-2"></i>수리 요청 현황
|
||||
</h3>
|
||||
<div id="repairList" class="space-y-2">
|
||||
<p class="text-gray-400 text-sm text-center py-4">로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 빠른 이동 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5">
|
||||
<h3 class="text-base font-semibold text-gray-800 mb-4">
|
||||
<i class="fas fa-rocket text-orange-500 mr-2"></i>빠른 이동
|
||||
</h3>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<a href="/pages/work/tbm.html" class="flex items-center gap-3 p-3 rounded-lg border border-gray-100 hover:border-orange-200 hover:bg-orange-50 transition-colors">
|
||||
<i class="fas fa-clipboard-list text-orange-500 w-5 text-center"></i>
|
||||
<span class="text-sm text-gray-700">TBM 관리</span>
|
||||
</a>
|
||||
<a href="/pages/work/report-create.html" class="flex items-center gap-3 p-3 rounded-lg border border-gray-100 hover:border-orange-200 hover:bg-orange-50 transition-colors">
|
||||
<i class="fas fa-file-alt text-orange-500 w-5 text-center"></i>
|
||||
<span class="text-sm text-gray-700">작업보고서</span>
|
||||
</a>
|
||||
<a href="/pages/attendance/checkin.html" class="flex items-center gap-3 p-3 rounded-lg border border-gray-100 hover:border-orange-200 hover:bg-orange-50 transition-colors">
|
||||
<i class="fas fa-user-check text-orange-500 w-5 text-center"></i>
|
||||
<span class="text-sm text-gray-700">출근 체크</span>
|
||||
</a>
|
||||
<a href="/pages/admin/repair-management.html" class="flex items-center gap-3 p-3 rounded-lg border border-gray-100 hover:border-orange-200 hover:bg-orange-50 transition-colors">
|
||||
<i class="fas fa-tools text-orange-500 w-5 text-center"></i>
|
||||
<span class="text-sm text-gray-700">시설설비 관리</span>
|
||||
</a>
|
||||
<a href="/pages/attendance/vacation-request.html" class="flex items-center gap-3 p-3 rounded-lg border border-gray-100 hover:border-orange-200 hover:bg-orange-50 transition-colors">
|
||||
<i class="fas fa-paper-plane text-orange-500 w-5 text-center"></i>
|
||||
<span class="text-sm text-gray-700">휴가 신청</span>
|
||||
</a>
|
||||
<a href="/pages/dashboard.html" class="flex items-center gap-3 p-3 rounded-lg border border-gray-100 hover:border-orange-200 hover:bg-orange-50 transition-colors">
|
||||
<i class="fas fa-map text-orange-500 w-5 text-center"></i>
|
||||
<span class="text-sm text-gray-700">작업장 현황</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/static/js/tkfb-dashboard.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,546 +1,334 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>작업 현황판 | 테크니컬코리아</title>
|
||||
|
||||
<!-- 리소스 프리로딩 -->
|
||||
<!-- preconnect는 Gateway 프록시 사용 시 불필요 -->
|
||||
<link rel="preload" href="/css/design-system.css" as="style">
|
||||
<link rel="preload" href="/js/api-base.js?v=3" as="script">
|
||||
<link rel="preload" href="/js/app-init.js?v=9" as="script">
|
||||
|
||||
<!-- 모던 디자인 시스템 적용 -->
|
||||
<link rel="stylesheet" href="/css/design-system.css">
|
||||
<link rel="stylesheet" href="/css/modern-dashboard.css?v=3">
|
||||
<link rel="stylesheet" href="/css/mobile.css?v=4">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
|
||||
<!-- api-base.js에서 SW 캐시 강제 해제 처리 -->
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></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?v=3" defer></script>
|
||||
<script src="/js/mobile-dashboard.js?v=4" defer></script>
|
||||
<!-- instant.page: 링크 호버 시 페이지 프리로딩 -->
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>작업장 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/modern-dashboard.css?v=3">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- 메인 컨테이너 -->
|
||||
<div class="dashboard-container">
|
||||
|
||||
<!-- 네비게이션 헤더 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="dashboard-main">
|
||||
|
||||
<!-- 모바일 대시보드 (작업장 리스트 뷰) -->
|
||||
<section id="mobileDashboardView" class="mobile-dashboard-view" style="display:none;">
|
||||
<div class="md-date-header">
|
||||
<span class="md-date-label">금일 현황</span>
|
||||
<time class="md-date-value" id="mDateValue"></time>
|
||||
</div>
|
||||
|
||||
<!-- 카테고리 탭 -->
|
||||
<div class="md-category-tabs" id="mCategoryTabs"></div>
|
||||
|
||||
<!-- 작업장 리스트 -->
|
||||
<div class="md-workplace-list" id="mWorkplaceList"></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; 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>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</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>
|
||||
|
||||
<!-- 임시 이동된 설비 현황 -->
|
||||
<section class="moved-equipment-section" style="margin-top: 24px;">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="flex justify-between items-center">
|
||||
<h2 class="card-title">🚚 임시 이동된 설비</h2>
|
||||
<button class="btn btn-outline btn-sm" onclick="loadMovedEquipments()">새로고침</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="movedEquipmentList" class="moved-equipment-grid">
|
||||
<!-- 동적 로드 -->
|
||||
</div>
|
||||
<div id="noMovedEquipment" style="display: none; text-align: center; padding: 40px; color: var(--gray-500);">
|
||||
<div style="font-size: 48px; margin-bottom: 12px;">✅</div>
|
||||
<p>임시 이동된 설비가 없습니다.</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" class="workplace-modal-overlay">
|
||||
<div class="workplace-modal-container">
|
||||
<!-- 모달 헤더 -->
|
||||
<div class="workplace-modal-header">
|
||||
<div class="workplace-modal-title-section">
|
||||
<h2 id="modalWorkplaceName" class="workplace-modal-title"></h2>
|
||||
<p id="modalWorkplaceDesc" class="workplace-modal-subtitle"></p>
|
||||
</div>
|
||||
<button class="workplace-modal-close" onclick="closeWorkplaceModal()">×</button>
|
||||
</div>
|
||||
|
||||
<!-- 모달 바디 -->
|
||||
<div class="workplace-modal-body">
|
||||
<!-- 탭 네비게이션 -->
|
||||
<div class="workplace-modal-tabs">
|
||||
<button class="workplace-tab active" data-tab="overview" onclick="switchWorkplaceTab('overview')">
|
||||
<span class="tab-icon">📊</span>
|
||||
<span class="tab-text">현황 개요</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="workers" onclick="switchWorkplaceTab('workers')">
|
||||
<span class="tab-icon">👷</span>
|
||||
<span class="tab-text">작업자</span>
|
||||
<span id="workerCountBadge" class="tab-badge">0</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="visitors" onclick="switchWorkplaceTab('visitors')">
|
||||
<span class="tab-icon">🚪</span>
|
||||
<span class="tab-text">방문자</span>
|
||||
<span id="visitorCountBadge" class="tab-badge">0</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="detail-map" onclick="switchWorkplaceTab('detail-map')">
|
||||
<span class="tab-icon">🗺️</span>
|
||||
<span class="tab-text">상세 지도</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="moved-eq" onclick="switchWorkplaceTab('moved-eq')">
|
||||
<span class="tab-icon">🚚</span>
|
||||
<span class="tab-text">이동 설비</span>
|
||||
<span id="movedEqCountBadge" class="tab-badge" style="display:none;">0</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 탭 콘텐츠 -->
|
||||
<div class="workplace-tab-contents">
|
||||
<!-- 현황 개요 탭 -->
|
||||
<div id="tab-overview" class="workplace-tab-content active">
|
||||
<!-- 요약 카드 -->
|
||||
<div class="workplace-summary-cards">
|
||||
<div class="summary-card workers">
|
||||
<div class="summary-icon">👷</div>
|
||||
<div class="summary-info">
|
||||
<span class="summary-value" id="summaryWorkerCount">0</span>
|
||||
<span class="summary-label">작업자</span>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card visitors">
|
||||
<div class="summary-icon">🚪</div>
|
||||
<div class="summary-info">
|
||||
<span class="summary-value" id="summaryVisitorCount">0</span>
|
||||
<span class="summary-label">방문자</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Mobile overlay -->
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<!-- Sidebar Nav -->
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 모바일 대시보드 (작업장 리스트 뷰) -->
|
||||
<section id="mobileDashboardView" class="mobile-dashboard-view" style="display:none;">
|
||||
<div class="md-date-header">
|
||||
<span class="md-date-label">금일 현황</span>
|
||||
<time class="md-date-value" id="mDateValue"></time>
|
||||
</div>
|
||||
<div class="md-category-tabs" id="mCategoryTabs"></div>
|
||||
<div class="md-workplace-list" id="mWorkplaceList"></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; display: none;">
|
||||
<canvas id="workplaceMapCanvas" style="width: 100%; max-width: 100%; cursor: pointer; border: 2px solid #d1d5db; border-radius: 0.5rem;"></canvas>
|
||||
<div id="mapLegend" style="position: absolute; top: 16px; right: 16px; background: white; padding: 16px; border-radius: 0.5rem; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
|
||||
<h4 style="font-size: 0.875rem; 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: 0.875rem;">작업 중 (내부 작업자)</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: 0.875rem;">방문 예정 (외부 인원)</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: 0.875rem;">작업 + 방문</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mapPlaceholder" style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 400px; color: #6b7280;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">🏭</div>
|
||||
<h3 style="margin-bottom: 8px;">공장을 선택하세요</h3>
|
||||
<p style="font-size: 0.875rem;">위에서 공장을 선택하면 작업장 현황을 확인할 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 임시 이동된 설비 현황 -->
|
||||
<section class="moved-equipment-section" style="margin-top: 24px;">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="flex justify-between items-center">
|
||||
<h2 class="card-title">🚚 임시 이동된 설비</h2>
|
||||
<button class="btn btn-outline btn-sm" onclick="loadMovedEquipments()">새로고침</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="movedEquipmentList" class="moved-equipment-grid"></div>
|
||||
<div id="noMovedEquipment" style="display: none; text-align: center; padding: 40px; color: #6b7280;">
|
||||
<div style="font-size: 48px; margin-bottom: 12px;">✅</div>
|
||||
<p>임시 이동된 설비가 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 토스트 -->
|
||||
<div class="toast-container" id="toastContainer"></div>
|
||||
|
||||
<!-- 작업장 상세 정보 모달 -->
|
||||
<div id="workplaceDetailModal" class="workplace-modal-overlay">
|
||||
<div class="workplace-modal-container">
|
||||
<div class="workplace-modal-header">
|
||||
<div class="workplace-modal-title-section">
|
||||
<h2 id="modalWorkplaceName" class="workplace-modal-title"></h2>
|
||||
<p id="modalWorkplaceDesc" class="workplace-modal-subtitle"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card tasks">
|
||||
<div class="summary-icon">📋</div>
|
||||
<div class="summary-info">
|
||||
<span class="summary-value" id="summaryTaskCount">0</span>
|
||||
<span class="summary-label">작업 수</span>
|
||||
<button class="workplace-modal-close" onclick="closeWorkplaceModal()">×</button>
|
||||
</div>
|
||||
<div class="workplace-modal-body">
|
||||
<div class="workplace-modal-tabs">
|
||||
<button class="workplace-tab active" data-tab="overview" onclick="switchWorkplaceTab('overview')">
|
||||
<span class="tab-icon">📊</span><span class="tab-text">현황 개요</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="workers" onclick="switchWorkplaceTab('workers')">
|
||||
<span class="tab-icon">👷</span><span class="tab-text">작업자</span>
|
||||
<span id="workerCountBadge" class="tab-badge">0</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="visitors" onclick="switchWorkplaceTab('visitors')">
|
||||
<span class="tab-icon">🚪</span><span class="tab-text">방문자</span>
|
||||
<span id="visitorCountBadge" class="tab-badge">0</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="detail-map" onclick="switchWorkplaceTab('detail-map')">
|
||||
<span class="tab-icon">🗺️</span><span class="tab-text">상세 지도</span>
|
||||
</button>
|
||||
<button class="workplace-tab" data-tab="moved-eq" onclick="switchWorkplaceTab('moved-eq')">
|
||||
<span class="tab-icon">🚚</span><span class="tab-text">이동 설비</span>
|
||||
<span id="movedEqCountBadge" class="tab-badge" style="display:none;">0</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 현재 작업 목록 -->
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title">
|
||||
<span class="section-icon">🔧</span>
|
||||
진행 중인 작업
|
||||
</h4>
|
||||
<div id="currentTasksList" class="current-tasks-list">
|
||||
<p class="empty-message">진행 중인 작업이 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비 현황 (간략) -->
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title">
|
||||
<span class="section-icon">⚙️</span>
|
||||
설비 현황
|
||||
</h4>
|
||||
<div id="equipmentSummary" class="equipment-summary">
|
||||
<p class="empty-message">설비 정보를 불러오는 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업자 탭 -->
|
||||
<div id="tab-workers" class="workplace-tab-content">
|
||||
<div id="internalWorkersList" class="workers-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- 방문자 탭 -->
|
||||
<div id="tab-visitors" class="workplace-tab-content">
|
||||
<div id="externalVisitorsList" class="visitors-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- 상세 지도 탭 -->
|
||||
<div id="tab-detail-map" class="workplace-tab-content">
|
||||
<div id="detailMapContainer" class="detail-map-container">
|
||||
<div class="detail-map-placeholder">
|
||||
<span class="placeholder-icon">🗺️</span>
|
||||
<p>상세 지도를 불러오는 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="detailMapLegend" class="detail-map-legend"></div>
|
||||
</div>
|
||||
|
||||
<!-- 이동 설비 탭 -->
|
||||
<div id="tab-moved-eq" class="workplace-tab-content">
|
||||
<div class="moved-eq-tab-content">
|
||||
<!-- 이 작업장으로 이동해 온 설비 -->
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title">
|
||||
<span class="section-icon">📥</span>
|
||||
이 작업장으로 이동해 온 설비
|
||||
</h4>
|
||||
<div id="movedInEquipmentList" class="moved-eq-list">
|
||||
<p class="empty-message">없음</p>
|
||||
<div class="workplace-tab-contents">
|
||||
<div id="tab-overview" class="workplace-tab-content active">
|
||||
<div class="workplace-summary-cards">
|
||||
<div class="summary-card workers">
|
||||
<div class="summary-icon">👷</div>
|
||||
<div class="summary-info"><span class="summary-value" id="summaryWorkerCount">0</span><span class="summary-label">작업자</span></div>
|
||||
</div>
|
||||
<div class="summary-card visitors">
|
||||
<div class="summary-icon">🚪</div>
|
||||
<div class="summary-info"><span class="summary-value" id="summaryVisitorCount">0</span><span class="summary-label">방문자</span></div>
|
||||
</div>
|
||||
<div class="summary-card tasks">
|
||||
<div class="summary-icon">📋</div>
|
||||
<div class="summary-info"><span class="summary-value" id="summaryTaskCount">0</span><span class="summary-label">작업 수</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title"><span class="section-icon">🔧</span> 진행 중인 작업</h4>
|
||||
<div id="currentTasksList" class="current-tasks-list"><p class="empty-message">진행 중인 작업이 없습니다.</p></div>
|
||||
</div>
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title"><span class="section-icon">⚙️</span> 설비 현황</h4>
|
||||
<div id="equipmentSummary" class="equipment-summary"><p class="empty-message">설비 정보를 불러오는 중...</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-workers" class="workplace-tab-content"><div id="internalWorkersList" class="workers-list"></div></div>
|
||||
<div id="tab-visitors" class="workplace-tab-content"><div id="externalVisitorsList" class="visitors-list"></div></div>
|
||||
<div id="tab-detail-map" class="workplace-tab-content">
|
||||
<div id="detailMapContainer" class="detail-map-container">
|
||||
<div class="detail-map-placeholder"><span class="placeholder-icon">🗺️</span><p>상세 지도를 불러오는 중...</p></div>
|
||||
</div>
|
||||
<div id="detailMapLegend" class="detail-map-legend"></div>
|
||||
</div>
|
||||
<div id="tab-moved-eq" class="workplace-tab-content">
|
||||
<div class="moved-eq-tab-content">
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title"><span class="section-icon">📥</span> 이 작업장으로 이동해 온 설비</h4>
|
||||
<div id="movedInEquipmentList" class="moved-eq-list"><p class="empty-message">없음</p></div>
|
||||
</div>
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title"><span class="section-icon">📤</span> 다른 곳으로 이동한 설비</h4>
|
||||
<div id="movedOutEquipmentList" class="moved-eq-list"><p class="empty-message">없음</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이 작업장에서 다른 곳으로 이동한 설비 -->
|
||||
<div class="workplace-section">
|
||||
<h4 class="section-title">
|
||||
<span class="section-icon">📤</span>
|
||||
다른 곳으로 이동한 설비
|
||||
</h4>
|
||||
<div id="movedOutEquipmentList" class="moved-eq-list">
|
||||
<p class="empty-message">없음</p>
|
||||
</div>
|
||||
<div class="workplace-modal-footer">
|
||||
<button class="btn btn-outline" onclick="openPatrolPage()"><span>🔍</span> 순회점검</button>
|
||||
<button class="btn btn-primary" onclick="closeWorkplaceModal()">닫기</button>
|
||||
</div>
|
||||
<!-- 설비 상세 슬라이드 패널 -->
|
||||
<div id="equipmentSlidePanel" class="equipment-slide-panel">
|
||||
<div class="slide-panel-header">
|
||||
<button class="slide-panel-back" onclick="closeEquipmentPanel()">←</button>
|
||||
<div class="slide-panel-title-section">
|
||||
<h3 id="panelEquipmentTitle" class="slide-panel-title"></h3>
|
||||
<span id="panelEquipmentStatus" class="slide-panel-status"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide-panel-body">
|
||||
<div class="panel-section"><div class="panel-info-grid" id="panelEquipmentInfo"></div></div>
|
||||
<div class="panel-section">
|
||||
<div class="panel-section-header"><h4>설비 사진</h4><button class="btn-icon-sm" onclick="openPanelPhotoUpload()">+</button></div>
|
||||
<div class="panel-photo-grid" id="panelPhotoGrid"><div class="panel-empty">등록된 사진이 없습니다</div></div>
|
||||
</div>
|
||||
<div class="panel-actions">
|
||||
<button class="panel-action-btn move" onclick="openPanelMoveModal()"><span>↔</span> 임시이동</button>
|
||||
<button class="panel-action-btn repair" onclick="openPanelRepairModal()"><span>🔧</span> 수리신청</button>
|
||||
<button class="panel-action-btn export" onclick="openPanelExportModal()"><span>🚚</span> 외부반출</button>
|
||||
</div>
|
||||
<div class="panel-section"><h4 class="panel-section-title">수리 이력</h4><div id="panelRepairHistory" class="panel-history-list"><div class="panel-empty">수리 이력이 없습니다</div></div></div>
|
||||
<div class="panel-section"><h4 class="panel-section-title">외부반출 이력</h4><div id="panelExternalHistory" class="panel-history-list"><div class="panel-empty">외부반출 이력이 없습니다</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 모달 푸터 -->
|
||||
<div class="workplace-modal-footer">
|
||||
<button class="btn btn-outline" onclick="openPatrolPage()">
|
||||
<span>🔍</span> 순회점검
|
||||
</button>
|
||||
<button class="btn btn-primary" onclick="closeWorkplaceModal()">닫기</button>
|
||||
</div>
|
||||
|
||||
<!-- 설비 상세 슬라이드 패널 -->
|
||||
<div id="equipmentSlidePanel" class="equipment-slide-panel">
|
||||
<div class="slide-panel-header">
|
||||
<button class="slide-panel-back" onclick="closeEquipmentPanel()">←</button>
|
||||
<div class="slide-panel-title-section">
|
||||
<h3 id="panelEquipmentTitle" class="slide-panel-title"></h3>
|
||||
<span id="panelEquipmentStatus" class="slide-panel-status"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="slide-panel-body">
|
||||
<!-- 기본 정보 -->
|
||||
<div class="panel-section">
|
||||
<div class="panel-info-grid" id="panelEquipmentInfo"></div>
|
||||
</div>
|
||||
|
||||
<!-- 사진 -->
|
||||
<div class="panel-section">
|
||||
<div class="panel-section-header">
|
||||
<h4>설비 사진</h4>
|
||||
<button class="btn-icon-sm" onclick="openPanelPhotoUpload()">+</button>
|
||||
<!-- 설비 사진 업로드 모달 -->
|
||||
<div id="panelPhotoModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal">
|
||||
<div class="mini-modal-header"><h4>사진 추가</h4><button onclick="closePanelPhotoModal()">×</button></div>
|
||||
<div class="mini-modal-body">
|
||||
<input type="file" id="panelPhotoInput" accept="image/*" onchange="previewPanelPhoto(event)">
|
||||
<div id="panelPhotoPreview" class="mini-photo-preview"></div>
|
||||
<input type="text" id="panelPhotoDesc" class="form-control" placeholder="설명 (선택)">
|
||||
</div>
|
||||
<div class="panel-photo-grid" id="panelPhotoGrid">
|
||||
<div class="panel-empty">등록된 사진이 없습니다</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelPhotoModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="uploadPanelPhoto()">업로드</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 액션 버튼 -->
|
||||
<div class="panel-actions">
|
||||
<button class="panel-action-btn move" onclick="openPanelMoveModal()">
|
||||
<span>↔</span> 임시이동
|
||||
</button>
|
||||
<button class="panel-action-btn repair" onclick="openPanelRepairModal()">
|
||||
<span>🔧</span> 수리신청
|
||||
</button>
|
||||
<button class="panel-action-btn export" onclick="openPanelExportModal()">
|
||||
<span>🚚</span> 외부반출
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 수리 이력 -->
|
||||
<div class="panel-section">
|
||||
<h4 class="panel-section-title">수리 이력</h4>
|
||||
<div id="panelRepairHistory" class="panel-history-list">
|
||||
<div class="panel-empty">수리 이력이 없습니다</div>
|
||||
<!-- 설비 임시이동 모달 -->
|
||||
<div id="panelMoveModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal" style="max-width:700px;">
|
||||
<div class="mini-modal-header"><h4 id="panelMoveTitle">설비 임시 이동</h4><button onclick="closePanelMoveModal()">×</button></div>
|
||||
<div class="mini-modal-body" style="padding:0;">
|
||||
<div id="moveStep1" class="move-step-content">
|
||||
<div class="move-step-header"><span class="step-badge">1</span><span>공장 선택</span></div>
|
||||
<div class="move-factory-grid" id="moveFactoryGrid"></div>
|
||||
</div>
|
||||
<div id="moveStep2" class="move-step-content" style="display:none;">
|
||||
<div class="move-step-header"><button class="btn-step-back" onclick="moveBackToStep1()">←</button><span class="step-badge">2</span><span id="moveStep2Title">작업장 선택</span></div>
|
||||
<p class="move-help-text">지도에서 이동할 작업장을 클릭하세요</p>
|
||||
<div class="move-layout-map" id="moveLayoutMapContainer"></div>
|
||||
</div>
|
||||
<div id="moveStep3" class="move-step-content" style="display:none;">
|
||||
<div class="move-step-header"><button class="btn-step-back" onclick="moveBackToStep2()">←</button><span class="step-badge">3</span><span id="moveStep3Title">위치 선택</span></div>
|
||||
<p class="move-help-text">지도에서 설비를 배치할 위치를 클릭하세요</p>
|
||||
<div class="move-detail-map" id="moveDetailMapContainer"></div>
|
||||
<div class="form-group" style="padding:12px;"><input type="text" id="panelMoveReason" class="form-control" placeholder="이동 사유 (선택)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 외부반출 이력 -->
|
||||
<div class="panel-section">
|
||||
<h4 class="panel-section-title">외부반출 이력</h4>
|
||||
<div id="panelExternalHistory" class="panel-history-list">
|
||||
<div class="panel-empty">외부반출 이력이 없습니다</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelMoveModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" id="panelMoveConfirmBtn" onclick="confirmPanelMove()" disabled>이동 확인</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비 사진 업로드 모달 -->
|
||||
<div id="panelPhotoModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal">
|
||||
<div class="mini-modal-header">
|
||||
<h4>사진 추가</h4>
|
||||
<button onclick="closePanelPhotoModal()">×</button>
|
||||
</div>
|
||||
<div class="mini-modal-body">
|
||||
<input type="file" id="panelPhotoInput" accept="image/*" onchange="previewPanelPhoto(event)">
|
||||
<div id="panelPhotoPreview" class="mini-photo-preview"></div>
|
||||
<input type="text" id="panelPhotoDesc" class="form-control" placeholder="설명 (선택)">
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelPhotoModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="uploadPanelPhoto()">업로드</button>
|
||||
</div>
|
||||
<!-- 설비 수리신청 모달 -->
|
||||
<div id="panelRepairModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal">
|
||||
<div class="mini-modal-header"><h4>수리 신청</h4><button onclick="closePanelRepairModal()">×</button></div>
|
||||
<div class="mini-modal-body">
|
||||
<div class="form-group"><label>수리 유형</label><select id="panelRepairItem" class="form-control" onchange="onRepairTypeChange()"><option value="">선택하세요</option></select></div>
|
||||
<div class="form-group" id="newRepairTypeGroup" style="display:none;"><label>새 유형 이름</label><input type="text" id="newRepairTypeName" class="form-control" placeholder="새로운 수리 유형 입력"></div>
|
||||
<div class="form-group"><label>상세 내용</label><textarea id="panelRepairDesc" class="form-control" rows="3" placeholder="수리 필요 내용"></textarea></div>
|
||||
<div class="form-group"><label>사진 첨부</label><input type="file" id="panelRepairPhotoInput" accept="image/*" multiple></div>
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelRepairModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="submitPanelRepair()">신청</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비 임시이동 모달 -->
|
||||
<div id="panelMoveModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal" style="max-width:700px;">
|
||||
<div class="mini-modal-header">
|
||||
<h4 id="panelMoveTitle">설비 임시 이동</h4>
|
||||
<button onclick="closePanelMoveModal()">×</button>
|
||||
</div>
|
||||
<div class="mini-modal-body" style="padding:0;">
|
||||
<!-- Step 1: 공장 선택 (대분류 지도) -->
|
||||
<div id="moveStep1" class="move-step-content">
|
||||
<div class="move-step-header">
|
||||
<span class="step-badge">1</span>
|
||||
<span>공장 선택</span>
|
||||
</div>
|
||||
<div class="move-factory-grid" id="moveFactoryGrid">
|
||||
<!-- 공장 카드들 -->
|
||||
</div>
|
||||
<!-- 설비 외부반출 모달 -->
|
||||
<div id="panelExportModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal">
|
||||
<div class="mini-modal-header"><h4>외부 반출</h4><button onclick="closePanelExportModal()">×</button></div>
|
||||
<div class="mini-modal-body">
|
||||
<div class="form-group"><label class="checkbox-inline"><input type="checkbox" id="panelIsRepairExport"> 수리 외주</label></div>
|
||||
<div class="form-group"><label>반출일</label><input type="date" id="panelExportDate" class="form-control"></div>
|
||||
<div class="form-group"><label>반입 예정일</label><input type="date" id="panelExpectedReturn" class="form-control"></div>
|
||||
<div class="form-group"><label>반출처</label><input type="text" id="panelExportDest" class="form-control" placeholder="업체명"></div>
|
||||
<div class="form-group"><label>반출 사유</label><textarea id="panelExportReason" class="form-control" rows="2"></textarea></div>
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelExportModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="submitPanelExport()">반출</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: 작업장 선택 (공장 레이아웃 지도) -->
|
||||
<div id="moveStep2" class="move-step-content" style="display:none;">
|
||||
<div class="move-step-header">
|
||||
<button class="btn-step-back" onclick="moveBackToStep1()">←</button>
|
||||
<span class="step-badge">2</span>
|
||||
<span id="moveStep2Title">작업장 선택</span>
|
||||
</div>
|
||||
<p class="move-help-text">지도에서 이동할 작업장을 클릭하세요</p>
|
||||
<div class="move-layout-map" id="moveLayoutMapContainer"></div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: 위치 선택 (상세 지도) -->
|
||||
<div id="moveStep3" class="move-step-content" style="display:none;">
|
||||
<div class="move-step-header">
|
||||
<button class="btn-step-back" onclick="moveBackToStep2()">←</button>
|
||||
<span class="step-badge">3</span>
|
||||
<span id="moveStep3Title">위치 선택</span>
|
||||
</div>
|
||||
<p class="move-help-text">지도에서 설비를 배치할 위치를 클릭하세요</p>
|
||||
<div class="move-detail-map" id="moveDetailMapContainer"></div>
|
||||
<div class="form-group" style="padding:12px;">
|
||||
<input type="text" id="panelMoveReason" class="form-control" placeholder="이동 사유 (선택)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelMoveModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" id="panelMoveConfirmBtn" onclick="confirmPanelMove()" disabled>이동 확인</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비 수리신청 모달 -->
|
||||
<div id="panelRepairModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal">
|
||||
<div class="mini-modal-header">
|
||||
<h4>수리 신청</h4>
|
||||
<button onclick="closePanelRepairModal()">×</button>
|
||||
</div>
|
||||
<div class="mini-modal-body">
|
||||
<div class="form-group">
|
||||
<label>수리 유형</label>
|
||||
<select id="panelRepairItem" class="form-control" onchange="onRepairTypeChange()">
|
||||
<option value="">선택하세요</option>
|
||||
</select>
|
||||
<!-- 설비 반입 모달 -->
|
||||
<div id="panelReturnModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal" style="max-width:350px;">
|
||||
<div class="mini-modal-header"><h4>설비 반입</h4><button onclick="closePanelReturnModal()">×</button></div>
|
||||
<div class="mini-modal-body">
|
||||
<input type="hidden" id="panelReturnLogId">
|
||||
<div class="form-group"><label>반입일</label><input type="date" id="panelReturnDate" class="form-control"></div>
|
||||
<div class="form-group"><label>반입 후 상태</label><select id="panelReturnStatus" class="form-control"><option value="active">정상 가동</option><option value="maintenance">점검 필요</option><option value="repair_needed">추가 수리 필요</option></select></div>
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelReturnModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="submitPanelReturn()">반입</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="newRepairTypeGroup" style="display:none;">
|
||||
<label>새 유형 이름</label>
|
||||
<input type="text" id="newRepairTypeName" class="form-control" placeholder="새로운 수리 유형 입력">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>상세 내용</label>
|
||||
<textarea id="panelRepairDesc" class="form-control" rows="3" placeholder="수리 필요 내용"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>사진 첨부</label>
|
||||
<input type="file" id="panelRepairPhotoInput" accept="image/*" multiple>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelRepairModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="submitPanelRepair()">신청</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비 외부반출 모달 -->
|
||||
<div id="panelExportModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal">
|
||||
<div class="mini-modal-header">
|
||||
<h4>외부 반출</h4>
|
||||
<button onclick="closePanelExportModal()">×</button>
|
||||
</div>
|
||||
<div class="mini-modal-body">
|
||||
<div class="form-group">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="panelIsRepairExport"> 수리 외주
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>반출일</label>
|
||||
<input type="date" id="panelExportDate" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>반입 예정일</label>
|
||||
<input type="date" id="panelExpectedReturn" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>반출처</label>
|
||||
<input type="text" id="panelExportDest" class="form-control" placeholder="업체명">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>반출 사유</label>
|
||||
<textarea id="panelExportReason" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelExportModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="submitPanelExport()">반출</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비 반입 모달 -->
|
||||
<div id="panelReturnModal" class="mini-modal-overlay" style="display:none;">
|
||||
<div class="mini-modal" style="max-width:350px;">
|
||||
<div class="mini-modal-header">
|
||||
<h4>설비 반입</h4>
|
||||
<button onclick="closePanelReturnModal()">×</button>
|
||||
</div>
|
||||
<div class="mini-modal-body">
|
||||
<input type="hidden" id="panelReturnLogId">
|
||||
<div class="form-group">
|
||||
<label>반입일</label>
|
||||
<input type="date" id="panelReturnDate" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>반입 후 상태</label>
|
||||
<select id="panelReturnStatus" class="form-control">
|
||||
<option value="active">정상 가동</option>
|
||||
<option value="maintenance">점검 필요</option>
|
||||
<option value="repair_needed">추가 수리 필요</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" onclick="closePanelReturnModal()">취소</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="submitPanelReturn()">반입</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 모바일 하단 네비게이션 -->
|
||||
<div id="mobile-nav-container"></div>
|
||||
<script>
|
||||
// 모바일에서만 하단 네비게이션 로드
|
||||
if (window.innerWidth <= 768) {
|
||||
fetch('/components/mobile-nav.html')
|
||||
.then(r => r.text())
|
||||
.then(html => {
|
||||
document.getElementById('mobile-nav-container').innerHTML = html;
|
||||
// 스크립트 실행
|
||||
const scripts = document.getElementById('mobile-nav-container').querySelectorAll('script');
|
||||
scripts.forEach(s => eval(s.textContent));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script type="module" src="/js/modern-dashboard.js?v=10"></script>
|
||||
<script type="module" src="/js/group-leader-dashboard.js?v=1"></script>
|
||||
<script src="/js/workplace-status.js?v=3"></script>
|
||||
<script src="/js/mobile-dashboard.js?v=4"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -3,129 +3,141 @@
|
||||
<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=8">
|
||||
<title>일일순회점검 - TK 공장관리</title>
|
||||
<link rel="stylesheet" href="/css/daily-patrol.css?v=4">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 레이아웃 -->
|
||||
<div class="page-container">
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">일일순회점검</h1>
|
||||
<p class="page-description">작업장을 순회하며 안전 및 정리정돈 상태를 점검합니다</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 점검 시작 영역 -->
|
||||
<div class="patrol-start-section">
|
||||
<!-- 오늘 점검 현황 요약 -->
|
||||
<div id="todayStatusSummary" class="today-status-summary">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary btn-lg" id="startPatrolBtn" onclick="showFactorySelection()">
|
||||
<span class="btn-icon">▶</span> 순회점검 시작
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 공장 선택 영역 (점검 시작 후 표시) -->
|
||||
<div id="factorySelectionArea" class="factory-selection-area" style="display: none;">
|
||||
<div class="factory-selection-header">
|
||||
<h3>공장을 선택하세요</h3>
|
||||
<p class="factory-selection-subtitle" id="patrolSessionInfo"><!-- JS에서 렌더링 --></p>
|
||||
</div>
|
||||
<div id="factoryCardsContainer" class="factory-cards-container">
|
||||
<!-- JS에서 공장 카드 렌더링 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 점검 진행 영역 (세션 시작 후 표시) -->
|
||||
<div id="patrolArea" class="patrol-area" style="display: none;">
|
||||
<!-- 세션 정보 -->
|
||||
<div id="sessionInfo" class="session-info-bar">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
|
||||
<!-- 지도 및 체크리스트 영역 -->
|
||||
<div class="patrol-content">
|
||||
<!-- 작업장 지도 (좌측) -->
|
||||
<div class="patrol-map-section">
|
||||
<div class="map-header">
|
||||
<h3>작업장 지도</h3>
|
||||
<div class="map-legend">
|
||||
<span class="legend-item completed"><span class="dot"></span> 점검완료</span>
|
||||
<span class="legend-item in-progress"><span class="dot"></span> 점검중</span>
|
||||
<span class="legend-item pending"><span class="dot"></span> 미점검</span>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="patrolMapContainer" class="patrol-map-container">
|
||||
<!-- 지도 이미지 및 작업장 마커 -->
|
||||
</div>
|
||||
<!-- 작업장 목록 (지도 대신 사용 가능) -->
|
||||
<div id="workplaceListContainer" class="workplace-list-container">
|
||||
<!-- 작업장 목록 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 체크리스트 영역 (우측) -->
|
||||
<div class="patrol-checklist-section">
|
||||
<div id="checklistHeader" class="checklist-header">
|
||||
<h3>체크리스트</h3>
|
||||
<p class="checklist-subtitle">작업장을 선택하면 체크리스트가 표시됩니다</p>
|
||||
</div>
|
||||
<div id="checklistContent" class="checklist-content">
|
||||
<!-- 체크리스트 항목들 -->
|
||||
<div class="checklist-placeholder">
|
||||
<p>좌측 지도에서 점검할 작업장을 선택해주세요</p>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="checklistActions" class="checklist-actions" style="display: none;">
|
||||
<button type="button" class="btn btn-secondary" onclick="saveChecklistDraft()">임시저장</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveChecklist()">저장 후 다음</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 물품 현황 영역 -->
|
||||
<div id="itemsSection" class="items-section" style="display: none;">
|
||||
<div class="items-header">
|
||||
<h3><span id="selectedWorkplaceName">작업장</span> 물품 현황</h3>
|
||||
<button type="button" class="btn btn-sm btn-outline" onclick="toggleItemEditMode()">
|
||||
<span id="itemEditModeText">편집모드</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="itemsMapContainer" class="items-map-container">
|
||||
<!-- 작업장 상세 지도 및 물품 마커 -->
|
||||
</div>
|
||||
<div id="itemsLegend" class="items-legend">
|
||||
<!-- 물품 유형 범례 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 순회점검 완료 버튼 -->
|
||||
<div class="patrol-complete-section">
|
||||
<div class="form-group">
|
||||
<label for="patrolNotes">특이사항</label>
|
||||
<textarea id="patrolNotes" class="form-control" rows="2" placeholder="순회 중 발견한 특이사항을 기록하세요..."></textarea>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-lg" onclick="completePatrol()">
|
||||
순회점검 완료
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">일일순회점검</h1>
|
||||
<p class="page-description">작업장을 순회하며 안전 및 정리정돈 상태를 점검합니다</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 점검 시작 영역 -->
|
||||
<div class="patrol-start-section">
|
||||
<!-- 오늘 점검 현황 요약 -->
|
||||
<div id="todayStatusSummary" class="today-status-summary">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary btn-lg" id="startPatrolBtn" onclick="showFactorySelection()">
|
||||
<span class="btn-icon">▶</span> 순회점검 시작
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 공장 선택 영역 (점검 시작 후 표시) -->
|
||||
<div id="factorySelectionArea" class="factory-selection-area" style="display: none;">
|
||||
<div class="factory-selection-header">
|
||||
<h3>공장을 선택하세요</h3>
|
||||
<p class="factory-selection-subtitle" id="patrolSessionInfo"><!-- JS에서 렌더링 --></p>
|
||||
</div>
|
||||
<div id="factoryCardsContainer" class="factory-cards-container">
|
||||
<!-- JS에서 공장 카드 렌더링 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 점검 진행 영역 (세션 시작 후 표시) -->
|
||||
<div id="patrolArea" class="patrol-area" style="display: none;">
|
||||
<!-- 세션 정보 -->
|
||||
<div id="sessionInfo" class="session-info-bar">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
|
||||
<!-- 지도 및 체크리스트 영역 -->
|
||||
<div class="patrol-content">
|
||||
<!-- 작업장 지도 (좌측) -->
|
||||
<div class="patrol-map-section">
|
||||
<div class="map-header">
|
||||
<h3>작업장 지도</h3>
|
||||
<div class="map-legend">
|
||||
<span class="legend-item completed"><span class="dot"></span> 점검완료</span>
|
||||
<span class="legend-item in-progress"><span class="dot"></span> 점검중</span>
|
||||
<span class="legend-item pending"><span class="dot"></span> 미점검</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="patrolMapContainer" class="patrol-map-container">
|
||||
<!-- 지도 이미지 및 작업장 마커 -->
|
||||
</div>
|
||||
<!-- 작업장 목록 (지도 대신 사용 가능) -->
|
||||
<div id="workplaceListContainer" class="workplace-list-container">
|
||||
<!-- 작업장 목록 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 체크리스트 영역 (우측) -->
|
||||
<div class="patrol-checklist-section">
|
||||
<div id="checklistHeader" class="checklist-header">
|
||||
<h3>체크리스트</h3>
|
||||
<p class="checklist-subtitle">작업장을 선택하면 체크리스트가 표시됩니다</p>
|
||||
</div>
|
||||
<div id="checklistContent" class="checklist-content">
|
||||
<!-- 체크리스트 항목들 -->
|
||||
<div class="checklist-placeholder">
|
||||
<p>좌측 지도에서 점검할 작업장을 선택해주세요</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="checklistActions" class="checklist-actions" style="display: none;">
|
||||
<button type="button" class="btn btn-secondary" onclick="saveChecklistDraft()">임시저장</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveChecklist()">저장 후 다음</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 물품 현황 영역 -->
|
||||
<div id="itemsSection" class="items-section" style="display: none;">
|
||||
<div class="items-header">
|
||||
<h3><span id="selectedWorkplaceName">작업장</span> 물품 현황</h3>
|
||||
<button type="button" class="btn btn-sm btn-outline" onclick="toggleItemEditMode()">
|
||||
<span id="itemEditModeText">편집모드</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="itemsMapContainer" class="items-map-container">
|
||||
<!-- 작업장 상세 지도 및 물품 마커 -->
|
||||
</div>
|
||||
<div id="itemsLegend" class="items-legend">
|
||||
<!-- 물품 유형 범례 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 순회점검 완료 버튼 -->
|
||||
<div class="patrol-complete-section">
|
||||
<div class="form-group">
|
||||
<label for="patrolNotes">특이사항</label>
|
||||
<textarea id="patrolNotes" class="form-control" rows="2" placeholder="순회 중 발견한 특이사항을 기록하세요..."></textarea>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-lg" onclick="completePatrol()">
|
||||
순회점검 완료
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 물품 추가/수정 모달 -->
|
||||
<div id="itemModal" class="modal-overlay" style="display: none;">
|
||||
@@ -197,6 +209,9 @@
|
||||
}, 50);
|
||||
})();
|
||||
</script>
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/daily-patrol.js?v=6"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,148 +3,160 @@
|
||||
<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=8">
|
||||
<title>구역 상세 - TK 공장관리</title>
|
||||
<link rel="stylesheet" href="/css/zone-detail.css?v=4">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 레이아웃 -->
|
||||
<div class="page-container">
|
||||
<main class="main-content">
|
||||
<div class="dashboard-main">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="zone-header">
|
||||
<div class="zone-header-left">
|
||||
<button class="btn btn-back" onclick="goBack()">
|
||||
<span>←</span> 돌아가기
|
||||
</button>
|
||||
</div>
|
||||
<div class="zone-header-center">
|
||||
<h1 id="zoneName" class="zone-title">작업장</h1>
|
||||
<p id="zoneCategory" class="zone-subtitle">공장</p>
|
||||
</div>
|
||||
<div class="zone-header-right">
|
||||
<span id="currentDate" class="current-date"></span>
|
||||
</div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="zone-header">
|
||||
<div class="zone-header-left">
|
||||
<button class="btn btn-back" onclick="goBack()">
|
||||
<span>←</span> 돌아가기
|
||||
</button>
|
||||
</div>
|
||||
<div class="zone-header-center">
|
||||
<h1 id="zoneName" class="zone-title">작업장</h1>
|
||||
<p id="zoneCategory" class="zone-subtitle">공장</p>
|
||||
</div>
|
||||
<div class="zone-header-right">
|
||||
<span id="currentDate" class="current-date"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 요약 카드 -->
|
||||
<div id="summaryCards" class="summary-cards">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
<!-- 요약 카드 -->
|
||||
<div id="summaryCards" class="summary-cards">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
|
||||
<!-- 탭 네비게이션 -->
|
||||
<div class="tab-navigation">
|
||||
<button class="tab-btn active" data-tab="map" onclick="switchTab('map')">
|
||||
🗺️ 구역 현황
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="issues" onclick="switchTab('issues')">
|
||||
🚨 안전신고/부적합
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="equipment" onclick="switchTab('equipment')">
|
||||
⚙️ 설비/수리
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="visits" onclick="switchTab('visits')">
|
||||
🚶 출입현황
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="tbm" onclick="switchTab('tbm')">
|
||||
📋 TBM
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="patrol" onclick="switchTab('patrol')">
|
||||
🔍 순회점검
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 탭 콘텐츠 -->
|
||||
<div class="tab-contents">
|
||||
<!-- 구역 현황 탭 -->
|
||||
<div id="tab-map" class="tab-content active">
|
||||
<div class="map-editor-section">
|
||||
<div class="map-editor-header">
|
||||
<h3>구역 현황</h3>
|
||||
<div class="map-editor-actions">
|
||||
<button class="btn btn-primary btn-sm" id="addItemBtn" onclick="startAddItem()">
|
||||
➕ 현황 등록
|
||||
<!-- 탭 네비게이션 -->
|
||||
<div class="tab-navigation">
|
||||
<button class="tab-btn active" data-tab="map" onclick="switchTab('map')">
|
||||
🗺️ 구역 현황
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="issues" onclick="switchTab('issues')">
|
||||
🚨 안전신고/부적합
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="equipment" onclick="switchTab('equipment')">
|
||||
⚙️ 설비/수리
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="visits" onclick="switchTab('visits')">
|
||||
🚶 출입현황
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="tbm" onclick="switchTab('tbm')">
|
||||
📋 TBM
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="patrol" onclick="switchTab('patrol')">
|
||||
🔍 순회점검
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-editor-container">
|
||||
<div id="zoneMapContainer" class="zone-map-container">
|
||||
<div class="map-placeholder">지도를 로딩 중...</div>
|
||||
</div>
|
||||
<div class="map-legend">
|
||||
<div class="legend-title">주의 수준</div>
|
||||
<div class="legend-items">
|
||||
<div class="legend-item"><span class="legend-color" style="background: #10b981;"></span> 양호</div>
|
||||
<div class="legend-item"><span class="legend-color" style="background: #f59e0b;"></span> 주의</div>
|
||||
<div class="legend-item"><span class="legend-color" style="background: #ef4444;"></span> 관리필요</div>
|
||||
|
||||
<!-- 탭 콘텐츠 -->
|
||||
<div class="tab-contents">
|
||||
<!-- 구역 현황 탭 -->
|
||||
<div id="tab-map" class="tab-content active">
|
||||
<div class="map-editor-section">
|
||||
<div class="map-editor-header">
|
||||
<h3>구역 현황</h3>
|
||||
<div class="map-editor-actions">
|
||||
<button class="btn btn-primary btn-sm" id="addItemBtn" onclick="startAddItem()">
|
||||
➕ 현황 등록
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-editor-container">
|
||||
<div id="zoneMapContainer" class="zone-map-container">
|
||||
<div class="map-placeholder">지도를 로딩 중...</div>
|
||||
</div>
|
||||
<div class="map-legend">
|
||||
<div class="legend-title">주의 수준</div>
|
||||
<div class="legend-items">
|
||||
<div class="legend-item"><span class="legend-color" style="background: #10b981;"></span> 양호</div>
|
||||
<div class="legend-item"><span class="legend-color" style="background: #f59e0b;"></span> 주의</div>
|
||||
<div class="legend-item"><span class="legend-color" style="background: #ef4444;"></span> 관리필요</div>
|
||||
</div>
|
||||
<div class="legend-title" style="margin-top: 1rem;">설비 상태</div>
|
||||
<div class="legend-items">
|
||||
<div class="legend-item"><span style="margin-right: 4px;">⚙️</span> 정상 가동</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">🔧</span> 수리 필요</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">⚠️</span> 점검중</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">📤</span> 타 작업장 이동</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">📥</span> 임시 배치</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="zoneItemsList" class="zone-items-list">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="legend-title" style="margin-top: 1rem;">설비 상태</div>
|
||||
<div class="legend-items">
|
||||
<div class="legend-item"><span style="margin-right: 4px;">⚙️</span> 정상 가동</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">🔧</span> 수리 필요</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">⚠️</span> 점검중</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">📤</span> 타 작업장 이동</div>
|
||||
<div class="legend-item"><span style="margin-right: 4px;">📥</span> 임시 배치</div>
|
||||
|
||||
<!-- 안전신고/부적합 탭 -->
|
||||
<div id="tab-issues" class="tab-content">
|
||||
<div id="issuesContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비/수리 탭 -->
|
||||
<div id="tab-equipment" class="tab-content">
|
||||
<div id="equipmentContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 출입현황 탭 -->
|
||||
<div id="tab-visits" class="tab-content">
|
||||
<div id="visitsContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TBM 탭 -->
|
||||
<div id="tab-tbm" class="tab-content">
|
||||
<div id="tbmContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 순회점검 탭 -->
|
||||
<div id="tab-patrol" class="tab-content">
|
||||
<div id="patrolContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="zoneItemsList" class="zone-items-list">
|
||||
<!-- JS에서 렌더링 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 안전신고/부적합 탭 -->
|
||||
<div id="tab-issues" class="tab-content">
|
||||
<div id="issuesContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설비/수리 탭 -->
|
||||
<div id="tab-equipment" class="tab-content">
|
||||
<div id="equipmentContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 출입현황 탭 -->
|
||||
<div id="tab-visits" class="tab-content">
|
||||
<div id="visitsContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TBM 탭 -->
|
||||
<div id="tab-tbm" class="tab-content">
|
||||
<div id="tbmContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 순회점검 탭 -->
|
||||
<div id="tab-patrol" class="tab-content">
|
||||
<div id="patrolContent" class="content-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 현황 등록/수정 모달 -->
|
||||
<div id="zoneItemModal" class="modal-overlay" style="display: none;">
|
||||
@@ -292,6 +304,9 @@
|
||||
}, 50);
|
||||
})();
|
||||
</script>
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/zone-detail.js?v=6"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,21 +3,23 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>내 프로필 | (주)테크니컬코리아</title>
|
||||
<link rel="stylesheet" href="/css/main-layout.css">
|
||||
|
||||
<title>내 프로필 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
|
||||
<style>
|
||||
.profile-page {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
|
||||
.profile-header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
|
||||
.profile-avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
@@ -31,32 +33,32 @@
|
||||
margin: 0 auto 20px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
|
||||
.profile-name {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
|
||||
.profile-role {
|
||||
font-size: 1.2rem;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
.profile-cards {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
|
||||
.profile-card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.08);
|
||||
padding: 28px;
|
||||
}
|
||||
|
||||
|
||||
.card-title {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
@@ -66,38 +68,38 @@
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
|
||||
.info-label {
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
.info-value {
|
||||
font-size: 1.05rem;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
|
||||
.action-btn {
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
@@ -112,37 +114,37 @@
|
||||
text-decoration: none;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
|
||||
.btn-primary {
|
||||
background: #1976d2;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #1565c0;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
|
||||
.btn-secondary {
|
||||
background: #f5f5f5;
|
||||
color: #333;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
|
||||
.btn-warning {
|
||||
background: #ff9800;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
.btn-warning:hover {
|
||||
background: #f57c00;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
|
||||
/* 통계 카드 */
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
@@ -150,14 +152,14 @@
|
||||
gap: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
|
||||
.stat-box {
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.stat-number {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
@@ -165,35 +167,35 @@
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.profile-page {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
|
||||
.profile-avatar {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
|
||||
.profile-name {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
|
||||
.info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
|
||||
.action-buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.action-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
@@ -201,103 +203,126 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-layout-no-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<div class="profile-page">
|
||||
<div class="profile-header">
|
||||
<div class="profile-avatar" id="profileAvatar"></div>
|
||||
<h1 class="profile-name" id="profileName">사용자</h1>
|
||||
<p class="profile-role" id="profileRole">역할</p>
|
||||
</div>
|
||||
|
||||
<div class="profile-cards">
|
||||
<!-- 기본 정보 -->
|
||||
<div class="profile-card">
|
||||
<h2 class="card-title">기본 정보</h2>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="info-label">사용자 ID</span>
|
||||
<span class="info-value" id="userId">-</span>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">사용자명</span>
|
||||
<span class="info-value" id="username">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">이름</span>
|
||||
<span class="info-value" id="fullName">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">권한 레벨</span>
|
||||
<span class="info-value" id="accessLevel">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">작업자 ID</span>
|
||||
<span class="info-value" id="workerId">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">가입일</span>
|
||||
<span class="info-value" id="createdAt">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 활동 정보 -->
|
||||
<div class="profile-card">
|
||||
<h2 class="card-title">활동 정보</h2>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="info-label">마지막 로그인</span>
|
||||
<span class="info-value" id="lastLogin">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">이메일</span>
|
||||
<span class="info-value" id="email">-</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 간단한 통계 (준비중) -->
|
||||
<div class="stats-grid" style="margin-top: 24px; opacity: 0.5;">
|
||||
<div class="stat-box">
|
||||
<span class="stat-number">-</span>
|
||||
<span class="stat-label">작업 보고서</span>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<span class="stat-number">-</span>
|
||||
<span class="stat-label">이번 달 활동</span>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<span class="stat-number">-</span>
|
||||
<span class="stat-label">팀 기여도</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 빠른 작업 -->
|
||||
<div class="profile-card">
|
||||
<h2 class="card-title">빠른 작업</h2>
|
||||
<div class="action-buttons">
|
||||
<a href="/pages/profile/password.html" class="action-btn btn-warning">
|
||||
비밀번호 변경
|
||||
</a>
|
||||
<button class="action-btn btn-secondary" disabled>
|
||||
프로필 수정 (준비중)
|
||||
</button>
|
||||
<button class="action-btn btn-secondary" disabled>
|
||||
설정 (준비중)
|
||||
</button>
|
||||
<a href="javascript:history.back()" class="action-btn btn-secondary">
|
||||
<span>←</span>
|
||||
<span>돌아가기</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="profile-page">
|
||||
<div class="profile-header">
|
||||
<div class="profile-avatar" id="profileAvatar"></div>
|
||||
<h1 class="profile-name" id="profileName">사용자</h1>
|
||||
<p class="profile-role" id="profileRole">역할</p>
|
||||
</div>
|
||||
|
||||
<div class="profile-cards">
|
||||
<!-- 기본 정보 -->
|
||||
<div class="profile-card">
|
||||
<h2 class="card-title">기본 정보</h2>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="info-label">사용자 ID</span>
|
||||
<span class="info-value" id="userId">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">사용자명</span>
|
||||
<span class="info-value" id="username">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">이름</span>
|
||||
<span class="info-value" id="fullName">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">권한 레벨</span>
|
||||
<span class="info-value" id="accessLevel">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">작업자 ID</span>
|
||||
<span class="info-value" id="workerId">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">가입일</span>
|
||||
<span class="info-value" id="createdAt">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 활동 정보 -->
|
||||
<div class="profile-card">
|
||||
<h2 class="card-title">활동 정보</h2>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="info-label">마지막 로그인</span>
|
||||
<span class="info-value" id="lastLogin">-</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">이메일</span>
|
||||
<span class="info-value" id="email">-</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 간단한 통계 (준비중) -->
|
||||
<div class="stats-grid" style="margin-top: 24px; opacity: 0.5;">
|
||||
<div class="stat-box">
|
||||
<span class="stat-number">-</span>
|
||||
<span class="stat-label">작업 보고서</span>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<span class="stat-number">-</span>
|
||||
<span class="stat-label">이번 달 활동</span>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<span class="stat-number">-</span>
|
||||
<span class="stat-label">팀 기여도</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 빠른 작업 -->
|
||||
<div class="profile-card">
|
||||
<h2 class="card-title">빠른 작업</h2>
|
||||
<div class="action-buttons">
|
||||
<a href="/pages/profile/password.html" class="action-btn btn-warning">
|
||||
비밀번호 변경
|
||||
</a>
|
||||
<button class="action-btn btn-secondary" disabled>
|
||||
프로필 수정 (준비중)
|
||||
</button>
|
||||
<button class="action-btn btn-secondary" disabled>
|
||||
설정 (준비중)
|
||||
</button>
|
||||
<a href="javascript:history.back()" class="action-btn btn-secondary">
|
||||
<span>←</span>
|
||||
<span>돌아가기</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script type="module" src="/js/my-profile.js"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>비밀번호 변경 | (주)테크니컬코리아</title>
|
||||
<link rel="stylesheet" href="/css/main-layout.css">
|
||||
|
||||
<title>비밀번호 변경 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
|
||||
<style>
|
||||
/* 페이지 전용 스타일 */
|
||||
.password-page {
|
||||
@@ -13,23 +15,23 @@
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
|
||||
.page-title {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
|
||||
.page-title h1 {
|
||||
font-size: 2rem;
|
||||
color: #333;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
|
||||
.page-title p {
|
||||
color: #666;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
|
||||
/* 카드 스타일 */
|
||||
.password-card {
|
||||
background: white;
|
||||
@@ -37,13 +39,13 @@
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.card-header {
|
||||
background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
|
||||
color: white;
|
||||
padding: 24px 32px;
|
||||
}
|
||||
|
||||
|
||||
.card-header h2 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
@@ -52,11 +54,11 @@
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
|
||||
.card-body {
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
|
||||
/* 알림 박스 */
|
||||
.info-box {
|
||||
background: #e3f2fd;
|
||||
@@ -65,7 +67,7 @@
|
||||
padding: 16px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
|
||||
.info-box h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #1565c0;
|
||||
@@ -74,30 +76,30 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
|
||||
.info-box ul {
|
||||
margin: 0;
|
||||
padding-left: 24px;
|
||||
color: #0d47a1;
|
||||
}
|
||||
|
||||
|
||||
.info-box li {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
|
||||
/* 폼 스타일 */
|
||||
.password-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
|
||||
.form-group label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
@@ -106,11 +108,11 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
|
||||
.input-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 14px 48px 14px 16px;
|
||||
@@ -120,13 +122,13 @@
|
||||
transition: all 0.3s ease;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
|
||||
.form-control:focus {
|
||||
outline: none;
|
||||
border-color: #ff9800;
|
||||
box-shadow: 0 0 0 3px rgba(255, 152, 0, 0.1);
|
||||
}
|
||||
|
||||
|
||||
.password-toggle {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
@@ -140,18 +142,18 @@
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.password-toggle:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
/* 버튼 */
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
|
||||
.btn {
|
||||
padding: 14px 28px;
|
||||
border: none;
|
||||
@@ -166,35 +168,35 @@
|
||||
gap: 8px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
|
||||
.btn-primary {
|
||||
background: #ff9800;
|
||||
color: white;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #f57c00;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(255, 152, 0, 0.3);
|
||||
}
|
||||
|
||||
|
||||
.btn-primary:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
|
||||
.btn-secondary {
|
||||
background: #f5f5f5;
|
||||
color: #666;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
|
||||
/* 메시지 */
|
||||
.message-box {
|
||||
padding: 16px;
|
||||
@@ -202,19 +204,19 @@
|
||||
margin-bottom: 20px;
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
|
||||
.message-box.error {
|
||||
background: #ffebee;
|
||||
border: 1px solid #ffcdd2;
|
||||
color: #c62828;
|
||||
}
|
||||
|
||||
|
||||
.message-box.success {
|
||||
background: #e8f5e9;
|
||||
border: 1px solid #c8e6c9;
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
@@ -225,7 +227,7 @@
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 하단 링크 */
|
||||
.back-link {
|
||||
text-align: center;
|
||||
@@ -233,7 +235,7 @@
|
||||
padding-top: 32px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
|
||||
.back-link a {
|
||||
color: #1976d2;
|
||||
text-decoration: none;
|
||||
@@ -243,131 +245,154 @@
|
||||
gap: 6px;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.back-link a:hover {
|
||||
color: #1565c0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 768px) {
|
||||
.password-page {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
|
||||
.card-body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
|
||||
.form-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-layout-no-sidebar">
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<div class="password-page">
|
||||
<div class="page-title">
|
||||
<h1>비밀번호 변경</h1>
|
||||
<p>계정 보안을 위해 정기적으로 비밀번호를 변경해주세요</p>
|
||||
</div>
|
||||
|
||||
<div class="password-card">
|
||||
<div class="card-header">
|
||||
<h2>새 비밀번호 설정</h2>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<!-- 메시지 영역 -->
|
||||
<div id="message-area"></div>
|
||||
|
||||
<!-- 안내 정보 -->
|
||||
<div class="info-box">
|
||||
<h4>비밀번호 요구사항</h4>
|
||||
<ul>
|
||||
<li>최소 6자 이상 입력해주세요</li>
|
||||
<li>영문 대/소문자, 숫자, 특수문자를 조합하면 더 안전합니다</li>
|
||||
<li>개인정보나 쉬운 단어는 피해주세요</li>
|
||||
<li>이전 비밀번호와 다르게 설정해주세요</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 비밀번호 변경 폼 -->
|
||||
<form id="changePasswordForm" class="password-form">
|
||||
<div class="form-group">
|
||||
<label for="currentPassword">현재 비밀번호</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
type="password"
|
||||
id="currentPassword"
|
||||
class="form-control"
|
||||
placeholder="현재 비밀번호를 입력하세요"
|
||||
required
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
<button type="button" class="password-toggle" data-target="currentPassword">보기</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="newPassword">새 비밀번호</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
type="password"
|
||||
id="newPassword"
|
||||
class="form-control"
|
||||
placeholder="새 비밀번호를 입력하세요"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<button type="button" class="password-toggle" data-target="newPassword">보기</button>
|
||||
</div>
|
||||
<div id="passwordStrength"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirmPassword">새 비밀번호 확인</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
type="password"
|
||||
id="confirmPassword"
|
||||
class="form-control"
|
||||
placeholder="새 비밀번호를 다시 입력하세요"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<button type="button" class="password-toggle" data-target="confirmPassword">보기</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary" id="submitBtn">
|
||||
비밀번호 변경
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" id="resetBtn">
|
||||
초기화
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="back-link">
|
||||
<a href="javascript:history.back()">
|
||||
<span>←</span>
|
||||
<span>이전 페이지로 돌아가기</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="password-page">
|
||||
<div class="page-title">
|
||||
<h1>비밀번호 변경</h1>
|
||||
<p>계정 보안을 위해 정기적으로 비밀번호를 변경해주세요</p>
|
||||
</div>
|
||||
|
||||
<div class="password-card">
|
||||
<div class="card-header">
|
||||
<h2>새 비밀번호 설정</h2>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<!-- 메시지 영역 -->
|
||||
<div id="message-area"></div>
|
||||
|
||||
<!-- 안내 정보 -->
|
||||
<div class="info-box">
|
||||
<h4>비밀번호 요구사항</h4>
|
||||
<ul>
|
||||
<li>최소 6자 이상 입력해주세요</li>
|
||||
<li>영문 대/소문자, 숫자, 특수문자를 조합하면 더 안전합니다</li>
|
||||
<li>개인정보나 쉬운 단어는 피해주세요</li>
|
||||
<li>이전 비밀번호와 다르게 설정해주세요</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 비밀번호 변경 폼 -->
|
||||
<form id="changePasswordForm" class="password-form">
|
||||
<div class="form-group">
|
||||
<label for="currentPassword">현재 비밀번호</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
type="password"
|
||||
id="currentPassword"
|
||||
class="form-control"
|
||||
placeholder="현재 비밀번호를 입력하세요"
|
||||
required
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
<button type="button" class="password-toggle" data-target="currentPassword">보기</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="newPassword">새 비밀번호</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
type="password"
|
||||
id="newPassword"
|
||||
class="form-control"
|
||||
placeholder="새 비밀번호를 입력하세요"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<button type="button" class="password-toggle" data-target="newPassword">보기</button>
|
||||
</div>
|
||||
<div id="passwordStrength"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirmPassword">새 비밀번호 확인</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
type="password"
|
||||
id="confirmPassword"
|
||||
class="form-control"
|
||||
placeholder="새 비밀번호를 다시 입력하세요"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<button type="button" class="password-toggle" data-target="confirmPassword">보기</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary" id="submitBtn">
|
||||
비밀번호 변경
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" id="resetBtn">
|
||||
초기화
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="back-link">
|
||||
<a href="javascript:history.back()">
|
||||
<span>←</span>
|
||||
<span>이전 페이지로 돌아가기</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script type="module" src="/js/change-password.js"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,635 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>안전 체크리스트 관리 - TK-FB</title>
|
||||
<link rel="stylesheet" href="/css/design-system.css">
|
||||
<link rel="stylesheet" href="/css/common.css">
|
||||
<style>
|
||||
.page-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary, #111827);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 탭 메뉴 */
|
||||
.tab-menu {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
border-bottom: 2px solid #e5e7eb;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
color: #6b7280;
|
||||
transition: all 0.2s;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
color: #3b82f6;
|
||||
border-bottom-color: #3b82f6;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 체크리스트 카드 */
|
||||
.checklist-group {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
margin-bottom: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 1.25rem;
|
||||
background: #f9fafb;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.group-icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.group-count {
|
||||
background: #e5e7eb;
|
||||
color: #6b7280;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.checklist-items {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.checklist-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.875rem 1.25rem;
|
||||
border-bottom: 1px solid #f3f4f6;
|
||||
}
|
||||
|
||||
.checklist-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-weight: 500;
|
||||
color: #111827;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
font-size: 0.8rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.item-badge {
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.badge-required {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.badge-optional {
|
||||
background: #e5e7eb;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background: #eff6ff;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background: #dbeafe;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background: #fee2e2;
|
||||
}
|
||||
|
||||
/* 필터/검색 */
|
||||
.filter-bar {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-select {
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
/* 모달 */
|
||||
.modal-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 1000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
color: #6b7280;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 1.5rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
color: #374151;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.form-input, .form-select, .form-textarea {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.form-input:focus, .form-select:focus, .form-textarea:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
min-height: 80px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.form-radio-group {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.form-radio {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-radio input {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-checkbox input {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.conditional-fields {
|
||||
display: none;
|
||||
margin-top: 1rem;
|
||||
padding: 1rem;
|
||||
background: #f9fafb;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.conditional-fields.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: #e5e7eb;
|
||||
color: #374151;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #d1d5db;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 3rem 1rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.empty-state-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* 인라인 추가 행 */
|
||||
.inline-add-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.25rem;
|
||||
background: #f9fafb;
|
||||
border-top: 1px dashed #e5e7eb;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.inline-add-input {
|
||||
flex: 1;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.inline-add-input:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.inline-add-btn {
|
||||
padding: 0.5rem 1rem;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.inline-add-btn:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.inline-add-select {
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
max-width: 160px;
|
||||
}
|
||||
|
||||
.inline-add-standalone {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
margin-bottom: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.inline-add-standalone .inline-add-row {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
/* 날씨 아이콘 */
|
||||
.weather-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.weather-icon.rain::before { content: '[rain]'; }
|
||||
.weather-icon.snow::before { content: '[snow]'; }
|
||||
.weather-icon.heat::before { content: '[heat]'; }
|
||||
.weather-icon.cold::before { content: '[cold]'; }
|
||||
.weather-icon.wind::before { content: '[wind]'; }
|
||||
.weather-icon.fog::before { content: '[fog]'; }
|
||||
.weather-icon.dust::before { content: '[dust]'; }
|
||||
.weather-icon.clear::before { content: '[clear]'; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.checklist-item {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<div class="page-container">
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">안전 체크리스트 관리</h1>
|
||||
</div>
|
||||
|
||||
<!-- 탭 메뉴 -->
|
||||
<div class="tab-menu">
|
||||
<button class="tab-btn active" data-tab="basic" onclick="switchTab('basic')">
|
||||
기본 사항
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="weather" onclick="switchTab('weather')">
|
||||
날씨별
|
||||
</button>
|
||||
<button class="tab-btn" data-tab="task" onclick="switchTab('task')">
|
||||
작업별
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 기본 사항 탭 -->
|
||||
<div id="basicTab" class="tab-content active">
|
||||
<div id="basicChecklistContainer">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 날씨별 탭 -->
|
||||
<div id="weatherTab" class="tab-content">
|
||||
<div class="filter-bar">
|
||||
<select id="weatherFilter" class="filter-select" onchange="filterByWeather()">
|
||||
<option value="">모든 날씨 조건</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="weatherChecklistContainer">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업별 탭 -->
|
||||
<div id="taskTab" class="tab-content">
|
||||
<div class="filter-bar">
|
||||
<select id="workTypeFilter" class="filter-select" onchange="filterByWorkType()">
|
||||
<option value="">공정 선택</option>
|
||||
</select>
|
||||
<select id="taskFilter" class="filter-select" onchange="filterByTask()">
|
||||
<option value="">작업 선택</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="taskChecklistContainer">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 추가/수정 모달 -->
|
||||
<div id="checkModal" class="modal-overlay">
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="modalTitle">체크 항목 추가</h2>
|
||||
<button class="modal-close" onclick="closeModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="checkForm">
|
||||
<input type="hidden" id="checkId">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">유형</label>
|
||||
<div class="form-radio-group">
|
||||
<label class="form-radio">
|
||||
<input type="radio" name="checkType" value="basic" checked onchange="toggleConditionalFields()">
|
||||
<span>기본</span>
|
||||
</label>
|
||||
<label class="form-radio">
|
||||
<input type="radio" name="checkType" value="weather" onchange="toggleConditionalFields()">
|
||||
<span>날씨별</span>
|
||||
</label>
|
||||
<label class="form-radio">
|
||||
<input type="radio" name="checkType" value="task" onchange="toggleConditionalFields()">
|
||||
<span>작업별</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 기본 유형: 카테고리 선택 -->
|
||||
<div id="basicFields" class="conditional-fields show">
|
||||
<div class="form-group">
|
||||
<label class="form-label">카테고리</label>
|
||||
<select id="checkCategory" class="form-select">
|
||||
<option value="PPE">PPE (개인보호장비)</option>
|
||||
<option value="EQUIPMENT">EQUIPMENT (장비점검)</option>
|
||||
<option value="ENVIRONMENT">ENVIRONMENT (작업환경)</option>
|
||||
<option value="EMERGENCY">EMERGENCY (비상대응)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 날씨별 유형: 날씨 조건 선택 -->
|
||||
<div id="weatherFields" class="conditional-fields">
|
||||
<div class="form-group">
|
||||
<label class="form-label">날씨 조건</label>
|
||||
<select id="weatherCondition" class="form-select">
|
||||
<!-- 동적 로드 -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업별 유형: 공정/작업 선택 -->
|
||||
<div id="taskFields" class="conditional-fields">
|
||||
<div class="form-group">
|
||||
<label class="form-label">공정</label>
|
||||
<select id="modalWorkType" class="form-select" onchange="loadModalTasks()">
|
||||
<option value="">공정 선택</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">작업</label>
|
||||
<select id="modalTask" class="form-select">
|
||||
<option value="">작업 선택</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">체크 항목</label>
|
||||
<input type="text" id="checkItem" class="form-input" placeholder="예: 안전모 착용 확인" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">설명 (선택)</label>
|
||||
<textarea id="checkDescription" class="form-textarea" placeholder="항목에 대한 상세 설명"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-checkbox">
|
||||
<input type="checkbox" id="isRequired" checked>
|
||||
<span>필수 체크 항목</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">표시 순서</label>
|
||||
<input type="number" id="displayOrder" class="form-input" value="0" min="0">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn-secondary" onclick="closeModal()">취소</button>
|
||||
<button type="button" class="btn-primary" onclick="saveCheck()">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<script type="module" src="/js/safety-checklist-manage.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,23 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>리다이렉트 중...</title>
|
||||
<script>
|
||||
(function() {
|
||||
var hostname = window.location.hostname;
|
||||
var protocol = window.location.protocol;
|
||||
var target;
|
||||
if (hostname.includes('technicalkorea.net')) {
|
||||
target = protocol + '//tkreport.technicalkorea.net/pages/safety/issue-detail.html';
|
||||
} else {
|
||||
target = protocol + '//' + hostname + ':30180/pages/safety/issue-detail.html';
|
||||
}
|
||||
window.location.replace(target + window.location.search);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>신고 시스템으로 이동 중...</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,23 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>리다이렉트 중...</title>
|
||||
<script>
|
||||
(function() {
|
||||
var hostname = window.location.hostname;
|
||||
var protocol = window.location.protocol;
|
||||
var target;
|
||||
if (hostname.includes('technicalkorea.net')) {
|
||||
target = protocol + '//tkreport.technicalkorea.net/pages/safety/issue-report.html';
|
||||
} else {
|
||||
target = protocol + '//' + hostname + ':30180/pages/safety/issue-report.html';
|
||||
}
|
||||
window.location.replace(target + window.location.search);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>신고 시스템으로 이동 중...</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,291 +0,0 @@
|
||||
<!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/common.css?v=2">
|
||||
<link rel="stylesheet" href="/css/project-management.css?v=3">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<style>
|
||||
.status-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 24px;
|
||||
border-bottom: 2px solid var(--gray-200);
|
||||
}
|
||||
|
||||
.status-tab {
|
||||
padding: 12px 24px;
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: var(--gray-600);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.status-tab:hover {
|
||||
color: var(--primary-600);
|
||||
}
|
||||
|
||||
.status-tab.active {
|
||||
color: var(--primary-600);
|
||||
border-bottom-color: var(--primary-600);
|
||||
}
|
||||
|
||||
.request-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: white;
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.request-table th {
|
||||
background: var(--gray-50);
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: var(--gray-700);
|
||||
border-bottom: 2px solid var(--gray-200);
|
||||
}
|
||||
|
||||
.request-table td {
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid var(--gray-200);
|
||||
}
|
||||
|
||||
.request-table tr:hover {
|
||||
background: var(--gray-50);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 4px 12px;
|
||||
border-radius: var(--radius-full);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-badge.pending {
|
||||
background: var(--yellow-100);
|
||||
color: var(--yellow-700);
|
||||
}
|
||||
|
||||
.status-badge.approved {
|
||||
background: var(--green-100);
|
||||
color: var(--green-700);
|
||||
}
|
||||
|
||||
.status-badge.rejected {
|
||||
background: var(--red-100);
|
||||
color: var(--red-700);
|
||||
}
|
||||
|
||||
.status-badge.training_completed {
|
||||
background: var(--blue-100);
|
||||
color: var(--blue-700);
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 6px 12px;
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
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;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 32px;
|
||||
max-width: 600px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: var(--shadow-2xl);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.modal-header h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 120px 1fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-weight: 600;
|
||||
color: var(--gray-600);
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 64px 32px;
|
||||
color: var(--gray-500);
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
padding: 20px;
|
||||
background: white;
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
border-left: 4px solid var(--primary-500);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-600);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 700;
|
||||
color: var(--gray-900);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="work-report-main">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">안전관리</h1>
|
||||
<p class="page-description">출입 신청 승인 및 안전교육 관리</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 통계 -->
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">승인 대기</div>
|
||||
<div class="stat-value" id="statPending">0</div>
|
||||
</div>
|
||||
<div class="stat-card" style="border-left-color: var(--green-500);">
|
||||
<div class="stat-label">승인 완료</div>
|
||||
<div class="stat-value" id="statApproved">0</div>
|
||||
</div>
|
||||
<div class="stat-card" style="border-left-color: var(--blue-500);">
|
||||
<div class="stat-label">교육 완료</div>
|
||||
<div class="stat-value" id="statTrainingCompleted">0</div>
|
||||
</div>
|
||||
<div class="stat-card" style="border-left-color: var(--red-500);">
|
||||
<div class="stat-label">반려</div>
|
||||
<div class="stat-value" id="statRejected">0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 탭 -->
|
||||
<div class="code-section">
|
||||
<div class="status-tabs">
|
||||
<button class="status-tab active" data-status="pending" onclick="switchTab('pending')">
|
||||
승인 대기
|
||||
</button>
|
||||
<button class="status-tab" data-status="approved" onclick="switchTab('approved')">
|
||||
승인 완료
|
||||
</button>
|
||||
<button class="status-tab" data-status="training_completed" onclick="switchTab('training_completed')">
|
||||
교육 완료
|
||||
</button>
|
||||
<button class="status-tab" data-status="rejected" onclick="switchTab('rejected')">
|
||||
반려
|
||||
</button>
|
||||
<button class="status-tab" data-status="all" onclick="switchTab('all')">
|
||||
전체
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 테이블 -->
|
||||
<div id="requestTableContainer">
|
||||
<!-- 동적으로 로드됨 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 상세보기 모달 -->
|
||||
<div id="detailModal" class="modal-overlay">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>출입 신청 상세</h2>
|
||||
<button class="btn btn-secondary btn-sm" onclick="closeDetailModal()">닫기</button>
|
||||
</div>
|
||||
<div id="detailContent">
|
||||
<!-- 동적으로 로드됨 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 반려 사유 입력 모달 -->
|
||||
<div id="rejectModal" class="modal-overlay">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>반려 사유 입력</h2>
|
||||
<button class="btn btn-secondary btn-sm" onclick="closeRejectModal()">취소</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="form-group">
|
||||
<label for="rejectionReason">반려 사유 *</label>
|
||||
<textarea id="rejectionReason" rows="4" style="width: 100%; padding: 12px; border: 1px solid var(--gray-300); border-radius: var(--radius-md);" placeholder="반려 사유를 입력하세요"></textarea>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: flex-end; gap: 12px; margin-top: 24px;">
|
||||
<button class="btn btn-secondary" onclick="closeRejectModal()">취소</button>
|
||||
<button class="btn btn-danger" onclick="confirmReject()">반려 확정</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="/js/safety-management.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>리다이렉트 중...</title>
|
||||
<script>
|
||||
// 안전신고 현황 → System 2 (신고 시스템)로 리다이렉트
|
||||
(function() {
|
||||
var hostname = window.location.hostname;
|
||||
var protocol = window.location.protocol;
|
||||
var target;
|
||||
if (hostname.includes('technicalkorea.net')) {
|
||||
target = protocol + '//tkreport.technicalkorea.net/pages/safety/report-status.html';
|
||||
} else {
|
||||
target = protocol + '//' + hostname + ':30180/pages/safety/report-status.html';
|
||||
}
|
||||
window.location.replace(target + window.location.search);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>신고 시스템으로 이동 중...</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,778 +0,0 @@
|
||||
<!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/common.css?v=2">
|
||||
<link rel="stylesheet" href="/css/project-management.css?v=3">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<style>
|
||||
/* 스텝 인디케이터 */
|
||||
.step-indicator {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
margin-bottom: 2rem;
|
||||
padding: 1.5rem;
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: #9ca3af;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.step-connector {
|
||||
width: 60px;
|
||||
height: 2px;
|
||||
background: #e5e7eb;
|
||||
margin: 0 1rem;
|
||||
}
|
||||
|
||||
.step.active .step-connector,
|
||||
.step.completed .step-connector {
|
||||
background: #3b82f6;
|
||||
}
|
||||
|
||||
.step.active {
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.step.completed {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
background: #f3f4f6;
|
||||
border: 2px solid #e5e7eb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.step.active .step-number {
|
||||
background: #3b82f6;
|
||||
border-color: #3b82f6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.step.completed .step-number {
|
||||
background: #10b981;
|
||||
border-color: #10b981;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.step-text {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 폼 섹션 */
|
||||
.form-section {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.form-section-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
margin-bottom: 1.25rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-section-title .section-number {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 지도 컨테이너 */
|
||||
.map-container {
|
||||
position: relative;
|
||||
background: #f9fafb;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#issueMapCanvas {
|
||||
display: block;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.selected-location-info {
|
||||
margin-top: 1rem;
|
||||
padding: 1rem;
|
||||
background: #eff6ff;
|
||||
border: 1px solid #bfdbfe;
|
||||
border-radius: 0.5rem;
|
||||
color: #1e40af;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.selected-location-info.empty {
|
||||
background: #f9fafb;
|
||||
border-color: #e5e7eb;
|
||||
color: #6b7280;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.custom-location-toggle {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem;
|
||||
background: #f9fafb;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.custom-location-toggle input[type="checkbox"] {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
accent-color: #3b82f6;
|
||||
}
|
||||
|
||||
.custom-location-input {
|
||||
margin-top: 0.75rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.custom-location-input.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.custom-location-input input {
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.custom-location-input input:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
/* 유형 선택 버튼 */
|
||||
.type-buttons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.type-btn {
|
||||
padding: 1.5rem;
|
||||
border: 2px solid #e5e7eb;
|
||||
border-radius: 0.75rem;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.type-btn:hover {
|
||||
border-color: #d1d5db;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.type-btn.selected {
|
||||
border-color: #3b82f6;
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
.type-btn.nonconformity.selected {
|
||||
border-color: #f97316;
|
||||
background: #fff7ed;
|
||||
}
|
||||
|
||||
.type-btn.safety.selected {
|
||||
border-color: #ef4444;
|
||||
background: #fef2f2;
|
||||
}
|
||||
|
||||
.type-btn-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.type-btn-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.type-btn-desc {
|
||||
font-size: 0.8rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
/* 카테고리 선택 */
|
||||
#categoryContainer {
|
||||
margin-top: 1.5rem;
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.category-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.category-btn {
|
||||
padding: 1rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-align: center;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.category-btn:hover {
|
||||
border-color: #3b82f6;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.category-btn.selected {
|
||||
border-color: #3b82f6;
|
||||
background: #eff6ff;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
/* 항목 선택 */
|
||||
.item-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.item-btn {
|
||||
padding: 0.625rem 1rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 9999px;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.item-btn:hover {
|
||||
border-color: #3b82f6;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.item-btn.selected {
|
||||
border-color: #3b82f6;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.item-btn[data-severity="critical"].selected {
|
||||
background: #ef4444;
|
||||
border-color: #ef4444;
|
||||
}
|
||||
|
||||
.item-btn[data-severity="high"].selected {
|
||||
background: #f97316;
|
||||
border-color: #f97316;
|
||||
}
|
||||
|
||||
.item-btn.custom-input-btn {
|
||||
border-style: dashed;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.item-btn.custom-input-btn:hover {
|
||||
border-color: #3b82f6;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.item-btn.custom-input-btn.selected {
|
||||
border-style: solid;
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
/* 직접 입력 영역 */
|
||||
.custom-item-input {
|
||||
margin-top: 1rem;
|
||||
padding: 1rem;
|
||||
background: #f0f9ff;
|
||||
border: 1px solid #bae6fd;
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.custom-item-input input {
|
||||
flex: 1;
|
||||
padding: 0.625rem 0.875rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.custom-item-input input:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.btn-confirm-custom {
|
||||
padding: 0.625rem 1rem;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-confirm-custom:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.btn-cancel-custom {
|
||||
padding: 0.625rem 1rem;
|
||||
background: white;
|
||||
color: #4b5563;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-cancel-custom:hover {
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
/* 사진 업로드 */
|
||||
.photo-upload-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.photo-slot {
|
||||
aspect-ratio: 1;
|
||||
border: 2px dashed #d1d5db;
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.photo-slot:hover {
|
||||
border-color: #3b82f6;
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
.photo-slot.has-photo {
|
||||
border-style: solid;
|
||||
border-color: #10b981;
|
||||
}
|
||||
|
||||
.photo-slot img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.photo-slot .add-icon {
|
||||
font-size: 1.5rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.photo-slot .remove-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.photo-slot.has-photo .remove-btn {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.photo-slot.has-photo .add-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 추가 설명 */
|
||||
.additional-textarea {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
resize: vertical;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.additional-textarea:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
/* 제출 버튼 */
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
padding: 0.875rem 2rem;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.btn-submit:disabled {
|
||||
background: #9ca3af;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
padding: 0.875rem 1.5rem;
|
||||
background: white;
|
||||
color: #4b5563;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
/* 작업 선택 모달 */
|
||||
.work-selection-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.work-selection-modal.visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.work-selection-content {
|
||||
background: white;
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.work-selection-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.work-option {
|
||||
padding: 1rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.work-option:hover {
|
||||
border-color: #3b82f6;
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
.work-option-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.work-option-desc {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 768px) {
|
||||
.type-buttons {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.photo-upload-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.step-indicator {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.step-connector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.step-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<main class="work-report-main">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">신고</h1>
|
||||
<p class="page-description">작업 중 발견된 부적합 사항 또는 안전 문제를 신고합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 단계 표시 -->
|
||||
<div class="step-indicator">
|
||||
<div class="step active" data-step="1">
|
||||
<span class="step-number">1</span>
|
||||
<span class="step-text">위치 선택</span>
|
||||
</div>
|
||||
<div class="step-connector"></div>
|
||||
<div class="step" data-step="2">
|
||||
<span class="step-number">2</span>
|
||||
<span class="step-text">유형 선택</span>
|
||||
</div>
|
||||
<div class="step-connector"></div>
|
||||
<div class="step" data-step="3">
|
||||
<span class="step-number">3</span>
|
||||
<span class="step-text">항목 선택</span>
|
||||
</div>
|
||||
<div class="step-connector"></div>
|
||||
<div class="step" data-step="4">
|
||||
<span class="step-number">4</span>
|
||||
<span class="step-text">사진/설명</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 1: 위치 선택 -->
|
||||
<div class="form-section" id="step1Section">
|
||||
<h2 class="form-section-title">
|
||||
<span class="section-number">1</span>
|
||||
발생 위치 선택
|
||||
</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">공장 선택</label>
|
||||
<select id="factorySelect" class="form-control">
|
||||
<option value="">공장을 선택하세요</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="map-container">
|
||||
<canvas id="issueMapCanvas"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="selected-location-info empty" id="selectedLocationInfo">
|
||||
지도에서 작업장을 클릭하여 위치를 선택하세요
|
||||
</div>
|
||||
|
||||
<div class="custom-location-toggle">
|
||||
<input type="checkbox" id="useCustomLocation">
|
||||
<label for="useCustomLocation">지도에 없는 위치 직접 입력</label>
|
||||
</div>
|
||||
|
||||
<div class="custom-location-input" id="customLocationInput">
|
||||
<input type="text" id="customLocation" placeholder="위치를 입력하세요 (예: 야적장 입구, 주차장 등)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: 문제 유형 선택 -->
|
||||
<div class="form-section" id="step2Section">
|
||||
<h2 class="form-section-title">
|
||||
<span class="section-number">2</span>
|
||||
문제 유형 선택
|
||||
</h2>
|
||||
|
||||
<div class="type-buttons">
|
||||
<div class="type-btn nonconformity" data-type="nonconformity">
|
||||
<div class="type-btn-icon">📋</div>
|
||||
<div class="type-btn-title">부적합 사항</div>
|
||||
<div class="type-btn-desc">자재, 설계, 검사 관련 문제</div>
|
||||
</div>
|
||||
<div class="type-btn safety" data-type="safety">
|
||||
<div class="type-btn-icon">⚠</div>
|
||||
<div class="type-btn-title">안전 문제</div>
|
||||
<div class="type-btn-desc">보호구, 위험구역, 안전수칙 관련</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="categoryContainer" style="display: none;">
|
||||
<label class="form-label">세부 카테고리</label>
|
||||
<div class="category-grid" id="categoryGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: 신고 항목 선택 -->
|
||||
<div class="form-section" id="step3Section">
|
||||
<h2 class="form-section-title">
|
||||
<span class="section-number">3</span>
|
||||
신고 항목 선택
|
||||
</h2>
|
||||
<p style="color: #6b7280; margin-bottom: 1rem; font-size: 0.875rem;">해당하는 항목을 선택하거나 직접 입력하세요.</p>
|
||||
|
||||
<div class="item-grid" id="itemGrid">
|
||||
<p style="color: #9ca3af;">먼저 카테고리를 선택하세요</p>
|
||||
</div>
|
||||
|
||||
<!-- 직접 입력 영역 -->
|
||||
<div class="custom-item-input" id="customItemInput" style="display: none;">
|
||||
<input type="text" id="customItemName" placeholder="신고 항목을 직접 입력하세요..." maxlength="100">
|
||||
<button type="button" class="btn-confirm-custom" onclick="confirmCustomItem()">확인</button>
|
||||
<button type="button" class="btn-cancel-custom" onclick="cancelCustomItem()">취소</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 4: 사진 및 추가 설명 -->
|
||||
<div class="form-section" id="step4Section">
|
||||
<h2 class="form-section-title">
|
||||
<span class="section-number">4</span>
|
||||
사진 및 추가 설명
|
||||
</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">사진 첨부 (최대 5장)</label>
|
||||
<div class="photo-upload-grid">
|
||||
<div class="photo-slot" data-index="0">
|
||||
<span class="add-icon">+</span>
|
||||
<button class="remove-btn" type="button">×</button>
|
||||
</div>
|
||||
<div class="photo-slot" data-index="1">
|
||||
<span class="add-icon">+</span>
|
||||
<button class="remove-btn" type="button">×</button>
|
||||
</div>
|
||||
<div class="photo-slot" data-index="2">
|
||||
<span class="add-icon">+</span>
|
||||
<button class="remove-btn" type="button">×</button>
|
||||
</div>
|
||||
<div class="photo-slot" data-index="3">
|
||||
<span class="add-icon">+</span>
|
||||
<button class="remove-btn" type="button">×</button>
|
||||
</div>
|
||||
<div class="photo-slot" data-index="4">
|
||||
<span class="add-icon">+</span>
|
||||
<button class="remove-btn" type="button">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<input type="file" id="photoInput" accept="image/*" capture="environment" style="display: none;">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="additionalDescription">추가 설명 (선택)</label>
|
||||
<textarea id="additionalDescription" class="additional-textarea" placeholder="추가로 설명이 필요한 내용을 입력하세요..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 제출 버튼 -->
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn-cancel" onclick="history.back()">취소</button>
|
||||
<button type="button" class="btn-submit" id="submitBtn" onclick="submitReport()">신고 제출</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 작업 선택 모달 -->
|
||||
<div class="work-selection-modal" id="workSelectionModal">
|
||||
<div class="work-selection-content">
|
||||
<h3 class="work-selection-title">작업 선택</h3>
|
||||
<p style="margin-bottom: 1rem; color: #6b7280; font-size: 0.875rem;">이 위치에 등록된 작업이 있습니다. 연결할 작업을 선택하세요.</p>
|
||||
<div id="workOptionsList"></div>
|
||||
<button type="button" onclick="closeWorkModal()" style="width: 100%; padding: 0.75rem; margin-top: 0.5rem; background: #f3f4f6; border: none; border-radius: 0.5rem; cursor: pointer; font-size: 0.875rem;">
|
||||
작업 연결 없이 진행
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/issue-report.js?v=2"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,327 +0,0 @@
|
||||
<!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/common.css?v=2">
|
||||
<link rel="stylesheet" href="/css/project-management.css?v=3">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<style>
|
||||
.training-container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.request-info-card {
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
border-left: 4px solid var(--primary-500);
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-600);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: var(--text-base);
|
||||
font-weight: 600;
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
.checklist-section {
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.checklist-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
background: var(--gray-50);
|
||||
border-radius: var(--radius-md);
|
||||
border: 2px solid transparent;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.checklist-item:hover {
|
||||
border-color: var(--primary-300);
|
||||
background: var(--primary-50);
|
||||
}
|
||||
|
||||
.checklist-item input[type="checkbox"] {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checklist-item label {
|
||||
flex: 1;
|
||||
font-size: var(--text-base);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.checklist-item input[type="checkbox"]:checked + label {
|
||||
color: var(--gray-500);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.signature-section {
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.signature-canvas-container {
|
||||
border: 2px solid var(--gray-300);
|
||||
border-radius: var(--radius-md);
|
||||
background: white;
|
||||
margin-top: 16px;
|
||||
position: relative;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.signature-canvas {
|
||||
display: block;
|
||||
cursor: crosshair;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.signature-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.signature-placeholder {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: var(--gray-400);
|
||||
font-size: var(--text-base);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.warning-box {
|
||||
background: var(--yellow-50);
|
||||
border: 2px solid var(--yellow-300);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 16px;
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
align-items: start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
flex: 1;
|
||||
color: var(--yellow-800);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.saved-signature-card {
|
||||
background: var(--gray-50);
|
||||
border: 2px solid var(--gray-300);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.saved-signature-card img {
|
||||
max-width: 300px;
|
||||
height: auto;
|
||||
border: 1px solid var(--gray-300);
|
||||
border-radius: var(--radius-sm);
|
||||
background: white;
|
||||
}
|
||||
|
||||
.saved-signature-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.saved-signature-number {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 700;
|
||||
color: var(--primary-600);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.saved-signature-date {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-600);
|
||||
}
|
||||
|
||||
.saved-signature-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="work-report-main">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">안전교육 진행</h1>
|
||||
<p class="page-description">방문자 안전교육 실시 및 서명 받기</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="training-container">
|
||||
<!-- 출입 신청 정보 -->
|
||||
<div class="request-info-card">
|
||||
<h2 class="section-title" style="margin-bottom: 16px;">출입 신청 정보</h2>
|
||||
<div id="requestInfo" class="info-grid">
|
||||
<!-- 동적으로 로드됨 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 안전교육 체크리스트 -->
|
||||
<div class="checklist-section">
|
||||
<h2 class="section-title" style="margin-bottom: 16px;">안전교육 체크리스트</h2>
|
||||
<p style="color: var(--gray-600); margin-bottom: 20px;">
|
||||
방문자에게 다음 안전 사항을 교육하고 체크해주세요.
|
||||
</p>
|
||||
|
||||
<div id="checklistContainer">
|
||||
<div class="checklist-item">
|
||||
<input type="checkbox" id="check1" name="safety-check" value="개인보호구 착용" onchange="updateCompleteButton()">
|
||||
<label for="check1">개인보호구(안전모, 안전화, 안전복) 착용 방법 교육</label>
|
||||
</div>
|
||||
<div class="checklist-item">
|
||||
<input type="checkbox" id="check2" name="safety-check" value="작업장 위험요소" onchange="updateCompleteButton()">
|
||||
<label for="check2">작업장 내 위험요소 및 주의사항 안내</label>
|
||||
</div>
|
||||
<div class="checklist-item">
|
||||
<input type="checkbox" id="check3" name="safety-check" value="비상대피로" onchange="updateCompleteButton()">
|
||||
<label for="check3">비상대피로 및 비상연락망 안내</label>
|
||||
</div>
|
||||
<div class="checklist-item">
|
||||
<input type="checkbox" id="check4" name="safety-check" value="출입통제구역" onchange="updateCompleteButton()">
|
||||
<label for="check4">출입통제구역 및 금지사항 안내</label>
|
||||
</div>
|
||||
<div class="checklist-item">
|
||||
<input type="checkbox" id="check5" name="safety-check" value="사고발생시 대응" onchange="updateCompleteButton()">
|
||||
<label for="check5">사고 발생 시 대응 절차 교육</label>
|
||||
</div>
|
||||
<div class="checklist-item">
|
||||
<input type="checkbox" id="check6" name="safety-check" value="안전수칙 준수" onchange="updateCompleteButton()">
|
||||
<label for="check6">현장 안전수칙 준수 서약</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 경고 -->
|
||||
<div class="warning-box">
|
||||
<div class="warning-icon"></div>
|
||||
<div class="warning-text">
|
||||
<strong>중요:</strong> 모든 체크리스트 항목을 완료하고 방문자의 서명을 받은 후 교육 완료 처리를 해주세요.
|
||||
교육 완료 후에는 수정할 수 없습니다.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 서명 섹션 -->
|
||||
<div class="signature-section">
|
||||
<h2 class="section-title" style="margin-bottom: 16px;">방문자 서명 (<span id="signatureCount">0</span>명)</h2>
|
||||
<p style="color: var(--gray-600); margin-bottom: 20px;">
|
||||
각 방문자가 왼쪽에 이름을 쓰고 오른쪽에 서명한 후 "저장" 버튼을 눌러주세요.
|
||||
</p>
|
||||
|
||||
<div class="signature-canvas-container" style="position: relative;">
|
||||
<!-- 이름과 서명 구분선 및 라벨 -->
|
||||
<div style="position: absolute; top: 10px; left: 10px; right: 10px; display: flex; justify-content: space-between; z-index: 1; pointer-events: none;">
|
||||
<span style="font-size: var(--text-sm); color: var(--gray-500); font-weight: 600;">이름</span>
|
||||
<span style="position: absolute; left: 250px; top: 0; bottom: 0; width: 2px; background: var(--gray-300);"></span>
|
||||
<span style="font-size: var(--text-sm); color: var(--gray-500); font-weight: 600); margin-left: auto;">서명</span>
|
||||
</div>
|
||||
<canvas id="signatureCanvas" class="signature-canvas" width="800" height="300"></canvas>
|
||||
<div id="signaturePlaceholder" class="signature-placeholder" style="display: flex; flex-direction: column; align-items: center; gap: 8px;">
|
||||
<div>왼쪽에 이름을 쓰고, 오른쪽에 서명해주세요</div>
|
||||
<div style="font-size: var(--text-sm); color: var(--gray-400);">(마우스, 터치, 또는 Apple Pencil 사용)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="signature-actions">
|
||||
<button type="button" class="btn btn-secondary" onclick="clearSignature()">
|
||||
서명 지우기
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveSignature()">
|
||||
서명 저장
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style="font-size: var(--text-sm); color: var(--gray-600); margin-top: 12px;">
|
||||
서명 날짜: <span id="signatureDate"></span>
|
||||
</div>
|
||||
|
||||
<!-- 저장된 서명 목록 -->
|
||||
<div id="savedSignatures" style="margin-top: 24px;">
|
||||
<!-- 동적으로 추가됨 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 제출 버튼 -->
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn btn-secondary" onclick="goBack()">
|
||||
취소
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" onclick="completeTraining()" id="completeBtn" disabled>
|
||||
교육 완료 처리
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="/js/safety-training-conduct.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,371 +0,0 @@
|
||||
<!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/common.css?v=2">
|
||||
<link rel="stylesheet" href="/css/project-management.css?v=3">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<style>
|
||||
.visit-form-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
color: var(--gray-700);
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--gray-300);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group select:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-500);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
min-height: 100px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.workplace-selection {
|
||||
padding: 20px;
|
||||
background: var(--gray-50);
|
||||
border-radius: var(--radius-md);
|
||||
border: 2px dashed var(--gray-300);
|
||||
min-height: 150px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.workplace-selection:hover {
|
||||
border-color: var(--primary-500);
|
||||
background: var(--primary-50);
|
||||
}
|
||||
|
||||
.workplace-selection.selected {
|
||||
border-color: var(--primary-500);
|
||||
border-style: solid;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.workplace-selection .icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.workplace-selection .text {
|
||||
font-size: var(--text-base);
|
||||
color: var(--gray-600);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.workplace-selection.selected .text {
|
||||
color: var(--primary-600);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
/* 지도 모달 스타일 */
|
||||
.map-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 1000;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.map-modal-content {
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
overflow: auto;
|
||||
padding: 32px;
|
||||
box-shadow: var(--shadow-2xl);
|
||||
}
|
||||
|
||||
.map-canvas-container {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
border: 2px solid var(--gray-300);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.map-canvas {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.workplace-info-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--primary-50);
|
||||
border: 2px solid var(--primary-200);
|
||||
border-radius: var(--radius-md);
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.workplace-info-card .icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.workplace-info-card .details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.workplace-info-card .name {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 700;
|
||||
color: var(--primary-700);
|
||||
}
|
||||
|
||||
.workplace-info-card .category {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-600);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.my-requests-section {
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
.request-card {
|
||||
padding: 20px;
|
||||
background: white;
|
||||
border: 1px solid var(--gray-200);
|
||||
border-radius: var(--radius-md);
|
||||
margin-bottom: 16px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.request-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.request-status {
|
||||
padding: 6px 12px;
|
||||
border-radius: var(--radius-full);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.request-status.pending {
|
||||
background: var(--yellow-100);
|
||||
color: var(--yellow-700);
|
||||
}
|
||||
|
||||
.request-status.approved {
|
||||
background: var(--green-100);
|
||||
color: var(--green-700);
|
||||
}
|
||||
|
||||
.request-status.rejected {
|
||||
background: var(--red-100);
|
||||
color: var(--red-700);
|
||||
}
|
||||
|
||||
.request-status.training_completed {
|
||||
background: var(--blue-100);
|
||||
color: var(--blue-700);
|
||||
}
|
||||
|
||||
.request-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 12px;
|
||||
color: var(--gray-700);
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-500);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="work-report-main">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">출입 신청</h1>
|
||||
<p class="page-description">작업장 출입 및 안전교육 신청</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 출입 신청 폼 -->
|
||||
<div class="visit-form-container">
|
||||
<div class="code-section">
|
||||
<h2 class="section-title">출입 정보 입력</h2>
|
||||
|
||||
<form id="visitRequestForm">
|
||||
<!-- 방문자 정보 -->
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="visitorCompany">방문자 소속 *</label>
|
||||
<input type="text" id="visitorCompany" placeholder="예: (주)협력업체, 일용직 등" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="visitorCount">방문 인원 *</label>
|
||||
<input type="number" id="visitorCount" value="1" min="1" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업장 선택 -->
|
||||
<div class="form-group">
|
||||
<label>방문 작업장 *</label>
|
||||
<div id="workplaceSelection" class="workplace-selection" onclick="openMapModal()">
|
||||
<div class="icon"></div>
|
||||
<div class="text">지도에서 작업장을 선택하세요</div>
|
||||
</div>
|
||||
<div id="selectedWorkplaceInfo" style="display: none;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 방문 일시 -->
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="visitDate">방문 날짜 *</label>
|
||||
<input type="date" id="visitDate" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="visitTime">방문 시간 *</label>
|
||||
<input type="time" id="visitTime" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 방문 목적 -->
|
||||
<div class="form-group">
|
||||
<label for="visitPurpose">방문 목적 *</label>
|
||||
<select id="visitPurpose" required>
|
||||
<option value="">선택하세요</option>
|
||||
<!-- 동적으로 로드됨 -->
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 비고 -->
|
||||
<div class="form-group">
|
||||
<label for="notes">비고 (선택)</label>
|
||||
<textarea id="notes" placeholder="추가 전달 사항이 있다면 입력하세요"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- 버튼 -->
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn btn-secondary" onclick="resetForm()">초기화</button>
|
||||
<button type="submit" class="btn btn-primary">출입 신청 및 안전교육 신청</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 내 신청 목록 -->
|
||||
<div class="my-requests-section">
|
||||
<div class="code-section">
|
||||
<h2 class="section-title">내 출입 신청 현황</h2>
|
||||
<div id="myRequestsList">
|
||||
<!-- 동적으로 로드됨 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 작업장 지도 모달 -->
|
||||
<div id="mapModal" class="map-modal">
|
||||
<div class="map-modal-content">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px;">
|
||||
<h2 style="margin: 0;">작업장 선택</h2>
|
||||
<button class="btn btn-secondary" onclick="closeMapModal()">닫기</button>
|
||||
</div>
|
||||
|
||||
<!-- 구역(공장) 선택 -->
|
||||
<div class="form-group">
|
||||
<label for="categorySelect">구역(공장) 선택</label>
|
||||
<select id="categorySelect" onchange="loadWorkplaceMap()">
|
||||
<option value="">구역을 선택하세요</option>
|
||||
<!-- 동적으로 로드됨 -->
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 지도 캔버스 -->
|
||||
<div id="mapCanvasContainer" style="display: none;">
|
||||
<div class="map-canvas-container">
|
||||
<canvas id="workplaceMapCanvas" class="map-canvas"></canvas>
|
||||
</div>
|
||||
<p style="margin-top: 12px; color: var(--gray-600); font-size: var(--text-sm);">
|
||||
지도에서 방문할 작업장을 클릭하세요
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="/js/visit-request.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,23 +3,35 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>작업 분석 | (주)테크니컬코리아</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/design-system.css">
|
||||
<title>작업 분석 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/work-analysis.css?v=41">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<div class="analysis-container">
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 뒤로가기 버튼 -->
|
||||
<a href="javascript:history.back()" class="back-button" style="margin: 1rem 0;">
|
||||
← 뒤로가기
|
||||
@@ -261,10 +273,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- JavaScript -->
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script type="module" src="/js/work-analysis.js?v=5"></script>
|
||||
|
||||
<script>
|
||||
@@ -2855,5 +2869,6 @@
|
||||
// 초기 모드 설정
|
||||
window.currentAnalysisMode = 'period';
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,278 +3,71 @@
|
||||
<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/common.css?v=2">
|
||||
<link rel="stylesheet" href="/css/project-management.css?v=3">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<style>
|
||||
/* 통계 카드 */
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
padding: 1.25rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.stat-card.reported .stat-number { color: #3b82f6; }
|
||||
.stat-card.received .stat-number { color: #f97316; }
|
||||
.stat-card.in_progress .stat-number { color: #8b5cf6; }
|
||||
.stat-card.completed .stat-number { color: #10b981; }
|
||||
|
||||
/* 필터 바 */
|
||||
.filter-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 1rem 1.25rem;
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.filter-bar select,
|
||||
.filter-bar input {
|
||||
padding: 0.625rem 0.875rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.filter-bar select:focus,
|
||||
.filter-bar input:focus {
|
||||
outline: none;
|
||||
border-color: #f97316;
|
||||
box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.1);
|
||||
}
|
||||
|
||||
.btn-new-report {
|
||||
margin-left: auto;
|
||||
padding: 0.625rem 1.25rem;
|
||||
background: #f97316;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.btn-new-report:hover {
|
||||
background: #ea580c;
|
||||
}
|
||||
|
||||
/* 신고 목록 */
|
||||
.issue-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.issue-card {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.25rem;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.issue-card:hover {
|
||||
border-color: #fed7aa;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.issue-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.issue-id {
|
||||
font-size: 0.875rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.issue-status {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.issue-status.reported {
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.issue-status.received {
|
||||
background: #fed7aa;
|
||||
color: #c2410c;
|
||||
}
|
||||
|
||||
.issue-status.in_progress {
|
||||
background: #e9d5ff;
|
||||
color: #7c3aed;
|
||||
}
|
||||
|
||||
.issue-status.completed {
|
||||
background: #d1fae5;
|
||||
color: #047857;
|
||||
}
|
||||
|
||||
.issue-status.closed {
|
||||
background: #f3f4f6;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.issue-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.issue-category-badge {
|
||||
display: inline-block;
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
margin-right: 0.5rem;
|
||||
background: #fff7ed;
|
||||
color: #c2410c;
|
||||
}
|
||||
|
||||
.issue-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.issue-meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.issue-photos {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.issue-photos img {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
object-fit: cover;
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
/* 빈 상태 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 4rem 1.5rem;
|
||||
color: #6b7280;
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.empty-state-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.filter-bar {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.btn-new-report {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title>부적합 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="work-report-main">
|
||||
<div class="dashboard-main">
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">부적합 현황</h1>
|
||||
<p class="page-description">자재, 설계, 검사 등 작업 관련 부적합 신고 현황입니다.</p>
|
||||
</div>
|
||||
<!-- Mobile overlay -->
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<!-- Sidebar Nav -->
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="mb-5">
|
||||
<h2 class="text-xl font-bold text-gray-800">부적합 현황</h2>
|
||||
<p class="text-sm text-gray-500 mt-0.5">자재, 설계, 검사 등 작업 관련 부적합 신고 현황입니다.</p>
|
||||
</div>
|
||||
|
||||
<!-- 통계 카드 -->
|
||||
<div class="stats-grid" id="statsGrid">
|
||||
<div class="stat-card reported">
|
||||
<div class="stat-number" id="statReported">-</div>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-3 mb-5" id="statsGrid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-blue-600" id="statReported">-</div>
|
||||
<div class="stat-label">신고</div>
|
||||
</div>
|
||||
<div class="stat-card received">
|
||||
<div class="stat-number" id="statReceived">-</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-orange-600" id="statReceived">-</div>
|
||||
<div class="stat-label">접수</div>
|
||||
</div>
|
||||
<div class="stat-card in_progress">
|
||||
<div class="stat-number" id="statProgress">-</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-purple-600" id="statProgress">-</div>
|
||||
<div class="stat-label">처리중</div>
|
||||
</div>
|
||||
<div class="stat-card completed">
|
||||
<div class="stat-number" id="statCompleted">-</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value text-green-600" id="statCompleted">-</div>
|
||||
<div class="stat-label">완료</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 필터 바 -->
|
||||
<div class="filter-bar">
|
||||
<select id="filterStatus">
|
||||
<div class="bg-white rounded-xl shadow-sm p-4 mb-5 flex flex-wrap items-center gap-3">
|
||||
<select id="filterStatus" class="input-field px-3 py-2 rounded-lg text-sm">
|
||||
<option value="">전체 상태</option>
|
||||
<option value="reported">신고</option>
|
||||
<option value="received">접수</option>
|
||||
@@ -282,25 +75,22 @@
|
||||
<option value="completed">완료</option>
|
||||
<option value="closed">종료</option>
|
||||
</select>
|
||||
|
||||
<input type="date" id="filterStartDate" title="시작일">
|
||||
<input type="date" id="filterEndDate" title="종료일">
|
||||
|
||||
<a href="/pages/safety/report.html?type=nonconformity" class="btn-new-report">
|
||||
+ 부적합 신고
|
||||
<input type="date" id="filterStartDate" class="input-field px-3 py-2 rounded-lg text-sm" title="시작일">
|
||||
<input type="date" id="filterEndDate" class="input-field px-3 py-2 rounded-lg text-sm" title="종료일">
|
||||
<a id="btnNewReport" href="#" class="ml-auto inline-flex items-center gap-2 px-4 py-2 bg-orange-600 text-white rounded-lg text-sm font-semibold hover:bg-orange-700 transition-colors">
|
||||
<i class="fas fa-plus"></i>부적합 신고
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 신고 목록 -->
|
||||
<div class="issue-list" id="issueList">
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-title">로딩 중...</div>
|
||||
</div>
|
||||
<div id="issueList" class="space-y-3">
|
||||
<div class="bg-white rounded-xl shadow-sm p-8 text-center text-gray-400 text-sm">로딩 중...</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/nonconformity-list.js?v=2"></script>
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/static/js/tkfb-nonconformity.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>작업보고서 | (주)테크니컬코리아</title>
|
||||
<link rel="stylesheet" href="/css/design-system.css">
|
||||
<title>작업보고서 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/daily-work-report-mobile.css?v=1">
|
||||
<link rel="stylesheet" href="/css/mobile.css?v=1">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<style>
|
||||
/* 데스크탑이면 리다이렉트 */
|
||||
@media (min-width: 769px) {
|
||||
@@ -26,11 +24,29 @@
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 네비게이션 바 (app-init에서 로드) -->
|
||||
<div id="navbar-container"></div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<div class="m-container">
|
||||
<!-- Sticky 헤더 -->
|
||||
<div class="m-header">
|
||||
<h1 class="m-header-title">작업보고서</h1>
|
||||
@@ -85,7 +101,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 시간 선택 오버레이 -->
|
||||
<div class="m-time-overlay" id="mTimeOverlay" onclick="MobileReport.closeTimePicker()">
|
||||
@@ -169,7 +184,13 @@
|
||||
<!-- 토스트 -->
|
||||
<div class="m-toast" id="mToast"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 공통 모듈 -->
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/common/utils.js?v=1"></script>
|
||||
<script src="/js/common/base-state.js?v=1"></script>
|
||||
|
||||
@@ -180,19 +201,6 @@
|
||||
|
||||
<!-- 모바일 전용 UI 로직 -->
|
||||
<script src="/js/daily-work-report-mobile.js?v=4"></script>
|
||||
|
||||
<!-- 모바일 하단 네비게이션 -->
|
||||
<div id="mobile-nav-container"></div>
|
||||
<script>
|
||||
if (window.innerWidth <= 768) {
|
||||
fetch('/components/mobile-nav.html')
|
||||
.then(r => r.text())
|
||||
.then(html => {
|
||||
document.getElementById('mobile-nav-container').innerHTML = html;
|
||||
const scripts = document.getElementById('mobile-nav-container').querySelectorAll('script');
|
||||
scripts.forEach(s => eval(s.textContent));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,196 +1,162 @@
|
||||
<!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/daily-work-report.css?v=13">
|
||||
<link rel="stylesheet" href="/css/mobile.css?v=1">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<!-- api-base.js에서 SW 캐시 강제 해제 처리 -->
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>작업보고서 작성 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/daily-work-report.css?v=13">
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="work-report-main">
|
||||
<!-- 탭 메뉴 -->
|
||||
<div class="tab-menu" style="margin-bottom: var(--space-6);">
|
||||
<button class="tab-btn active" id="tbmReportTab" onclick="switchTab('tbm')">
|
||||
작업보고서 작성
|
||||
</button>
|
||||
<button class="tab-btn" id="completedReportTab" onclick="switchTab('completed')">
|
||||
작성 완료 보고서
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 메시지 영역 -->
|
||||
<div id="message-container"></div>
|
||||
|
||||
<!-- TBM 작업보고 섹션 -->
|
||||
<div id="tbmReportSection" class="step-section active">
|
||||
<!-- TBM 작업 목록 -->
|
||||
<div id="tbmWorkList">
|
||||
<!-- TBM 작업 항목들이 여기에 동적으로 추가됩니다 -->
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- 작성 완료 보고서 섹션 -->
|
||||
<div id="completedReportSection" class="step-section" style="display: none;">
|
||||
<!-- 날짜 선택 필터 -->
|
||||
<div class="form-group" style="max-width: 300px; margin-bottom: var(--space-5);">
|
||||
<label for="completedReportDate" class="form-label">조회 날짜</label>
|
||||
<input type="date" id="completedReportDate" class="form-input" onchange="loadCompletedReports()">
|
||||
</div>
|
||||
<!-- Mobile overlay -->
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<!-- 완료된 보고서 목록 -->
|
||||
<div id="completedReportsList">
|
||||
<!-- 완료된 보고서들이 여기에 동적으로 추가됩니다 -->
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<!-- Sidebar Nav -->
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<!-- 저장 결과 모달 -->
|
||||
<div id="saveResultModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container result-modal">
|
||||
<div class="modal-header">
|
||||
<h2 id="resultModalTitle">저장 결과</h2>
|
||||
<button class="modal-close-btn" onclick="closeSaveResultModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="resultModalContent" class="result-content">
|
||||
<!-- 결과 내용이 여기에 동적으로 추가됩니다 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 탭 메뉴 -->
|
||||
<div class="tab-menu" style="margin-bottom: 1.5rem;">
|
||||
<button class="tab-btn active" id="tbmReportTab" onclick="switchTab('tbm')">
|
||||
작업보고서 작성
|
||||
</button>
|
||||
<button class="tab-btn" id="completedReportTab" onclick="switchTab('completed')">
|
||||
작성 완료 보고서
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 메시지 영역 -->
|
||||
<div id="message-container"></div>
|
||||
|
||||
<!-- TBM 작업보고 섹션 -->
|
||||
<div id="tbmReportSection" class="step-section active">
|
||||
<div id="tbmWorkList"></div>
|
||||
</div>
|
||||
|
||||
<!-- 작성 완료 보고서 섹션 -->
|
||||
<div id="completedReportSection" class="step-section" style="display: none;">
|
||||
<div class="form-group" style="max-width: 300px; margin-bottom: 1.25rem;">
|
||||
<label for="completedReportDate" class="form-label">조회 날짜</label>
|
||||
<input type="date" id="completedReportDate" class="form-input" onchange="loadCompletedReports()">
|
||||
</div>
|
||||
<div id="completedReportsList"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" onclick="closeSaveResultModal()">
|
||||
확인
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업장소 선택 모달 (지도 기반) -->
|
||||
<div id="workplaceModal" class="modal-overlay" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 1002; align-items: center; justify-content: center; overflow-y: auto; padding: 2rem 0;">
|
||||
<div class="modal-container" style="background: white; border-radius: 8px; max-width: 1000px; width: 90%; max-height: none; margin: auto; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column;">
|
||||
<div class="modal-header" style="padding: 1.5rem; border-bottom: 1px solid #e5e7eb; display: flex; justify-content: space-between; align-items: center;">
|
||||
<h2 style="font-size: 1.25rem; font-weight: 600; color: #111827; margin: 0;">작업장소 선택</h2>
|
||||
<button class="modal-close" onclick="closeWorkplaceModal()" style="background: none; border: none; font-size: 1.5rem; cursor: pointer; color: #6b7280; padding: 0; width: 2rem; height: 2rem; display: flex; align-items: center; justify-content: center; border-radius: 4px;">×</button>
|
||||
</div>
|
||||
<div class="modal-body" style="padding: 1.5rem; flex: 1; overflow-y: visible;">
|
||||
<!-- 1단계: 카테고리 선택 -->
|
||||
<div id="categorySelectionArea">
|
||||
<h3 style="font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; color: #374151;">공장 선택</h3>
|
||||
<div id="workplaceCategoryList" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem;">
|
||||
<!-- 카테고리 버튼들 -->
|
||||
</div>
|
||||
<!-- 저장 결과 모달 -->
|
||||
<div id="saveResultModal" class="modal-overlay" style="display: none;">
|
||||
<div class="modal-container result-modal">
|
||||
<div class="modal-header">
|
||||
<h2 id="resultModalTitle">저장 결과</h2>
|
||||
<button class="modal-close-btn" onclick="closeSaveResultModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="resultModalContent" class="result-content"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" onclick="closeSaveResultModal()">확인</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2단계: 작업장 선택 (지도 + 리스트) -->
|
||||
<div id="workplaceSelectionArea" style="display: none; margin-top: 1.5rem;">
|
||||
<h3 style="font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; color: #374151;">
|
||||
<span id="selectedCategoryTitle">작업장 선택</span>
|
||||
</h3>
|
||||
|
||||
<!-- 지도 기반 선택 영역 -->
|
||||
<div id="layoutMapArea" style="display: none; margin-bottom: 1.5rem; padding: 1rem; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 0.5rem;">
|
||||
<div style="font-size: 0.875rem; color: #6b7280; margin-bottom: 0.75rem;">
|
||||
지도에서 작업장을 클릭하여 선택하세요
|
||||
</div>
|
||||
<div style="text-align: center; position: relative; display: inline-block; max-width: 100%;">
|
||||
<canvas id="workplaceMapCanvas" style="max-width: 100%; border-radius: 0.5rem; cursor: pointer; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 리스트 선택 영역 -->
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem;">
|
||||
<span style="font-size: 0.875rem; color: #6b7280;">리스트에서 선택</span>
|
||||
</div>
|
||||
<div id="workplaceListArea" style="display: flex; flex-direction: column; gap: 0.5rem; max-height: 200px; overflow-y: auto; padding: 0.75rem; border: 1px solid #e5e7eb; border-radius: 0.5rem; background: white;">
|
||||
<!-- 작업장소 목록 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 0.75rem; justify-content: flex-end; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #e5e7eb;">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeWorkplaceModal()">취소</button>
|
||||
<button type="button" class="btn btn-primary" id="confirmWorkplaceBtn" onclick="confirmWorkplaceSelection()" disabled>선택 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 시간 선택 팝오버 -->
|
||||
<div id="timePickerOverlay" class="time-picker-overlay" style="display: none;" onclick="closeTimePicker()">
|
||||
<div class="time-picker-popup" onclick="event.stopPropagation()">
|
||||
<div class="time-picker-header">
|
||||
<h3 id="timePickerTitle">작업시간 선택</h3>
|
||||
<button class="time-picker-close" onclick="closeTimePicker()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="quick-time-grid">
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(0.5)">
|
||||
<span class="time-value">30분</span>
|
||||
</button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(1)">
|
||||
<span class="time-value">1시간</span>
|
||||
</button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(2)">
|
||||
<span class="time-value">2시간</span>
|
||||
</button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(4)">
|
||||
<span class="time-value">4시간</span>
|
||||
</button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(8)">
|
||||
<span class="time-value">8시간</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="time-adjust-area">
|
||||
<span class="current-time-label">현재:</span>
|
||||
<strong id="currentTimeDisplay" class="current-time-value">0시간</strong>
|
||||
<div class="adjust-buttons">
|
||||
<button type="button" class="adjust-btn" onclick="adjustTime(-0.5)">-30분</button>
|
||||
<button type="button" class="adjust-btn" onclick="adjustTime(0.5)">+30분</button>
|
||||
<!-- 작업장소 선택 모달 (지도 기반) -->
|
||||
<div id="workplaceModal" class="modal-overlay" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 1002; align-items: center; justify-content: center; overflow-y: auto; padding: 2rem 0;">
|
||||
<div class="modal-container" style="background: white; border-radius: 8px; max-width: 1000px; width: 90%; max-height: none; margin: auto; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column;">
|
||||
<div class="modal-header" style="padding: 1.5rem; border-bottom: 1px solid #e5e7eb; display: flex; justify-content: space-between; align-items: center;">
|
||||
<h2 style="font-size: 1.25rem; font-weight: 600; color: #111827; margin: 0;">작업장소 선택</h2>
|
||||
<button class="modal-close" onclick="closeWorkplaceModal()" style="background: none; border: none; font-size: 1.5rem; cursor: pointer; color: #6b7280; padding: 0; width: 2rem; height: 2rem; display: flex; align-items: center; justify-content: center; border-radius: 4px;">×</button>
|
||||
</div>
|
||||
<div class="modal-body" style="padding: 1.5rem; flex: 1; overflow-y: visible;">
|
||||
<div id="categorySelectionArea">
|
||||
<h3 style="font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; color: #374151;">공장 선택</h3>
|
||||
<div id="workplaceCategoryList" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem;"></div>
|
||||
</div>
|
||||
<div id="workplaceSelectionArea" style="display: none; margin-top: 1.5rem;">
|
||||
<h3 style="font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; color: #374151;">
|
||||
<span id="selectedCategoryTitle">작업장 선택</span>
|
||||
</h3>
|
||||
<div id="layoutMapArea" style="display: none; margin-bottom: 1.5rem; padding: 1rem; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 0.5rem;">
|
||||
<div style="font-size: 0.875rem; color: #6b7280; margin-bottom: 0.75rem;">지도에서 작업장을 클릭하여 선택하세요</div>
|
||||
<div style="text-align: center; position: relative; display: inline-block; max-width: 100%;">
|
||||
<canvas id="workplaceMapCanvas" style="max-width: 100%; border-radius: 0.5rem; cursor: pointer; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem;">
|
||||
<span style="font-size: 0.875rem; color: #6b7280;">리스트에서 선택</span>
|
||||
</div>
|
||||
<div id="workplaceListArea" style="display: flex; flex-direction: column; gap: 0.5rem; max-height: 200px; overflow-y: auto; padding: 0.75rem; border: 1px solid #e5e7eb; border-radius: 0.5rem; background: white;"></div>
|
||||
</div>
|
||||
<div style="display: flex; gap: 0.75rem; justify-content: flex-end; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #e5e7eb;">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeWorkplaceModal()">취소</button>
|
||||
<button type="button" class="btn btn-primary" id="confirmWorkplaceBtn" onclick="confirmWorkplaceSelection()" disabled>선택 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="confirm-btn" onclick="confirmTimeSelection()">확인</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 공통 모듈 -->
|
||||
<script src="/js/common/utils.js?v=1"></script>
|
||||
<script src="/js/common/base-state.js?v=1"></script>
|
||||
<!-- 시간 선택 팝오버 -->
|
||||
<div id="timePickerOverlay" class="time-picker-overlay" style="display: none;" onclick="closeTimePicker()">
|
||||
<div class="time-picker-popup" onclick="event.stopPropagation()">
|
||||
<div class="time-picker-header">
|
||||
<h3 id="timePickerTitle">작업시간 선택</h3>
|
||||
<button class="time-picker-close" onclick="closeTimePicker()">×</button>
|
||||
</div>
|
||||
<div class="quick-time-grid">
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(0.5)"><span class="time-value">30분</span></button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(1)"><span class="time-value">1시간</span></button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(2)"><span class="time-value">2시간</span></button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(4)"><span class="time-value">4시간</span></button>
|
||||
<button type="button" class="time-btn" onclick="setTimeValue(8)"><span class="time-value">8시간</span></button>
|
||||
</div>
|
||||
<div class="time-adjust-area">
|
||||
<span class="current-time-label">현재:</span>
|
||||
<strong id="currentTimeDisplay" class="current-time-value">0시간</strong>
|
||||
<div class="adjust-buttons">
|
||||
<button type="button" class="adjust-btn" onclick="adjustTime(-0.5)">-30분</button>
|
||||
<button type="button" class="adjust-btn" onclick="adjustTime(0.5)">+30분</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="confirm-btn" onclick="confirmTimeSelection()">확인</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업보고서 모듈 (리팩토링된 구조) -->
|
||||
<script src="/js/daily-work-report/state.js?v=2"></script>
|
||||
<script src="/js/daily-work-report/utils.js?v=2"></script>
|
||||
<script src="/js/daily-work-report/api.js?v=2"></script>
|
||||
|
||||
<!-- 기존 UI 로직 (점진적 마이그레이션) -->
|
||||
<script defer src="/js/daily-work-report.js?v=36"></script>
|
||||
|
||||
<!-- 모바일 하단 네비게이션 -->
|
||||
<div id="mobile-nav-container"></div>
|
||||
<script>
|
||||
if (window.innerWidth <= 768) {
|
||||
fetch('/components/mobile-nav.html')
|
||||
.then(r => r.text())
|
||||
.then(html => {
|
||||
document.getElementById('mobile-nav-container').innerHTML = html;
|
||||
const scripts = document.getElementById('mobile-nav-container').querySelectorAll('script');
|
||||
scripts.forEach(s => eval(s.textContent));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/common/utils.js?v=1"></script>
|
||||
<script src="/js/common/base-state.js?v=1"></script>
|
||||
<script src="/js/daily-work-report/state.js?v=2"></script>
|
||||
<script src="/js/daily-work-report/utils.js?v=2"></script>
|
||||
<script src="/js/daily-work-report/api.js?v=2"></script>
|
||||
<script defer src="/js/daily-work-report.js?v=36"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -3,27 +3,18 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>TBM 시작 | (주)테크니컬코리아</title>
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<title>TBM 등록 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans KR', sans-serif;
|
||||
background: #f3f4f6;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
button, .worker-card, .list-item, .list-item-skip, .pill-btn, .pill-btn-add,
|
||||
.nav-btn, .select-all-btn, [onclick] {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
@media (min-width: 480px) {
|
||||
body { max-width: 480px; margin: 0 auto; min-height: 100vh; }
|
||||
.tbm-create-wrap { max-width: 480px; margin: 0 auto; min-height: 100vh; }
|
||||
}
|
||||
|
||||
/* Fixed header */
|
||||
@@ -781,52 +772,86 @@
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Fixed Header -->
|
||||
<div class="wizard-header">
|
||||
<button type="button" class="back-btn" onclick="goBack()">←</button>
|
||||
<h1>TBM 시작</h1>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<div class="tbm-create-wrap">
|
||||
<!-- Fixed Header -->
|
||||
<div class="wizard-header">
|
||||
<button type="button" class="back-btn" onclick="goBack()">←</button>
|
||||
<h1>TBM 시작</h1>
|
||||
</div>
|
||||
|
||||
<!-- Step Indicator -->
|
||||
<div class="step-indicator" id="stepIndicator">
|
||||
<div class="step active"><span class="step-dot">1</span><span>작업자</span></div>
|
||||
<div class="step-line"></div>
|
||||
<div class="step"><span class="step-dot">2</span><span>프로젝트+공정</span></div>
|
||||
<div class="step-line"></div>
|
||||
<div class="step"><span class="step-dot">3</span><span>확인</span></div>
|
||||
</div>
|
||||
|
||||
<!-- Step Content -->
|
||||
<div class="step-content" id="stepContainer">
|
||||
<!-- Dynamically rendered by tbm-create.js -->
|
||||
</div>
|
||||
|
||||
<!-- Fixed Bottom Nav -->
|
||||
<div class="wizard-nav" id="wizardNav">
|
||||
<button type="button" class="nav-btn nav-btn-prev" id="prevBtn" style="visibility:hidden;">← 이전</button>
|
||||
<button type="button" class="nav-btn nav-btn-next" id="nextBtn">다음 →</button>
|
||||
</div>
|
||||
|
||||
<!-- Landscape Map Overlay removed - workplace selection moved to detail edit stage -->
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="loading-overlay">
|
||||
<div class="loading-spinner"></div>
|
||||
<div class="loading-text" id="loadingText">데이터를 불러오는 중...</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div id="toastContainer" class="toast-container"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step Indicator -->
|
||||
<div class="step-indicator" id="stepIndicator">
|
||||
<div class="step active"><span class="step-dot">1</span><span>작업자</span></div>
|
||||
<div class="step-line"></div>
|
||||
<div class="step"><span class="step-dot">2</span><span>프로젝트+공정</span></div>
|
||||
<div class="step-line"></div>
|
||||
<div class="step"><span class="step-dot">3</span><span>확인</span></div>
|
||||
</div>
|
||||
|
||||
<!-- Step Content -->
|
||||
<div class="step-content" id="stepContainer">
|
||||
<!-- Dynamically rendered by tbm-create.js -->
|
||||
</div>
|
||||
|
||||
<!-- Fixed Bottom Nav -->
|
||||
<div class="wizard-nav" id="wizardNav">
|
||||
<button type="button" class="nav-btn nav-btn-prev" id="prevBtn" style="visibility:hidden;">← 이전</button>
|
||||
<button type="button" class="nav-btn nav-btn-next" id="nextBtn">다음 →</button>
|
||||
</div>
|
||||
|
||||
<!-- Landscape Map Overlay removed - workplace selection moved to detail edit stage -->
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="loading-overlay">
|
||||
<div class="loading-spinner"></div>
|
||||
<div class="loading-text" id="loadingText">데이터를 불러오는 중...</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div id="toastContainer" class="toast-container"></div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<!-- 공통 모듈 -->
|
||||
<script src="/js/common/utils.js?v=2"></script>
|
||||
<script src="/js/common/base-state.js?v=2"></script>
|
||||
|
||||
<script src="/js/tbm/state.js?v=3"></script>
|
||||
<script src="/js/tbm/utils.js?v=3"></script>
|
||||
<script src="/js/tbm/api.js?v=4"></script>
|
||||
<script src="/js/tbm-create.js?v=14"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,14 +3,35 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>TBM | (주)테크니컬코리아</title>
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<title>TBM - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/tbm-mobile.css?v=1">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="m-loading-overlay">
|
||||
@@ -270,7 +291,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 공통 모듈 -->
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/common/utils.js?v=2"></script>
|
||||
<script src="/js/common/base-state.js?v=2"></script>
|
||||
|
||||
@@ -278,5 +305,6 @@
|
||||
<script src="/js/tbm/utils.js?v=3"></script>
|
||||
<script src="/js/tbm/api.js?v=4"></script>
|
||||
<script src="/js/tbm-mobile.js?v=3"></script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,168 +3,172 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TBM 관리 | (주)테크니컬코리아</title>
|
||||
<link rel="stylesheet" href="/css/design-system.css">
|
||||
<link rel="stylesheet" href="/css/common.css?v=2">
|
||||
<title>TBM 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/css/tbm.css?v=5">
|
||||
<link rel="stylesheet" href="/css/mobile.css?v=1">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
<!-- 최적화된 로딩: API 설정 → 앱 초기화 (병렬 컴포넌트 로딩) -->
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/app-init.js?v=9" defer></script>
|
||||
<!-- instant.page: 링크 호버 시 페이지 프리로딩 -->
|
||||
<script src="https://instant.page/5.2.0" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="work-report-container">
|
||||
<!-- 네비게이션 바 -->
|
||||
<div id="navbar-container"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="work-report-main">
|
||||
<div class="tbm-container">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="tbm-page-header">
|
||||
<div class="tbm-title-section">
|
||||
<h1 class="tbm-page-title">
|
||||
<span class="tbm-page-title-icon">🛠</span>
|
||||
TBM (Tool Box Meeting)
|
||||
</h1>
|
||||
<p class="tbm-page-description">아침 안전 회의 및 팀 구성 관리</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TBM 탭 메뉴 -->
|
||||
<div class="tbm-tab-menu">
|
||||
<button class="tbm-tab-btn active" data-tab="tbm-input" onclick="switchTbmTab('tbm-input')">
|
||||
<span class="tbm-tab-icon">📝</span>
|
||||
TBM 입력
|
||||
</button>
|
||||
<button class="tbm-tab-btn" data-tab="tbm-manage" onclick="switchTbmTab('tbm-manage')">
|
||||
<span class="tbm-tab-icon">📊</span>
|
||||
TBM 관리
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- TBM 입력 탭 -->
|
||||
<div id="tbm-input-tab" class="tbm-tab-content active">
|
||||
<div class="tbm-section">
|
||||
<div class="tbm-section-header">
|
||||
<h2 class="tbm-section-title">
|
||||
<span>📅</span>
|
||||
오늘의 TBM
|
||||
</h2>
|
||||
<div class="tbm-section-actions">
|
||||
<button class="tbm-btn tbm-btn-primary" onclick="openNewTbmModal()">
|
||||
<span class="tbm-btn-icon">+</span>
|
||||
새 TBM 시작
|
||||
</button>
|
||||
</div>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
|
||||
<div class="tbm-stats-bar">
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">오늘 등록</span>
|
||||
<span class="tbm-stat-value highlight" id="todayTotalSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">완료</span>
|
||||
<span class="tbm-stat-value success" id="todayCompletedSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">진행중</span>
|
||||
<span class="tbm-stat-value warning" id="todayActiveSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="tbm-card-grid" id="todayTbmGrid">
|
||||
<!-- 오늘의 TBM 세션 카드들이 여기에 동적으로 생성됩니다 -->
|
||||
</div>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div class="tbm-empty-state" id="todayEmptyState" style="display: none;">
|
||||
<div class="tbm-empty-icon">📋</div>
|
||||
<h3 class="tbm-empty-title">오늘 등록된 TBM이 없습니다</h3>
|
||||
<p class="tbm-empty-description">"새 TBM 시작" 버튼을 눌러 오늘의 TBM을 시작해보세요.</p>
|
||||
<button class="tbm-btn tbm-btn-primary" onclick="openNewTbmModal()">
|
||||
<span class="tbm-btn-icon">+</span>
|
||||
첫 TBM 시작하기
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- TBM 관리 탭 -->
|
||||
<div id="tbm-manage-tab" class="tbm-tab-content">
|
||||
<div class="tbm-section">
|
||||
<div class="tbm-section-header">
|
||||
<h2 class="tbm-section-title">
|
||||
<span>📚</span>
|
||||
TBM 기록
|
||||
</h2>
|
||||
<div class="tbm-section-actions">
|
||||
<button class="tbm-btn tbm-btn-secondary" onclick="loadMoreTbmDays()" id="loadMoreBtn">
|
||||
더 보기
|
||||
<!-- Mobile overlay -->
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<!-- Sidebar Nav -->
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="tbm-container">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="tbm-page-header">
|
||||
<div class="tbm-title-section">
|
||||
<h1 class="tbm-page-title">
|
||||
<span class="tbm-page-title-icon">🛠</span>
|
||||
TBM (Tool Box Meeting)
|
||||
</h1>
|
||||
<p class="tbm-page-description">아침 안전 회의 및 팀 구성 관리</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TBM 탭 메뉴 -->
|
||||
<div class="tbm-tab-menu">
|
||||
<button class="tbm-tab-btn active" data-tab="tbm-input" onclick="switchTbmTab('tbm-input')">
|
||||
<span class="tbm-tab-icon">📝</span>
|
||||
TBM 입력
|
||||
</button>
|
||||
<button class="tbm-tab-btn" data-tab="tbm-manage" onclick="switchTbmTab('tbm-manage')">
|
||||
<span class="tbm-tab-icon">📊</span>
|
||||
TBM 관리
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-stats-bar">
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">총</span>
|
||||
<span class="tbm-stat-value" id="totalSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">완료</span>
|
||||
<span class="tbm-stat-value success" id="completedSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item" id="viewModeIndicator" style="display: none;">
|
||||
<span class="tbm-stat-value" id="viewModeText">내 TBM만</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- TBM 입력 탭 -->
|
||||
<div id="tbm-input-tab" class="tbm-tab-content active">
|
||||
<div class="tbm-section">
|
||||
<div class="tbm-section-header">
|
||||
<h2 class="tbm-section-title">
|
||||
<span>📅</span>
|
||||
오늘의 TBM
|
||||
</h2>
|
||||
<div class="tbm-section-actions">
|
||||
<button class="tbm-btn tbm-btn-primary" onclick="openNewTbmModal()">
|
||||
<span class="tbm-btn-icon">+</span>
|
||||
새 TBM 시작
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 날짜별 그룹 컨테이너 -->
|
||||
<div class="tbm-section-body" id="tbmDateGroupsContainer">
|
||||
<!-- 날짜별 TBM 그룹이 여기에 동적으로 생성됩니다 -->
|
||||
</div>
|
||||
<div class="tbm-stats-bar">
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">오늘 등록</span>
|
||||
<span class="tbm-stat-value highlight" id="todayTotalSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">완료</span>
|
||||
<span class="tbm-stat-value success" id="todayCompletedSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">진행중</span>
|
||||
<span class="tbm-stat-value warning" id="todayActiveSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div class="tbm-empty-state" id="emptyState" style="display: none;">
|
||||
<div class="tbm-empty-icon">📚</div>
|
||||
<h3 class="tbm-empty-title">등록된 TBM 세션이 없습니다</h3>
|
||||
<p class="tbm-empty-description">TBM 입력 탭에서 새로운 TBM을 시작해보세요.</p>
|
||||
<div class="tbm-card-grid" id="todayTbmGrid"></div>
|
||||
|
||||
<div class="tbm-empty-state" id="todayEmptyState" style="display: none;">
|
||||
<div class="tbm-empty-icon">📋</div>
|
||||
<h3 class="tbm-empty-title">오늘 등록된 TBM이 없습니다</h3>
|
||||
<p class="tbm-empty-description">"새 TBM 시작" 버튼을 눌러 오늘의 TBM을 시작해보세요.</p>
|
||||
<button class="tbm-btn tbm-btn-primary" onclick="openNewTbmModal()">
|
||||
<span class="tbm-btn-icon">+</span>
|
||||
첫 TBM 시작하기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TBM 관리 탭 -->
|
||||
<div id="tbm-manage-tab" class="tbm-tab-content">
|
||||
<div class="tbm-section">
|
||||
<div class="tbm-section-header">
|
||||
<h2 class="tbm-section-title">
|
||||
<span>📚</span>
|
||||
TBM 기록
|
||||
</h2>
|
||||
<div class="tbm-section-actions">
|
||||
<button class="tbm-btn tbm-btn-secondary" onclick="loadMoreTbmDays()" id="loadMoreBtn">
|
||||
더 보기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-stats-bar">
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">총</span>
|
||||
<span class="tbm-stat-value" id="totalSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item">
|
||||
<span class="tbm-stat-label">완료</span>
|
||||
<span class="tbm-stat-value success" id="completedSessions">0</span>
|
||||
<span class="tbm-stat-label">개</span>
|
||||
</span>
|
||||
<span class="tbm-stat-item" id="viewModeIndicator" style="display: none;">
|
||||
<span class="tbm-stat-value" id="viewModeText">내 TBM만</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="tbm-section-body" id="tbmDateGroupsContainer"></div>
|
||||
|
||||
<div class="tbm-empty-state" id="emptyState" style="display: none;">
|
||||
<div class="tbm-empty-icon">📚</div>
|
||||
<h3 class="tbm-empty-title">등록된 TBM 세션이 없습니다</h3>
|
||||
<p class="tbm-empty-description">TBM 입력 탭에서 새로운 TBM을 시작해보세요.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- TBM 생성 모달 (간소화) -->
|
||||
<!-- TBM 생성 모달 -->
|
||||
<div id="tbmModal" class="tbm-modal-overlay" style="display: none;">
|
||||
<div class="tbm-modal" style="max-width: 800px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title" id="modalTitle">
|
||||
<span>📝</span>
|
||||
새 TBM 시작
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title" id="modalTitle"><span>📝</span> 새 TBM 시작</h2>
|
||||
<button class="tbm-modal-close" onclick="closeTbmModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<form id="tbmForm" onsubmit="event.preventDefault(); saveTbmSession();">
|
||||
<input type="hidden" id="sessionId">
|
||||
|
||||
<!-- 기본 정보 섹션 -->
|
||||
<div class="tbm-form-section">
|
||||
<h3 class="tbm-form-section-title">
|
||||
<span>📅</span>
|
||||
기본 정보
|
||||
</h3>
|
||||
<h3 class="tbm-form-section-title"><span>📅</span> 기본 정보</h3>
|
||||
<div class="tbm-form-row">
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">TBM 날짜<span class="tbm-form-required">*</span></label>
|
||||
@@ -180,25 +184,18 @@
|
||||
<div class="tbm-form-row">
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">프로젝트</label>
|
||||
<select id="newTbmProjectId" class="tbm-form-input">
|
||||
<option value="">선택 안함</option>
|
||||
</select>
|
||||
<select id="newTbmProjectId" class="tbm-form-input"><option value="">선택 안함</option></select>
|
||||
</div>
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">공정<span class="tbm-form-required">*</span></label>
|
||||
<select id="newTbmWorkTypeId" class="tbm-form-input" required>
|
||||
<option value="">공정 선택...</option>
|
||||
</select>
|
||||
<select id="newTbmWorkTypeId" class="tbm-form-input" required><option value="">공정 선택...</option></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업자 선택 섹션 -->
|
||||
<div class="tbm-form-section">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
||||
<h3 class="tbm-form-section-title" style="margin: 0; border: 0; padding: 0;">
|
||||
<span>👥</span>
|
||||
작업자 선택
|
||||
<span>👥</span> 작업자 선택
|
||||
<span id="newTbmWorkerCount" style="color: #3b82f6; font-size: 0.875rem;">(0명)</span>
|
||||
</h3>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
@@ -206,11 +203,7 @@
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary tbm-btn-sm" onclick="deselectAllNewTbmWorkers()">전체 해제</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="newTbmWorkerGrid" class="tbm-worker-select-grid">
|
||||
<!-- 작업자 체크박스 그리드가 여기에 동적으로 생성됩니다 -->
|
||||
</div>
|
||||
|
||||
<div id="newTbmWorkerGrid" class="tbm-worker-select-grid"></div>
|
||||
<div class="tbm-alert tbm-alert-info" style="margin-top: 1rem;">
|
||||
<span class="tbm-alert-icon">💡</span>
|
||||
<div class="tbm-alert-content">
|
||||
@@ -220,13 +213,9 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeTbmModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="saveTbmSession()">
|
||||
<span class="tbm-btn-icon">✓</span>
|
||||
저장하기
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="saveTbmSession()"><span class="tbm-btn-icon">✓</span> 저장하기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -235,13 +224,9 @@
|
||||
<div id="bulkSettingModal" class="tbm-modal-overlay" style="display: none; z-index: 1101;">
|
||||
<div class="tbm-modal" style="max-width: 700px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>⚙</span>
|
||||
일괄 설정
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>⚙</span> 일괄 설정</h2>
|
||||
<button class="tbm-modal-close" onclick="closeBulkSettingModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<div class="tbm-alert tbm-alert-info">
|
||||
<span class="tbm-alert-icon">💡</span>
|
||||
@@ -250,8 +235,6 @@
|
||||
<div class="tbm-alert-text">선택한 작업자들의 <strong>첫 번째 작업 라인</strong>에 동일한 정보가 적용됩니다.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업자 선택 -->
|
||||
<div class="tbm-form-section">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem;">
|
||||
<label class="tbm-form-label">적용할 작업자 선택<span class="tbm-form-required">*</span></label>
|
||||
@@ -260,63 +243,38 @@
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary tbm-btn-sm" onclick="deselectAllForBulk()">해제</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bulkWorkerSelection" class="tbm-worker-select-grid" style="max-height: 180px;">
|
||||
<!-- 작업자 체크박스들이 여기에 생성됩니다 -->
|
||||
</div>
|
||||
<div id="bulkWorkerSelection" class="tbm-worker-select-grid" style="max-height: 180px;"></div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-section" style="border-top: 1px solid #e2e8f0; padding-top: 1.5rem;">
|
||||
<h3 class="tbm-form-section-title" style="border: 0; padding: 0; margin-bottom: 1rem;">
|
||||
<span>🛠</span>
|
||||
적용할 작업 정보
|
||||
</h3>
|
||||
|
||||
<h3 class="tbm-form-section-title" style="border: 0; padding: 0; margin-bottom: 1rem;"><span>🛠</span> 적용할 작업 정보</h3>
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">프로젝트</label>
|
||||
<button type="button" id="bulkProjectBtn" onclick="openBulkItemSelect('project')" class="tbm-select-btn">
|
||||
프로젝트 선택
|
||||
<span class="tbm-select-arrow">▼</span>
|
||||
</button>
|
||||
<button type="button" id="bulkProjectBtn" onclick="openBulkItemSelect('project')" class="tbm-select-btn">프로젝트 선택 <span class="tbm-select-arrow">▼</span></button>
|
||||
<input type="hidden" id="bulkProjectId">
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-row">
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">공정<span class="tbm-form-required">*</span></label>
|
||||
<button type="button" id="bulkWorkTypeBtn" onclick="openBulkItemSelect('workType')" class="tbm-select-btn">
|
||||
공정 선택
|
||||
<span class="tbm-select-arrow">▼</span>
|
||||
</button>
|
||||
<button type="button" id="bulkWorkTypeBtn" onclick="openBulkItemSelect('workType')" class="tbm-select-btn">공정 선택 <span class="tbm-select-arrow">▼</span></button>
|
||||
<input type="hidden" id="bulkWorkTypeId">
|
||||
</div>
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">작업<span class="tbm-form-required">*</span></label>
|
||||
<button type="button" id="bulkTaskBtn" onclick="openBulkItemSelect('task')" class="tbm-select-btn" disabled>
|
||||
작업 선택
|
||||
<span class="tbm-select-arrow">▼</span>
|
||||
</button>
|
||||
<button type="button" id="bulkTaskBtn" onclick="openBulkItemSelect('task')" class="tbm-select-btn" disabled>작업 선택 <span class="tbm-select-arrow">▼</span></button>
|
||||
<input type="hidden" id="bulkTaskId">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">작업장<span class="tbm-form-required">*</span></label>
|
||||
<button type="button" id="bulkWorkplaceBtn" onclick="openBulkWorkplaceSelect()" class="tbm-select-btn">
|
||||
작업장 선택
|
||||
<span class="tbm-select-arrow">▼</span>
|
||||
</button>
|
||||
<button type="button" id="bulkWorkplaceBtn" onclick="openBulkWorkplaceSelect()" class="tbm-select-btn">작업장 선택 <span class="tbm-select-arrow">▼</span></button>
|
||||
<input type="hidden" id="bulkWorkplaceCategoryId">
|
||||
<input type="hidden" id="bulkWorkplaceId">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeBulkSettingModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="applyBulkSettings()">
|
||||
<span class="tbm-btn-icon">✓</span>
|
||||
선택한 작업자에 적용
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="applyBulkSettings()"><span class="tbm-btn-icon">✓</span> 선택한 작업자에 적용</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -325,122 +283,81 @@
|
||||
<div id="workerSelectionModal" class="tbm-modal-overlay" style="display: none; z-index: 1101;">
|
||||
<div class="tbm-modal" style="max-width: 800px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>👥</span>
|
||||
작업자 선택
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>👥</span> 작업자 선택</h2>
|
||||
<button class="tbm-modal-close" onclick="closeWorkerSelectionModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<div style="margin-bottom: 1rem; display: flex; gap: 0.5rem;">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary tbm-btn-sm" onclick="selectAllWorkersInModal()">전체 선택</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary tbm-btn-sm" onclick="deselectAllWorkersInModal()">전체 해제</button>
|
||||
</div>
|
||||
|
||||
<div id="workerCardGrid" class="tbm-worker-select-grid">
|
||||
<!-- 작업자 카드들이 여기에 생성됩니다 -->
|
||||
</div>
|
||||
<div id="workerCardGrid" class="tbm-worker-select-grid"></div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeWorkerSelectionModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="confirmWorkerSelection()">
|
||||
<span class="tbm-btn-icon">✓</span>
|
||||
선택 완료
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="confirmWorkerSelection()"><span class="tbm-btn-icon">✓</span> 선택 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 항목 선택 모달 (프로젝트/공정/작업 선택용) -->
|
||||
<!-- 항목 선택 모달 -->
|
||||
<div id="itemSelectModal" class="tbm-modal-overlay" style="display: none; z-index: 1102;">
|
||||
<div class="tbm-modal" style="max-width: 600px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title" id="itemSelectModalTitle">항목 선택</h2>
|
||||
<button class="tbm-modal-close" onclick="closeItemSelectModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<div id="itemSelectList" class="tbm-item-list">
|
||||
<!-- 선택 항목들이 여기에 생성됩니다 -->
|
||||
</div>
|
||||
<div id="itemSelectList" class="tbm-item-list"></div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeItemSelectModal()">취소</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 작업장 선택 모달 (2단계: 공장 → 작업장) -->
|
||||
<!-- 작업장 선택 모달 -->
|
||||
<div id="workplaceSelectModal" class="tbm-modal-overlay" style="display: none; z-index: 1102;">
|
||||
<div class="tbm-modal" style="max-width: 1000px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>🏭</span>
|
||||
작업장 선택
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>🏭</span> 작업장 선택</h2>
|
||||
<button class="tbm-modal-close" onclick="closeWorkplaceSelectModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<!-- 1단계: 공장 선택 -->
|
||||
<div class="tbm-form-section">
|
||||
<h3 class="tbm-form-section-title">
|
||||
<span style="background: #3b82f6; color: white; width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 0.8rem;">1</span>
|
||||
공장 선택
|
||||
</h3>
|
||||
<div id="categoryList" style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
|
||||
<!-- 공장 카테고리 버튼들이 여기에 생성됩니다 -->
|
||||
</div>
|
||||
<div id="categoryList" style="display: flex; flex-wrap: wrap; gap: 0.5rem;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 2단계: 작업장 선택 (지도 기본 + 리스트 토글) -->
|
||||
<div id="workplaceSelectionArea" style="display: none;">
|
||||
<div class="tbm-form-section">
|
||||
<h3 class="tbm-form-section-title">
|
||||
<span style="background: #3b82f6; color: white; width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 0.8rem;">2</span>
|
||||
작업장 선택
|
||||
</h3>
|
||||
|
||||
<!-- 지도 기반 선택 (기본 표시) -->
|
||||
<div id="layoutMapArea" style="display: none; padding: 1rem; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px;">
|
||||
<div style="font-size: 0.875rem; color: #64748b; margin-bottom: 0.75rem;">
|
||||
지도에서 작업장을 클릭하여 선택하세요
|
||||
</div>
|
||||
<div style="font-size: 0.875rem; color: #64748b; margin-bottom: 0.75rem;">지도에서 작업장을 클릭하여 선택하세요</div>
|
||||
<div class="tbm-workplace-map-container">
|
||||
<canvas id="workplaceMapCanvas"></canvas>
|
||||
</div>
|
||||
<button type="button" class="landscape-trigger-btn" id="landscapeTriggerBtn" onclick="openLandscapeMap()" style="display:none;">
|
||||
📺 전체화면 지도
|
||||
</button>
|
||||
<button type="button" class="landscape-trigger-btn" id="landscapeTriggerBtn" onclick="openLandscapeMap()" style="display:none;">📺 전체화면 지도</button>
|
||||
</div>
|
||||
|
||||
<!-- 리스트 기반 선택 (모바일에서 토글) -->
|
||||
<div style="margin-top: 0.75rem;">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary tbm-btn-sm"
|
||||
onclick="toggleWorkplaceList()" id="toggleListBtn" style="display: none;">
|
||||
리스트로 선택
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary tbm-btn-sm" onclick="toggleWorkplaceList()" id="toggleListBtn" style="display: none;">리스트로 선택</button>
|
||||
<div id="workplaceListSection">
|
||||
<div id="workplaceList" class="tbm-item-list">
|
||||
<div style="color: #94a3b8; text-align: center; padding: 2rem;">
|
||||
공장을 먼저 선택해주세요
|
||||
</div>
|
||||
<div style="color: #94a3b8; text-align: center; padding: 2rem;">공장을 먼저 선택해주세요</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeWorkplaceSelectModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="confirmWorkplaceSelection()" id="confirmWorkplaceBtn" disabled>
|
||||
<span class="tbm-btn-icon">✓</span>
|
||||
선택 완료
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="confirmWorkplaceSelection()" id="confirmWorkplaceBtn" disabled><span class="tbm-btn-icon">✓</span> 선택 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -449,13 +366,9 @@
|
||||
<div id="teamModal" class="tbm-modal-overlay" style="display: none;">
|
||||
<div class="tbm-modal" style="max-width: 900px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>👥</span>
|
||||
팀 구성
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>👥</span> 팀 구성</h2>
|
||||
<button class="tbm-modal-close" onclick="closeTeamModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
||||
<h3 class="tbm-form-section-title" style="margin: 0; border: 0; padding: 0;">작업자 선택</h3>
|
||||
@@ -464,27 +377,17 @@
|
||||
<button class="tbm-btn tbm-btn-secondary tbm-btn-sm" onclick="deselectAllWorkers()">전체 해제</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="workerSelectionGrid" class="tbm-worker-select-grid">
|
||||
<!-- 작업자 체크박스 목록이 여기에 생성됩니다 -->
|
||||
</div>
|
||||
|
||||
<div id="workerSelectionGrid" class="tbm-worker-select-grid"></div>
|
||||
<div style="margin-top: 1.5rem;">
|
||||
<h3 class="tbm-form-section-title">
|
||||
선택된 팀원 <span id="selectedCount" style="color: #3b82f6;">0</span>명
|
||||
</h3>
|
||||
<h3 class="tbm-form-section-title">선택된 팀원 <span id="selectedCount" style="color: #3b82f6;">0</span>명</h3>
|
||||
<div id="selectedWorkersList" style="display: flex; flex-wrap: wrap; gap: 0.5rem; min-height: 50px; padding: 0.75rem; background: #f8fafc; border-radius: 10px; border: 1px solid #e2e8f0;">
|
||||
<p style="margin: 0; color: #94a3b8; font-size: 0.875rem;">작업자를 선택해주세요</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeTeamModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="saveTeamComposition()">
|
||||
<span class="tbm-btn-icon">✓</span>
|
||||
팀 구성 완료
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="saveTeamComposition()"><span class="tbm-btn-icon">✓</span> 팀 구성 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -493,25 +396,15 @@
|
||||
<div id="safetyModal" class="tbm-modal-overlay" style="display: none;">
|
||||
<div class="tbm-modal" style="max-width: 700px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>🛡</span>
|
||||
안전 체크리스트
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>🛡</span> 안전 체크리스트</h2>
|
||||
<button class="tbm-modal-close" onclick="closeSafetyModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<div id="safetyChecklistContainer" class="tbm-safety-list">
|
||||
<!-- 안전 체크리스트가 여기에 생성됩니다 -->
|
||||
</div>
|
||||
<div id="safetyChecklistContainer" class="tbm-safety-list"></div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeSafetyModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-success" onclick="saveSafetyChecklist()">
|
||||
<span class="tbm-btn-icon">✓</span>
|
||||
안전 체크 완료
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-success" onclick="saveSafetyChecklist()"><span class="tbm-btn-icon">✓</span> 안전 체크 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -520,13 +413,9 @@
|
||||
<div id="completeModal" class="tbm-modal-overlay" style="display: none;">
|
||||
<div class="tbm-modal" style="max-width: 500px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>✓</span>
|
||||
TBM 완료
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>✓</span> TBM 완료</h2>
|
||||
<button class="tbm-modal-close" onclick="closeCompleteModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<div class="tbm-alert tbm-alert-warning">
|
||||
<span class="tbm-alert-icon">⚠</span>
|
||||
@@ -535,12 +424,10 @@
|
||||
<div class="tbm-alert-text">완료 후에는 수정할 수 없습니다.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-group" style="margin-top: 1.5rem;">
|
||||
<label class="tbm-form-label">종료 시간</label>
|
||||
<input type="time" id="endTime" class="tbm-form-input">
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-group" style="margin-top: 1rem;">
|
||||
<label class="tbm-form-label">작업자 근태</label>
|
||||
<div id="completeAttendanceList" style="max-height: 300px; overflow-y: auto; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 0.5rem;">
|
||||
@@ -548,13 +435,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeCompleteModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-success" id="completeModalBtn" onclick="completeTbmSession()">
|
||||
<span class="tbm-btn-icon">✓</span>
|
||||
완료
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-success" id="completeModalBtn" onclick="completeTbmSession()"><span class="tbm-btn-icon">✓</span> 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -563,17 +446,12 @@
|
||||
<div id="handoverModal" class="tbm-modal-overlay" style="display: none;">
|
||||
<div class="tbm-modal" style="max-width: 600px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>👉</span>
|
||||
작업 인계
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>👉</span> 작업 인계</h2>
|
||||
<button class="tbm-modal-close" onclick="closeHandoverModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<form id="handoverForm">
|
||||
<input type="hidden" id="handoverSessionId">
|
||||
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">인계 사유<span class="tbm-form-required">*</span></label>
|
||||
<select id="handoverReason" class="tbm-form-input" required>
|
||||
@@ -584,14 +462,10 @@
|
||||
<option value="other">기타</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">인수자 (다음 팀장)<span class="tbm-form-required">*</span></label>
|
||||
<select id="toLeaderId" class="tbm-form-input" required>
|
||||
<option value="">인수자 선택...</option>
|
||||
</select>
|
||||
<select id="toLeaderId" class="tbm-form-input" required><option value="">인수자 선택...</option></select>
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-row">
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">인계 날짜<span class="tbm-form-required">*</span></label>
|
||||
@@ -602,27 +476,19 @@
|
||||
<input type="time" id="handoverTime" class="tbm-form-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label">인계 내용</label>
|
||||
<textarea id="handoverNotes" class="tbm-form-input" rows="4" placeholder="인수자에게 전달할 내용을 입력하세요" style="resize: vertical;"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="tbm-form-group">
|
||||
<label class="tbm-form-label" style="margin-bottom: 0.75rem;">인계할 팀원 선택</label>
|
||||
<div id="handoverTeamList" style="max-height: 200px; overflow-y: auto; border: 1px solid #e2e8f0; border-radius: 10px; padding: 0.75rem; background: #f8fafc;">
|
||||
<!-- 팀원 체크박스 목록 -->
|
||||
</div>
|
||||
<div id="handoverTeamList" style="max-height: 200px; overflow-y: auto; border: 1px solid #e2e8f0; border-radius: 10px; padding: 0.75rem; background: #f8fafc;"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeHandoverModal()">취소</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="saveHandover()">
|
||||
<span class="tbm-btn-icon">👉</span>
|
||||
인계 요청
|
||||
</button>
|
||||
<button type="button" class="tbm-btn tbm-btn-primary" onclick="saveHandover()"><span class="tbm-btn-icon">👉</span> 인계 요청</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -631,129 +497,77 @@
|
||||
<div id="detailModal" class="tbm-modal-overlay" style="display: none;">
|
||||
<div class="tbm-modal" style="max-width: 900px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2 class="tbm-modal-title">
|
||||
<span>📋</span>
|
||||
TBM 상세 정보
|
||||
</h2>
|
||||
<h2 class="tbm-modal-title"><span>📋</span> TBM 상세 정보</h2>
|
||||
<button class="tbm-modal-close" onclick="closeDetailModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-body">
|
||||
<!-- 세션 기본 정보 -->
|
||||
<div class="tbm-form-section">
|
||||
<h3 class="tbm-form-section-title">
|
||||
<span>📅</span>
|
||||
기본 정보
|
||||
</h3>
|
||||
<div id="detailBasicInfo" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem;">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
<h3 class="tbm-form-section-title"><span>📅</span> 기본 정보</h3>
|
||||
<div id="detailBasicInfo" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 팀 구성 -->
|
||||
<div class="tbm-form-section">
|
||||
<h3 class="tbm-form-section-title">
|
||||
<span>👥</span>
|
||||
팀 구성
|
||||
</h3>
|
||||
<div id="detailTeamMembers" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem;">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
<h3 class="tbm-form-section-title"><span>👥</span> 팀 구성</h3>
|
||||
<div id="detailTeamMembers" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 안전 체크 -->
|
||||
<div class="tbm-form-section">
|
||||
<h3 class="tbm-form-section-title">
|
||||
<span>🛡</span>
|
||||
안전 체크리스트
|
||||
</h3>
|
||||
<div id="detailSafetyChecks">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
<h3 class="tbm-form-section-title"><span>🛡</span> 안전 체크리스트</h3>
|
||||
<div id="detailSafetyChecks"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbm-modal-footer" id="detailModalFooter">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeDetailModal()">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 가로모드 전체화면 지도 오버레이 -->
|
||||
<!-- 가로모드 전체화면 지도 -->
|
||||
<div id="landscapeOverlay" class="landscape-overlay" style="display:none;">
|
||||
<div id="landscapeInner" class="landscape-inner">
|
||||
<div class="landscape-header">
|
||||
<h3>🏭 작업장 선택</h3>
|
||||
<button type="button" class="landscape-close-btn" onclick="closeLandscapeMap()">×</button>
|
||||
<div id="landscapeInner" class="landscape-inner">
|
||||
<div class="landscape-header">
|
||||
<h3>🏭 작업장 선택</h3>
|
||||
<button type="button" class="landscape-close-btn" onclick="closeLandscapeMap()">×</button>
|
||||
</div>
|
||||
<div class="landscape-canvas-wrap">
|
||||
<canvas id="landscapeCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="landscape-canvas-wrap">
|
||||
<canvas id="landscapeCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 분할 모달 -->
|
||||
<div id="splitModal" class="tbm-modal-overlay" style="display:none;">
|
||||
<div class="tbm-modal-container" style="max-width:500px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2>작업 분할</h2>
|
||||
<button type="button" class="tbm-modal-close" onclick="closeSplitModal()">×</button>
|
||||
<div class="tbm-modal-container" style="max-width:500px;">
|
||||
<div class="tbm-modal-header"><h2>작업 분할</h2><button type="button" class="tbm-modal-close" onclick="closeSplitModal()">×</button></div>
|
||||
<div class="tbm-modal-body">
|
||||
<p style="font-size:0.8125rem; color:#6b7280; margin-bottom:0.75rem;">작업자의 배정 시간을 분할합니다.</p>
|
||||
<div id="splitMemberList" style="display:flex; flex-direction:column; gap:0.5rem;"></div>
|
||||
</div>
|
||||
<div class="tbm-modal-footer"><button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeSplitModal()">닫기</button></div>
|
||||
</div>
|
||||
<div class="tbm-modal-body">
|
||||
<p style="font-size:0.8125rem; color:#6b7280; margin-bottom:0.75rem;">작업자의 배정 시간을 분할합니다.</p>
|
||||
<div id="splitMemberList" style="display:flex; flex-direction:column; gap:0.5rem;"></div>
|
||||
</div>
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closeSplitModal()">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 빼오기 모달 -->
|
||||
<div id="pullModal" class="tbm-modal-overlay" style="display:none;">
|
||||
<div class="tbm-modal-container" style="max-width:500px;">
|
||||
<div class="tbm-modal-header">
|
||||
<h2>빼오기</h2>
|
||||
<button type="button" class="tbm-modal-close" onclick="closePullModal()">×</button>
|
||||
<div class="tbm-modal-container" style="max-width:500px;">
|
||||
<div class="tbm-modal-header"><h2>빼오기</h2><button type="button" class="tbm-modal-close" onclick="closePullModal()">×</button></div>
|
||||
<div class="tbm-modal-body">
|
||||
<p style="font-size:0.8125rem; color:#6b7280; margin-bottom:0.75rem;">다른 반장의 TBM에서 작업자를 빼옵니다.</p>
|
||||
<div id="pullSessionList"></div>
|
||||
</div>
|
||||
<div class="tbm-modal-footer"><button type="button" class="tbm-btn tbm-btn-secondary" onclick="closePullModal()">닫기</button></div>
|
||||
</div>
|
||||
<div class="tbm-modal-body">
|
||||
<p style="font-size:0.8125rem; color:#6b7280; margin-bottom:0.75rem;">다른 반장의 TBM에서 작업자를 빼옵니다.</p>
|
||||
<div id="pullSessionList"></div>
|
||||
</div>
|
||||
<div class="tbm-modal-footer">
|
||||
<button type="button" class="tbm-btn tbm-btn-secondary" onclick="closePullModal()">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 토스트 알림 -->
|
||||
<!-- 토스트 -->
|
||||
<div class="toast-container" id="toastContainer"></div>
|
||||
</div>
|
||||
|
||||
<!-- 공통 모듈 -->
|
||||
<script src="/static/js/tkfb-core.js"></script>
|
||||
<script src="/js/api-base.js?v=3"></script>
|
||||
<script src="/js/common/utils.js?v=2"></script>
|
||||
<script src="/js/common/base-state.js?v=2"></script>
|
||||
|
||||
<!-- TBM 모듈 (리팩토링된 구조) -->
|
||||
<script src="/js/tbm/state.js?v=3"></script>
|
||||
<script src="/js/tbm/utils.js?v=3"></script>
|
||||
<script src="/js/tbm/api.js?v=4"></script>
|
||||
|
||||
<!-- 기존 UI 로직 (점진적 마이그레이션) -->
|
||||
<script defer src="/js/tbm.js?v=13"></script>
|
||||
|
||||
<!-- 모바일 하단 네비게이션 -->
|
||||
<div id="mobile-nav-container"></div>
|
||||
<script>
|
||||
if (window.innerWidth <= 768) {
|
||||
fetch('/components/mobile-nav.html')
|
||||
.then(r => r.text())
|
||||
.then(html => {
|
||||
document.getElementById('mobile-nav-container').innerHTML = html;
|
||||
const scripts = document.getElementById('mobile-nav-container').querySelectorAll('script');
|
||||
scripts.forEach(s => eval(s.textContent));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>initAuth();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user