🎨 시연회용 데모 페이지 완성 - DevonThink UI 스타일
핵심 구현사항: ✅ 4개 핵심 기능 페이지 완성 - 📋 프로젝트 정보 등록 (2단계 시스템) - 🏭 생산회의록 시스템 (4구역 레이아웃) - 📦 입고 검수 & 보관 관리 - 🔧 생산팀 작업 관리 (그룹장용) 🎨 DevonThink 스타일 디자인 - 회색(#F8F9FA~#202124) + 하늘색(#4A90E2) 컬러 팔레트 - 미니멀하고 전문적인 UI/UX - 반응형 디자인 (데스크톱/태블릿/모바일) - CSS Grid + Flexbox 레이아웃 ⚡ 인터랙티브 기능 - 페이지 전환 애니메이션 (fade-in, slide-in) - 버튼 클릭 상태 변경 및 알림 시스템 - 진행률 슬라이더, 창고 선반 선택 - 키보드 단축키 (Ctrl+1~4) 📁 파일 구조 - demo/index.html (메인 HTML) - demo/styles/devonthink.css (DevonThink 스타일) - demo/styles/main.css (기본 CSS + 유틸리티) - demo/scripts/main.js (JavaScript 기능) - demo/README.md (사용법 및 시연 시나리오) 💾 하드코딩 데이터 - TK-2024-015 프로젝트 (ABC 공장 배관공사) - 공정표, 일정, 자재 현황, 이슈 사항 - 실제 업무 시나리오 반영 🎯 시연 준비 완료 - 브라우저에서 index.html 실행 가능 - 4개 페이지 완전 구현 - 실무진 시연용 데모 완성
This commit is contained in:
177
demo/README.md
Normal file
177
demo/README.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# TK Project - 시연회용 데모
|
||||
|
||||
## 📋 개요
|
||||
TK Project 통합 프로젝트 관리 시스템의 시연회용 데모 페이지입니다.
|
||||
DevonThink UI 스타일을 참조하여 회색과 하늘색 위주의 깔끔한 디자인으로 구현되었습니다.
|
||||
|
||||
## 🚀 핵심 기능 4선
|
||||
|
||||
### 1. 📋 프로젝트 정보 등록 (2단계 시스템)
|
||||
- **1단계**: 프로젝트 생성 및 기본 정보 입력
|
||||
- **2단계**: 세부 사양 입력 (킥오프 미팅, 기술 사양서)
|
||||
- **특징**: Job No. 자동 생성, 프로젝트 승인 시스템
|
||||
|
||||
### 2. 🏭 생산회의록 시스템 (4구역 레이아웃)
|
||||
- **상단**: 프로젝트 공정표 (Gantt Chart 스타일)
|
||||
- **중앙 좌측**: 캘린더 기반 일정 관리
|
||||
- **우측**: 입고 예정 품목 현황
|
||||
- **하단**: Follow-up 리스트 (미해결 사항)
|
||||
|
||||
### 3. 📦 입고 검수 & 보관 관리
|
||||
- **상단**: 발주 연동 입고 대시보드
|
||||
- **중앙**: 3단계 검수 프로세스
|
||||
- **하단**: 창고 구역 관리 및 인수인계 현황
|
||||
|
||||
### 4. 🔧 생산팀 작업 관리 (그룹장용)
|
||||
- **좌측**: 일일 작업 현황 입력 (TK-FB 스타일)
|
||||
- **우측**: 자재 확인 기능 (확인 전용)
|
||||
- **특징**: 이슈 등록, 데일리 체크 연동
|
||||
|
||||
## 🎨 디자인 특징
|
||||
|
||||
### DevonThink 스타일
|
||||
- **컬러 팔레트**: 회색(#F8F9FA ~ #202124), 하늘색(#4A90E2)
|
||||
- **최소한의 색상 사용**: 깔끔하고 전문적인 느낌
|
||||
- **그림자 효과**: 미묘한 그림자로 깊이감 표현
|
||||
- **타이포그래피**: 시스템 폰트 사용으로 가독성 향상
|
||||
|
||||
### 반응형 디자인
|
||||
- **데스크톱**: 사이드바 + 메인 컨텐츠 레이아웃
|
||||
- **태블릿/모바일**: 스택형 레이아웃으로 자동 변환
|
||||
- **그리드 시스템**: CSS Grid를 활용한 유연한 레이아웃
|
||||
|
||||
## 🖥️ 사용 방법
|
||||
|
||||
### 실행
|
||||
1. `index.html` 파일을 웹 브라우저에서 열기
|
||||
2. 또는 로컬 서버 실행:
|
||||
```bash
|
||||
# Python 3
|
||||
python -m http.server 8000
|
||||
|
||||
# Node.js (http-server)
|
||||
npx http-server
|
||||
```
|
||||
|
||||
### 네비게이션
|
||||
- **사이드바**: 각 기능별 페이지 이동
|
||||
- **키보드 단축키**: Ctrl + 1~4 (페이지 전환)
|
||||
- **반응형**: 모바일에서는 상하 스택 레이아웃
|
||||
|
||||
### 인터랙티브 기능
|
||||
- **버튼 클릭**: 상태 변경 및 알림 표시
|
||||
- **진행률 슬라이더**: 실시간 값 업데이트
|
||||
- **창고 선반 선택**: 클릭으로 위치 지정
|
||||
- **애니메이션**: 페이지 전환시 fade-in 효과
|
||||
|
||||
## 📁 파일 구조
|
||||
```
|
||||
demo/
|
||||
├── index.html # 메인 HTML 파일
|
||||
├── styles/
|
||||
│ ├── devonthink.css # DevonThink 스타일 CSS
|
||||
│ └── main.css # 기본 CSS 및 유틸리티
|
||||
├── scripts/
|
||||
│ └── main.js # JavaScript 기능
|
||||
└── README.md # 이 파일
|
||||
```
|
||||
|
||||
## 🎯 시연 시나리오
|
||||
|
||||
### Scene 1: 프로젝트 등록
|
||||
1. 새 프로젝트 "ABC 공장 배관공사" 등록
|
||||
2. Job No. TK-2024-015 자동 생성
|
||||
3. 기본 정보 입력 → 프로젝트 승인
|
||||
4. 세부 사양 입력 (킥오프 미팅 결과)
|
||||
|
||||
### Scene 2: 생산회의
|
||||
1. 프로젝트 현황 대시보드 확인
|
||||
2. 공정표에서 진행률 확인 (설계 100%, 구매 85%)
|
||||
3. 캘린더 일정 확인 (도장 외주, 압력시험)
|
||||
4. Follow-up 리스트에서 긴급 사항 확인
|
||||
|
||||
### Scene 3: 입고 검수
|
||||
1. 발주 연동 대시보드에서 입고 예정 품목 확인
|
||||
2. 검수 프로세스 진행 (입고확인 → 검수진행 → 결과처리)
|
||||
3. 창고 구역에서 보관 위치 선택
|
||||
4. 인수인계 현황 확인
|
||||
|
||||
### Scene 4: 생산팀 작업
|
||||
1. 김그룹장 일일 작업 현황 입력
|
||||
2. 자재 현황 확인 (BOM 조회)
|
||||
3. 부족한 자재 발견 → 데일리 체크 기록
|
||||
4. 가용 자재 인수 처리
|
||||
|
||||
## 💡 하드코딩 데이터
|
||||
|
||||
### 프로젝트 정보
|
||||
- **Job No**: TK-2024-015
|
||||
- **프로젝트명**: ABC 공장 배관공사
|
||||
- **고객사**: ABC 케미칼
|
||||
- **납기일**: 2024-03-30
|
||||
|
||||
### 자재 현황
|
||||
- 파이프 4인치: 사용가능 (A-3-상단, 45EA)
|
||||
- 엘보 4인치: 발주중 (입고예정 09/18)
|
||||
- 플랜지 4인치: 미요청 (설계팀 대기)
|
||||
- 밸브 2인치: 입고완료 (B-2-중단)
|
||||
|
||||
### 이슈 사항
|
||||
- 14:30 자재부족: 엘보 4인치 10EA 부족
|
||||
- 10:15 품질이슈: 용접부 기공 발견
|
||||
|
||||
## 🔧 기술 스택
|
||||
|
||||
### Frontend
|
||||
- **HTML5**: 시맨틱 마크업
|
||||
- **CSS3**: Grid, Flexbox, 애니메이션
|
||||
- **Vanilla JavaScript**: ES6+ 문법 사용
|
||||
|
||||
### 스타일링
|
||||
- **CSS Variables**: 일관된 컬러 시스템
|
||||
- **CSS Grid**: 복잡한 레이아웃 구현
|
||||
- **CSS Animations**: 부드러운 전환 효과
|
||||
|
||||
### 호환성
|
||||
- **모던 브라우저**: Chrome, Firefox, Safari, Edge
|
||||
- **반응형**: 모바일, 태블릿, 데스크톱
|
||||
- **접근성**: 키보드 네비게이션 지원
|
||||
|
||||
## 📝 개발 노트
|
||||
|
||||
### 디자인 철학
|
||||
- **미니멀리즘**: 불필요한 요소 제거
|
||||
- **일관성**: 통일된 컴포넌트 시스템
|
||||
- **사용성**: 직관적인 인터페이스
|
||||
|
||||
### 성능 최적화
|
||||
- **CSS 최적화**: 효율적인 선택자 사용
|
||||
- **JavaScript 최적화**: 이벤트 위임 패턴
|
||||
- **이미지 최적화**: 아이콘은 이모지 사용
|
||||
|
||||
### 확장성
|
||||
- **모듈화**: 기능별 함수 분리
|
||||
- **데이터 분리**: 하드코딩 데이터 객체화
|
||||
- **컴포넌트화**: 재사용 가능한 UI 요소
|
||||
|
||||
## 🚀 향후 계획
|
||||
|
||||
### Phase 1: 기본 기능 (완료)
|
||||
- [x] 4개 핵심 페이지 구현
|
||||
- [x] DevonThink 스타일 적용
|
||||
- [x] 인터랙티브 기능 추가
|
||||
|
||||
### Phase 2: 고도화 (예정)
|
||||
- [ ] 실제 데이터베이스 연동
|
||||
- [ ] 사용자 인증 시스템
|
||||
- [ ] 실시간 데이터 업데이트
|
||||
|
||||
### Phase 3: 확장 (예정)
|
||||
- [ ] 모바일 앱 개발
|
||||
- [ ] API 연동
|
||||
- [ ] 고급 분석 기능
|
||||
|
||||
---
|
||||
|
||||
**TK Project Demo v1.0**
|
||||
*DevonThink 스타일 기반 프로젝트 관리 시스템*
|
||||
630
demo/index.html
Normal file
630
demo/index.html
Normal file
@@ -0,0 +1,630 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TK Project - 통합 프로젝트 관리 시스템</title>
|
||||
<link rel="stylesheet" href="styles/main.css">
|
||||
<link rel="stylesheet" href="styles/devonthink.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 사이드바 -->
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>TK Project</h1>
|
||||
<p class="version">v1.0 Demo</p>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<div class="nav-section">
|
||||
<h3>프로젝트 관리</h3>
|
||||
<ul>
|
||||
<li><a href="#" onclick="showPage('project-registration')" class="nav-item active">
|
||||
<span class="nav-icon">📋</span>
|
||||
프로젝트 등록
|
||||
</a></li>
|
||||
<li><a href="#" onclick="showPage('production-meeting')" class="nav-item">
|
||||
<span class="nav-icon">🏭</span>
|
||||
생산회의록
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="nav-section">
|
||||
<h3>자재 관리</h3>
|
||||
<ul>
|
||||
<li><a href="#" onclick="showPage('incoming-inspection')" class="nav-item">
|
||||
<span class="nav-icon">📦</span>
|
||||
입고 검수
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="nav-section">
|
||||
<h3>생산 관리</h3>
|
||||
<ul>
|
||||
<li><a href="#" onclick="showPage('production-work')" class="nav-item">
|
||||
<span class="nav-icon">🔧</span>
|
||||
생산팀 작업
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<div class="user-info">
|
||||
<div class="user-avatar">김</div>
|
||||
<div class="user-details">
|
||||
<div class="user-name">김그룹장</div>
|
||||
<div class="user-role">생산팀</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 메인 컨텐츠 -->
|
||||
<div class="main-content">
|
||||
<!-- 프로젝트 등록 페이지 -->
|
||||
<div id="project-registration" class="page active">
|
||||
<div class="page-header">
|
||||
<h2>프로젝트 정보 등록</h2>
|
||||
<p class="page-description">새로운 프로젝트를 등록하고 기본 정보를 입력합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="content-grid">
|
||||
<!-- 1단계: 기본 정보 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>1단계: 프로젝트 생성</h3>
|
||||
<span class="status-badge status-active">진행중</span>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<form class="form-grid">
|
||||
<div class="form-group">
|
||||
<label>프로젝트명 *</label>
|
||||
<input type="text" value="ABC 공장 배관공사" class="form-input">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>고객사 *</label>
|
||||
<input type="text" value="ABC 케미칼" class="form-input">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>계약금액</label>
|
||||
<input type="text" value="150,000,000원" class="form-input">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>납기일 *</label>
|
||||
<input type="date" value="2024-03-30" class="form-input">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>납품방식</label>
|
||||
<select class="form-select">
|
||||
<option value="현장납품" selected>현장납품</option>
|
||||
<option value="공장인도">공장인도</option>
|
||||
<option value="부분납품">부분납품</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>제작방식</label>
|
||||
<select class="form-select">
|
||||
<option value="자체제작" selected>자체제작</option>
|
||||
<option value="외주제작">외주제작</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="auto-generated">
|
||||
<div class="generated-item">
|
||||
<span class="label">자동 생성된 Job No.</span>
|
||||
<span class="value">TK-2024-015</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary">✅ 프로젝트 승인 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2단계: 세부 사양 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>2단계: 세부 사양 입력</h3>
|
||||
<span class="status-badge status-optional">선택적</span>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="info-section">
|
||||
<h4>킥오프 미팅 결과</h4>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="info-label">미팅 일자</span>
|
||||
<span class="info-value">2024-01-20</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">참석자</span>
|
||||
<span class="info-value">김영업, 이PM, 박설계, 최고객</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="decisions">
|
||||
<h5>주요 결정사항</h5>
|
||||
<ul>
|
||||
<li>압력등급 150LB로 확정</li>
|
||||
<li>재질 SS316L로 변경</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-section">
|
||||
<h4>기술 사양서</h4>
|
||||
<div class="spec-grid">
|
||||
<div class="spec-item">
|
||||
<span class="spec-label">설계기준</span>
|
||||
<span class="spec-value">ASME B31.3</span>
|
||||
</div>
|
||||
<div class="spec-item">
|
||||
<span class="spec-label">사용압력</span>
|
||||
<span class="spec-value">10 bar</span>
|
||||
</div>
|
||||
<div class="spec-item">
|
||||
<span class="spec-label">사용온도</span>
|
||||
<span class="spec-value">80°C</span>
|
||||
</div>
|
||||
<div class="spec-item">
|
||||
<span class="spec-label">유체</span>
|
||||
<span class="spec-value">화학용매</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-secondary">📝 세부사양 업데이트</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 생산회의록 페이지 -->
|
||||
<div id="production-meeting" class="page">
|
||||
<div class="page-header">
|
||||
<h2>생산회의록 시스템</h2>
|
||||
<p class="page-description">TK-2024-015 (ABC 공장 배관공사) 프로젝트 현황</p>
|
||||
</div>
|
||||
|
||||
<!-- 공정표 (상단) -->
|
||||
<div class="process-chart">
|
||||
<h3>프로젝트 공정표</h3>
|
||||
<div class="gantt-container">
|
||||
<div class="process-item completed">
|
||||
<div class="process-info">
|
||||
<span class="process-name">설계</span>
|
||||
<span class="process-responsible">박설계</span>
|
||||
</div>
|
||||
<div class="process-bar">
|
||||
<div class="progress-fill" style="width: 100%"></div>
|
||||
<span class="progress-text">100%</span>
|
||||
</div>
|
||||
<span class="process-date">2024-02-15</span>
|
||||
</div>
|
||||
|
||||
<div class="process-item in-progress">
|
||||
<div class="process-info">
|
||||
<span class="process-name">구매</span>
|
||||
<span class="process-responsible">김구매</span>
|
||||
</div>
|
||||
<div class="process-bar">
|
||||
<div class="progress-fill" style="width: 85%"></div>
|
||||
<span class="progress-text">85%</span>
|
||||
</div>
|
||||
<span class="process-date">2024-02-28</span>
|
||||
</div>
|
||||
|
||||
<div class="process-item in-progress">
|
||||
<div class="process-info">
|
||||
<span class="process-name">제작</span>
|
||||
<span class="process-responsible">이생산</span>
|
||||
</div>
|
||||
<div class="process-bar">
|
||||
<div class="progress-fill" style="width: 60%"></div>
|
||||
<span class="progress-text">60%</span>
|
||||
</div>
|
||||
<span class="process-date">2024-03-20</span>
|
||||
</div>
|
||||
|
||||
<div class="process-item pending">
|
||||
<div class="process-info">
|
||||
<span class="process-name">검사</span>
|
||||
<span class="process-responsible">최품질</span>
|
||||
</div>
|
||||
<div class="process-bar">
|
||||
<div class="progress-fill" style="width: 0%"></div>
|
||||
<span class="progress-text">대기</span>
|
||||
</div>
|
||||
<span class="process-date">2024-03-25</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="meeting-layout">
|
||||
<!-- 캘린더 일정 (중앙 좌측) -->
|
||||
<div class="schedule-section">
|
||||
<h3>캘린더 일정</h3>
|
||||
<div class="schedule-list">
|
||||
<div class="schedule-item urgent">
|
||||
<div class="schedule-date">09/20</div>
|
||||
<div class="schedule-content">
|
||||
<div class="schedule-title">도장 작업 출고</div>
|
||||
<div class="schedule-type">외주출고</div>
|
||||
<div class="schedule-memo">A구역 파이프 20본, B구역 밸브 5개</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="schedule-item normal">
|
||||
<div class="schedule-date">09/22</div>
|
||||
<div class="schedule-content">
|
||||
<div class="schedule-title">압력시험</div>
|
||||
<div class="schedule-type">검사일정</div>
|
||||
<div class="schedule-memo">시험압력: 15bar, 30분간 유지</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 입고 예정 품목 (우측) -->
|
||||
<div class="delivery-section">
|
||||
<h3>입고 예정 품목</h3>
|
||||
<div class="delivery-list">
|
||||
<div class="delivery-item completed">
|
||||
<span class="delivery-status">✅</span>
|
||||
<div class="delivery-info">
|
||||
<div class="delivery-name">파이프 4인치 x 50EA</div>
|
||||
<div class="delivery-date">입고완료 - 09/10</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="delivery-item warning">
|
||||
<span class="delivery-status">🟡</span>
|
||||
<div class="delivery-info">
|
||||
<div class="delivery-name">밸브 2인치 x 10EA</div>
|
||||
<div class="delivery-date">입고예정 - 09/16</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="delivery-item delayed">
|
||||
<span class="delivery-status">🔴</span>
|
||||
<div class="delivery-info">
|
||||
<div class="delivery-name">엘보 4인치 x 20EA</div>
|
||||
<div class="delivery-date">지연 - 09/12 → 09/18</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Follow-up 리스트 (하단) -->
|
||||
<div class="followup-section">
|
||||
<h3>Follow-up 리스트</h3>
|
||||
<div class="followup-list">
|
||||
<div class="followup-item priority-high">
|
||||
<div class="followup-priority">🔴 긴급</div>
|
||||
<div class="followup-content">
|
||||
<div class="followup-title">밸브 A 납기 지연 대응</div>
|
||||
<div class="followup-description">주 공급업체 생산 지연으로 대체 업체 검토 필요</div>
|
||||
<div class="followup-meta">
|
||||
<span class="followup-responsible">김구매</span>
|
||||
<span class="followup-date">등록: 09/10 | 예상해결: 09/17</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="followup-status">진행중</div>
|
||||
</div>
|
||||
|
||||
<div class="followup-item priority-medium">
|
||||
<div class="followup-priority">🟡 높음</div>
|
||||
<div class="followup-content">
|
||||
<div class="followup-title">용접 검사 일정 조정</div>
|
||||
<div class="followup-description">고객사 일정 변경으로 검사일 재조정 필요</div>
|
||||
<div class="followup-meta">
|
||||
<span class="followup-responsible">최품질</span>
|
||||
<span class="followup-date">등록: 09/12 | 예상해결: 09/20</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="followup-status">검토중</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 입고 검수 페이지 -->
|
||||
<div id="incoming-inspection" class="page">
|
||||
<div class="page-header">
|
||||
<h2>입고 검수 & 보관 관리</h2>
|
||||
<p class="page-description">발주 정보 연동을 통한 입고 처리 및 보관 관리</p>
|
||||
</div>
|
||||
|
||||
<!-- 발주 연동 대시보드 (상단) -->
|
||||
<div class="purchase-dashboard">
|
||||
<h3>발주 연동 입고 대시보드</h3>
|
||||
<div class="purchase-list">
|
||||
<div class="purchase-item status-pending">
|
||||
<div class="purchase-info">
|
||||
<div class="purchase-header">
|
||||
<span class="po-number">PO-2024-0156</span>
|
||||
<span class="purchase-status status-pending">입고대기</span>
|
||||
</div>
|
||||
<div class="purchase-details">
|
||||
<div class="item-name">스테인리스 파이프 4인치 SCH40</div>
|
||||
<div class="item-meta">수량: 50EA | 공급업체: 대한파이프 | 담당: 김구매</div>
|
||||
<div class="item-dates">발주일: 2024-09-01 | 예정일: 2024-09-15</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary">검수 시작</button>
|
||||
</div>
|
||||
|
||||
<div class="purchase-item status-inspecting">
|
||||
<div class="purchase-info">
|
||||
<div class="purchase-header">
|
||||
<span class="po-number">PO-2024-0157</span>
|
||||
<span class="purchase-status status-inspecting">검수중</span>
|
||||
</div>
|
||||
<div class="purchase-details">
|
||||
<div class="item-name">게이트밸브 2인치 150LB</div>
|
||||
<div class="item-meta">수량: 10EA | 공급업체: 코리아밸브 | 담당: 김구매</div>
|
||||
<div class="item-dates">발주일: 2024-09-05 | 예정일: 2024-09-16</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-warning">검수 진행중</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inspection-layout">
|
||||
<!-- 검수 프로세스 (좌측) -->
|
||||
<div class="inspection-process">
|
||||
<h3>입고 검수 프로세스</h3>
|
||||
|
||||
<div class="process-steps">
|
||||
<div class="step completed">
|
||||
<div class="step-number">1</div>
|
||||
<div class="step-content">
|
||||
<h4>입고 확인</h4>
|
||||
<ul class="checklist">
|
||||
<li class="checked">✅ 납품서 확인</li>
|
||||
<li class="checked">✅ 검사성적서 확인</li>
|
||||
<li class="checked">✅ 포장 상태 체크</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step active">
|
||||
<div class="step-number">2</div>
|
||||
<div class="step-content">
|
||||
<h4>검수 진행</h4>
|
||||
<ul class="checklist">
|
||||
<li class="checked">✅ 수량 검수 (10/10 EA)</li>
|
||||
<li class="checked">✅ 외관 검사</li>
|
||||
<li class="active">🔄 규격 검사 진행중</li>
|
||||
<li>📷 사진 촬영 대기</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step pending">
|
||||
<div class="step-number">3</div>
|
||||
<div class="step-content">
|
||||
<h4>검수 결과</h4>
|
||||
<div class="result-options">
|
||||
<button class="btn btn-success btn-sm">✅ 합격</button>
|
||||
<button class="btn btn-danger btn-sm">❌ 불합격</button>
|
||||
<button class="btn btn-warning btn-sm">📝 조건부 합격</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 보관 위치 관리 (우측) -->
|
||||
<div class="storage-management">
|
||||
<h3>보관 위치 관리</h3>
|
||||
|
||||
<div class="warehouse-zones">
|
||||
<div class="zone-item">
|
||||
<div class="zone-header">
|
||||
<span class="zone-name">A구역 (파이프류)</span>
|
||||
<span class="zone-capacity">75/100</span>
|
||||
</div>
|
||||
<div class="zone-shelves">
|
||||
<div class="shelf available">A-1</div>
|
||||
<div class="shelf occupied">A-2</div>
|
||||
<div class="shelf available">A-3</div>
|
||||
<div class="shelf occupied">A-4</div>
|
||||
<div class="shelf available">A-5</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-item">
|
||||
<div class="zone-header">
|
||||
<span class="zone-name">B구역 (밸브류)</span>
|
||||
<span class="zone-capacity">45/80</span>
|
||||
</div>
|
||||
<div class="zone-shelves">
|
||||
<div class="shelf available">B-1</div>
|
||||
<div class="shelf available">B-2</div>
|
||||
<div class="shelf occupied">B-3</div>
|
||||
<div class="shelf available">B-4</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="storage-actions">
|
||||
<div class="selected-location">
|
||||
<span class="label">선택된 위치:</span>
|
||||
<span class="location">B-2-중단</span>
|
||||
</div>
|
||||
<button class="btn btn-primary">📍 위치 지정 완료</button>
|
||||
<button class="btn btn-secondary">🏷️ QR코드 라벨 출력</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 인수인계 현황 -->
|
||||
<div class="handover-status">
|
||||
<h3>인수인계 현황</h3>
|
||||
<div class="handover-list">
|
||||
<div class="handover-item">
|
||||
<div class="item-info">
|
||||
<span class="item-name">파이프 4인치</span>
|
||||
<span class="item-location">A-3-상단</span>
|
||||
</div>
|
||||
<div class="quantity-info">
|
||||
<span class="total">전체: 50EA</span>
|
||||
<span class="handed">인수: 30EA</span>
|
||||
<span class="remaining">잔량: 20EA</span>
|
||||
</div>
|
||||
<span class="handover-status-badge status-partial">부분인수</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 생산팀 작업 관리 페이지 -->
|
||||
<div id="production-work" class="page">
|
||||
<div class="page-header">
|
||||
<h2>생산팀 작업 관리</h2>
|
||||
<p class="page-description">김그룹장 - 용접팀 일일 작업 현황</p>
|
||||
</div>
|
||||
|
||||
<div class="work-layout">
|
||||
<!-- 일일 작업 현황 (좌측) -->
|
||||
<div class="daily-work">
|
||||
<h3>일일 작업 현황 입력</h3>
|
||||
|
||||
<div class="work-form">
|
||||
<div class="form-section">
|
||||
<h4>기본 정보</h4>
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label>프로젝트</label>
|
||||
<select class="form-select">
|
||||
<option selected>TK-2024-015 (ABC 공장 배관공사)</option>
|
||||
<option>TK-2024-016 (DEF 플랜트)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>작업 인원</label>
|
||||
<input type="number" value="5" class="form-input">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>작업 내용</label>
|
||||
<input type="text" value="메인 라인 파이프 용접" class="form-input">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>진행률</label>
|
||||
<div class="progress-input">
|
||||
<input type="range" min="0" max="100" value="75" class="progress-slider">
|
||||
<span class="progress-value">75%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<h4>이슈 사항</h4>
|
||||
<div class="issue-list">
|
||||
<div class="issue-item">
|
||||
<div class="issue-header">
|
||||
<span class="issue-time">14:30</span>
|
||||
<span class="issue-type type-material">자재부족</span>
|
||||
<span class="issue-urgency urgency-high">높음</span>
|
||||
</div>
|
||||
<div class="issue-content">
|
||||
<div class="issue-description">엘보 4인치 10EA 부족으로 작업 중단</div>
|
||||
<div class="issue-solution">구매팀에 긴급 요청, 대체재 검토</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="issue-item">
|
||||
<div class="issue-header">
|
||||
<span class="issue-time">10:15</span>
|
||||
<span class="issue-type type-quality">품질이슈</span>
|
||||
<span class="issue-urgency urgency-medium">보통</span>
|
||||
</div>
|
||||
<div class="issue-content">
|
||||
<div class="issue-description">용접부 기공 발견, 재작업 필요</div>
|
||||
<div class="issue-solution">해당 부위 그라인딩 후 재용접</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-secondary">➕ 새 이슈 등록</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 자재 확인 (우측) -->
|
||||
<div class="material-check">
|
||||
<h3>자재 확인 기능</h3>
|
||||
|
||||
<div class="material-search">
|
||||
<div class="search-input">
|
||||
<input type="text" placeholder="Job No. 입력 (TK-2024-015)" class="form-input">
|
||||
<button class="btn btn-primary">🔍 BOM 조회</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="material-list">
|
||||
<div class="material-item status-available">
|
||||
<div class="material-info">
|
||||
<div class="material-name">파이프 4인치 SCH40</div>
|
||||
<div class="material-details">필요: 50EA | 위치: A-3-상단</div>
|
||||
</div>
|
||||
<div class="material-status">
|
||||
<span class="status-badge status-available">🟢 사용가능</span>
|
||||
<span class="material-qty">45EA</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="material-item status-ordered">
|
||||
<div class="material-info">
|
||||
<div class="material-name">엘보 4인치 150LB</div>
|
||||
<div class="material-details">필요: 20EA | 구매 진행 중</div>
|
||||
</div>
|
||||
<div class="material-status">
|
||||
<span class="status-badge status-ordered">🟠 발주중</span>
|
||||
<span class="material-date">입고예정: 09/18</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="material-item status-not-requested">
|
||||
<div class="material-info">
|
||||
<div class="material-name">플랜지 4인치 150LB</div>
|
||||
<div class="material-details">필요: 15EA | 설계팀 구매 요청 대기</div>
|
||||
</div>
|
||||
<div class="material-status">
|
||||
<span class="status-badge status-not-requested">⚫ 미요청</span>
|
||||
<span class="material-note">사양 확정 대기</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="material-item status-ready">
|
||||
<div class="material-info">
|
||||
<div class="material-name">밸브 2인치 150LB</div>
|
||||
<div class="material-details">필요: 5EA | 위치: B-2-중단</div>
|
||||
</div>
|
||||
<div class="material-status">
|
||||
<span class="status-badge status-ready">🟡 입고완료</span>
|
||||
<button class="btn btn-sm btn-primary">인수 처리</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="material-actions">
|
||||
<div class="action-note">
|
||||
<p><strong>⚠️ 중요:</strong> 생산팀은 자재 요청을 하지 않습니다.</p>
|
||||
<p>부족한 자재 발견시 → 데일리 체크에 이슈 등록</p>
|
||||
</div>
|
||||
<button class="btn btn-warning">📝 데일리 체크에 기록</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="scripts/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
641
demo/scripts/main.js
Normal file
641
demo/scripts/main.js
Normal file
@@ -0,0 +1,641 @@
|
||||
// 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 = `
|
||||
<div class="modal">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"></h3>
|
||||
</div>
|
||||
<div class="modal-body"></div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" onclick="hideModal()">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 오버레이 클릭시 모달 닫기
|
||||
modal.addEventListener('click', function(e) {
|
||||
if (e.target === modal) {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
return modal;
|
||||
}
|
||||
|
||||
// 유틸리티 함수들
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('ko-KR');
|
||||
}
|
||||
|
||||
function formatNumber(number) {
|
||||
return number.toLocaleString('ko-KR');
|
||||
}
|
||||
|
||||
function formatCurrency(amount) {
|
||||
return new Intl.NumberFormat('ko-KR', {
|
||||
style: 'currency',
|
||||
currency: 'KRW'
|
||||
}).format(amount);
|
||||
}
|
||||
|
||||
// 검색 기능
|
||||
function searchItems(query, items, searchFields) {
|
||||
if (!query) return items;
|
||||
|
||||
const lowercaseQuery = query.toLowerCase();
|
||||
return items.filter(item => {
|
||||
return searchFields.some(field => {
|
||||
const value = item[field];
|
||||
return value && value.toString().toLowerCase().includes(lowercaseQuery);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 정렬 기능
|
||||
function sortItems(items, field, direction = 'asc') {
|
||||
return items.sort((a, b) => {
|
||||
const aValue = a[field];
|
||||
const bValue = b[field];
|
||||
|
||||
if (direction === 'asc') {
|
||||
return aValue > bValue ? 1 : -1;
|
||||
} else {
|
||||
return aValue < bValue ? 1 : -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 필터 기능
|
||||
function filterItems(items, filters) {
|
||||
return items.filter(item => {
|
||||
return Object.entries(filters).every(([key, value]) => {
|
||||
if (!value) return true;
|
||||
return item[key] === value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 로컬 스토리지 관련
|
||||
function saveToLocalStorage(key, data) {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(data));
|
||||
} catch (error) {
|
||||
console.error('로컬 스토리지 저장 실패:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function loadFromLocalStorage(key, defaultValue = null) {
|
||||
try {
|
||||
const data = localStorage.getItem(key);
|
||||
return data ? JSON.parse(data) : defaultValue;
|
||||
} catch (error) {
|
||||
console.error('로컬 스토리지 로드 실패:', error);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
// 키보드 단축키
|
||||
document.addEventListener('keydown', function(e) {
|
||||
// Ctrl + 숫자키로 페이지 전환
|
||||
if (e.ctrlKey && e.key >= '1' && e.key <= '4') {
|
||||
e.preventDefault();
|
||||
const pages = ['project-registration', 'production-meeting', 'incoming-inspection', 'production-work'];
|
||||
const pageIndex = parseInt(e.key) - 1;
|
||||
if (pages[pageIndex]) {
|
||||
showPage(pages[pageIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
// ESC로 모달 닫기
|
||||
if (e.key === 'Escape') {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
// 전역 함수로 노출 (HTML onclick에서 사용)
|
||||
window.showPage = showPage;
|
||||
window.showModal = showModal;
|
||||
window.hideModal = hideModal;
|
||||
window.showNotification = showNotification;
|
||||
|
||||
console.log('TK Project Demo JavaScript 로드 완료');
|
||||
1447
demo/styles/devonthink.css
Normal file
1447
demo/styles/devonthink.css
Normal file
File diff suppressed because it is too large
Load Diff
455
demo/styles/main.css
Normal file
455
demo/styles/main.css
Normal file
@@ -0,0 +1,455 @@
|
||||
/* 기본 CSS - DevonThink 스타일과 함께 사용 */
|
||||
|
||||
/* 추가 유틸리티 클래스 */
|
||||
.text-center { text-align: center; }
|
||||
.text-left { text-align: left; }
|
||||
.text-right { text-align: right; }
|
||||
|
||||
.mb-0 { margin-bottom: 0; }
|
||||
.mb-1 { margin-bottom: 8px; }
|
||||
.mb-2 { margin-bottom: 16px; }
|
||||
.mb-3 { margin-bottom: 24px; }
|
||||
.mb-4 { margin-bottom: 32px; }
|
||||
|
||||
.mt-0 { margin-top: 0; }
|
||||
.mt-1 { margin-top: 8px; }
|
||||
.mt-2 { margin-top: 16px; }
|
||||
.mt-3 { margin-top: 24px; }
|
||||
.mt-4 { margin-top: 32px; }
|
||||
|
||||
.p-0 { padding: 0; }
|
||||
.p-1 { padding: 8px; }
|
||||
.p-2 { padding: 16px; }
|
||||
.p-3 { padding: 24px; }
|
||||
.p-4 { padding: 32px; }
|
||||
|
||||
.d-none { display: none; }
|
||||
.d-block { display: block; }
|
||||
.d-flex { display: flex; }
|
||||
.d-grid { display: grid; }
|
||||
|
||||
.flex-1 { flex: 1; }
|
||||
.flex-column { flex-direction: column; }
|
||||
.align-items-center { align-items: center; }
|
||||
.justify-content-center { justify-content: center; }
|
||||
.justify-content-between { justify-content: space-between; }
|
||||
|
||||
.w-100 { width: 100%; }
|
||||
.h-100 { height: 100%; }
|
||||
|
||||
/* 애니메이션 */
|
||||
.fade-in {
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.slide-in {
|
||||
animation: slideIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from { transform: translateX(-20px); opacity: 0; }
|
||||
to { transform: translateX(0); opacity: 1; }
|
||||
}
|
||||
|
||||
/* 호버 효과 */
|
||||
.hover-lift {
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.hover-lift:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--dt-shadow-lg);
|
||||
}
|
||||
|
||||
/* 포커스 효과 */
|
||||
.focus-ring:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.2);
|
||||
}
|
||||
|
||||
/* 로딩 스피너 */
|
||||
.spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid var(--dt-gray-300);
|
||||
border-top: 2px solid var(--dt-primary);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 툴팁 */
|
||||
.tooltip {
|
||||
position: relative;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.tooltip::after {
|
||||
content: attr(data-tooltip);
|
||||
position: absolute;
|
||||
bottom: 125%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: var(--dt-gray-800);
|
||||
color: white;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s ease;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.tooltip:hover::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 알림 배지 */
|
||||
.notification-badge {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
background-color: var(--dt-danger);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 진행률 바 */
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background-color: var(--dt-gray-200);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar-fill {
|
||||
height: 100%;
|
||||
background-color: var(--dt-primary);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
/* 드래그 앤 드롭 */
|
||||
.drop-zone {
|
||||
border: 2px dashed var(--dt-gray-300);
|
||||
border-radius: 8px;
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
color: var(--dt-gray-600);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.drop-zone.drag-over {
|
||||
border-color: var(--dt-primary);
|
||||
background-color: rgba(74, 144, 226, 0.05);
|
||||
color: var(--dt-primary);
|
||||
}
|
||||
|
||||
/* 테이블 */
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--dt-shadow);
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
padding: 12px 16px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--dt-gray-200);
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: var(--dt-gray-50);
|
||||
font-weight: 600;
|
||||
color: var(--dt-gray-700);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.table td {
|
||||
font-size: 14px;
|
||||
color: var(--dt-gray-800);
|
||||
}
|
||||
|
||||
.table tr:hover {
|
||||
background-color: var(--dt-gray-50);
|
||||
}
|
||||
|
||||
/* 모달 */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-overlay.active {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.modal {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--dt-shadow-lg);
|
||||
max-width: 600px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-overlay.active .modal {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 20px 24px 16px 24px;
|
||||
border-bottom: 1px solid var(--dt-gray-200);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--dt-gray-800);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 16px 24px 20px 24px;
|
||||
border-top: 1px solid var(--dt-gray-200);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* 탭 */
|
||||
.tabs {
|
||||
border-bottom: 1px solid var(--dt-gray-200);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.tab-list {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.tab-link {
|
||||
display: block;
|
||||
padding: 12px 0;
|
||||
color: var(--dt-gray-600);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.tab-link:hover {
|
||||
color: var(--dt-gray-800);
|
||||
}
|
||||
|
||||
.tab-link.active {
|
||||
color: var(--dt-primary);
|
||||
border-bottom-color: var(--dt-primary);
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 아코디언 */
|
||||
.accordion-item {
|
||||
border: 1px solid var(--dt-gray-200);
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.accordion-header {
|
||||
padding: 16px 20px;
|
||||
background-color: var(--dt-gray-50);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: var(--dt-gray-800);
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.accordion-header:hover {
|
||||
background-color: var(--dt-gray-100);
|
||||
}
|
||||
|
||||
.accordion-header.active {
|
||||
background-color: var(--dt-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.accordion-icon {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.accordion-header.active .accordion-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.accordion-content {
|
||||
padding: 0 20px;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease, padding 0.3s ease;
|
||||
}
|
||||
|
||||
.accordion-content.active {
|
||||
padding: 20px;
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
/* 알림 메시지 */
|
||||
.alert {
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 14px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: rgba(52, 168, 83, 0.1);
|
||||
border-color: var(--dt-success);
|
||||
color: var(--dt-success);
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-color: rgba(251, 188, 4, 0.1);
|
||||
border-color: var(--dt-warning);
|
||||
color: #B8860B;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-color: rgba(234, 67, 53, 0.1);
|
||||
border-color: var(--dt-danger);
|
||||
color: var(--dt-danger);
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: rgba(74, 144, 226, 0.1);
|
||||
border-color: var(--dt-primary);
|
||||
color: var(--dt-primary);
|
||||
}
|
||||
|
||||
/* 빈 상태 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
color: var(--dt-gray-500);
|
||||
}
|
||||
|
||||
.empty-state-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 16px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-state-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
color: var(--dt-gray-700);
|
||||
}
|
||||
|
||||
.empty-state-description {
|
||||
font-size: 14px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* 스크롤바 스타일링 */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--dt-gray-100);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--dt-gray-400);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--dt-gray-500);
|
||||
}
|
||||
|
||||
/* 인쇄 스타일 */
|
||||
@media print {
|
||||
.sidebar,
|
||||
.btn,
|
||||
.modal-overlay {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.page {
|
||||
display: block !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid #ccc !important;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user