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

@@ -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) {