feat(tkfb): 공정표 + 생산회의록 시스템 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
199
system1-factory/web/pages/work/meeting-detail.html
Normal file
199
system1-factory/web/pages/work/meeting-detail.html
Normal file
@@ -0,0 +1,199 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>회의록 상세 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031701">
|
||||
<style>
|
||||
.attendee-tag { display: inline-flex; align-items: center; gap: 4px; background: #eff6ff; color: #2563eb; padding: 2px 8px; border-radius: 9999px; font-size: 0.75rem; }
|
||||
.attendee-tag .remove-btn { cursor: pointer; color: #93c5fd; }
|
||||
.attendee-tag .remove-btn:hover { color: #dc2626; }
|
||||
.user-search-results { position: absolute; top: 100%; left: 0; right: 0; background: white; border: 1px solid #e2e8f0; border-radius: 0.5rem; max-height: 200px; overflow-y: auto; z-index: 50; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
||||
.user-search-item { padding: 0.5rem 0.75rem; cursor: pointer; font-size: 0.875rem; }
|
||||
.user-search-item:hover { background: #f1f5f9; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- 상단 -->
|
||||
<div class="flex items-center gap-3 mb-5">
|
||||
<a href="/pages/work/meetings.html" class="text-gray-400 hover:text-gray-600"><i class="fas fa-arrow-left"></i></a>
|
||||
<h2 id="pageTitle" class="text-xl font-bold text-gray-800">새 회의록</h2>
|
||||
<span id="statusBadge" class="badge badge-gray hidden">초안</span>
|
||||
</div>
|
||||
|
||||
<!-- 기본 정보 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 mb-4">
|
||||
<h3 class="font-semibold text-gray-800 mb-3">기본 정보</h3>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">날짜 *</label>
|
||||
<input type="date" id="meetingDate" class="input-field w-full rounded-lg px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">시간</label>
|
||||
<input type="time" id="meetingTime" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">장소</label>
|
||||
<input type="text" id="meetingLocation" class="input-field w-full rounded-lg px-3 py-2 text-sm" placeholder="회의 장소">
|
||||
</div>
|
||||
<div class="sm:col-span-2 lg:col-span-3">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">제목 *</label>
|
||||
<input type="text" id="meetingTitle" class="input-field w-full rounded-lg px-3 py-2 text-sm" placeholder="회의 제목" required>
|
||||
</div>
|
||||
<div class="sm:col-span-2 lg:col-span-3">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">요약</label>
|
||||
<textarea id="meetingSummary" class="input-field w-full rounded-lg px-3 py-2 text-sm" rows="3" placeholder="회의 요약"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 참석자 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 mb-4">
|
||||
<h3 class="font-semibold text-gray-800 mb-3">참석자</h3>
|
||||
<div class="relative mb-3">
|
||||
<input type="text" id="attendeeSearch" class="input-field w-full rounded-lg px-3 py-2 text-sm" placeholder="이름 또는 아이디로 검색" autocomplete="off">
|
||||
<div id="attendeeResults" class="user-search-results hidden"></div>
|
||||
</div>
|
||||
<div id="attendeeTags" class="flex flex-wrap gap-2"></div>
|
||||
</div>
|
||||
|
||||
<!-- 안건 목록 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 mb-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h3 class="font-semibold text-gray-800">안건</h3>
|
||||
<button id="btnAddItem" class="hidden text-sm text-orange-600 hover:text-orange-700 font-medium" onclick="openItemModal()">
|
||||
<i class="fas fa-plus mr-1"></i>안건 추가
|
||||
</button>
|
||||
</div>
|
||||
<div id="agendaList" class="space-y-3"></div>
|
||||
<div id="agendaEmpty" class="text-center py-6 text-gray-400 text-sm">
|
||||
<i class="fas fa-clipboard-list text-2xl mb-2"></i>
|
||||
<p>안건이 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 하단 버튼 -->
|
||||
<div class="flex flex-wrap gap-2 justify-end mb-8" id="bottomActions">
|
||||
<button id="btnSave" class="hidden bg-orange-600 text-white px-5 py-2 rounded-lg text-sm hover:bg-orange-700" onclick="saveMeeting()">
|
||||
<i class="fas fa-save mr-1"></i>저장
|
||||
</button>
|
||||
<button id="btnPublish" class="hidden bg-green-600 text-white px-5 py-2 rounded-lg text-sm hover:bg-green-700" onclick="publishMeeting()">
|
||||
<i class="fas fa-paper-plane mr-1"></i>발행
|
||||
</button>
|
||||
<button id="btnUnpublish" class="hidden bg-gray-500 text-white px-5 py-2 rounded-lg text-sm hover:bg-gray-600" onclick="unpublishMeeting()">
|
||||
<i class="fas fa-undo mr-1"></i>발행 취소
|
||||
</button>
|
||||
<button id="btnDelete" class="hidden bg-red-500 text-white px-5 py-2 rounded-lg text-sm hover:bg-red-600" onclick="deleteMeeting()">
|
||||
<i class="fas fa-trash mr-1"></i>삭제
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 안건 모달 -->
|
||||
<div id="itemModal" class="modal-overlay hidden">
|
||||
<div class="modal-content p-6">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 id="itemModalTitle" class="text-lg font-bold">안건 추가</h3>
|
||||
<button onclick="closeItemModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times text-xl"></i></button>
|
||||
</div>
|
||||
<input type="hidden" id="itemId">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">유형</label>
|
||||
<select id="itemType" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="schedule_update">공정현황</option>
|
||||
<option value="issue">이슈</option>
|
||||
<option value="decision">결정사항</option>
|
||||
<option value="action_item">조치사항</option>
|
||||
<option value="other">기타</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">관련 프로젝트</label>
|
||||
<select id="itemProject" class="input-field w-full rounded-lg px-3 py-2 text-sm" onchange="loadItemMilestones()">
|
||||
<option value="">선택안함</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">관련 마일스톤</label>
|
||||
<select id="itemMilestone" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="">선택안함</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">상태</label>
|
||||
<select id="itemStatus" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="open">미처리</option>
|
||||
<option value="in_progress">진행중</option>
|
||||
<option value="completed">완료</option>
|
||||
<option value="cancelled">취소</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">내용 *</label>
|
||||
<textarea id="itemContent" class="input-field w-full rounded-lg px-3 py-2 text-sm" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">결정사항</label>
|
||||
<textarea id="itemDecision" class="input-field w-full rounded-lg px-3 py-2 text-sm" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">필요조치</label>
|
||||
<textarea id="itemAction" class="input-field w-full rounded-lg px-3 py-2 text-sm" rows="2"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">담당자</label>
|
||||
<select id="itemResponsible" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="">선택안함</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">기한</label>
|
||||
<input type="date" id="itemDueDate" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<button type="button" onclick="closeItemModal()" class="px-4 py-2 text-sm border rounded-lg hover:bg-gray-50">취소</button>
|
||||
<button type="button" onclick="saveItem()" class="px-4 py-2 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js?v=2026031701"></script>
|
||||
<script src="/js/meeting-detail.js?v=2026031701"></script>
|
||||
</body>
|
||||
</html>
|
||||
86
system1-factory/web/pages/work/meetings.html
Normal file
86
system1-factory/web/pages/work/meetings.html
Normal file
@@ -0,0 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>생산회의록 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031701">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="mb-5">
|
||||
<h2 class="text-xl font-bold text-gray-800">생산회의록</h2>
|
||||
<p class="text-sm text-gray-500 mt-0.5">생산회의 기록을 관리합니다</p>
|
||||
</div>
|
||||
|
||||
<!-- 필터 + 버튼 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-4 mb-4 flex flex-wrap items-center gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<select id="yearFilter" class="input-field rounded-lg px-3 py-1.5 text-sm w-24"></select>
|
||||
<select id="monthFilter" class="input-field rounded-lg px-3 py-1.5 text-sm w-20">
|
||||
<option value="">전체</option>
|
||||
<option value="1">1월</option><option value="2">2월</option><option value="3">3월</option>
|
||||
<option value="4">4월</option><option value="5">5월</option><option value="6">6월</option>
|
||||
<option value="7">7월</option><option value="8">8월</option><option value="9">9월</option>
|
||||
<option value="10">10월</option><option value="11">11월</option><option value="12">12월</option>
|
||||
</select>
|
||||
</div>
|
||||
<input type="text" id="searchInput" class="input-field rounded-lg px-3 py-1.5 text-sm w-48" placeholder="제목/내용 검색">
|
||||
<button id="btnNewMeeting" class="hidden ml-auto bg-orange-600 text-white px-4 py-1.5 rounded-lg text-sm hover:bg-orange-700">
|
||||
<i class="fas fa-plus mr-1"></i>새 회의록
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 미완료 조치사항 요약 -->
|
||||
<div id="actionSummary" class="hidden bg-amber-50 border border-amber-200 rounded-xl p-4 mb-4">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i class="fas fa-exclamation-triangle text-amber-600"></i>
|
||||
<span class="font-semibold text-amber-800 text-sm">미완료 조치사항</span>
|
||||
<span id="actionCount" class="badge badge-amber">0</span>
|
||||
</div>
|
||||
<div id="actionList" class="space-y-1 text-sm max-h-40 overflow-y-auto"></div>
|
||||
</div>
|
||||
|
||||
<!-- 회의록 목록 -->
|
||||
<div id="meetingList" class="space-y-3"></div>
|
||||
<div id="emptyState" class="hidden text-center py-12 text-gray-400">
|
||||
<i class="fas fa-clipboard text-4xl mb-3"></i>
|
||||
<p>회의록이 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js?v=2026031701"></script>
|
||||
<script src="/js/meetings.js?v=2026031701"></script>
|
||||
</body>
|
||||
</html>
|
||||
321
system1-factory/web/pages/work/schedule.html
Normal file
321
system1-factory/web/pages/work/schedule.html
Normal file
@@ -0,0 +1,321 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>공정표 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031701">
|
||||
<style>
|
||||
/* Gantt container */
|
||||
.gantt-wrapper { position: relative; overflow: auto; border: 1px solid #e2e8f0; border-radius: 0.5rem; background: #fff; }
|
||||
.gantt-container { position: relative; min-width: 100%; }
|
||||
|
||||
/* Left column sticky */
|
||||
.gantt-label { position: sticky; left: 0; z-index: 20; background: #fff; border-right: 2px solid #e2e8f0; min-width: 250px; max-width: 250px; }
|
||||
.gantt-header .gantt-label { background: #f1f5f9; z-index: 25; }
|
||||
|
||||
/* Row styles */
|
||||
.gantt-row { display: flex; border-bottom: 1px solid #f1f5f9; min-height: 32px; align-items: stretch; }
|
||||
.gantt-row:hover { background: #fafbfc; }
|
||||
.gantt-row.project-row { background: #f8fafc; font-weight: 600; }
|
||||
.gantt-row.project-row .gantt-label { background: #f8fafc; }
|
||||
.gantt-row.phase-row .gantt-label { padding-left: 1.25rem; color: #6b7280; font-size: 0.8rem; }
|
||||
.gantt-row.task-row .gantt-label { padding-left: 2.25rem; font-size: 0.8rem; }
|
||||
.gantt-row.milestone-row .gantt-label { padding-left: 1.25rem; font-size: 0.8rem; color: #7c3aed; }
|
||||
.gantt-row.nc-row .gantt-label { padding-left: 1.25rem; font-size: 0.8rem; color: #dc2626; }
|
||||
|
||||
/* Header */
|
||||
.gantt-header { display: flex; border-bottom: 2px solid #e2e8f0; background: #f1f5f9; position: sticky; top: 0; z-index: 22; }
|
||||
.gantt-month-header { display: flex; border-bottom: 1px solid #e2e8f0; background: #f8fafc; position: sticky; top: 0; z-index: 22; }
|
||||
|
||||
/* Timeline cells */
|
||||
.gantt-timeline { display: flex; flex: 1; position: relative; }
|
||||
.gantt-day { flex: 0 0 var(--day-width); border-right: 1px solid #f1f5f9; display: flex; align-items: center; justify-content: center; font-size: 0.65rem; color: #9ca3af; }
|
||||
.gantt-day.weekend { background: #fafafa; }
|
||||
.gantt-day.month-label { font-weight: 600; color: #475569; font-size: 0.75rem; justify-content: flex-start; padding-left: 4px; border-right: 1px solid #cbd5e1; }
|
||||
|
||||
/* Bars */
|
||||
.gantt-bar { position: absolute; height: 20px; top: 6px; border-radius: 3px; cursor: pointer; transition: opacity 0.15s; min-width: 4px; z-index: 5; }
|
||||
.gantt-bar:hover { opacity: 0.85; filter: brightness(1.1); }
|
||||
.gantt-bar-progress { height: 100%; border-radius: 3px; opacity: 0.4; }
|
||||
.gantt-bar-label { position: absolute; left: 4px; top: 1px; font-size: 0.65rem; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: calc(100% - 8px); line-height: 18px; }
|
||||
|
||||
/* Today marker */
|
||||
.today-marker { position: absolute; top: 0; bottom: 0; width: 2px; background: #ef4444; z-index: 10; pointer-events: none; }
|
||||
|
||||
/* Milestone diamond */
|
||||
.milestone-marker { position: absolute; top: 6px; width: 14px; height: 14px; background: #7c3aed; transform: rotate(45deg); z-index: 5; cursor: pointer; border: 1px solid #6d28d9; }
|
||||
.milestone-marker:hover { filter: brightness(1.2); }
|
||||
|
||||
/* NC badge */
|
||||
.nc-badge { display: inline-flex; align-items: center; justify-content: center; background: #fef2f2; color: #dc2626; border-radius: 9999px; padding: 0 0.5rem; font-size: 0.7rem; font-weight: 600; height: 20px; cursor: pointer; position: absolute; top: 6px; z-index: 5; }
|
||||
|
||||
/* Collapse toggle */
|
||||
.collapse-toggle { cursor: pointer; user-select: none; }
|
||||
.collapse-toggle .arrow { display: inline-block; transition: transform 0.2s; font-size: 0.6rem; margin-right: 4px; }
|
||||
.collapse-toggle.collapsed .arrow { transform: rotate(-90deg); }
|
||||
|
||||
/* Zoom controls */
|
||||
.zoom-btn.active { background: #ea580c; color: #fff; }
|
||||
|
||||
/* Label content */
|
||||
.label-content { display: flex; align-items: center; height: 100%; padding: 0 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white">
|
||||
<i class="fas fa-bars text-xl"></i>
|
||||
</button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
|
||||
<div class="max-w-full mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="mb-4">
|
||||
<h2 class="text-xl font-bold text-gray-800">공정표</h2>
|
||||
<p class="text-sm text-gray-500 mt-0.5">프로젝트별 공정 일정을 Gantt 차트로 관리합니다</p>
|
||||
</div>
|
||||
|
||||
<!-- 툴바 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-4 mb-4 flex flex-wrap items-center gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="text-sm font-medium text-gray-600">연도:</label>
|
||||
<select id="yearSelect" class="input-field rounded-lg px-3 py-1.5 text-sm w-24"></select>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<button class="zoom-btn px-3 py-1.5 rounded-lg text-sm border" data-zoom="month">월간</button>
|
||||
<button class="zoom-btn px-3 py-1.5 rounded-lg text-sm border active" data-zoom="quarter">분기</button>
|
||||
<button class="zoom-btn px-3 py-1.5 rounded-lg text-sm border" data-zoom="year">연간</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 ml-auto">
|
||||
<button id="btnAddEntry" class="hidden bg-orange-600 text-white px-3 py-1.5 rounded-lg text-sm hover:bg-orange-700">
|
||||
<i class="fas fa-plus mr-1"></i>항목 추가
|
||||
</button>
|
||||
<button id="btnBatchAdd" class="hidden bg-blue-600 text-white px-3 py-1.5 rounded-lg text-sm hover:bg-blue-700">
|
||||
<i class="fas fa-layer-group mr-1"></i>일괄 생성
|
||||
</button>
|
||||
<button id="btnAddMilestone" class="hidden bg-purple-600 text-white px-3 py-1.5 rounded-lg text-sm hover:bg-purple-700">
|
||||
<i class="fas fa-diamond mr-1"></i>마일스톤
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gantt Chart -->
|
||||
<div class="gantt-wrapper" id="ganttWrapper" style="max-height: calc(100vh - 220px);">
|
||||
<div class="gantt-container" id="ganttContainer">
|
||||
<!-- Rendered by JS -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 항목 추가/수정 모달 -->
|
||||
<div id="entryModal" class="modal-overlay hidden">
|
||||
<div class="modal-content p-6">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 id="entryModalTitle" class="text-lg font-bold">공정표 항목 추가</h3>
|
||||
<button onclick="closeEntryModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times text-xl"></i></button>
|
||||
</div>
|
||||
<form id="entryForm" onsubmit="return false;">
|
||||
<input type="hidden" id="entryId">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">프로젝트 *</label>
|
||||
<select id="entryProject" class="input-field w-full rounded-lg px-3 py-2 text-sm" required></select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">공정 단계 *</label>
|
||||
<select id="entryPhase" class="input-field w-full rounded-lg px-3 py-2 text-sm" required></select>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">작업명 *</label>
|
||||
<div class="flex gap-2">
|
||||
<select id="entryTemplate" class="input-field flex-1 rounded-lg px-3 py-2 text-sm">
|
||||
<option value="">직접 입력</option>
|
||||
</select>
|
||||
<input type="text" id="entryTaskName" class="input-field flex-1 rounded-lg px-3 py-2 text-sm" placeholder="작업명 입력">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">시작일 *</label>
|
||||
<input type="date" id="entryStartDate" class="input-field w-full rounded-lg px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">종료일 *</label>
|
||||
<input type="date" id="entryEndDate" class="input-field w-full rounded-lg px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">담당자</label>
|
||||
<input type="text" id="entryAssignee" class="input-field w-full rounded-lg px-3 py-2 text-sm" placeholder="담당자">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">진행률 (%)</label>
|
||||
<input type="number" id="entryProgress" class="input-field w-full rounded-lg px-3 py-2 text-sm" min="0" max="100" value="0">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">상태</label>
|
||||
<select id="entryStatus" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="planned">계획</option>
|
||||
<option value="in_progress">진행중</option>
|
||||
<option value="completed">완료</option>
|
||||
<option value="delayed">지연</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">선행작업 (의존관계)</label>
|
||||
<select id="entryDependencies" class="input-field w-full rounded-lg px-3 py-2 text-sm" multiple style="min-height: 60px;"></select>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">메모</label>
|
||||
<textarea id="entryNotes" class="input-field w-full rounded-lg px-3 py-2 text-sm" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<button type="button" onclick="closeEntryModal()" class="px-4 py-2 text-sm border rounded-lg hover:bg-gray-50">취소</button>
|
||||
<button type="button" onclick="saveEntry()" class="px-4 py-2 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700">저장</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 일괄 생성 모달 -->
|
||||
<div id="batchModal" class="modal-overlay hidden">
|
||||
<div class="modal-content p-6">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-bold">템플릿 기반 일괄 생성</h3>
|
||||
<button onclick="closeBatchModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times text-xl"></i></button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">프로젝트 *</label>
|
||||
<select id="batchProject" class="input-field w-full rounded-lg px-3 py-2 text-sm"></select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">공정 단계 *</label>
|
||||
<select id="batchPhase" class="input-field w-full rounded-lg px-3 py-2 text-sm" onchange="loadBatchTemplates()"></select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">기준 시작일 *</label>
|
||||
<input type="date" id="batchStartDate" class="input-field w-full rounded-lg px-3 py-2 text-sm" onchange="recalcBatchDates()">
|
||||
</div>
|
||||
</div>
|
||||
<div id="batchTemplateList" class="space-y-2 mb-4 max-h-60 overflow-y-auto">
|
||||
<!-- 템플릿 목록 동적 생성 -->
|
||||
</div>
|
||||
<div class="flex justify-end gap-2">
|
||||
<button type="button" onclick="closeBatchModal()" class="px-4 py-2 text-sm border rounded-lg hover:bg-gray-50">취소</button>
|
||||
<button type="button" onclick="saveBatchEntries()" class="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700">일괄 생성</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 마일스톤 모달 -->
|
||||
<div id="milestoneModal" class="modal-overlay hidden">
|
||||
<div class="modal-content p-6">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 id="milestoneModalTitle" class="text-lg font-bold">마일스톤 추가</h3>
|
||||
<button onclick="closeMilestoneModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times text-xl"></i></button>
|
||||
</div>
|
||||
<form id="milestoneForm" onsubmit="return false;">
|
||||
<input type="hidden" id="milestoneId">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">프로젝트 *</label>
|
||||
<select id="milestoneProject" class="input-field w-full rounded-lg px-3 py-2 text-sm" required></select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">마일스톤명 *</label>
|
||||
<input type="text" id="milestoneName" class="input-field w-full rounded-lg px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">날짜 *</label>
|
||||
<input type="date" id="milestoneDate" class="input-field w-full rounded-lg px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">유형</label>
|
||||
<select id="milestoneType" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="deadline">납기</option>
|
||||
<option value="review">검토</option>
|
||||
<option value="inspection">검사</option>
|
||||
<option value="delivery">출하</option>
|
||||
<option value="meeting">회의</option>
|
||||
<option value="other">기타</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">상태</label>
|
||||
<select id="milestoneStatus" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="upcoming">예정</option>
|
||||
<option value="completed">완료</option>
|
||||
<option value="missed">미달성</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">연결 작업</label>
|
||||
<select id="milestoneEntry" class="input-field w-full rounded-lg px-3 py-2 text-sm">
|
||||
<option value="">없음</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">메모</label>
|
||||
<textarea id="milestoneNotes" class="input-field w-full rounded-lg px-3 py-2 text-sm" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<button type="button" onclick="closeMilestoneModal()" class="px-4 py-2 text-sm border rounded-lg hover:bg-gray-50">취소</button>
|
||||
<button type="button" onclick="saveMilestone()" class="px-4 py-2 text-sm bg-purple-600 text-white rounded-lg hover:bg-purple-700">저장</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 부적합 팝업 -->
|
||||
<div id="ncPopup" class="modal-overlay hidden">
|
||||
<div class="modal-content p-6" style="max-width: 600px;">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 id="ncPopupTitle" class="text-lg font-bold">부적합 현황</h3>
|
||||
<button onclick="document.getElementById('ncPopup').classList.add('hidden')" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times text-xl"></i></button>
|
||||
</div>
|
||||
<div id="ncPopupContent" class="space-y-2 max-h-80 overflow-y-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 바 상세 팝업 -->
|
||||
<div id="barDetailPopup" class="modal-overlay hidden">
|
||||
<div class="modal-content p-6" style="max-width: 500px;">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 id="barDetailTitle" class="text-lg font-bold">작업 상세</h3>
|
||||
<button onclick="document.getElementById('barDetailPopup').classList.add('hidden')" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times text-xl"></i></button>
|
||||
</div>
|
||||
<div id="barDetailContent"></div>
|
||||
<div id="barDetailActions" class="flex justify-end gap-2 mt-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/tkfb-core.js?v=2026031701"></script>
|
||||
<script src="/js/schedule.js?v=2026031701"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user