refactor: 전체 페이지 이모지 제거 및 사이드바 레이아웃 수정

- 모든 페이지에서 이모지 제거 (CODING_GUIDE 준수)
  - admin/ (9개), safety/ (7개), work/ (4개)
  - attendance/ (8개), profile/ (2개)
- 사이드바 CSS에 누락된 컨테이너 클래스 추가
  - work-report-container, analysis-container, dashboard-main
  - 사이드바 토글 시 메인 콘텐츠 정상 반응하도록 수정

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-02-02 15:09:37 +09:00
parent 09b3cf8e65
commit 4b158de1eb
31 changed files with 298 additions and 946 deletions

View File

@@ -307,14 +307,20 @@
/* 메인 콘텐츠 여백 */
body.has-sidebar .dashboard-container,
body.has-sidebar .main-content,
body.has-sidebar .page-container {
body.has-sidebar .page-container,
body.has-sidebar .work-report-container,
body.has-sidebar .analysis-container,
body.has-sidebar > .dashboard-main {
margin-left: 260px;
transition: margin-left 0.3s ease;
}
body.has-sidebar.sidebar-collapsed .dashboard-container,
body.has-sidebar.sidebar-collapsed .main-content,
body.has-sidebar.sidebar-collapsed .page-container {
body.has-sidebar.sidebar-collapsed .page-container,
body.has-sidebar.sidebar-collapsed .work-report-container,
body.has-sidebar.sidebar-collapsed .analysis-container,
body.has-sidebar.sidebar-collapsed > .dashboard-main {
margin-left: 60px;
}
@@ -330,7 +336,10 @@ body.has-sidebar.sidebar-collapsed .page-container {
body.has-sidebar .dashboard-container,
body.has-sidebar .main-content,
body.has-sidebar .page-container {
body.has-sidebar .page-container,
body.has-sidebar .work-report-container,
body.has-sidebar .analysis-container,
body.has-sidebar > .dashboard-main {
margin-left: 0;
}
}

View File

@@ -20,10 +20,7 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">⚙️</span>
관리자 설정
</h1>
<h1 class="page-title">관리자 설정</h1>
<p class="page-description">시스템 사용자 계정 및 권한을 관리합니다</p>
</div>
</div>
@@ -31,21 +28,15 @@
<!-- 사용자 관리 섹션 -->
<div class="settings-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">👥</span>
사용자 계정 관리
</h2>
<button class="btn btn-primary" id="addUserBtn">
<span class="btn-icon"></span>
새 사용자 추가
</button>
<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>
<span class="search-icon"></span>
</div>
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">전체</button>
@@ -74,7 +65,6 @@
</div>
<div class="empty-state" id="emptyState" style="display: none;">
<div class="empty-icon">👥</div>
<h3>등록된 사용자가 없습니다</h3>
<p>새 사용자를 추가해보세요.</p>
</div>
@@ -158,7 +148,7 @@
<div class="modal-body">
<div class="delete-warning">
<div class="warning-icon">⚠️</div>
<div class="warning-icon"></div>
<p>정말로 이 사용자를 삭제하시겠습니까?</p>
<p class="warning-text">삭제된 사용자는 복구할 수 없습니다.</p>
</div>
@@ -209,7 +199,8 @@
<!-- JavaScript -->
<script type="module" src="/js/api-config.js?v=13"></script>
<script type="module" src="/js/load-navbar.js?v=4"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/admin-settings.js?v=8"></script>
</body>
</html>

View File

@@ -106,17 +106,12 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🔍</span>
출퇴근-작업보고서 대조
</h1>
<h1 class="page-title">출퇴근-작업보고서 대조</h1>
<p class="page-description">출퇴근 기록과 작업보고서를 비교 분석합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="loadComparisonData()">
<span>🔄 새로고침</span>
</button>
<button class="btn btn-primary" onclick="loadComparisonData()">새로고침</button>
</div>
</div>
@@ -150,9 +145,7 @@
</select>
</div>
<div style="align-self: flex-end;">
<button class="btn btn-primary" onclick="loadComparisonData()">
<span>🔍 조회</span>
</button>
<button class="btn btn-primary" onclick="loadComparisonData()">조회</button>
</div>
</div>
</div>
@@ -184,7 +177,8 @@
</main>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
import '/js/api-config.js?v=3';
</script>

View File

@@ -14,127 +14,43 @@
<!-- 네비게이션 바 -->
<div id="navbar-container"></div>
<!-- 메인 레이아웃: 사이드바 + 콘텐츠 -->
<!-- 메인 레이아웃 -->
<div class="page-container">
<!-- 사이드바 -->
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="sidebar-header">
<h3 class="sidebar-title">관리 메뉴</h3>
</div>
<ul class="sidebar-menu">
<li class="menu-item">
<a href="/pages/admin/projects.html">
<span class="menu-icon">📁</span>
<span class="menu-text">프로젝트 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workers.html">
<span class="menu-icon">👥</span>
<span class="menu-text">작업자 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workplaces.html">
<span class="menu-icon">🏗️</span>
<span class="menu-text">작업장 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/equipments.html">
<span class="menu-icon">⚙️</span>
<span class="menu-text">설비 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/tasks.html">
<span class="menu-icon">📋</span>
<span class="menu-text">작업 관리</span>
</a>
</li>
<li class="menu-item active">
<a href="/pages/admin/codes.html">
<span class="menu-icon">🏷️</span>
<span class="menu-text">코드 관리</span>
</a>
</li>
<li class="menu-divider"></li>
<li class="menu-item">
<a href="/pages/dashboard.html">
<span class="menu-icon">🏠</span>
<span class="menu-text">대시보드로</span>
</a>
</li>
</ul>
</nav>
</aside>
<!-- 메인 콘텐츠 -->
<main class="main-content">
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🏷️</span>
코드 관리
</h1>
<h1 class="page-title">코드 관리</h1>
<p class="page-description">작업 상태, 오류 유형, 작업 유형 등 시스템에서 사용하는 코드를 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-secondary" onclick="refreshAllCodes()">
<span class="btn-icon">🔄</span>
전체 새로고침
</button>
<button class="btn btn-secondary" onclick="refreshAllCodes()">전체 새로고침</button>
</div>
</div>
<!-- 코드 유형 탭 -->
<div class="code-tabs">
<button class="tab-btn active" data-tab="work-status" onclick="switchCodeTab('work-status')">
<span class="tab-icon">📊</span>
작업 상태 유형
</button>
<button class="tab-btn" data-tab="error-types" onclick="switchCodeTab('error-types')">
<span class="tab-icon">⚠️</span>
오류 유형
</button>
<button class="tab-btn" data-tab="work-types" onclick="switchCodeTab('work-types')">
<span class="tab-icon">🔧</span>
작업 유형
</button>
<button class="tab-btn active" data-tab="work-status" onclick="switchCodeTab('work-status')">작업 상태 유형</button>
<button class="tab-btn" data-tab="error-types" onclick="switchCodeTab('error-types')">오류 유형</button>
<button class="tab-btn" data-tab="work-types" onclick="switchCodeTab('work-types')">작업 유형</button>
</div>
<!-- 작업 상태 유형 관리 -->
<div id="work-status-tab" class="code-tab-content active">
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">📊</span>
작업 상태 유형 관리
</h2>
<h2 class="section-title">작업 상태 유형 관리</h2>
<div class="section-actions">
<button class="btn btn-primary" onclick="openCodeModal('work-status')">
<span class="btn-icon"></span>
새 상태 추가
</button>
<button class="btn btn-primary" onclick="openCodeModal('work-status')">새 상태 추가</button>
</div>
</div>
<div class="code-stats">
<span class="stat-item">
<span class="stat-icon">📊</span>
<span id="workStatusCount">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
정상 <span id="normalStatusCount">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
오류 <span id="errorStatusCount">0</span>
</span>
<span class="stat-item"><span id="workStatusCount">0</span></span>
<span class="stat-item">정상 <span id="normalStatusCount">0</span></span>
<span class="stat-item">오류 <span id="errorStatusCount">0</span></span>
</div>
<div class="code-grid" id="workStatusGrid">
@@ -147,39 +63,18 @@
<div id="error-types-tab" class="code-tab-content">
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">⚠️</span>
오류 유형 관리
</h2>
<h2 class="section-title">오류 유형 관리</h2>
<div class="section-actions">
<button class="btn btn-primary" onclick="openCodeModal('error-types')">
<span class="btn-icon"></span>
새 오류 유형 추가
</button>
<button class="btn btn-primary" onclick="openCodeModal('error-types')">새 오류 유형 추가</button>
</div>
</div>
<div class="code-stats">
<span class="stat-item">
<span class="stat-icon">⚠️</span>
<span id="errorTypesCount">0</span>
</span>
<span class="stat-item critical-stat">
<span class="stat-icon">🔴</span>
심각 <span id="criticalErrorsCount">0</span>
</span>
<span class="stat-item high-stat">
<span class="stat-icon">🟠</span>
높음 <span id="highErrorsCount">0</span>
</span>
<span class="stat-item medium-stat">
<span class="stat-icon">🟡</span>
보통 <span id="mediumErrorsCount">0</span>
</span>
<span class="stat-item low-stat">
<span class="stat-icon">🟢</span>
낮음 <span id="lowErrorsCount">0</span>
</span>
<span class="stat-item"><span id="errorTypesCount">0</span></span>
<span class="stat-item critical-stat">심각 <span id="criticalErrorsCount">0</span></span>
<span class="stat-item high-stat">높음 <span id="highErrorsCount">0</span></span>
<span class="stat-item medium-stat">보통 <span id="mediumErrorsCount">0</span></span>
<span class="stat-item low-stat">낮음 <span id="lowErrorsCount">0</span></span>
</div>
<div class="code-grid" id="errorTypesGrid">
@@ -192,27 +87,15 @@
<div id="work-types-tab" class="code-tab-content">
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">🔧</span>
작업 유형 관리
</h2>
<h2 class="section-title">작업 유형 관리</h2>
<div class="section-actions">
<button class="btn btn-primary" onclick="openCodeModal('work-types')">
<span class="btn-icon"></span>
새 작업 유형 추가
</button>
<button class="btn btn-primary" onclick="openCodeModal('work-types')">새 작업 유형 추가</button>
</div>
</div>
<div class="code-stats">
<span class="stat-item">
<span class="stat-icon">🔧</span>
<span id="workTypesCount">0</span>
</span>
<span class="stat-item">
<span class="stat-icon">📁</span>
카테고리 <span id="workCategoriesCount">0</span>
</span>
<span class="stat-item"><span id="workTypesCount">0</span></span>
<span class="stat-item">카테고리 <span id="workCategoriesCount">0</span></span>
</div>
<div class="code-grid" id="workTypesGrid">
@@ -285,18 +168,15 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeCodeModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteCodeBtn" onclick="deleteCode()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveCode()">
💾 저장
</button>
<button type="button" class="btn btn-danger" id="deleteCodeBtn" onclick="deleteCode()" style="display: none;">삭제</button>
<button type="button" class="btn btn-primary" onclick="saveCode()">저장</button>
</div>
</div>
</div>
</div>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module" src="/js/code-management.js?v=2"></script>
</body>
</html>

View File

@@ -14,71 +14,14 @@
<!-- 네비게이션 바 -->
<div id="navbar-container"></div>
<!-- 메인 레이아웃: 사이드바 + 콘텐츠 -->
<!-- 메인 레이아웃 -->
<div class="page-container">
<!-- 사이드바 -->
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="sidebar-header">
<h3 class="sidebar-title">관리 메뉴</h3>
</div>
<ul class="sidebar-menu">
<li class="menu-item">
<a href="/pages/admin/projects.html">
<span class="menu-icon">📁</span>
<span class="menu-text">프로젝트 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workers.html">
<span class="menu-icon">👥</span>
<span class="menu-text">작업자 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workplaces.html">
<span class="menu-icon">🏗️</span>
<span class="menu-text">작업장 관리</span>
</a>
</li>
<li class="menu-item active">
<a href="/pages/admin/equipments.html">
<span class="menu-icon">⚙️</span>
<span class="menu-text">설비 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/tasks.html">
<span class="menu-icon">📋</span>
<span class="menu-text">작업 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/codes.html">
<span class="menu-icon">🏷️</span>
<span class="menu-text">코드 관리</span>
</a>
</li>
<li class="menu-divider"></li>
<li class="menu-item">
<a href="/pages/dashboard.html">
<span class="menu-icon">🏠</span>
<span class="menu-text">대시보드로</span>
</a>
</li>
</ul>
</nav>
</aside>
<!-- 메인 콘텐츠 -->
<main class="main-content">
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">⚙️</span>
설비 관리
</h1>
<h1 class="page-title">설비 관리</h1>
<p class="page-description">작업장별 설비 정보를 등록하고 관리합니다</p>
</div>
@@ -214,6 +157,7 @@
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
// API 설정 먼저 로드
import '/js/api-config.js?v=3';
@@ -238,7 +182,7 @@
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
console.log('📤 요청:', config.method.toUpperCase(), config.url);
console.log('[Request]', config.method.toUpperCase(), config.url);
return config;
},
error => {
@@ -249,11 +193,11 @@
// axios 응답 인터셉터 추가 (에러 처리)
axios.interceptors.response.use(
response => {
console.log('✅ 응답:', response.status, response.config.url);
console.log('[Response]', response.status, response.config.url);
return response;
},
error => {
console.error('❌ 에러:', error.response?.status, error.config?.url, error.message);
console.error('[Error]', error.response?.status, error.config?.url, error.message);
if (error.response?.status === 401) {
alert('세션이 만료되었습니다. 다시 로그인해주세요.');
window.location.href = '/pages/login.html';
@@ -262,7 +206,7 @@
}
);
console.log('Axios 설정 완료:', axios.defaults.baseURL);
console.log('[Axios Ready]', axios.defaults.baseURL);
}
}, 50);
})();

View File

@@ -20,10 +20,7 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🔐</span>
페이지 접근 권한 관리
</h1>
<h1 class="page-title">페이지 접근 권한 관리</h1>
<p class="page-description">작업자에게 특정 페이지 접근 권한을 부여하거나 회수합니다</p>
</div>
</div>
@@ -31,10 +28,7 @@
<!-- 사용자 목록 섹션 -->
<div class="settings-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">👥</span>
사용자 목록
</h2>
<h2 class="section-title">사용자 목록</h2>
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">전체</button>
<button class="filter-btn" data-filter="with-access">권한 있음</button>
@@ -67,7 +61,6 @@
</div>
<div class="empty-state" id="emptyState" style="display: none;">
<div class="empty-icon">👥</div>
<h3>등록된 사용자가 없습니다</h3>
<p>권한을 부여할 사용자 계정이 없습니다.</p>
</div>
@@ -134,7 +127,8 @@
<!-- JavaScript -->
<script type="module" src="/js/api-config.js?v=13"></script>
<script type="module" src="/js/load-navbar.js?v=4"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/page-access-management.js?v=1"></script>
</body>
</html>

View File

@@ -13,83 +13,20 @@
<!-- 네비게이션 바 -->
<div id="navbar-container"></div>
<!-- 메인 레이아웃: 사이드바 + 콘텐츠 -->
<!-- 메인 레이아웃 -->
<div class="page-container">
<!-- 사이드바 -->
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="sidebar-header">
<h3 class="sidebar-title">관리 메뉴</h3>
</div>
<ul class="sidebar-menu">
<li class="menu-item active">
<a href="/pages/admin/projects.html">
<span class="menu-icon">📁</span>
<span class="menu-text">프로젝트 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workers.html">
<span class="menu-icon">👥</span>
<span class="menu-text">작업자 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workplaces.html">
<span class="menu-icon">🏗️</span>
<span class="menu-text">작업장 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/equipments.html">
<span class="menu-icon">⚙️</span>
<span class="menu-text">설비 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/tasks.html">
<span class="menu-icon">📋</span>
<span class="menu-text">작업 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/codes.html">
<span class="menu-icon">🏷️</span>
<span class="menu-text">코드 관리</span>
</a>
</li>
<li class="menu-divider"></li>
<li class="menu-item">
<a href="/pages/dashboard.html">
<span class="menu-icon">🏠</span>
<span class="menu-text">대시보드로</span>
</a>
</li>
</ul>
</nav>
</aside>
<!-- 메인 콘텐츠 -->
<main class="main-content">
<div class="dashboard-main">
<!-- 페이지 헤더: 타이틀 + 액션 버튼 -->
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">📁</span>
프로젝트 관리
</h1>
<h1 class="page-title">프로젝트 관리</h1>
<p class="page-description">프로젝트 등록, 수정, 삭제 및 기본 정보를 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="openProjectModal()">
<span class="btn-icon"></span>
새 프로젝트 등록
</button>
<button class="btn btn-secondary" onclick="refreshProjectList()">
<span class="btn-icon">🔄</span>
새로고침
</button>
<button class="btn btn-primary" onclick="openProjectModal()">새 프로젝트 등록</button>
<button class="btn btn-secondary" onclick="refreshProjectList()">새로고침</button>
</div>
</div>
@@ -97,9 +34,7 @@
<div class="search-section">
<div class="search-bar">
<input type="text" id="searchInput" placeholder="프로젝트명 또는 Job No.로 검색..." class="search-input">
<button class="search-btn" onclick="searchProjects()">
<span class="search-icon">🔍</span>
</button>
<button class="search-btn" onclick="searchProjects()">검색</button>
</div>
<div class="filter-options">
@@ -123,18 +58,9 @@
<div class="section-header">
<h2 class="section-title">등록된 프로젝트</h2>
<div class="project-stats">
<span class="stat-item active-stat" onclick="filterByStatus('active')" title="활성 프로젝트만 보기">
<span class="stat-icon">🟢</span>
활성 <span id="activeProjects">0</span>
</span>
<span class="stat-item inactive-stat" onclick="filterByStatus('inactive')" title="비활성 프로젝트만 보기">
<span class="stat-icon">🔴</span>
비활성 <span id="inactiveProjects">0</span>
</span>
<span class="stat-item total-stat" onclick="filterByStatus('all')" title="전체 프로젝트 보기">
<span class="stat-icon">📊</span>
<span id="totalProjects">0</span>
</span>
<span class="stat-item active-stat" onclick="filterByStatus('active')" title="활성 프로젝트만 보기">활성 <span id="activeProjects">0</span></span>
<span class="stat-item inactive-stat" onclick="filterByStatus('inactive')" title="비활성 프로젝트만 보기">비활성 <span id="inactiveProjects">0</span></span>
<span class="stat-item total-stat" onclick="filterByStatus('all')" title="전체 프로젝트 보기"> <span id="totalProjects">0</span></span>
</div>
</div>
@@ -143,13 +69,9 @@
</div>
<div class="empty-state" id="emptyState" style="display: none;">
<div class="empty-icon">📁</div>
<h3>등록된 프로젝트가 없습니다</h3>
<p>새 프로젝트를 등록해보세요.</p>
<button class="btn btn-primary" onclick="openProjectModal()">
<span class="btn-icon"></span>
첫 번째 프로젝트 등록
</button>
<button class="btn btn-primary" onclick="openProjectModal()">첫 번째 프로젝트 등록</button>
</div>
</div>
</main>
@@ -214,10 +136,10 @@
<div class="form-group">
<label class="form-label">프로젝트 상태</label>
<select id="projectStatus" class="form-control">
<option value="planning">📋 계획</option>
<option value="active" selected>🚀 진행중</option>
<option value="completed">완료</option>
<option value="cancelled">취소</option>
<option value="planning">계획</option>
<option value="active" selected>진행중</option>
<option value="completed">완료</option>
<option value="cancelled">취소</option>
</select>
</div>
<div class="form-group">
@@ -238,12 +160,8 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeProjectModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteProjectBtn" onclick="deleteProject()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveProject()">
💾 저장
</button>
<button type="button" class="btn btn-danger" id="deleteProjectBtn" onclick="deleteProject()" style="display: none;">삭제</button>
<button type="button" class="btn btn-primary" onclick="saveProject()">저장</button>
</div>
</div>
</div>
@@ -253,6 +171,7 @@
<!-- JavaScript -->
<script type="module" src="/js/api-config.js?v=3"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module" src="/js/project-management.js?v=3"></script>
</body>
</html>

View File

@@ -14,117 +14,39 @@
<!-- 네비게이션 바 -->
<div id="navbar-container"></div>
<!-- 메인 레이아웃: 사이드바 + 콘텐츠 -->
<!-- 메인 레이아웃 -->
<div class="page-container">
<!-- 사이드바 -->
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="sidebar-header">
<h3 class="sidebar-title">관리 메뉴</h3>
</div>
<ul class="sidebar-menu">
<li class="menu-item">
<a href="/pages/admin/projects.html">
<span class="menu-icon">📁</span>
<span class="menu-text">프로젝트 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workers.html">
<span class="menu-icon">👥</span>
<span class="menu-text">작업자 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workplaces.html">
<span class="menu-icon">🏗️</span>
<span class="menu-text">작업장 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/equipments.html">
<span class="menu-icon">⚙️</span>
<span class="menu-text">설비 관리</span>
</a>
</li>
<li class="menu-item active">
<a href="/pages/admin/tasks.html">
<span class="menu-icon">📋</span>
<span class="menu-text">작업 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/codes.html">
<span class="menu-icon">🏷️</span>
<span class="menu-text">코드 관리</span>
</a>
</li>
<li class="menu-divider"></li>
<li class="menu-item">
<a href="/pages/dashboard.html">
<span class="menu-icon">🏠</span>
<span class="menu-text">대시보드로</span>
</a>
</li>
</ul>
</nav>
</aside>
<!-- 메인 콘텐츠 -->
<main class="main-content">
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">📋</span>
작업 관리
</h1>
<h1 class="page-title">작업 관리</h1>
<p class="page-description">공정별 세부 작업을 등록하고 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="openWorkTypeModal()">
<span class="btn-icon">🔧</span>
공정 추가
</button>
<button class="btn btn-primary" onclick="openTaskModal()">
<span class="btn-icon"></span>
작업 추가
</button>
<button class="btn btn-secondary" onclick="refreshTasks()">
<span class="btn-icon">🔄</span>
새로고침
</button>
<button class="btn btn-primary" onclick="openWorkTypeModal()">공정 추가</button>
<button class="btn btn-primary" onclick="openTaskModal()">작업 추가</button>
<button class="btn btn-secondary" onclick="refreshTasks()">새로고침</button>
</div>
</div>
<!-- 공정(work_types) 탭 -->
<div class="code-tabs" id="workTypeTabs">
<button class="tab-btn active" data-work-type="" onclick="switchWorkType('')">
<span class="tab-icon">📋</span>
전체
</button>
<button class="tab-btn active" data-work-type="" onclick="switchWorkType('')">전체</button>
<!-- 공정 탭들이 여기에 동적으로 생성됩니다 -->
</div>
<!-- 작업 목록 -->
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">🔧</span>
작업 목록
</h2>
<h2 class="section-title">작업 목록</h2>
</div>
<div class="code-stats" id="taskStats">
<span class="stat-item">
<span class="stat-icon">📋</span>
전체 <span id="totalCount">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
활성 <span id="activeCount">0</span>
</span>
<span class="stat-item">전체 <span id="totalCount">0</span></span>
<span class="stat-item">활성 <span id="activeCount">0</span></span>
</div>
<div class="code-grid" id="taskGrid">
@@ -177,12 +99,8 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeTaskModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteTaskBtn" onclick="deleteTask()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveTask()">
💾 저장
</button>
<button type="button" class="btn btn-danger" id="deleteTaskBtn" onclick="deleteTask()" style="display: none;">삭제</button>
<button type="button" class="btn btn-primary" onclick="saveTask()">저장</button>
</div>
</div>
</div>
@@ -219,18 +137,15 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkTypeModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteWorkTypeBtn" onclick="deleteWorkType()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveWorkType()">
💾 저장
</button>
<button type="button" class="btn btn-danger" id="deleteWorkTypeBtn" onclick="deleteWorkType()" style="display: none;">삭제</button>
<button type="button" class="btn btn-primary" onclick="saveWorkType()">저장</button>
</div>
</div>
</div>
</div>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module" src="/js/task-management.js?v=1"></script>
</body>
</html>

View File

@@ -14,83 +14,20 @@
<!-- 네비게이션 바 -->
<div id="navbar-container"></div>
<!-- 메인 레이아웃: 사이드바 + 콘텐츠 -->
<!-- 메인 레이아웃 -->
<div class="page-container">
<!-- 사이드바 -->
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="sidebar-header">
<h3 class="sidebar-title">관리 메뉴</h3>
</div>
<ul class="sidebar-menu">
<li class="menu-item">
<a href="/pages/admin/projects.html">
<span class="menu-icon">📁</span>
<span class="menu-text">프로젝트 관리</span>
</a>
</li>
<li class="menu-item active">
<a href="/pages/admin/workers.html">
<span class="menu-icon">👥</span>
<span class="menu-text">작업자 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workplaces.html">
<span class="menu-icon">🏗️</span>
<span class="menu-text">작업장 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/equipments.html">
<span class="menu-icon">⚙️</span>
<span class="menu-text">설비 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/tasks.html">
<span class="menu-icon">📋</span>
<span class="menu-text">작업 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/codes.html">
<span class="menu-icon">🏷️</span>
<span class="menu-text">코드 관리</span>
</a>
</li>
<li class="menu-divider"></li>
<li class="menu-item">
<a href="/pages/dashboard.html">
<span class="menu-icon">🏠</span>
<span class="menu-text">대시보드로</span>
</a>
</li>
</ul>
</nav>
</aside>
<!-- 메인 콘텐츠 -->
<main class="main-content">
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">👥</span>
작업자 관리
</h1>
<h1 class="page-title">작업자 관리</h1>
<p class="page-description">작업자 등록, 수정, 삭제 및 기본 정보를 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="openWorkerModal()">
<span class="btn-icon"></span>
새 작업자 등록
</button>
<button class="btn btn-secondary" onclick="refreshWorkerList()">
<span class="btn-icon">🔄</span>
새로고침
</button>
<button class="btn btn-primary" onclick="openWorkerModal()">새 작업자 등록</button>
<button class="btn btn-secondary" onclick="refreshWorkerList()">새로고침</button>
</div>
</div>
@@ -98,9 +35,7 @@
<div class="search-section">
<div class="search-bar">
<input type="text" id="searchInput" class="search-input" placeholder="작업자명, 직책, 전화번호로 검색...">
<button class="search-btn" onclick="searchWorkers()">
<span>🔍</span>
</button>
<button class="search-btn" onclick="searchWorkers()">검색</button>
</div>
<div class="filter-options">
@@ -130,18 +65,9 @@
<div class="section-header">
<h2 class="section-title">등록된 작업자</h2>
<div class="project-stats">
<span class="stat-item active-stat" onclick="filterByStatus('active')" title="활성 작업자만 보기">
<span class="stat-icon">🟢</span>
활성 <span id="activeWorkers">0</span>
</span>
<span class="stat-item inactive-stat" onclick="filterByStatus('inactive')" title="비활성 작업자만 보기">
<span class="stat-icon">🔴</span>
비활성 <span id="inactiveWorkers">0</span>
</span>
<span class="stat-item total-stat" onclick="filterByStatus('all')" title="전체 작업자 보기">
<span class="stat-icon">📊</span>
<span id="totalWorkers">0</span>
</span>
<span class="stat-item active-stat" onclick="filterByStatus('active')" title="활성 작업자만 보기">활성 <span id="activeWorkers">0</span></span>
<span class="stat-item inactive-stat" onclick="filterByStatus('inactive')" title="비활성 작업자만 보기">비활성 <span id="inactiveWorkers">0</span></span>
<span class="stat-item total-stat" onclick="filterByStatus('all')" title="전체 작업자 보기"> <span id="totalWorkers">0</span></span>
</div>
</div>
@@ -171,12 +97,9 @@
<!-- Empty State -->
<div class="empty-state" id="emptyState" style="display: none;">
<div class="empty-icon">👥</div>
<h3>등록된 작업자가 없습니다.</h3>
<p>"새 작업자 등록" 버튼을 눌러 작업자를 등록해보세요.</p>
<button class="btn btn-primary" onclick="openWorkerModal()">
첫 작업자 등록하기
</button>
<button class="btn btn-primary" onclick="openWorkerModal()">첫 작업자 등록하기</button>
</div>
</div>
</div>
@@ -202,9 +125,9 @@
<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>
<option value="worker">작업자</option>
<option value="leader">그룹장</option>
<option value="admin">관리자</option>
</select>
</div>
</div>
@@ -244,7 +167,7 @@
<!-- 계정 생성/연동 -->
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
<input type="checkbox" id="hasAccount" style="margin: 0; cursor: pointer;">
<span>🔐 계정 생성/연동</span>
<span>계정 생성/연동</span>
</label>
<small style="color: #6b7280; font-size: 0.75rem; margin-top: -0.5rem; margin-left: 1.5rem;">
체크 시 로그인 계정이 자동 생성됩니다 (나의 대시보드, 연차/출퇴근 관리 가능)
@@ -253,7 +176,7 @@
<!-- 현장직/사무직 구분 -->
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
<input type="checkbox" id="isActive" checked style="margin: 0; cursor: pointer;">
<span>🏭 현장직 (활성화)</span>
<span>현장직 (활성화)</span>
</label>
<small style="color: #6b7280; font-size: 0.75rem; margin-top: -0.5rem; margin-left: 1.5rem;">
체크: 현장직 (출퇴근 관리 필요) / 체크 해제: 사무직 (출퇴근 관리 불필요)
@@ -262,7 +185,7 @@
<!-- 퇴사 처리 -->
<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>
<span style="color: #ef4444;">퇴사 처리</span>
</label>
<small style="color: #ef4444; font-size: 0.75rem; margin-top: -0.5rem; margin-left: 1.5rem;">
퇴사한 작업자로 표시됩니다. 작업 보고서에서 제외됩니다
@@ -274,18 +197,15 @@
<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>
<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>
</div>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module" src="/js/worker-management.js?v=7"></script>
</body>
</html>

View File

@@ -14,110 +14,35 @@
<!-- 네비게이션 바 -->
<div id="navbar-container"></div>
<!-- 메인 레이아웃: 사이드바 + 콘텐츠 -->
<!-- 메인 레이아웃 -->
<div class="page-container">
<!-- 사이드바 -->
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="sidebar-header">
<h3 class="sidebar-title">관리 메뉴</h3>
</div>
<ul class="sidebar-menu">
<li class="menu-item">
<a href="/pages/admin/projects.html">
<span class="menu-icon">📁</span>
<span class="menu-text">프로젝트 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/workers.html">
<span class="menu-icon">👥</span>
<span class="menu-text">작업자 관리</span>
</a>
</li>
<li class="menu-item active">
<a href="/pages/admin/workplaces.html">
<span class="menu-icon">🏗️</span>
<span class="menu-text">작업장 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/equipments.html">
<span class="menu-icon">⚙️</span>
<span class="menu-text">설비 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/tasks.html">
<span class="menu-icon">📋</span>
<span class="menu-text">작업 관리</span>
</a>
</li>
<li class="menu-item">
<a href="/pages/admin/codes.html">
<span class="menu-icon">🏷️</span>
<span class="menu-text">코드 관리</span>
</a>
</li>
<li class="menu-divider"></li>
<li class="menu-item">
<a href="/pages/dashboard.html">
<span class="menu-icon">🏠</span>
<span class="menu-text">대시보드로</span>
</a>
</li>
</ul>
</nav>
</aside>
<!-- 메인 콘텐츠 -->
<main class="main-content">
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🏗️</span>
작업장 관리
</h1>
<h1 class="page-title">작업장 관리</h1>
<p class="page-description">공장 및 작업장을 등록하고 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="openCategoryModal()">
<span class="btn-icon"></span>
공장 추가
</button>
<button class="btn btn-primary" onclick="openWorkplaceModal()">
<span class="btn-icon"></span>
작업장 추가
</button>
<button class="btn btn-secondary" onclick="refreshWorkplaces()">
<span class="btn-icon">🔄</span>
새로고침
</button>
<button class="btn btn-primary" onclick="openCategoryModal()">공장 추가</button>
<button class="btn btn-primary" onclick="openWorkplaceModal()">작업장 추가</button>
<button class="btn btn-secondary" onclick="refreshWorkplaces()">새로고침</button>
</div>
</div>
<!-- 공장(카테고리) 탭 -->
<div class="code-tabs" id="categoryTabs">
<button class="tab-btn active" data-category="" onclick="switchCategory('')">
<span class="tab-icon">🏗️</span>
전체
</button>
<button class="tab-btn active" data-category="" onclick="switchCategory('')">전체</button>
<!-- 공장 탭들이 여기에 동적으로 생성됩니다 -->
</div>
<!-- 공장 레이아웃 지도 관리 섹션 (카테고리가 선택된 경우에만 표시) -->
<div class="code-section" id="layoutMapSection" style="display: none;">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">🗺️</span>
<span id="selectedCategoryName"></span> 레이아웃 지도
</h2>
<button class="btn btn-secondary" onclick="openLayoutMapModal()">
<span class="btn-icon">⚙️</span>
지도 설정
</button>
<h2 class="section-title"><span id="selectedCategoryName"></span> 레이아웃 지도</h2>
<button class="btn btn-secondary" onclick="openLayoutMapModal()">지도 설정</button>
</div>
<div id="layoutMapPreview" style="padding: 20px; background: #f9fafb; border-radius: 8px; text-align: center;">
<!-- 레이아웃 이미지 미리보기가 여기에 표시됩니다 -->
@@ -127,21 +52,12 @@
<!-- 작업장 목록 -->
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">🏭</span>
작업장 목록
</h2>
<h2 class="section-title">작업장 목록</h2>
</div>
<div class="code-stats" id="workplaceStats">
<span class="stat-item">
<span class="stat-icon">🏗️</span>
전체 <span id="totalCount">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
활성 <span id="activeCount">0</span>
</span>
<span class="stat-item">전체 <span id="totalCount">0</span></span>
<span class="stat-item">활성 <span id="activeCount">0</span></span>
</div>
<div class="code-grid" id="workplaceGrid">
@@ -183,12 +99,8 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeCategoryModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteCategoryBtn" onclick="deleteCategory()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveCategory()">
💾 저장
</button>
<button type="button" class="btn btn-danger" id="deleteCategoryBtn" onclick="deleteCategory()" style="display: none;">삭제</button>
<button type="button" class="btn btn-primary" onclick="saveCategory()">저장</button>
</div>
</div>
</div>
@@ -247,12 +159,8 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkplaceModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteWorkplaceBtn" onclick="deleteWorkplace()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveWorkplace()">
💾 저장
</button>
<button type="button" class="btn btn-danger" id="deleteWorkplaceBtn" onclick="deleteWorkplace()" style="display: none;">삭제</button>
<button type="button" class="btn btn-primary" onclick="saveWorkplace()">저장</button>
</div>
</div>
</div>
@@ -286,9 +194,7 @@
<small class="form-help">JPG, PNG, GIF 형식 지원 (최대 5MB)</small>
</div>
<button type="button" class="btn btn-primary" onclick="uploadWorkplaceLayout()">
📤 이미지 업로드
</button>
<button type="button" class="btn btn-primary" onclick="uploadWorkplaceLayout()">이미지 업로드</button>
</div>
<!-- Step 2: 설비/영역 정의 -->
@@ -309,12 +215,8 @@
<input type="text" id="equipmentNameInput" class="form-control" placeholder="예: CNC-01, 선반기-A" style="margin-bottom: 12px;">
<small class="form-help">드래그로 영역을 선택한 후 설비 이름을 입력하고 저장하세요</small>
<div style="display: flex; gap: 8px; margin-top: 12px;">
<button type="button" class="btn btn-secondary" onclick="clearWorkplaceCurrentRegion()">
🗑️ 현재 영역 지우기
</button>
<button type="button" class="btn btn-primary" onclick="saveWorkplaceEquipmentRegion()">
💾 설비 위치 저장
</button>
<button type="button" class="btn btn-secondary" onclick="clearWorkplaceCurrentRegion()">현재 영역 지우기</button>
<button type="button" class="btn btn-primary" onclick="saveWorkplaceEquipmentRegion()">설비 위치 저장</button>
</div>
</div>
@@ -338,7 +240,7 @@
<div id="layoutMapModal" class="modal-overlay" style="display: none;">
<div class="modal-container" style="max-width: 90vw; max-height: 90vh;">
<div class="modal-header">
<h2>🗺️ 공장 레이아웃 지도 설정</h2>
<h2>공장 레이아웃 지도 설정</h2>
<button class="modal-close-btn" onclick="closeLayoutMapModal()">×</button>
</div>
@@ -357,9 +259,7 @@
<input type="file" id="layoutImageFile" accept="image/*" class="form-control" onchange="previewLayoutImage(event)">
<small class="form-help">JPG, PNG, GIF 형식 지원 (최대 5MB)</small>
</div>
<button type="button" class="btn btn-primary" onclick="uploadLayoutImage()">
📤 이미지 업로드
</button>
<button type="button" class="btn btn-primary" onclick="uploadLayoutImage()">이미지 업로드</button>
</div>
<!-- Step 2: 작업장 영역 정의 -->
@@ -381,12 +281,8 @@
<option value="">작업장을 선택하세요</option>
</select>
<div style="display: flex; gap: 8px;">
<button type="button" class="btn btn-secondary" onclick="clearCurrentRegion()">
🗑️ 현재 영역 지우기
</button>
<button type="button" class="btn btn-primary" onclick="saveRegion()">
💾 선택 영역 저장
</button>
<button type="button" class="btn btn-secondary" onclick="clearCurrentRegion()">현재 영역 지우기</button>
<button type="button" class="btn btn-primary" onclick="saveRegion()">선택 영역 저장</button>
</div>
</div>
@@ -408,6 +304,7 @@
</div>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module" src="/js/workplace-management.js?v=3"></script>
<script type="module" src="/js/workplace-layout-map.js?v=1"></script>
</body>

View File

@@ -15,6 +15,7 @@
<script type="module" src="/js/api-config.js"></script>
<script type="module" src="/js/auth-check.js" defer></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0"></script>
<script type="module" src="/js/annual-vacation-overview.js" defer></script>
</head>
@@ -32,7 +33,7 @@
<!-- 페이지 헤더 -->
<div class="page-header">
<h1 class="page-title">📊 연간 연차 현황</h1>
<h1 class="page-title">연간 연차 현황</h1>
<p class="page-description">모든 작업자의 연간 휴가 현황을 차트로 확인합니다</p>
</div>
@@ -98,7 +99,7 @@
<option value="12">12월</option>
</select>
<button id="exportExcelBtn" class="btn btn-sm btn-secondary">
📥 엑셀 다운로드
엑셀 다운로드
</button>
</div>
</div>

View File

@@ -19,17 +19,14 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">📅</span>
일일 출퇴근 입력
</h1>
<h1 class="page-title">일일 출퇴근 입력</h1>
<p class="page-description">오늘 출근한 작업자들의 출퇴근 기록을 입력합니다</p>
</div>
<div class="page-actions">
<input type="date" id="selectedDate" class="form-control" style="width: auto;">
<button class="btn btn-primary" onclick="loadAttendanceRecords()">
<span>🔄 새로고침</span>
새로고침
</button>
</div>
</div>
@@ -48,7 +45,7 @@
<div style="text-align: center; margin-top: 2rem;">
<button class="btn btn-primary" onclick="saveAllAttendance()" style="padding: 1rem 3rem; font-size: 1.1rem;">
<span>💾 전체 저장</span>
전체 저장
</button>
</div>
</div>
@@ -58,7 +55,8 @@
</main>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
import '/js/api-config.js?v=3';
</script>

View File

@@ -118,17 +118,14 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">📆</span>
월별 출퇴근 현황
</h1>
<h1 class="page-title">월별 출퇴근 현황</h1>
<p class="page-description">이번 달 출퇴근 현황을 조회합니다</p>
</div>
<div class="page-actions">
<input type="month" id="selectedMonth" class="form-control" style="width: auto;">
<button class="btn btn-primary" onclick="loadMonthlyData()">
<span>🔄 새로고침</span>
새로고침
</button>
</div>
</div>
@@ -189,7 +186,8 @@
</main>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
import '/js/api-config.js?v=3';
</script>

View File

@@ -15,6 +15,7 @@
<script type="module" src="/js/api-config.js"></script>
<script type="module" src="/js/auth-check.js" defer></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module" src="/js/vacation-allocation.js" defer></script>
</head>
@@ -31,7 +32,7 @@
<!-- 페이지 헤더 -->
<div class="page-header">
<h1 class="page-title"> 휴가 발생 입력</h1>
<h1 class="page-title">휴가 발생 입력</h1>
<p class="page-description">작업자별 휴가를 입력하고 특별 휴가를 관리합니다</p>
</div>
@@ -82,7 +83,7 @@
<div class="section-header">
<h3>자동 계산 (연차만 해당)</h3>
<button id="autoCalculateBtn" class="btn btn-secondary btn-sm">
🔄 입사일 기준 자동 계산
입사일 기준 자동 계산
</button>
</div>
<div id="autoCalculateResult" class="alert alert-info" style="display: none;">

View File

@@ -50,10 +50,7 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon"></span>
휴가 승인 관리
</h1>
<h1 class="page-title">휴가 승인 관리</h1>
<p class="page-description">휴가 신청을 승인하거나 거부합니다</p>
</div>
</div>
@@ -92,10 +89,10 @@
<span style="margin: 0 0.5rem;">~</span>
<input type="date" id="filterEndDate" class="form-control" style="width: auto;">
<button class="btn btn-secondary" onclick="filterAllRequests()">
<span>🔍 조회</span>
조회
</button>
<button class="btn btn-secondary" onclick="resetFilter()">
<span>🔄 전체</span>
전체
</button>
</div>
</div>
@@ -112,7 +109,8 @@
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="/js/vacation-common.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
import '/js/api-config.js?v=3';
</script>

View File

@@ -19,10 +19,7 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">📝</span>
휴가 직접 입력
</h1>
<h1 class="page-title">휴가 직접 입력</h1>
<p class="page-description">관리자 권한으로 작업자의 휴가 정보를 직접 입력합니다</p>
</div>
</div>
@@ -81,7 +78,7 @@
<div style="text-align: center; margin-top: 2rem;">
<button type="submit" class="btn btn-primary" style="padding: 1rem 3rem;">
<span>💾 즉시 입력 (자동 승인)</span>
즉시 입력 (자동 승인)
</button>
</div>
</form>
@@ -96,7 +93,7 @@
<h2 class="card-title">최근 입력 내역</h2>
<div class="page-actions">
<button class="btn btn-secondary" onclick="loadRecentInputs()">
<span>🔄 새로고침</span>
새로고침
</button>
</div>
</div>
@@ -112,7 +109,8 @@
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="/js/vacation-common.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
import '/js/api-config.js?v=3';
</script>

View File

@@ -50,10 +50,7 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🏖️</span>
휴가 관리
</h1>
<h1 class="page-title">휴가 관리</h1>
<p class="page-description">휴가 신청을 승인하고 작업자 휴가 정보를 관리합니다</p>
</div>
</div>
@@ -137,7 +134,7 @@
<div style="text-align: center; margin-top: 2rem;">
<button type="submit" class="btn btn-primary" style="padding: 1rem 3rem;">
<span>💾 즉시 입력 (자동 승인)</span>
즉시 입력 (자동 승인)
</button>
</div>
</form>
@@ -150,7 +147,7 @@
<h2 class="card-title">최근 입력 내역</h2>
<div class="page-actions">
<button class="btn btn-secondary" onclick="loadRecentInputs()">
<span>🔄 새로고침</span>
새로고침
</button>
</div>
</div>
@@ -174,10 +171,10 @@
<span style="margin: 0 0.5rem;">~</span>
<input type="date" id="filterEndDate" class="form-control" style="width: auto;">
<button class="btn btn-secondary" onclick="filterAllRequests()">
<span>🔍 조회</span>
조회
</button>
<button class="btn btn-secondary" onclick="resetFilter()">
<span>🔄 전체</span>
전체
</button>
</div>
</div>
@@ -194,7 +191,8 @@
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="/js/vacation-common.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
import '/js/api-config.js?v=3';
</script>

View File

@@ -19,10 +19,7 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">📝</span>
휴가 신청
</h1>
<h1 class="page-title">휴가 신청</h1>
<p class="page-description">휴가를 신청하고 신청 내역을 확인합니다</p>
</div>
</div>
@@ -80,7 +77,7 @@
<div style="text-align: center; margin-top: 2rem;">
<button type="submit" class="btn btn-primary" style="padding: 1rem 3rem;">
<span>📝 신청하기</span>
신청하기
</button>
</div>
</form>
@@ -106,7 +103,8 @@
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="/js/vacation-common.js"></script>
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module">
import '/js/api-config.js?v=3';
</script>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>👤 내 프로필 | (주)테크니컬코리아</title>
<title>내 프로필 | (주)테크니컬코리아</title>
<link rel="stylesheet" href="/css/main-layout.css">
<script src="/js/auth-check.js" defer></script>
@@ -208,7 +208,7 @@
<div class="profile-page">
<div class="profile-header">
<div class="profile-avatar" id="profileAvatar">👤</div>
<div class="profile-avatar" id="profileAvatar"></div>
<h1 class="profile-name" id="profileName">사용자</h1>
<p class="profile-role" id="profileRole">역할</p>
</div>
@@ -216,10 +216,7 @@
<div class="profile-cards">
<!-- 기본 정보 -->
<div class="profile-card">
<h2 class="card-title">
<span>📋</span>
<span>기본 정보</span>
</h2>
<h2 class="card-title">기본 정보</h2>
<div class="info-grid">
<div class="info-item">
<span class="info-label">사용자 ID</span>
@@ -250,10 +247,7 @@
<!-- 활동 정보 -->
<div class="profile-card">
<h2 class="card-title">
<span>📊</span>
<span>활동 정보</span>
</h2>
<h2 class="card-title">활동 정보</h2>
<div class="info-grid">
<div class="info-item">
<span class="info-label">마지막 로그인</span>
@@ -284,22 +278,16 @@
<!-- 빠른 작업 -->
<div class="profile-card">
<h2 class="card-title">
<span></span>
<span>빠른 작업</span>
</h2>
<h2 class="card-title">빠른 작업</h2>
<div class="action-buttons">
<a href="/pages/profile/change-password.html" class="action-btn btn-warning">
<span>🔐</span>
<span>비밀번호 변경</span>
<a href="/pages/profile/password.html" class="action-btn btn-warning">
비밀번호 변경
</a>
<button class="action-btn btn-secondary" disabled>
<span>✏️</span>
<span>프로필 수정 (준비중)</span>
프로필 수정 (준비중)
</button>
<button class="action-btn btn-secondary" disabled>
<span>⚙️</span>
<span>설정 (준비중)</span>
설정 (준비중)
</button>
<a href="javascript:history.back()" class="action-btn btn-secondary">
<span></span>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔐 비밀번호 변경 | (주)테크니컬코리아</title>
<title>비밀번호 변경 | (주)테크니컬코리아</title>
<link rel="stylesheet" href="/css/main-layout.css">
<script src="/js/auth-check.js" defer></script>
@@ -276,16 +276,13 @@
<div class="password-page">
<div class="page-title">
<h1>🔐 비밀번호 변경</h1>
<h1>비밀번호 변경</h1>
<p>계정 보안을 위해 정기적으로 비밀번호를 변경해주세요</p>
</div>
<div class="password-card">
<div class="card-header">
<h2>
<span>🔑</span>
<span>새 비밀번호 설정</span>
</h2>
<h2>새 비밀번호 설정</h2>
</div>
<div class="card-body">
@@ -294,10 +291,7 @@
<!-- 안내 정보 -->
<div class="info-box">
<h4>
<span></span>
<span>비밀번호 요구사항</span>
</h4>
<h4>비밀번호 요구사항</h4>
<ul>
<li>최소 6자 이상 입력해주세요</li>
<li>영문 대/소문자, 숫자, 특수문자를 조합하면 더 안전합니다</li>
@@ -309,64 +303,54 @@
<!-- 비밀번호 변경 폼 -->
<form id="changePasswordForm" class="password-form">
<div class="form-group">
<label for="currentPassword">
<span>🔓</span>
<span>현재 비밀번호</span>
</label>
<label for="currentPassword">현재 비밀번호</label>
<div class="input-wrapper">
<input
type="password"
id="currentPassword"
<input
type="password"
id="currentPassword"
class="form-control"
placeholder="현재 비밀번호를 입력하세요"
required
placeholder="현재 비밀번호를 입력하세요"
required
autocomplete="current-password"
/>
<button type="button" class="password-toggle" data-target="currentPassword">👁️</button>
<button type="button" class="password-toggle" data-target="currentPassword">보기</button>
</div>
</div>
<div class="form-group">
<label for="newPassword">
<span>🔐</span>
<span>새 비밀번호</span>
</label>
<label for="newPassword">새 비밀번호</label>
<div class="input-wrapper">
<input
type="password"
id="newPassword"
<input
type="password"
id="newPassword"
class="form-control"
placeholder="새 비밀번호를 입력하세요"
placeholder="새 비밀번호를 입력하세요"
required
autocomplete="new-password"
/>
<button type="button" class="password-toggle" data-target="newPassword">👁️</button>
<button type="button" class="password-toggle" data-target="newPassword">보기</button>
</div>
<div id="passwordStrength"></div>
</div>
<div class="form-group">
<label for="confirmPassword">
<span></span>
<span>새 비밀번호 확인</span>
</label>
<label for="confirmPassword">새 비밀번호 확인</label>
<div class="input-wrapper">
<input
type="password"
id="confirmPassword"
<input
type="password"
id="confirmPassword"
class="form-control"
placeholder="새 비밀번호를 다시 입력하세요"
placeholder="새 비밀번호를 다시 입력하세요"
required
autocomplete="new-password"
/>
<button type="button" class="password-toggle" data-target="confirmPassword">👁️</button>
<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">
<span>🔑</span>
<span>비밀번호 변경</span>
비밀번호 변경
</button>
<button type="button" class="btn btn-secondary" id="resetBtn">
초기화

View File

@@ -408,14 +408,14 @@
gap: 0.5rem;
}
.weather-icon.rain::before { content: '🌧️'; }
.weather-icon.snow::before { content: '❄️'; }
.weather-icon.heat::before { content: '🔥'; }
.weather-icon.cold::before { content: '🥶'; }
.weather-icon.wind::before { content: '💨'; }
.weather-icon.fog::before { content: '🌫️'; }
.weather-icon.dust::before { content: '😷'; }
.weather-icon.clear::before { content: '☀️'; }
.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 {
@@ -591,6 +591,7 @@
<script type="module" src="/js/api-config.js"></script>
<script src="/js/auth-check.js" defer></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script type="module" src="/js/safety-checklist-manage.js"></script>
</body>
</html>

View File

@@ -451,7 +451,8 @@
<img id="photoModalImg" src="" alt="">
</div>
<script src="/js/load-navbar.js?v=1"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/work-issue-detail.js?v=1"></script>
</body>
</html>

View File

@@ -295,7 +295,8 @@
</div>
</main>
<script src="/js/load-navbar.js?v=1"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/work-issue-list.js?v=1"></script>
</body>
</html>

View File

@@ -612,7 +612,8 @@
</div>
</div>
<script src="/js/load-navbar.js?v=1"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/work-issue-report.js?v=1"></script>
</body>
</html>

View File

@@ -285,7 +285,8 @@
</div>
<!-- Scripts -->
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/safety-management.js"></script>
</body>
</html>

View File

@@ -259,7 +259,7 @@
<!-- 경고 -->
<div class="warning-box">
<div class="warning-icon">⚠️</div>
<div class="warning-icon"></div>
<div class="warning-text">
<strong>중요:</strong> 모든 체크리스트 항목을 완료하고 방문자의 서명을 받은 후 교육 완료 처리를 해주세요.
교육 완료 후에는 수정할 수 없습니다.
@@ -321,7 +321,8 @@
</div>
<!-- Scripts -->
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/safety-training-conduct.js"></script>
</body>
</html>

View File

@@ -280,7 +280,7 @@
<div class="form-group">
<label>방문 작업장 *</label>
<div id="workplaceSelection" class="workplace-selection" onclick="openMapModal()">
<div class="icon">📍</div>
<div class="icon"></div>
<div class="text">지도에서 작업장을 선택하세요</div>
</div>
<div id="selectedWorkplaceInfo" style="display: none;"></div>
@@ -365,7 +365,8 @@
</div>
<!-- Scripts -->
<script type="module" src="/js/load-navbar.js?v=5"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="/js/visit-request.js"></script>
</body>
</html>

View File

@@ -12,6 +12,8 @@
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js?v=1" defer></script>
<script type="module" src="/js/api-config.js?v=3"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
</head>
<body>
@@ -26,20 +28,17 @@
<!-- 페이지 헤더 -->
<header class="page-header fade-in">
<h1 class="page-title">
<span class="icon">📊</span>
작업 분석
</h1>
<h1 class="page-title">작업 분석</h1>
<p class="page-subtitle">기간별/프로젝트별 작업 현황을 분석하고 통계를 확인합니다</p>
</header>
<!-- 분석 모드 탭 -->
<nav class="analysis-tabs fade-in">
<button class="tab-button active" data-mode="period" onclick="switchAnalysisMode('period')">
📅 기간별 분석
기간별 분석
</button>
<button class="tab-button" data-mode="project" onclick="switchAnalysisMode('project')">
🏗️ 프로젝트별 분석
프로젝트별 분석
</button>
</nav>
@@ -48,33 +47,23 @@
<div class="controls-grid">
<!-- 기간 설정 -->
<div class="form-group">
<label class="form-label" for="startDate">
<span class="icon">📅</span>
시작일
</label>
<label class="form-label" for="startDate">시작일</label>
<input type="date" id="startDate" class="form-input" required>
</div>
<div class="form-group">
<label class="form-label" for="endDate">
<span class="icon">📅</span>
종료일
</label>
<label class="form-label" for="endDate">종료일</label>
<input type="date" id="endDate" class="form-input" required>
</div>
<!-- 기간 확정 버튼 -->
<div class="form-group">
<button class="confirm-period-button" onclick="confirmPeriod()">
<span class="icon"></span>
기간 확정
</button>
<button class="confirm-period-button" onclick="confirmPeriod()">기간 확정</button>
</div>
<!-- 기간 상태 표시 -->
<div class="form-group" id="periodStatusGroup" style="display: none;">
<div class="period-status">
<span class="icon"></span>
<div>
<div style="font-size: 0.8rem; opacity: 0.8; margin-bottom: 2px;">분석 기간</div>
<div id="periodText">기간이 설정되지 않았습니다</div>
@@ -96,19 +85,15 @@
<div id="analysisTabNavigation" class="tab-navigation" style="display: none;">
<div class="tab-buttons">
<button class="tab-button active" data-tab="work-status">
<span class="icon">📈</span>
기간별 작업 현황
</button>
<button class="tab-button" data-tab="project-distribution">
<span class="icon">🥧</span>
프로젝트별 분포
</button>
<button class="tab-button" data-tab="worker-performance">
<span class="icon">👤</span>
작업자별 성과
</button>
<button class="tab-button" data-tab="error-analysis">
<span class="icon">⚠️</span>
오류 분석
</button>
</div>
@@ -125,14 +110,8 @@
<div id="work-status-tab" class="tab-content active">
<div class="chart-container table-type">
<div class="chart-header">
<h3 class="chart-title">
<span class="icon">📈</span>
기간별 작업 현황
</h3>
<button class="chart-analyze-btn" onclick="analyzeWorkStatus()" disabled>
<span class="icon">🔍</span>
분석 실행
</button>
<h3 class="chart-title">기간별 작업 현황</h3>
<button class="chart-analyze-btn" onclick="analyzeWorkStatus()" disabled>분석 실행</button>
</div>
<div class="table-container">
<table class="work-report-table" id="workReportTable">
@@ -172,14 +151,8 @@
<div id="project-distribution-tab" class="tab-content">
<div class="chart-container table-type">
<div class="chart-header">
<h3 class="chart-title">
<span class="icon">📋</span>
프로젝트별 작업 분포
</h3>
<button class="chart-analyze-btn" onclick="analyzeProjectDistribution()" disabled>
<span class="icon">🔍</span>
분석 실행
</button>
<h3 class="chart-title">프로젝트별 작업 분포</h3>
<button class="chart-analyze-btn" onclick="analyzeProjectDistribution()" disabled>분석 실행</button>
</div>
<div class="table-container">
<table class="production-report-table" id="projectDistributionTable">
@@ -216,14 +189,8 @@
<div id="worker-performance-tab" class="tab-content">
<div class="chart-container chart-type">
<div class="chart-header">
<h3 class="chart-title">
<span class="icon">👤</span>
작업자별 성과
</h3>
<button class="chart-analyze-btn" onclick="analyzeWorkerPerformance()" disabled>
<span class="icon">🔍</span>
분석 실행
</button>
<h3 class="chart-title">작업자별 성과</h3>
<button class="chart-analyze-btn" onclick="analyzeWorkerPerformance()" disabled>분석 실행</button>
</div>
<canvas id="workerPerformanceChart" class="chart-canvas"></canvas>
</div>
@@ -233,14 +200,8 @@
<div id="error-analysis-tab" class="tab-content">
<div class="chart-container table-type">
<div class="chart-header">
<h3 class="chart-title">
<span class="icon">⚠️</span>
오류 분석
</h3>
<button class="chart-analyze-btn" onclick="analyzeErrorAnalysis()" disabled>
<span class="icon">🔍</span>
분석 실행
</button>
<h3 class="chart-title">오류 분석</h3>
<button class="chart-analyze-btn" onclick="analyzeErrorAnalysis()" disabled>분석 실행</button>
</div>
<div class="table-container">
<table class="error-analysis-table" id="errorAnalysisTable">
@@ -279,10 +240,7 @@
<!-- 상세 데이터 테이블 -->
<div id="dataTableContainer" class="data-table-container" style="display: none;">
<div class="table-header">
<h3 class="table-title">
<span class="icon">📋</span>
상세 작업 데이터
</h3>
<h3 class="table-title">상세 작업 데이터</h3>
</div>
<div style="overflow-x: auto;">
<table class="data-table" id="detailDataTable">
@@ -330,13 +288,13 @@
if (useCache && this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.CACHE_DURATION) {
console.log('📦 캐시에서 데이터 반환:', endpoint);
console.log('[Cache] 캐시에서 데이터 반환:', endpoint);
return cached.data;
}
}
try {
console.log('🌐 API 호출:', endpoint);
console.log('[API] 호출:', endpoint);
const response = await window.apiCall(endpoint, method, data);
// 성공 시 캐시 저장
@@ -349,34 +307,34 @@
return response;
} catch (error) {
console.error(' API 호출 실패:', endpoint, error);
console.error('[Error] API 호출 실패:', endpoint, error);
throw error;
}
},
// 배치 API 호출 (병렬 처리)
async batchCall(requests) {
console.log('🔄 배치 API 호출 시작:', requests.length, '개');
console.log('[Batch] API 호출 시작:', requests.length, '개');
const promises = requests.map(async (req) => {
try {
const result = await this.call(req.endpoint, req.method, req.data, req.useCache);
return { name: req.name, success: true, data: result };
} catch (error) {
console.warn(`⚠️ ${req.name} API 실패:`, error);
console.warn(`[Warning] ${req.name} API 실패:`, error);
return { name: req.name, success: false, error: error.message, data: null };
}
});
const results = await Promise.all(promises);
console.log(' 배치 API 호출 완료');
console.log('[Complete] 배치 API 호출 완료');
return results;
},
// 캐시 초기화
clearCache() {
this.cache.clear();
console.log('🗑️ API 캐시 초기화');
console.log('[Clear] API 캐시 초기화');
}
};
@@ -453,7 +411,7 @@
toast.className = `error-toast toast-${type}`;
toast.innerHTML = `
<div class="toast-content">
<span class="toast-icon">${type === 'error' ? '⚠️' : type === 'success' ? '' : ''}</span>
<span class="toast-icon">${type === 'error' ? '[!]' : type === 'success' ? '[v]' : '[i]'}</span>
<span class="toast-message">${message}</span>
<button class="toast-close" onclick="this.parentElement.parentElement.remove()">×</button>
</div>
@@ -491,7 +449,7 @@
const userMessage = this.UserMessages[errorType];
// 콘솔에 상세 로그
console.error(` [${context}] ${errorType.toUpperCase()} 오류:`, error);
console.error(`[Error] [${context}] ${errorType.toUpperCase()} 오류:`, error);
// 사용자에게 친화적 메시지 표시
if (showUserMessage) {

View File

@@ -8,6 +8,9 @@
<link rel="stylesheet" href="/css/daily-work-report.css?v=11">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js" defer></script>
<script type="module" src="/js/api-config.js"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
</head>
<body>
<div class="work-report-container">
@@ -77,17 +80,13 @@
<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;">
<span style="margin-right: 0.5rem;">🗺️</span>작업장소 선택
</h2>
<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;">&times;</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;">
<span style="margin-right: 0.5rem;">🏭</span>공장 선택
</h3>
<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>
@@ -96,14 +95,12 @@
<!-- 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 style="margin-right: 0.5rem;">📍</span>
<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;">
<span style="margin-right: 0.25rem;">🗺️</span>
지도에서 작업장을 클릭하여 선택하세요
</div>
<div style="text-align: center; position: relative; display: inline-block; max-width: 100%;">
@@ -114,10 +111,7 @@
<!-- 리스트 선택 영역 -->
<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 style="margin-right: 0.25rem;">📋</span>
리스트에서 선택
</span>
<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;">
<!-- 작업장소 목록 -->

View File

@@ -8,6 +8,10 @@
<link rel="stylesheet" href="/css/common.css?v=13">
<link rel="stylesheet" href="/css/modern-dashboard.css?v=14">
<link rel="stylesheet" href="/css/work-report-calendar.css?v=29">
<script src="/js/auth-check.js" defer></script>
<script type="module" src="/js/api-config.js"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
</head>
<body>
<!-- 네비게이션 헤더 -->
@@ -18,7 +22,7 @@
<div class="calendar-page-container">
<!-- 페이지 제목 -->
<div class="page-title-section">
<h2 class="page-title">📅 작업 현황 확인</h2>
<h2 class="page-title">작업 현황 확인</h2>
<p class="page-subtitle">월별 작업자 현황을 한눈에 확인하세요</p>
</div>
@@ -101,28 +105,28 @@
<!-- 요약 정보 -->
<div class="daily-summary">
<div class="summary-card">
<div class="summary-icon success">👥</div>
<div class="summary-icon success"></div>
<div class="summary-content">
<div class="summary-label">총 작업자</div>
<div class="summary-value" id="modalTotalWorkers">0명</div>
</div>
</div>
<div class="summary-card">
<div class="summary-icon primary"></div>
<div class="summary-icon primary"></div>
<div class="summary-content">
<div class="summary-label">총 작업시간</div>
<div class="summary-value" id="modalTotalHours">0.0h</div>
</div>
</div>
<div class="summary-card">
<div class="summary-icon warning">📝</div>
<div class="summary-icon warning"></div>
<div class="summary-content">
<div class="summary-label">작업 건수</div>
<div class="summary-value" id="modalTotalTasks">0건</div>
</div>
</div>
<div class="summary-card">
<div class="summary-icon error">⚠️</div>
<div class="summary-icon error"></div>
<div class="summary-content">
<div class="summary-label">오류 건수</div>
<div class="summary-value" id="modalErrorCount">0건</div>
@@ -151,7 +155,7 @@
</div>
<div id="modalNoData" class="empty-state" style="display: none;">
<div class="empty-icon">📭</div>
<div class="empty-icon"></div>
<h3>해당 날짜의 작업 보고서가 없습니다</h3>
<p>다른 날짜를 선택해 주세요.</p>
</div>
@@ -172,10 +176,10 @@
<!-- 탭 네비게이션 -->
<div class="modal-tabs">
<button class="tab-btn active" data-tab="existing" onclick="switchTab('existing')">
📋 기존 작업 (0건)
기존 작업 (0건)
</button>
<button class="tab-btn" data-tab="new" onclick="switchTab('new')">
새 작업 추가
새 작업 추가
</button>
</div>
@@ -193,7 +197,7 @@
</div>
<div id="noExistingWork" class="empty-state" style="display: none;">
<div class="empty-icon">📝</div>
<div class="empty-icon"></div>
<h3>등록된 작업이 없습니다</h3>
<p>"새 작업 추가" 탭에서 작업을 등록해보세요.</p>
</div>
@@ -271,12 +275,8 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkEntryModal()">취소</button>
<div class="footer-actions">
<button type="button" class="btn btn-danger" id="deleteWorkBtn" onclick="deleteWork()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" id="saveWorkBtn" onclick="saveWorkEntry()">
💾 저장
</button>
<button type="button" class="btn btn-danger" id="deleteWorkBtn" onclick="deleteWork()" style="display: none;">삭제</button>
<button type="button" class="btn btn-primary" id="saveWorkBtn" onclick="saveWorkEntry()">저장</button>
</div>
</div>
</div>

View File

@@ -10,6 +10,8 @@
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js?v=1" defer></script>
<script type="module" src="/js/api-config.js?v=3"></script>
<script type="module" src="/js/load-navbar.js"></script>
<script type="module" src="/js/load-sidebar.js"></script>
<style>
.date-group {
margin-bottom: 2rem;
@@ -67,10 +69,7 @@
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🛠️</span>
TBM (Tool Box Meeting)
</h1>
<h1 class="page-title">TBM (Tool Box Meeting)</h1>
<p class="page-description">아침 안전 회의 및 팀 구성 관리</p>
</div>
@@ -82,11 +81,9 @@
<!-- TBM 탭 -->
<div class="code-tabs">
<button class="tab-btn active" data-tab="tbm-input" onclick="switchTbmTab('tbm-input')">
<span class="tab-icon"></span>
TBM 입력
</button>
<button class="tab-btn" data-tab="tbm-manage" onclick="switchTbmTab('tbm-manage')">
<span class="tab-icon">📋</span>
TBM 관리
</button>
</div>
@@ -95,29 +92,20 @@
<div id="tbm-input-tab" class="code-tab-content active">
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">🌅</span>
오늘의 TBM
</h2>
<h2 class="section-title">오늘의 TBM</h2>
<div class="section-actions">
<button class="btn btn-primary" onclick="openNewTbmModal()">
<span class="btn-icon"></span>
새 TBM 시작
</button>
<button class="btn btn-primary" onclick="openNewTbmModal()">새 TBM 시작</button>
</div>
</div>
<div class="code-stats">
<span class="stat-item">
<span class="stat-icon">📋</span>
오늘 등록 <span id="todayTotalSessions">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
완료 <span id="todayCompletedSessions">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
진행중 <span id="todayActiveSessions">0</span>
</span>
</div>
@@ -128,11 +116,11 @@
<!-- Empty State -->
<div class="empty-state" id="todayEmptyState" style="display: none;">
<div class="empty-icon">🛠️</div>
<div class="empty-icon"></div>
<h3>오늘 등록된 TBM이 없습니다</h3>
<p>"새 TBM 시작" 버튼을 눌러 오늘의 TBM을 시작해보세요.</p>
<button class="btn btn-primary" onclick="openNewTbmModal()">
첫 TBM 시작하기
첫 TBM 시작하기
</button>
</div>
</div>
@@ -142,29 +130,20 @@
<div id="tbm-manage-tab" class="code-tab-content">
<div class="code-section">
<div class="section-header">
<h2 class="section-title">
<span class="section-icon">📚</span>
TBM 기록
</h2>
<h2 class="section-title">TBM 기록</h2>
<div class="section-actions">
<button class="btn btn-secondary" onclick="loadMoreTbmDays()" id="loadMoreBtn">
<span class="btn-icon">📅</span>
더 보기
</button>
<button class="btn btn-secondary" onclick="loadMoreTbmDays()" id="loadMoreBtn">더 보기</button>
</div>
</div>
<div class="code-stats">
<span class="stat-item">
<span class="stat-icon">📋</span>
<span id="totalSessions">0</span>
</span>
<span class="stat-item">
<span class="stat-icon"></span>
완료 <span id="completedSessions">0</span>
</span>
<span class="stat-item" id="viewModeIndicator" style="display: none;">
<span class="stat-icon">👤</span>
<span id="viewModeText">내 TBM만</span>
</span>
</div>
@@ -176,7 +155,7 @@
<!-- Empty State -->
<div class="empty-state" id="emptyState" style="display: none;">
<div class="empty-icon">🛠️</div>
<div class="empty-icon"></div>
<h3>등록된 TBM 세션이 없습니다</h3>
<p>TBM 입력 탭에서 새로운 TBM을 시작해보세요.</p>
</div>
@@ -216,12 +195,10 @@
<div class="form-section">
<div class="section-header" style="margin-bottom: 1rem;">
<h3 style="font-size: 1.1rem; font-weight: 600; color: #1f2937;">
<span style="margin-right: 0.5rem;">👷</span>
작업자 및 작업 정보
</h3>
<div style="display: flex; gap: 0.5rem;">
<button type="button" class="btn btn-sm btn-secondary" onclick="openBulkSettingModal()" style="display: flex; align-items: center; gap: 0.25rem;">
<span>📋</span>
일괄 설정
</button>
<button type="button" class="btn btn-sm btn-primary" onclick="openWorkerSelectionModal()">
@@ -236,7 +213,6 @@
<!-- 작업자 카드들이 여기에 동적으로 추가됩니다 -->
<div class="empty-state-small" id="workerListEmpty" style="display: flex; align-items: center; justify-content: center; padding: 2rem; border: 2px dashed #d1d5db; border-radius: 0.5rem; color: #6b7280;">
<div style="text-align: center;">
<div style="font-size: 2rem; margin-bottom: 0.5rem;">👷‍♂️</div>
<p>작업자를 선택해주세요</p>
</div>
</div>
@@ -247,9 +223,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeTbmModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="saveTbmSession()">
💾 저장하기
</button>
<button type="button" class="btn btn-primary" onclick="saveTbmSession()">저장하기</button>
</div>
</div>
</div>
@@ -264,7 +238,7 @@
<div class="modal-body">
<div style="background: #dbeafe; border: 1px solid #3b82f6; padding: 1rem; border-radius: 0.5rem; margin-bottom: 1.5rem;">
<div style="font-weight: 600; color: #1e40af; margin-bottom: 0.25rem;">💡 일괄 설정</div>
<div style="font-weight: 600; color: #1e40af; margin-bottom: 0.25rem;">일괄 설정</div>
<div style="color: #1e40af; font-size: 0.9rem;">
선택한 작업자들의 <strong>첫 번째 작업 라인</strong>에 동일한 정보가 적용됩니다.
</div>
@@ -290,7 +264,7 @@
<div class="form-group">
<label class="form-label">프로젝트</label>
<button type="button" id="bulkProjectBtn" onclick="openBulkItemSelect('project')" class="btn btn-secondary" style="width: 100%; text-align: left; justify-content: flex-start;">
📁 프로젝트 선택
프로젝트 선택
</button>
<input type="hidden" id="bulkProjectId">
</div>
@@ -299,14 +273,14 @@
<div class="form-group">
<label class="form-label">공정 *</label>
<button type="button" id="bulkWorkTypeBtn" onclick="openBulkItemSelect('workType')" class="btn btn-secondary" style="width: 100%; text-align: left; justify-content: flex-start;">
⚙️ 공정 선택
공정 선택
</button>
<input type="hidden" id="bulkWorkTypeId">
</div>
<div class="form-group">
<label class="form-label">작업 *</label>
<button type="button" id="bulkTaskBtn" onclick="openBulkItemSelect('task')" class="btn btn-secondary" style="width: 100%; text-align: left; justify-content: flex-start;" disabled>
🔧 작업 선택
작업 선택
</button>
<input type="hidden" id="bulkTaskId">
</div>
@@ -315,7 +289,7 @@
<div class="form-group">
<label class="form-label">작업장 *</label>
<button type="button" id="bulkWorkplaceBtn" onclick="openBulkWorkplaceSelect()" class="btn btn-secondary" style="width: 100%; text-align: left; justify-content: flex-start;">
📍 작업장 선택
작업장 선택
</button>
<input type="hidden" id="bulkWorkplaceCategoryId">
<input type="hidden" id="bulkWorkplaceId">
@@ -326,7 +300,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeBulkSettingModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="applyBulkSettings()">
선택한 작업자에 적용
선택한 작업자에 적용
</button>
</div>
</div>
@@ -354,7 +328,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkerSelectionModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="confirmWorkerSelection()">
선택 완료
선택 완료
</button>
</div>
</div>
@@ -392,7 +366,6 @@
<!-- 1단계: 공장 선택 -->
<div style="margin-bottom: 1.5rem;">
<h3 style="font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; color: #374151;">
<span style="margin-right: 0.5rem;">🏭</span>
1. 공장 선택
</h3>
<div id="categoryList" style="display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0.75rem; border: 1px solid #e5e7eb; border-radius: 0.5rem; background: #f9fafb;">
@@ -403,14 +376,12 @@
<!-- 2단계: 작업장 선택 (지도 + 리스트) -->
<div id="workplaceSelectionArea" style="display: none;">
<h3 style="font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; color: #374151;">
<span style="margin-right: 0.5rem;">📍</span>
2. 작업장 선택
</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;">
<span style="margin-right: 0.25rem;">🗺️</span>
지도에서 작업장을 클릭하여 선택하세요
</div>
<div style="text-align: center; position: relative; display: inline-block; max-width: 100%;">
@@ -421,10 +392,7 @@
<!-- 리스트 기반 선택 (오류 대비용) -->
<div>
<div style="font-size: 0.875rem; color: #6b7280; margin-bottom: 0.75rem; display: flex; align-items: center; justify-content: space-between;">
<span>
<span style="margin-right: 0.25rem;">📋</span>
리스트에서 선택 (지도 오류 시)
</span>
<span>리스트에서 선택 (지도 오류 시)</span>
<button type="button" class="btn btn-sm btn-secondary" onclick="toggleWorkplaceList()" id="toggleListBtn">
<span id="toggleListIcon"></span>
리스트 보기
@@ -442,7 +410,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkplaceSelectModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="confirmWorkplaceSelection()" id="confirmWorkplaceBtn" disabled>
선택 완료
선택 완료
</button>
</div>
</div>
@@ -480,7 +448,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeTeamModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="saveTeamComposition()">
👥 팀 구성 완료
팀 구성 완료
</button>
</div>
</div>
@@ -503,7 +471,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeSafetyModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="saveSafetyChecklist()">
안전 체크 완료
안전 체크 완료
</button>
</div>
</div>
@@ -530,7 +498,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeCompleteModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="completeTbmSession()">
완료
완료
</button>
</div>
</div>
@@ -594,7 +562,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeHandoverModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="saveHandover()">
📤 인계 요청
인계 요청
</button>
</div>
</div>