feat: 작업 분석 시스템 및 관리 기능 대폭 개선

 새로운 기능:
- 작업 분석 페이지 구현 (기간별, 프로젝트별, 작업자별, 오류별)
- 개별 분석 실행 버튼으로 API 부하 최적화
- 연차/휴무 집계 방식 개선 (주말 제외, 작업내용 통합)
- 프로젝트 관리 시스템 (활성화/비활성화)
- 작업자 관리 시스템 (CRUD 기능)
- 코드 관리 시스템 (작업유형, 작업상태, 오류유형)

🎨 UI/UX 개선:
- 기간별 작업 현황을 테이블 형태로 변경
- 작업자별 rowspan 그룹화로 가독성 향상
- 연차/휴무 프로젝트 하단 배치 및 시각적 구분
- 기간 확정 시스템으로 사용자 경험 개선
- 반응형 디자인 적용

🔧 기술적 개선:
- Rate Limiting 제거 (내부 시스템 최적화)
- 주말 연차/휴무 자동 제외 로직
- 작업공수 계산 정확도 향상
- 데이터베이스 마이그레이션 추가
- API 엔드포인트 확장 및 최적화

🐛 버그 수정:
- projectSelect 요소 참조 오류 해결
- 차트 높이 무한 증가 문제 해결
- 날짜 표시 형식 단순화
- 작업보고서 저장 validation 오류 수정
This commit is contained in:
Hyungi Ahn
2025-11-04 16:56:47 +09:00
parent 746e09420b
commit de427c457b
46 changed files with 10912 additions and 530 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
<title>작업 현황 확인 - TK 건설</title>
<link rel="stylesheet" href="/css/common.css?v=13">
<link rel="stylesheet" href="/css/modern-dashboard.css?v=13">
<link rel="stylesheet" href="/css/work-report-calendar.css?v=22">
<link rel="stylesheet" href="/css/work-report-calendar.css?v=29">
</head>
<body>
<!-- 대시보드 헤더 -->
@@ -30,6 +30,13 @@
</div>
<div class="header-right">
<div class="header-actions">
<a href="/pages/dashboard/group-leader.html" class="dashboard-btn" title="대시보드로 이동">
<span class="btn-icon">📊</span>
<span class="btn-text">대시보드</span>
</a>
</div>
<div class="user-profile" id="userProfile">
<div class="user-avatar">
<span class="avatar-text" id="userInitial"></span>
@@ -208,71 +215,124 @@
</div>
</div>
<!-- 작업 입력 모달 -->
<!-- 작업 입력/수정 모달 -->
<div id="workEntryModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-container large-modal">
<div class="modal-header">
<h2 id="workEntryModalTitle">작업 입력</h2>
<h2 id="workEntryModalTitle">작업 관리</h2>
<button class="modal-close-btn" onclick="closeWorkEntryModal()">×</button>
</div>
<div class="modal-body">
<form id="workEntryForm">
<!-- 작업자 정보 -->
<div class="form-section">
<h3>작업자 정보</h3>
<div class="form-group">
<label class="form-label">작업자</label>
<input type="text" id="workerNameDisplay" class="form-control" readonly>
<input type="hidden" id="workerId">
</div>
<div class="form-group">
<label class="form-label">작업 날짜</label>
<input type="date" id="workDate" class="form-control" readonly>
</div>
</div>
<!-- 탭 네비게이션 -->
<div class="modal-tabs">
<button class="tab-btn active" data-tab="existing" onclick="switchTab('existing')">
📋 기존 작업 (0건)
</button>
<button class="tab-btn" data-tab="new" onclick="switchTab('new')">
새 작업 추가
</button>
</div>
<!-- 작업 내용 -->
<div class="form-section">
<h3>작업 내용</h3>
<div class="form-group">
<label class="form-label">프로젝트 *</label>
<select id="projectSelect" class="form-control" required>
<option value="">프로젝트를 선택하세요</option>
</select>
</div>
<div class="form-group">
<label class="form-label">작업 시간 (시간) *</label>
<input type="number" id="workHours" class="form-control" min="0" max="24" step="0.5" required>
</div>
<div class="form-group">
<label class="form-label">작업 상태 *</label>
<select id="workStatusSelect" class="form-control" required>
<option value="">상태를 선택하세요</option>
</select>
</div>
<div class="form-group">
<label class="form-label">작업 설명</label>
<textarea id="workDescription" class="form-control" rows="3" placeholder="작업 내용을 상세히 입력하세요"></textarea>
<!-- 기존 작업 목록 탭 -->
<div id="existingWorkTab" class="tab-content active">
<div class="existing-work-header">
<h3>등록된 작업 목록</h3>
<div class="work-summary" id="workSummary">
<span id="totalWorkCount">0</span>건 | 총 <span id="totalWorkHours">0</span>시간
</div>
</div>
<div id="existingWorkList" class="existing-work-list">
<!-- 기존 작업들이 여기에 동적으로 생성됩니다 -->
</div>
<div id="noExistingWork" class="empty-state" style="display: none;">
<div class="empty-icon">📝</div>
<h3>등록된 작업이 없습니다</h3>
<p>"새 작업 추가" 탭에서 작업을 등록해보세요.</p>
</div>
</div>
<!-- 휴가 처리 -->
<div class="form-section">
<h3>휴가 처리</h3>
<div class="vacation-buttons">
<button type="button" class="btn-vacation" onclick="handleVacation('full')">연차 (8시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('half')">반차 (4시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('quarter')">반반차 (2시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('early')">조퇴 (6시간)</button>
<!-- 새 작업 추가 탭 -->
<div id="newWorkTab" class="tab-content">
<form id="workEntryForm">
<!-- 작업자 정보 -->
<div class="form-section">
<h3>작업자 정보</h3>
<div class="form-group">
<label class="form-label">작업자</label>
<input type="text" id="workerNameDisplay" class="form-control" readonly>
<input type="hidden" id="workerId">
<input type="hidden" id="editingWorkId">
</div>
<div class="form-group">
<label class="form-label">작업 날짜</label>
<input type="date" id="workDate" class="form-control" readonly>
</div>
</div>
</div>
</form>
<!-- 작업 내용 -->
<div class="form-section">
<h3 id="workContentTitle">작업 내용</h3>
<div class="form-group">
<label class="form-label">프로젝트 *</label>
<select id="projectSelect" class="form-control" required>
<option value="">프로젝트를 선택하세요</option>
</select>
</div>
<div class="form-group">
<label class="form-label">작업 유형 *</label>
<select id="workTypeSelect" class="form-control" required>
<option value="">작업 유형을 선택하세요</option>
</select>
</div>
<div class="form-group">
<label class="form-label">작업 시간 (시간) *</label>
<input type="number" id="workHours" class="form-control" min="0" max="24" step="0.5" required>
</div>
<div class="form-group">
<label class="form-label">작업 상태 *</label>
<select id="workStatusSelect" class="form-control" required>
<option value="">상태를 선택하세요</option>
</select>
</div>
<div class="form-group">
<label class="form-label">오류 유형</label>
<select id="errorTypeSelect" class="form-control">
<option value="">오류 유형 (선택사항)</option>
</select>
</div>
<div class="form-group">
<label class="form-label">작업 설명</label>
<textarea id="workDescription" class="form-control" rows="3" placeholder="작업 내용을 상세히 입력하세요"></textarea>
</div>
</div>
<!-- 휴가 처리 -->
<div class="form-section" id="vacationSection">
<h3>휴가 처리</h3>
<div class="vacation-buttons">
<button type="button" class="btn-vacation" onclick="handleVacation('full')">연차 (8시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('half')">반차 (4시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('quarter')">반반차 (2시간)</button>
<button type="button" class="btn-vacation" onclick="handleVacation('early')">조퇴 (6시간)</button>
</div>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkEntryModal()">취소</button>
<button type="button" class="btn btn-primary" onclick="saveWorkEntry()">저장</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>
</div>
</div>
</div>
</div>
@@ -281,6 +341,6 @@
<script src="/js/api-config.js?v=13"></script>
<script src="/js/auth-check.js?v=13"></script>
<script src="/js/load-navbar.js?v=13"></script>
<script src="/js/work-report-calendar.js?v=27"></script>
<script src="/js/work-report-calendar.js?v=41"></script>
</body>
</html>

View File

@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>일일 작업보고서 작성 | (주)테크니컬코리아</title>
<link rel="stylesheet" href="/css/design-system.css">
<link rel="stylesheet" href="/css/daily-work-report.css">
<link rel="stylesheet" href="/css/daily-work-report.css?v=2">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js" defer></script>
</head>
@@ -150,9 +150,29 @@
</main>
</div>
<!-- 저장 결과 모달 -->
<div id="saveResultModal" class="modal-overlay" style="display: none;">
<div class="modal-container result-modal">
<div class="modal-header">
<h2 id="resultModalTitle">저장 결과</h2>
<button class="modal-close-btn" onclick="closeSaveResultModal()">×</button>
</div>
<div class="modal-body">
<div id="resultModalContent" class="result-content">
<!-- 결과 내용이 여기에 동적으로 추가됩니다 -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="closeSaveResultModal()">
확인
</button>
</div>
</div>
</div>
<!-- 스크립트 -->
<script src="/js/api-config.js"></script>
<script src="/js/load-navbar.js"></script>
<script src="/js/daily-work-report.js"></script>
<script src="/js/api-config.js?v=2"></script>
<script src="/js/load-navbar.js?v=2"></script>
<script src="/js/daily-work-report.js?v=10"></script>
</body>
</html>

View File

@@ -165,6 +165,6 @@
<!-- 스크립트 -->
<script src="/js/load-navbar.js"></script>
<script src="/js/worker-individual-report.js"></script>
<script src="/js/worker-individual-report.js?v=2"></script>
</body>
</html>

View File

@@ -7,7 +7,7 @@
<!-- 모던 디자인 시스템 적용 -->
<link rel="stylesheet" href="/css/design-system.css">
<link rel="stylesheet" href="/css/modern-dashboard.css">
<link rel="stylesheet" href="/css/modern-dashboard.css?v=2">
<link rel="icon" type="image/png" href="/img/favicon.png">
<!-- 스크립트 (순서 중요: api-config.js가 먼저 로드되어야 함) -->
@@ -96,7 +96,7 @@
<div class="action-arrow"></div>
</a>
<a href="/pages/analysis/daily_work_analysis.html" class="quick-action-card">
<a href="/pages/analysis/work-analysis.html" class="quick-action-card">
<div class="action-icon-large">📈</div>
<div class="action-content">
<h3>작업 분석</h3>
@@ -105,8 +105,8 @@
<div class="action-arrow"></div>
</a>
<a href="/pages/admin/manage-daily-work.html" class="quick-action-card admin-only">
<div class="action-icon-large">⚙️</div>
<a href="/pages/management/work-management.html" class="quick-action-card admin-only">
<div class="action-icon-large">🔧</div>
<div class="action-content">
<h3>작업 관리</h3>
<p>작업자 및 프로젝트를 관리합니다</p>

View File

@@ -0,0 +1,289 @@
<!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/common.css?v=1">
<link rel="stylesheet" href="/css/project-management.css?v=4">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js?v=1" defer></script>
<script src="/js/api-config.js?v=1" defer></script>
</head>
<body>
<!-- 헤더 -->
<header class="dashboard-header">
<div class="header-left">
<div class="logo-section">
<img src="/img/logo.png" alt="테크니컬코리아" class="logo">
<div class="company-info">
<h1 class="company-name">테크니컬코리아</h1>
<p class="company-subtitle">코드 관리</p>
</div>
</div>
</div>
<div class="header-center">
<div class="current-time">
<span class="time-label">현재 시각</span>
<span class="time-value" id="timeValue">--:--:--</span>
</div>
</div>
<div class="header-right">
<div class="header-actions">
<a href="/pages/management/work-management.html" class="back-btn" title="작업 관리로 돌아가기">
<span class="btn-icon"></span>
<span class="btn-text">작업 관리</span>
</a>
<a href="/pages/dashboard/group-leader.html" class="dashboard-btn" title="대시보드로 이동">
<span class="btn-icon">📊</span>
<span class="btn-text">대시보드</span>
</a>
</div>
<div class="user-profile" id="userProfile">
<div class="user-avatar">
<span class="avatar-text" id="userInitial"></span>
</div>
<div class="user-info">
<span class="user-name" id="userName">사용자</span>
<span class="user-role" id="userRole">작업자</span>
</div>
<div class="profile-dropdown" id="profileMenu" style="display: none;">
<button class="dropdown-item logout-btn" id="logoutBtn">
<span class="dropdown-icon">🚪</span>
로그아웃
</button>
</div>
</div>
</div>
</header>
<!-- 메인 콘텐츠 -->
<main class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🏷️</span>
코드 관리
</h1>
<p class="page-description">작업 상태, 오류 유형, 작업 유형 등 시스템에서 사용하는 코드를 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-secondary" onclick="refreshAllCodes()">
<span class="btn-icon">🔄</span>
전체 새로고침
</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>
</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>
<div class="section-actions">
<button class="btn btn-primary" onclick="openCodeModal('work-status')">
<span class="btn-icon"></span>
새 상태 추가
</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>
</div>
<div class="code-grid" id="workStatusGrid">
<!-- 작업 상태 유형 카드들이 여기에 동적으로 생성됩니다 -->
</div>
</div>
</div>
<!-- 오류 유형 관리 -->
<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>
<div class="section-actions">
<button class="btn btn-primary" onclick="openCodeModal('error-types')">
<span class="btn-icon"></span>
새 오류 유형 추가
</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>
</div>
<div class="code-grid" id="errorTypesGrid">
<!-- 오류 유형 카드들이 여기에 동적으로 생성됩니다 -->
</div>
</div>
</div>
<!-- 작업 유형 관리 -->
<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>
<div class="section-actions">
<button class="btn btn-primary" onclick="openCodeModal('work-types')">
<span class="btn-icon"></span>
새 작업 유형 추가
</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>
</div>
<div class="code-grid" id="workTypesGrid">
<!-- 작업 유형 카드들이 여기에 동적으로 생성됩니다 -->
</div>
</div>
</div>
</main>
<!-- 코드 추가/수정 모달 -->
<div id="codeModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h2 id="modalTitle">코드 추가</h2>
<button class="modal-close-btn" onclick="closeCodeModal()">×</button>
</div>
<div class="modal-body">
<form id="codeForm" onsubmit="event.preventDefault(); saveCode();">
<input type="hidden" id="codeId">
<input type="hidden" id="codeType">
<!-- 공통 필드 -->
<div class="form-group">
<label class="form-label">이름 *</label>
<input type="text" id="codeName" class="form-control" placeholder="코드명을 입력하세요" required>
</div>
<div class="form-group">
<label class="form-label">설명</label>
<textarea id="codeDescription" class="form-control" rows="3" placeholder="상세 설명을 입력하세요"></textarea>
</div>
<!-- 작업 상태 유형 전용 필드 -->
<div class="form-group" id="isErrorGroup" style="display: none;">
<label class="form-label">
<input type="checkbox" id="isError" class="form-checkbox">
오류 상태로 분류
</label>
<small class="form-help">체크하면 이 상태는 오류로 간주됩니다</small>
</div>
<!-- 오류 유형 전용 필드 -->
<div class="form-group" id="severityGroup" style="display: none;">
<label class="form-label">심각도 *</label>
<select id="severity" class="form-control">
<option value="low">낮음 (Low)</option>
<option value="medium" selected>보통 (Medium)</option>
<option value="high">높음 (High)</option>
<option value="critical">심각 (Critical)</option>
</select>
</div>
<div class="form-group" id="solutionGuideGroup" style="display: none;">
<label class="form-label">해결 가이드</label>
<textarea id="solutionGuide" class="form-control" rows="4" placeholder="이 오류 발생 시 해결 방법을 입력하세요"></textarea>
</div>
<!-- 작업 유형 전용 필드 -->
<div class="form-group" id="categoryGroup" style="display: none;">
<label class="form-label">카테고리</label>
<input type="text" id="category" class="form-control" placeholder="작업 카테고리 (예: PKG, Vessel)" list="categoryList">
<datalist id="categoryList">
<!-- 기존 카테고리 목록이 여기에 동적으로 생성됩니다 -->
</datalist>
</div>
</form>
</div>
<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>
</div>
</div>
</div>
<script src="/js/code-management.js?v=1"></script>
</body>
</html>

View File

@@ -0,0 +1,251 @@
<!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/common.css?v=1">
<link rel="stylesheet" href="/css/project-management.css?v=4">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js" defer></script>
</head>
<body>
<!-- 헤더 -->
<header class="dashboard-header">
<div class="header-left">
<div class="logo-section">
<img src="/img/logo.png" alt="테크니컬코리아" class="logo">
<div class="company-info">
<h1 class="company-name">테크니컬코리아</h1>
<span class="company-subtitle">생산팀 포털</span>
</div>
</div>
</div>
<div class="header-center">
<div class="current-time" id="currentTime">
<span class="time-label">현재 시간</span>
<span class="time-value" id="timeValue">--:--:--</span>
</div>
</div>
<div class="header-right">
<div class="header-actions">
<a href="/pages/management/work-management.html" class="back-btn" title="작업관리로 돌아가기">
<span class="btn-icon"></span>
<span class="btn-text">작업관리</span>
</a>
<a href="/pages/dashboard/group-leader.html" class="dashboard-btn" title="대시보드로 이동">
<span class="btn-icon">📊</span>
<span class="btn-text">대시보드</span>
</a>
</div>
<div class="user-profile" id="userProfile">
<div class="user-avatar" id="userInitial"></div>
<div class="user-info">
<span class="user-name" id="userName">사용자</span>
<span class="user-role" id="userRole">작업자</span>
</div>
<div class="profile-dropdown" id="profileMenu" style="display: none;">
<a href="/pages/profile/my-profile.html" class="dropdown-item">
<span class="dropdown-icon">👤</span>
내 프로필
</a>
<a href="/pages/profile/settings.html" class="dropdown-item">
<span class="dropdown-icon">⚙️</span>
설정
</a>
<div class="dropdown-divider"></div>
<button class="dropdown-item logout-btn" id="logoutBtn">
<span class="dropdown-icon">🚪</span>
로그아웃
</button>
</div>
</div>
</div>
</header>
<!-- 메인 콘텐츠 -->
<main class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">📁</span>
프로젝트 관리
</h1>
<p class="page-description">프로젝트 등록, 수정, 삭제 및 기본 정보를 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="openProjectModal()">
<span class="btn-icon"></span>
새 프로젝트 등록
</button>
<button class="btn btn-secondary" onclick="refreshProjectList()">
<span class="btn-icon">🔄</span>
새로고침
</button>
</div>
</div>
<!-- 검색 및 필터 -->
<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>
</div>
<div class="filter-options">
<select id="statusFilter" class="filter-select" onchange="filterProjects()">
<option value="">전체 상태</option>
<option value="active">진행중</option>
<option value="completed">완료</option>
<option value="paused">중단</option>
</select>
<select id="sortBy" class="filter-select" onchange="sortProjects()">
<option value="created_at">등록일순</option>
<option value="project_name">프로젝트명순</option>
<option value="due_date">납기일순</option>
</select>
</div>
</div>
<!-- 프로젝트 목록 -->
<div class="projects-section">
<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>
</div>
</div>
<div class="projects-grid" id="projectsGrid">
<!-- 프로젝트 카드들이 여기에 동적으로 생성됩니다 -->
</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>
</div>
</div>
</main>
<!-- 프로젝트 등록/수정 모달 -->
<div id="projectModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h2 id="modalTitle">새 프로젝트 등록</h2>
<button class="modal-close-btn" onclick="closeProjectModal()">×</button>
</div>
<div class="modal-body">
<form id="projectForm">
<input type="hidden" id="projectId">
<div class="form-row">
<div class="form-group">
<label class="form-label">Job No. *</label>
<input type="text" id="jobNo" class="form-control" required placeholder="예: TK-2024-001">
</div>
<div class="form-group">
<label class="form-label">프로젝트명 *</label>
<input type="text" id="projectName" class="form-control" required placeholder="프로젝트명을 입력하세요">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">계약일</label>
<input type="date" id="contractDate" class="form-control">
</div>
<div class="form-group">
<label class="form-label">납기일</label>
<input type="date" id="dueDate" class="form-control">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">납품방법</label>
<select id="deliveryMethod" class="form-control">
<option value="">선택하세요</option>
<option value="직접납품">직접납품</option>
<option value="택배">택배</option>
<option value="화물">화물</option>
<option value="현장설치">현장설치</option>
</select>
</div>
<div class="form-group">
<label class="form-label">현장</label>
<input type="text" id="site" class="form-control" placeholder="현장 위치를 입력하세요">
</div>
</div>
<div class="form-group">
<label class="form-label">PM (프로젝트 매니저)</label>
<input type="text" id="pm" class="form-control" placeholder="담당 PM을 입력하세요">
</div>
<div class="form-row">
<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>
</select>
</div>
<div class="form-group">
<label class="form-label">완료일 (납품일)</label>
<input type="date" id="completedDate" class="form-control">
</div>
</div>
<div class="form-group">
<label class="form-label" style="display: flex; align-items: center; gap: 0.5rem;">
<input type="checkbox" id="isActive" checked style="margin: 0;">
<span>프로젝트 활성화</span>
</label>
<small style="color: #6b7280; font-size: 0.8rem;">체크 해제 시 작업보고서 입력에서 숨겨집니다</small>
</div>
</form>
</div>
<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>
</div>
</div>
</div>
<!-- JavaScript -->
<script src="/js/api-config.js?v=13"></script>
<script src="/js/project-management.js?v=1"></script>
</body>
</html>

View File

@@ -0,0 +1,181 @@
<!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/common.css?v=1">
<link rel="stylesheet" href="/css/work-management.css?v=1">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js" defer></script>
</head>
<body>
<!-- 헤더 -->
<header class="dashboard-header">
<div class="header-left">
<div class="logo-section">
<img src="/img/logo.png" alt="테크니컬코리아" class="logo">
<div class="company-info">
<h1 class="company-name">테크니컬코리아</h1>
<span class="company-subtitle">생산팀 포털</span>
</div>
</div>
</div>
<div class="header-center">
<div class="current-time" id="currentTime">
<span class="time-label">현재 시간</span>
<span class="time-value" id="timeValue">--:--:--</span>
</div>
</div>
<div class="header-right">
<div class="header-actions">
<a href="/pages/dashboard/group-leader.html" class="dashboard-btn" title="대시보드로 이동">
<span class="btn-icon">📊</span>
<span class="btn-text">대시보드</span>
</a>
</div>
<div class="user-profile" id="userProfile">
<div class="user-avatar" id="userInitial"></div>
<div class="user-info">
<span class="user-name" id="userName">사용자</span>
<span class="user-role" id="userRole">작업자</span>
</div>
<div class="profile-dropdown" id="profileMenu" style="display: none;">
<a href="/pages/profile/my-profile.html" class="dropdown-item">
<span class="dropdown-icon">👤</span>
내 프로필
</a>
<a href="/pages/profile/settings.html" class="dropdown-item">
<span class="dropdown-icon">⚙️</span>
설정
</a>
<div class="dropdown-divider"></div>
<button class="dropdown-item logout-btn" id="logoutBtn">
<span class="dropdown-icon">🚪</span>
로그아웃
</button>
</div>
</div>
</div>
</header>
<!-- 메인 콘텐츠 -->
<main class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">🔧</span>
작업 관리
</h1>
<p class="page-description">프로젝트, 작업자, 작업 유형 등 기본 데이터를 관리합니다</p>
</div>
</div>
<!-- 관리 메뉴 카드들 -->
<div class="management-grid">
<!-- 프로젝트 관리 -->
<div class="management-card" onclick="navigateToPage('/pages/management/project-management.html')">
<div class="card-header">
<div class="card-icon">📁</div>
<h3 class="card-title">프로젝트 관리</h3>
</div>
<div class="card-content">
<p class="card-description">프로젝트 등록, 수정, 삭제 및 기본 정보 관리</p>
<div class="card-stats">
<div class="stat-item">
<span class="stat-label">등록된 프로젝트</span>
<span class="stat-value" id="projectCount">-</span>
</div>
</div>
</div>
<div class="card-footer">
<span class="card-action">관리하기 →</span>
</div>
</div>
<!-- 작업자 관리 -->
<div class="management-card" onclick="navigateToPage('/pages/management/worker-management.html')">
<div class="card-header">
<div class="card-icon">👥</div>
<h3 class="card-title">작업자 관리</h3>
</div>
<div class="card-content">
<p class="card-description">작업자 등록, 수정, 비활성화 및 정보 관리</p>
<div class="card-stats">
<div class="stat-item">
<span class="stat-label">활성 작업자</span>
<span class="stat-value" id="workerCount">-</span>
</div>
</div>
</div>
<div class="card-footer">
<span class="card-action">관리하기 →</span>
</div>
</div>
<!-- 코드 관리 -->
<div class="management-card" onclick="navigateToPage('/pages/management/code-management.html')">
<div class="card-header">
<div class="card-icon">🏷️</div>
<h3 class="card-title">코드 관리</h3>
</div>
<div class="card-content">
<p class="card-description">이슈 타입, 에러 타입, 작업 상태 등 코드 관리</p>
<div class="card-stats">
<div class="stat-item">
<span class="stat-label">코드 타입</span>
<span class="stat-value" id="codeTypeCount">-</span>
</div>
</div>
</div>
<div class="card-footer">
<span class="card-action">관리하기 →</span>
</div>
</div>
</div>
<!-- 최근 활동 -->
<div class="recent-activity-section">
<div class="section-header">
<h2 class="section-title">최근 관리 활동</h2>
<button class="refresh-btn" onclick="loadRecentActivity()">
<span class="refresh-icon">🔄</span>
새로고침
</button>
</div>
<div class="activity-list" id="activityList">
<div class="activity-item">
<div class="activity-icon">📁</div>
<div class="activity-content">
<div class="activity-title">효성화학 에틸렌 탱크 건설공사 프로젝트가 수정되었습니다</div>
<div class="activity-meta">
<span class="activity-user">김두수</span>
<span class="activity-time">2시간 전</span>
</div>
</div>
</div>
<div class="activity-item">
<div class="activity-icon">👥</div>
<div class="activity-content">
<div class="activity-title">새로운 작업자가 등록되었습니다</div>
<div class="activity-meta">
<span class="activity-user">관리자</span>
<span class="activity-time">1일 전</span>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- JavaScript -->
<script src="/js/api-config.js?v=13"></script>
<script src="/js/work-management.js?v=1"></script>
</body>
</html>

View File

@@ -0,0 +1,232 @@
<!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/common.css?v=1">
<link rel="stylesheet" href="/css/project-management.css?v=3">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/auth-check.js?v=1" defer></script>
<script src="/js/api-config.js?v=1" defer></script>
</head>
<body>
<!-- 헤더 -->
<header class="dashboard-header">
<div class="header-left">
<div class="logo-section">
<img src="/img/logo.png" alt="테크니컬코리아" class="logo">
<div class="company-info">
<h1 class="company-name">테크니컬코리아</h1>
<p class="company-subtitle">작업자 관리</p>
</div>
</div>
</div>
<div class="header-center">
<div class="current-time">
<span class="time-label">현재 시각</span>
<span class="time-value" id="timeValue">--:--:--</span>
</div>
</div>
<div class="header-right">
<div class="header-actions">
<a href="/pages/management/work-management.html" class="back-btn" title="작업 관리로 돌아가기">
<span class="btn-icon"></span>
<span class="btn-text">작업 관리</span>
</a>
<a href="/pages/dashboard/group-leader.html" class="dashboard-btn" title="대시보드로 이동">
<span class="btn-icon">📊</span>
<span class="btn-text">대시보드</span>
</a>
</div>
<div class="user-profile" id="userProfile">
<div class="user-avatar">
<span class="avatar-text" id="userInitial"></span>
</div>
<div class="user-info">
<span class="user-name" id="userName">사용자</span>
<span class="user-role" id="userRole">작업자</span>
</div>
<div class="profile-dropdown" id="profileMenu" style="display: none;">
<button class="dropdown-item logout-btn" id="logoutBtn">
<span class="dropdown-icon">🚪</span>
로그아웃
</button>
</div>
</div>
</div>
</header>
<!-- 메인 콘텐츠 -->
<main class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">
<span class="title-icon">👥</span>
작업자 관리
</h1>
<p class="page-description">작업자 등록, 수정, 삭제 및 기본 정보를 관리합니다</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" onclick="openWorkerModal()">
<span class="btn-icon"></span>
새 작업자 등록
</button>
<button class="btn btn-secondary" onclick="refreshWorkerList()">
<span class="btn-icon">🔄</span>
새로고침
</button>
</div>
</div>
<!-- 검색 및 필터 -->
<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>
</div>
<div class="filter-options">
<select id="jobTypeFilter" class="filter-select" onchange="filterWorkers()">
<option value="">모든 직책</option>
<option value="leader">그룹장</option>
<option value="worker">작업자</option>
<option value="admin">관리자</option>
</select>
<select id="statusFilter" class="filter-select" onchange="filterWorkers()">
<option value="">모든 상태</option>
<option value="active">활성</option>
<option value="inactive">비활성</option>
</select>
<select id="sortBy" class="filter-select" onchange="sortWorkers()">
<option value="created_at">등록일순</option>
<option value="worker_name">이름순</option>
<option value="job_type">직책순</option>
</select>
</div>
</div>
<!-- 작업자 목록 -->
<div class="projects-section">
<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>
</div>
</div>
<div class="projects-grid" id="workersGrid">
<!-- 작업자 카드들이 여기에 동적으로 생성됩니다 -->
</div>
<!-- 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>
</div>
</div>
</main>
<!-- 작업자 추가/수정 모달 -->
<div id="workerModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h2 id="modalTitle">새 작업자 등록</h2>
<button class="modal-close-btn" onclick="closeWorkerModal()">×</button>
</div>
<div class="modal-body">
<form id="workerForm" onsubmit="event.preventDefault(); saveWorker();">
<input type="hidden" id="workerId">
<div class="form-row">
<div class="form-group">
<label class="form-label">작업자명 *</label>
<input type="text" id="workerName" class="form-control" placeholder="작업자 이름을 입력하세요" required>
</div>
<div class="form-group">
<label class="form-label">직책</label>
<select id="jobType" class="form-control">
<option value="worker">👷 작업자</option>
<option value="leader">👨‍💼 그룹장</option>
<option value="admin">👨‍💻 관리자</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">전화번호</label>
<input type="tel" id="phoneNumber" class="form-control" placeholder="010-0000-0000">
</div>
<div class="form-group">
<label class="form-label">이메일</label>
<input type="email" id="email" class="form-control" placeholder="example@company.com">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">입사일</label>
<input type="date" id="hireDate" class="form-control">
</div>
<div class="form-group">
<label class="form-label">부서</label>
<input type="text" id="department" class="form-control" placeholder="소속 부서">
</div>
</div>
<div class="form-group">
<label class="form-label">비고</label>
<textarea id="notes" class="form-control" rows="3" placeholder="추가 정보나 특이사항을 입력하세요"></textarea>
</div>
<div class="form-group">
<label class="form-label" style="display: flex; align-items: center; gap: 0.5rem;">
<input type="checkbox" id="isActive" checked style="margin: 0;">
<span>작업자 활성화</span>
</label>
<small style="color: #6b7280; font-size: 0.8rem;">체크 해제 시 작업보고서 입력에서 숨겨집니다</small>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeWorkerModal()">취소</button>
<button type="button" class="btn btn-danger" id="deleteWorkerBtn" onclick="deleteWorker()" style="display: none;">
🗑️ 삭제
</button>
<button type="button" class="btn btn-primary" onclick="saveWorker()">
💾 저장
</button>
</div>
</div>
</div>
<script src="/js/worker-management.js?v=3"></script>
</body>
</html>