## 주요 변경사항
### 1. 미사용 페이지 아카이브 (24개)
- admin 폴더 전체 (8개) → .archived-admin/
- 분석 페이지 (5개) → .archived-*
- 공통 페이지 (5개) → .archived-*
- 대시보드 페이지 (2개) → .archived-*
- 기타 (4개) → .archived-*
### 2. 새로운 폴더 구조
```
pages/
├── dashboard.html (메인 대시보드)
├── work/ (작업 관련)
│ ├── report-create.html (작업보고서 작성)
│ ├── report-view.html (작업보고서 조회)
│ └── analysis.html (작업 분석)
├── admin/ (관리 기능)
│ ├── index.html (관리 메뉴 허브)
│ ├── projects.html (프로젝트 관리)
│ ├── workers.html (작업자 관리)
│ ├── codes.html (코드 관리)
│ └── accounts.html (계정 관리)
└── profile/ (프로필)
├── info.html (내 정보)
└── password.html (비밀번호 변경)
```
### 3. 파일명 개선
- group-leader.html → dashboard.html
- daily-work-report.html → work/report-create.html
- daily-work-report-viewer.html → work/report-view.html
- work-analysis.html → work/analysis.html
- work-management.html → admin/index.html
- project-management.html → admin/projects.html
- worker-management.html → admin/workers.html
- code-management.html → admin/codes.html
- my-profile.html → profile/info.html
- change-password.html → profile/password.html
- admin-settings.html → admin/accounts.html
### 4. 내부 링크 전면 수정
- navbar.html 프로필 메뉴 링크 업데이트
- dashboard.html 빠른 작업 링크 업데이트
- admin/* 페이지 간 링크 업데이트
- load-navbar.js 대시보드 경로 수정
영향받는 파일: 39개
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
723 lines
16 KiB
HTML
723 lines
16 KiB
HTML
<!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/main-layout.css">
|
|
<link rel="stylesheet" href="/css/admin.css">
|
|
<link rel="stylesheet" href="/css/work-report.css">
|
|
<link rel="icon" type="image/png" href="/img/favicon.png">
|
|
<script src="/js/auth-check.js" defer></script>
|
|
<style>
|
|
/* 검토 페이지 전용 스타일 */
|
|
.review-container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
display: grid;
|
|
grid-template-columns: 1fr 350px;
|
|
gap: 24px;
|
|
min-height: calc(100vh - 200px);
|
|
}
|
|
|
|
.main-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24px;
|
|
}
|
|
|
|
/* 상단 대시보드 */
|
|
.dashboard-section {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 16px;
|
|
}
|
|
|
|
.dashboard-card {
|
|
background: white;
|
|
padding: 24px;
|
|
border-radius: 12px;
|
|
border: 1px solid #e1e5e9;
|
|
text-align: center;
|
|
transition: transform 0.2s ease;
|
|
}
|
|
|
|
.dashboard-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.dashboard-number {
|
|
font-size: 32px;
|
|
font-weight: 700;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.dashboard-label {
|
|
color: #666;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.dashboard-card.total .dashboard-number { color: #007bff; }
|
|
.dashboard-card.error .dashboard-number { color: #dc3545; }
|
|
.dashboard-card.warning .dashboard-number { color: #ffc107; }
|
|
.dashboard-card.missing .dashboard-number { color: #6c757d; }
|
|
|
|
/* 필터 섹션 */
|
|
.filter-section {
|
|
background: white;
|
|
padding: 24px;
|
|
border-radius: 12px;
|
|
border: 1px solid #e1e5e9;
|
|
}
|
|
|
|
.filter-row {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 16px;
|
|
align-items: end;
|
|
}
|
|
|
|
.filter-group label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: 600;
|
|
color: #555;
|
|
}
|
|
|
|
.filter-input {
|
|
width: 100%;
|
|
padding: 12px;
|
|
border: 2px solid #e1e5e9;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.filter-input:focus {
|
|
outline: none;
|
|
border-color: #007bff;
|
|
}
|
|
|
|
.filter-btn {
|
|
padding: 12px 24px;
|
|
background: #007bff;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.filter-btn:hover {
|
|
background: #0056b3;
|
|
}
|
|
|
|
/* 알림 영역 */
|
|
.alerts-section {
|
|
background: white;
|
|
border-radius: 12px;
|
|
border: 1px solid #e1e5e9;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.alerts-header {
|
|
background: #f8f9fa;
|
|
padding: 16px 24px;
|
|
border-bottom: 1px solid #e1e5e9;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.alert-item {
|
|
padding: 16px 24px;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.alert-item:hover {
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.alert-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.alert-type {
|
|
display: inline-block;
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
margin-right: 12px;
|
|
}
|
|
|
|
.alert-type.error {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
.alert-type.warning {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
.alert-type.missing {
|
|
background: #d1ecf1;
|
|
color: #0c5460;
|
|
}
|
|
|
|
.alert-type.pending {
|
|
background: #e2e3e5;
|
|
color: #383d41;
|
|
}
|
|
|
|
.alert-content {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.alert-text {
|
|
flex: 1;
|
|
}
|
|
|
|
.alert-time {
|
|
color: #666;
|
|
font-size: 12px;
|
|
}
|
|
|
|
/* 메인 테이블 */
|
|
.table-section {
|
|
background: white;
|
|
border-radius: 12px;
|
|
border: 1px solid #e1e5e9;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.table-header {
|
|
background: #f8f9fa;
|
|
padding: 16px 24px;
|
|
border-bottom: 1px solid #e1e5e9;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.table-title {
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.table-actions {
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
|
|
.action-btn {
|
|
padding: 8px 16px;
|
|
border: 1px solid #dee2e6;
|
|
background: white;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.action-btn:hover {
|
|
border-color: #007bff;
|
|
color: #007bff;
|
|
}
|
|
|
|
.data-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.data-table th {
|
|
background: #f8f9fa;
|
|
padding: 16px;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
color: #555;
|
|
border-bottom: 2px solid #e1e5e9;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.data-table td {
|
|
padding: 16px;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.data-table tr {
|
|
transition: background 0.2s;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.data-table tr:hover {
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.data-table tr.selected {
|
|
background: #e7f3ff;
|
|
border-left: 4px solid #007bff;
|
|
}
|
|
|
|
/* 상태 표시 */
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-badge.normal {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.status-badge.error {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
.row-normal { background: #fff; }
|
|
.row-warning { background: #fffbf0; border-left: 4px solid #ffc107; }
|
|
.row-error { background: #fef5f5; border-left: 4px solid #dc3545; }
|
|
.row-missing { background: #f0f8ff; border-left: 4px solid #6c757d; }
|
|
.row-reviewed { background: #f0f9ff; border-left: 4px solid #28a745; }
|
|
|
|
/* 새로운 배지 스타일 */
|
|
.attendance-badge {
|
|
display: inline-block;
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.attendance-badge.NORMAL {
|
|
background: #e3f2fd;
|
|
color: #1565c0;
|
|
}
|
|
|
|
.attendance-badge.HALF_DAY {
|
|
background: #fff3e0;
|
|
color: #ef6c00;
|
|
}
|
|
|
|
.attendance-badge.HALF_HALF_DAY {
|
|
background: #f3e5f5;
|
|
color: #7b1fa2;
|
|
}
|
|
|
|
.attendance-badge.EARLY_LEAVE {
|
|
background: #ffebee;
|
|
color: #c62828;
|
|
}
|
|
|
|
.hours-status-badge {
|
|
display: inline-block;
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.hours-status-badge.NORMAL {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.hours-status-badge.UNDER {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
.hours-status-badge.OVER {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
.review-badge {
|
|
display: inline-block;
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.review-badge.reviewed {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.review-badge.pending {
|
|
background: #ffeaa7;
|
|
color: #856404;
|
|
}
|
|
|
|
.review-complete-btn {
|
|
background: #28a745;
|
|
color: white;
|
|
border: none;
|
|
padding: 6px 12px;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.review-complete-btn:hover {
|
|
background: #1e7e34;
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
/* 우측 수정 패널 */
|
|
.edit-panel {
|
|
background: white;
|
|
border-radius: 12px;
|
|
border: 1px solid #e1e5e9;
|
|
position: sticky;
|
|
top: 24px;
|
|
height: fit-content;
|
|
max-height: calc(100vh - 48px);
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.panel-header {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
border-bottom: 1px solid #e1e5e9;
|
|
}
|
|
|
|
.panel-title {
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.panel-subtitle {
|
|
color: #666;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.panel-content {
|
|
padding: 24px;
|
|
}
|
|
|
|
.panel-empty {
|
|
text-align: center;
|
|
color: #999;
|
|
padding: 60px 20px;
|
|
}
|
|
|
|
.panel-empty-icon {
|
|
font-size: 48px;
|
|
margin-bottom: 16px;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: 600;
|
|
color: #555;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.form-input {
|
|
width: 100%;
|
|
padding: 12px;
|
|
border: 2px solid #e1e5e9;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.form-input:focus {
|
|
outline: none;
|
|
border-color: #007bff;
|
|
}
|
|
|
|
.panel-actions {
|
|
padding: 20px;
|
|
border-top: 1px solid #e1e5e9;
|
|
background: #f8f9fa;
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
|
|
.panel-btn {
|
|
flex: 1;
|
|
padding: 12px;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.panel-btn.save {
|
|
background: #28a745;
|
|
color: white;
|
|
}
|
|
|
|
.panel-btn.save:hover {
|
|
background: #1e7e34;
|
|
}
|
|
|
|
.panel-btn.delete {
|
|
background: #dc3545;
|
|
color: white;
|
|
}
|
|
|
|
.panel-btn.delete:hover {
|
|
background: #c82333;
|
|
}
|
|
|
|
.panel-btn.cancel {
|
|
background: #6c757d;
|
|
color: white;
|
|
}
|
|
|
|
.panel-btn.cancel:hover {
|
|
background: #545b62;
|
|
}
|
|
|
|
/* 로딩 및 메시지 */
|
|
.loading-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0,0,0,0.5);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.loading-spinner {
|
|
background: white;
|
|
padding: 40px;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
}
|
|
|
|
.message {
|
|
padding: 16px 24px;
|
|
border-radius: 8px;
|
|
margin-bottom: 24px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.message.error {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
border: 1px solid #f5c6cb;
|
|
}
|
|
|
|
.message.success {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
border: 1px solid #c3e6cb;
|
|
}
|
|
|
|
.message.info {
|
|
background: #d1ecf1;
|
|
color: #0c5460;
|
|
border: 1px solid #bee5eb;
|
|
}
|
|
|
|
.message.warning {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
border: 1px solid #ffeaa7;
|
|
}
|
|
|
|
/* 반응형 */
|
|
@media (max-width: 1200px) {
|
|
.review-container {
|
|
grid-template-columns: 1fr;
|
|
gap: 16px;
|
|
}
|
|
|
|
.edit-panel {
|
|
position: relative;
|
|
top: 0;
|
|
max-height: none;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.dashboard-section {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
|
|
.filter-row {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.table-section {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.data-table {
|
|
min-width: 800px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="main-layout">
|
|
<div id="navbar-container"></div>
|
|
|
|
<div class="content-wrapper">
|
|
<div id="sidebar-container"></div>
|
|
|
|
<div id="content-container">
|
|
<div class="page-header">
|
|
<h1>🔍 작업보고서 검토</h1>
|
|
<p class="subtitle">전체 현황을 파악하고 이상 사항을 빠르게 처리하세요.</p>
|
|
</div>
|
|
|
|
<!-- 메시지 영역 -->
|
|
<div id="message-container"></div>
|
|
|
|
<div class="review-container">
|
|
<!-- 메인 콘텐츠 -->
|
|
<div class="main-content">
|
|
<!-- 상단 대시보드 -->
|
|
<div class="dashboard-section">
|
|
<div class="dashboard-card total">
|
|
<div class="dashboard-number" id="totalReports">-</div>
|
|
<div class="dashboard-label">총 보고서</div>
|
|
</div>
|
|
<div class="dashboard-card error">
|
|
<div class="dashboard-number" id="errorReports">-</div>
|
|
<div class="dashboard-label">에러 발생</div>
|
|
</div>
|
|
<div class="dashboard-card warning">
|
|
<div class="dashboard-number" id="warningReports">-</div>
|
|
<div class="dashboard-label">주의 필요</div>
|
|
</div>
|
|
<div class="dashboard-card missing">
|
|
<div class="dashboard-number" id="missingReports">-</div>
|
|
<div class="dashboard-label">미검토</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 필터 섹션 -->
|
|
<div class="filter-section">
|
|
<div class="filter-row">
|
|
<div class="filter-group">
|
|
<label>시작 날짜</label>
|
|
<input type="date" id="startDate" class="filter-input">
|
|
</div>
|
|
<div class="filter-group">
|
|
<label>종료 날짜</label>
|
|
<input type="date" id="endDate" class="filter-input">
|
|
</div>
|
|
<div class="filter-group">
|
|
<label>작업자</label>
|
|
<select id="workerFilter" class="filter-input">
|
|
<option value="">전체 작업자</option>
|
|
</select>
|
|
</div>
|
|
<div class="filter-group">
|
|
<label>프로젝트</label>
|
|
<select id="projectFilter" class="filter-input">
|
|
<option value="">전체 프로젝트</option>
|
|
</select>
|
|
</div>
|
|
<div class="filter-group">
|
|
<button type="button" id="applyFilter" class="filter-btn">필터 적용</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 알림 영역 -->
|
|
<div class="alerts-section">
|
|
<div class="alerts-header">
|
|
🚨 주의 필요 항목
|
|
</div>
|
|
<div id="alertsList">
|
|
<!-- 알림 항목들이 여기에 표시됩니다 -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 메인 테이블 -->
|
|
<div class="table-section">
|
|
<div class="table-header">
|
|
<div class="table-title">작업보고서 목록</div>
|
|
<div class="table-actions">
|
|
<button class="action-btn" id="refreshBtn">🔄 새로고침</button>
|
|
<button class="action-btn" id="exportBtn">📊 내보내기</button>
|
|
</div>
|
|
</div>
|
|
<div style="overflow-x: auto;">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>날짜</th>
|
|
<th>작업자</th>
|
|
<th>출근형태</th>
|
|
<th>기대시간</th>
|
|
<th>실제시간</th>
|
|
<th>시간상태</th>
|
|
<th>프로젝트</th>
|
|
<th>작업유형</th>
|
|
<th>상태</th>
|
|
<th>검토상태</th>
|
|
<th>액션</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="reportsTableBody">
|
|
<!-- 데이터가 여기에 표시됩니다 -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 우측 수정 패널 -->
|
|
<div class="edit-panel">
|
|
<div class="panel-header">
|
|
<div class="panel-title">빠른 수정</div>
|
|
<div class="panel-subtitle">항목을 선택하여 수정하세요</div>
|
|
</div>
|
|
<div class="panel-content" id="editPanelContent">
|
|
<div class="panel-empty">
|
|
<div class="panel-empty-icon">📝</div>
|
|
<div>수정할 항목을 선택해주세요</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 로딩 오버레이 -->
|
|
<div id="loadingOverlay" class="loading-overlay" style="display: none;">
|
|
<div class="loading-spinner">
|
|
<div style="font-size: 24px; margin-bottom: 16px;">⏳</div>
|
|
<div>데이터를 처리하는 중...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module" src="/js/load-navbar.js"></script>
|
|
<script type="module" src="/js/load-sidebar.js"></script>
|
|
<script type="module" src="/js/work-report-review.js"></script>
|
|
</body>
|
|
</html> |