// TK Project Demo - Main JavaScript // 전역 변수 let currentPage = 'project-registration'; let currentUser = { name: '김그룹장', role: '생산팀', avatar: '김' }; // 하드코딩된 데이터 const demoData = { projects: [ { jobNo: 'TK-2024-015', name: 'ABC 공장 배관공사', client: 'ABC 케미칼', contractAmount: '150,000,000', orderDate: '2024-01-15', deliveryDate: '2024-03-30', deliveryMethod: '현장납품', productionType: '자체제작', status: '승인완료' } ], processChart: { design: { progress: 100, status: '완료', dueDate: '2024-02-15', responsible: '박설계' }, procurement: { progress: 85, status: '진행중', dueDate: '2024-02-28', responsible: '김구매' }, production: { progress: 60, status: '진행중', dueDate: '2024-03-20', responsible: '이생산' }, inspection: { progress: 0, status: '대기', dueDate: '2024-03-25', responsible: '최품질' }, delivery: { progress: 0, status: '대기', dueDate: '2024-03-30', responsible: '박PM' } }, schedules: [ { date: '09/20', type: '외주출고', title: '도장 작업 출고', memo: 'A구역 파이프 20본, B구역 밸브 5개\n업체: 대한도장\n연락처: 010-1234-5678', responsible: '김구매', urgency: 'urgent' }, { date: '09/22', type: '검사일정', title: '압력시험', memo: '시험압력: 15bar, 30분간 유지\n검사자: 최품질, 이생산', responsible: '최품질', urgency: 'normal' } ], deliveries: [ { item: '파이프 4인치 x 50EA', date: '입고완료 - 09/10', status: 'completed' }, { item: '밸브 2인치 x 10EA', date: '입고예정 - 09/16', status: 'warning' }, { item: '엘보 4인치 x 20EA', date: '지연 - 09/12 → 09/18', status: 'delayed' } ], followUps: [ { priority: '긴급', title: '밸브 A 납기 지연 대응', description: '주 공급업체 생산 지연으로 대체 업체 검토 필요', responsible: '김구매', registeredDate: '09/10', expectedResolution: '09/17', status: '진행중', level: 'high' }, { priority: '높음', title: '용접 검사 일정 조정', description: '고객사 일정 변경으로 검사일 재조정 필요', responsible: '최품질', registeredDate: '09/12', expectedResolution: '09/20', status: '검토중', level: 'medium' } ], purchaseOrders: [ { poNumber: 'PO-2024-0156', project: 'TK-2024-015', item: '스테인리스 파이프 4인치 SCH40', qty: 50, unit: 'EA', supplier: '대한파이프', orderDate: '2024-09-01', expectedDate: '2024-09-15', buyer: '김구매', status: 'pending' }, { poNumber: 'PO-2024-0157', project: 'TK-2024-015', item: '게이트밸브 2인치 150LB', qty: 10, unit: 'EA', supplier: '코리아밸브', orderDate: '2024-09-05', expectedDate: '2024-09-16', buyer: '김구매', status: 'inspecting' } ], materials: [ { item: '파이프 4인치 SCH40', required: 50, status: 'available', location: 'A-3-상단', availableQty: 45, lastUpdate: '2024-09-14 09:00' }, { item: '엘보 4인치 150LB', required: 20, status: 'ordered', currentStage: '구매 진행 중', expectedDate: '2024-09-18', availableQty: 0 }, { item: '플랜지 4인치 150LB', required: 15, status: 'not-requested', currentStage: '설계팀 구매 요청 대기', availableQty: 0, note: '설계 변경으로 사양 확정 대기' }, { item: '밸브 2인치 150LB', required: 5, status: 'ready', location: 'B-2-중단', availableQty: 5, note: '인수 대기 중' } ], issues: [ { time: '14:30', type: '자재부족', description: '엘보 4인치 10EA 부족으로 작업 중단', urgency: '높음', solution: '구매팀에 긴급 요청, 대체재 검토', responsible: '김그룹장', photos: ['issue_001.jpg'] }, { time: '10:15', type: '품질이슈', description: '용접부 기공 발견, 재작업 필요', urgency: '보통', solution: '해당 부위 그라인딩 후 재용접', responsible: '이용접사', photos: ['quality_001.jpg'] } ] }; // DOM이 로드되면 초기화 document.addEventListener('DOMContentLoaded', function() { initializeApp(); setupEventListeners(); showPage(currentPage); }); // 앱 초기화 function initializeApp() { console.log('TK Project Demo 초기화 중...'); // 사용자 정보 업데이트 updateUserInfo(); // 데이터 로드 loadDemoData(); console.log('TK Project Demo 초기화 완료'); } // 이벤트 리스너 설정 function setupEventListeners() { // 네비게이션 클릭 이벤트 document.querySelectorAll('.nav-item').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); const pageId = this.getAttribute('onclick').match(/'([^']+)'/)[1]; showPage(pageId); }); }); // 진행률 슬라이더 이벤트 const progressSlider = document.querySelector('.progress-slider'); if (progressSlider) { progressSlider.addEventListener('input', function() { const value = this.value; const display = document.querySelector('.progress-value'); if (display) { display.textContent = value + '%'; } }); } // 버튼 클릭 이벤트 setupButtonEvents(); // 폼 이벤트 setupFormEvents(); } // 버튼 이벤트 설정 function setupButtonEvents() { // 프로젝트 승인 버튼 const approveBtn = document.querySelector('.btn-primary'); if (approveBtn && approveBtn.textContent.includes('프로젝트 승인')) { approveBtn.addEventListener('click', function() { showNotification('프로젝트가 성공적으로 승인되었습니다!', 'success'); }); } // 검수 시작 버튼 document.querySelectorAll('.btn').forEach(btn => { if (btn.textContent.includes('검수 시작')) { btn.addEventListener('click', function() { showNotification('검수 프로세스를 시작합니다.', 'info'); // 버튼 상태 변경 this.textContent = '🔄 검수 진행중'; this.classList.remove('btn-primary'); this.classList.add('btn-warning'); }); } if (btn.textContent.includes('인수 처리')) { btn.addEventListener('click', function() { showNotification('자재 인수가 완료되었습니다.', 'success'); this.textContent = '✅ 인수완료'; this.classList.remove('btn-primary'); this.classList.add('btn-success'); this.disabled = true; }); } if (btn.textContent.includes('데일리 체크에 기록')) { btn.addEventListener('click', function() { showNotification('데일리 체크에 이슈가 등록되었습니다.', 'warning'); }); } }); // 선반 클릭 이벤트 document.querySelectorAll('.shelf.available').forEach(shelf => { shelf.addEventListener('click', function() { // 기존 선택 해제 document.querySelectorAll('.shelf').forEach(s => s.classList.remove('selected')); // 현재 선택 this.classList.add('selected'); // 선택된 위치 업데이트 const locationDisplay = document.querySelector('.selected-location .location'); if (locationDisplay) { locationDisplay.textContent = this.textContent + '-중단'; } showNotification(`${this.textContent} 선반이 선택되었습니다.`, 'info'); }); }); } // 폼 이벤트 설정 function setupFormEvents() { // BOM 조회 버튼 const bomSearchBtn = document.querySelector('.search-input .btn-primary'); if (bomSearchBtn && bomSearchBtn.textContent.includes('BOM 조회')) { bomSearchBtn.addEventListener('click', function() { const input = document.querySelector('.search-input .form-input'); const jobNo = input.value || 'TK-2024-015'; showNotification(`${jobNo} 프로젝트의 BOM 정보를 조회했습니다.`, 'success'); // 자재 리스트 업데이트 (이미 하드코딩되어 있음) animateElements('.material-item'); }); } } // 페이지 표시 function showPage(pageId) { // 모든 페이지 숨기기 document.querySelectorAll('.page').forEach(page => { page.classList.remove('active'); }); // 모든 네비게이션 아이템 비활성화 document.querySelectorAll('.nav-item').forEach(item => { item.classList.remove('active'); }); // 선택된 페이지 표시 const targetPage = document.getElementById(pageId); if (targetPage) { targetPage.classList.add('active'); targetPage.classList.add('fade-in'); // 네비게이션 아이템 활성화 const navItem = document.querySelector(`[onclick*="${pageId}"]`); if (navItem) { navItem.classList.add('active'); } currentPage = pageId; // 페이지별 초기화 initializePage(pageId); } } // 페이지별 초기화 function initializePage(pageId) { switch (pageId) { case 'project-registration': initializeProjectRegistration(); break; case 'production-meeting': initializeProductionMeeting(); break; case 'incoming-inspection': initializeIncomingInspection(); break; case 'production-work': initializeProductionWork(); break; } } // 프로젝트 등록 페이지 초기화 function initializeProjectRegistration() { console.log('프로젝트 등록 페이지 초기화'); // 자동 생성된 Job No. 애니메이션 const jobNoValue = document.querySelector('.generated-item .value'); if (jobNoValue) { setTimeout(() => { jobNoValue.style.transform = 'scale(1.1)'; setTimeout(() => { jobNoValue.style.transform = 'scale(1)'; }, 200); }, 500); } } // 생산회의록 페이지 초기화 function initializeProductionMeeting() { console.log('생산회의록 페이지 초기화'); // 공정표 애니메이션 animateElements('.process-item'); // 일정 및 배송 아이템 애니메이션 setTimeout(() => { animateElements('.schedule-item'); animateElements('.delivery-item'); }, 300); // Follow-up 아이템 애니메이션 setTimeout(() => { animateElements('.followup-item'); }, 600); } // 입고 검수 페이지 초기화 function initializeIncomingInspection() { console.log('입고 검수 페이지 초기화'); // 구매 아이템 애니메이션 animateElements('.purchase-item'); // 검수 단계 애니메이션 setTimeout(() => { animateElements('.step'); }, 300); // 창고 구역 애니메이션 setTimeout(() => { animateElements('.zone-item'); }, 600); } // 생산팀 작업 페이지 초기화 function initializeProductionWork() { console.log('생산팀 작업 페이지 초기화'); // 이슈 아이템 애니메이션 animateElements('.issue-item'); // 자재 아이템 애니메이션 setTimeout(() => { animateElements('.material-item'); }, 300); } // 사용자 정보 업데이트 function updateUserInfo() { const userAvatar = document.querySelector('.user-avatar'); const userName = document.querySelector('.user-name'); const userRole = document.querySelector('.user-role'); if (userAvatar) userAvatar.textContent = currentUser.avatar; if (userName) userName.textContent = currentUser.name; if (userRole) userRole.textContent = currentUser.role; } // 데모 데이터 로드 function loadDemoData() { console.log('데모 데이터 로드 중...'); // 여기서 필요한 경우 동적으로 데이터를 DOM에 삽입할 수 있습니다. // 현재는 HTML에 하드코딩되어 있으므로 추가 작업 불필요 console.log('데모 데이터 로드 완료'); } // 요소 애니메이션 function animateElements(selector) { const elements = document.querySelectorAll(selector); elements.forEach((element, index) => { setTimeout(() => { element.classList.add('slide-in'); }, index * 100); }); } // 알림 표시 function showNotification(message, type = 'info') { // 기존 알림 제거 const existingNotification = document.querySelector('.notification'); if (existingNotification) { existingNotification.remove(); } // 새 알림 생성 const notification = document.createElement('div'); notification.className = `notification alert alert-${type}`; notification.textContent = message; // 스타일 설정 notification.style.position = 'fixed'; notification.style.top = '20px'; notification.style.right = '20px'; notification.style.zIndex = '9999'; notification.style.minWidth = '300px'; notification.style.maxWidth = '500px'; notification.style.boxShadow = 'var(--dt-shadow-lg)'; notification.style.transform = 'translateX(100%)'; notification.style.transition = 'transform 0.3s ease'; // DOM에 추가 document.body.appendChild(notification); // 애니메이션 setTimeout(() => { notification.style.transform = 'translateX(0)'; }, 100); // 자동 제거 setTimeout(() => { notification.style.transform = 'translateX(100%)'; setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 300); }, 3000); } // 모달 관련 함수들 function showModal(title, content) { let modal = document.querySelector('.modal-overlay'); if (!modal) { modal = createModal(); document.body.appendChild(modal); } const modalTitle = modal.querySelector('.modal-title'); const modalBody = modal.querySelector('.modal-body'); modalTitle.textContent = title; modalBody.innerHTML = content; modal.classList.add('active'); } function hideModal() { const modal = document.querySelector('.modal-overlay'); if (modal) { modal.classList.remove('active'); } } function createModal() { const modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.innerHTML = `