diff --git a/system1-factory/api/config/routes.js b/system1-factory/api/config/routes.js
index 6bc8d7e..bbe6d0e 100644
--- a/system1-factory/api/config/routes.js
+++ b/system1-factory/api/config/routes.js
@@ -47,12 +47,10 @@ function setupRoutes(app) {
const vacationRequestRoutes = require('../routes/vacationRequestRoutes');
const vacationTypeRoutes = require('../routes/vacationTypeRoutes');
const vacationBalanceRoutes = require('../routes/vacationBalanceRoutes');
- const visitRequestRoutes = require('../routes/visitRequestRoutes');
const workIssueRoutes = require('../routes/workIssueRoutes');
const departmentRoutes = require('../routes/departmentRoutes');
const patrolRoutes = require('../routes/patrolRoutes');
const notificationRoutes = require('../routes/notificationRoutes');
- const notificationRecipientRoutes = require('../routes/notificationRecipientRoutes');
// Rate Limiters 설정
const rateLimit = require('express-rate-limit');
@@ -154,13 +152,11 @@ function setupRoutes(app) {
app.use('/api/vacation-requests', vacationRequestRoutes); // 휴가 신청 관리
app.use('/api/vacation-types', vacationTypeRoutes); // 휴가 유형 관리
app.use('/api/vacation-balances', vacationBalanceRoutes); // 휴가 잔액 관리
- app.use('/api/workplace-visits', visitRequestRoutes); // 출입 신청 및 안전교육 관리
app.use('/api/tbm', tbmRoutes); // TBM 시스템
app.use('/api/work-issues', workIssueRoutes); // 카테고리/아이템 + 신고 조회 (같은 MariaDB 공유)
app.use('/api/departments', departmentRoutes); // 부서 관리
app.use('/api/patrol', patrolRoutes); // 일일순회점검 시스템
app.use('/api/notifications', notificationRoutes); // 알림 시스템
- app.use('/api/notification-recipients', notificationRecipientRoutes); // 알림 수신자 설정
app.use('/api', uploadBgRoutes);
// Swagger API 문서
diff --git a/system1-factory/api/routes.js b/system1-factory/api/routes.js
index 6bc8d7e..bbe6d0e 100644
--- a/system1-factory/api/routes.js
+++ b/system1-factory/api/routes.js
@@ -47,12 +47,10 @@ function setupRoutes(app) {
const vacationRequestRoutes = require('../routes/vacationRequestRoutes');
const vacationTypeRoutes = require('../routes/vacationTypeRoutes');
const vacationBalanceRoutes = require('../routes/vacationBalanceRoutes');
- const visitRequestRoutes = require('../routes/visitRequestRoutes');
const workIssueRoutes = require('../routes/workIssueRoutes');
const departmentRoutes = require('../routes/departmentRoutes');
const patrolRoutes = require('../routes/patrolRoutes');
const notificationRoutes = require('../routes/notificationRoutes');
- const notificationRecipientRoutes = require('../routes/notificationRecipientRoutes');
// Rate Limiters 설정
const rateLimit = require('express-rate-limit');
@@ -154,13 +152,11 @@ function setupRoutes(app) {
app.use('/api/vacation-requests', vacationRequestRoutes); // 휴가 신청 관리
app.use('/api/vacation-types', vacationTypeRoutes); // 휴가 유형 관리
app.use('/api/vacation-balances', vacationBalanceRoutes); // 휴가 잔액 관리
- app.use('/api/workplace-visits', visitRequestRoutes); // 출입 신청 및 안전교육 관리
app.use('/api/tbm', tbmRoutes); // TBM 시스템
app.use('/api/work-issues', workIssueRoutes); // 카테고리/아이템 + 신고 조회 (같은 MariaDB 공유)
app.use('/api/departments', departmentRoutes); // 부서 관리
app.use('/api/patrol', patrolRoutes); // 일일순회점검 시스템
app.use('/api/notifications', notificationRoutes); // 알림 시스템
- app.use('/api/notification-recipients', notificationRecipientRoutes); // 알림 수신자 설정
app.use('/api', uploadBgRoutes);
// Swagger API 문서
diff --git a/system1-factory/api/routes/notificationRecipientRoutes.js b/system1-factory/api/routes/notificationRecipientRoutes.js
deleted file mode 100644
index 12f91bb..0000000
--- a/system1-factory/api/routes/notificationRecipientRoutes.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// routes/notificationRecipientRoutes.js
-const express = require('express');
-const router = express.Router();
-const notificationRecipientController = require('../controllers/notificationRecipientController');
-const { verifyToken, requireMinLevel } = require('../middlewares/auth');
-
-// 모든 라우트에 인증 필요
-router.use(verifyToken);
-
-// 알림 유형 목록
-router.get('/types', notificationRecipientController.getTypes);
-
-// 전체 수신자 목록 (유형별 그룹화)
-router.get('/', notificationRecipientController.getAll);
-
-// 유형별 수신자 조회
-router.get('/:type', notificationRecipientController.getByType);
-
-// 수신자 추가 (관리자만)
-router.post('/', requireMinLevel('admin'), notificationRecipientController.add);
-
-// 유형별 수신자 일괄 설정 (관리자만)
-router.put('/:type', requireMinLevel('admin'), notificationRecipientController.setRecipients);
-
-// 수신자 제거 (관리자만)
-router.delete('/:type/:userId', requireMinLevel('admin'), notificationRecipientController.remove);
-
-module.exports = router;
diff --git a/system1-factory/api/routes/systemRoutes.js b/system1-factory/api/routes/systemRoutes.js
index e2d5243..b2d4a98 100644
--- a/system1-factory/api/routes/systemRoutes.js
+++ b/system1-factory/api/routes/systemRoutes.js
@@ -2,7 +2,6 @@
const express = require('express');
const router = express.Router();
const systemController = require('../controllers/systemController');
-const userController = require('../controllers/userController');
const { requireAuth, requireRole } = require('../middlewares/auth');
// 모든 라우트에 인증 및 시스템 권한 확인 적용
@@ -35,44 +34,6 @@ router.get('/alerts', systemController.getSystemAlerts);
*/
router.get('/recent-activities', systemController.getRecentActivities);
-// ===== 사용자 관리 관련 =====
-
-/**
- * GET /api/system/users/stats
- * 사용자 통계 조회
- */
-router.get('/users/stats', systemController.getUserStats);
-
-/**
- * GET /api/system/users
- * 모든 사용자 목록 조회
- */
-router.get('/users', userController.getAllUsers);
-
-/**
- * POST /api/system/users
- * 새 사용자 생성
- */
-router.post('/users', userController.createUser);
-
-/**
- * PUT /api/system/users/:id
- * 사용자 정보 수정
- */
-router.put('/users/:id', userController.updateUser);
-
-/**
- * DELETE /api/system/users/:id
- * 사용자 삭제
- */
-router.delete('/users/:id', userController.deleteUser);
-
-/**
- * POST /api/system/users/:id/reset-password
- * 사용자 비밀번호 재설정
- */
-router.post('/users/:id/reset-password', userController.resetUserPassword);
-
// ===== 시스템 로그 관련 =====
/**
diff --git a/system1-factory/api/routes/visitRequestRoutes.js b/system1-factory/api/routes/visitRequestRoutes.js
deleted file mode 100644
index 9adf676..0000000
--- a/system1-factory/api/routes/visitRequestRoutes.js
+++ /dev/null
@@ -1,66 +0,0 @@
-const express = require('express');
-const router = express.Router();
-const visitRequestController = require('../controllers/visitRequestController');
-const { verifyToken } = require('../middlewares/auth');
-
-// 모든 라우트에 인증 미들웨어 적용
-router.use(verifyToken);
-
-// ==================== 출입 신청 관리 ====================
-
-// 출입 신청 생성
-router.post('/requests', visitRequestController.createVisitRequest);
-
-// 출입 신청 목록 조회 (필터: status, visit_date, start_date, end_date, requester_id, category_id)
-router.get('/requests', visitRequestController.getAllVisitRequests);
-
-// 출입 신청 상세 조회
-router.get('/requests/:id', visitRequestController.getVisitRequestById);
-
-// 출입 신청 수정
-router.put('/requests/:id', visitRequestController.updateVisitRequest);
-
-// 출입 신청 삭제
-router.delete('/requests/:id', visitRequestController.deleteVisitRequest);
-
-// 출입 신청 승인
-router.put('/requests/:id/approve', visitRequestController.approveVisitRequest);
-
-// 출입 신청 반려
-router.put('/requests/:id/reject', visitRequestController.rejectVisitRequest);
-
-// ==================== 방문 목적 관리 ====================
-
-// 모든 방문 목적 조회
-router.get('/purposes', visitRequestController.getAllVisitPurposes);
-
-// 활성 방문 목적만 조회
-router.get('/purposes/active', visitRequestController.getActiveVisitPurposes);
-
-// 방문 목적 추가
-router.post('/purposes', visitRequestController.createVisitPurpose);
-
-// 방문 목적 수정
-router.put('/purposes/:id', visitRequestController.updateVisitPurpose);
-
-// 방문 목적 삭제
-router.delete('/purposes/:id', visitRequestController.deleteVisitPurpose);
-
-// ==================== 안전교육 기록 관리 ====================
-
-// 안전교육 기록 생성
-router.post('/training', visitRequestController.createTrainingRecord);
-
-// 안전교육 기록 목록 조회 (필터: training_date, start_date, end_date, trainer_id)
-router.get('/training', visitRequestController.getTrainingRecords);
-
-// 특정 출입 신청의 안전교육 기록 조회
-router.get('/training/request/:requestId', visitRequestController.getTrainingRecordByRequestId);
-
-// 안전교육 기록 수정
-router.put('/training/:id', visitRequestController.updateTrainingRecord);
-
-// 안전교육 완료 (서명 포함)
-router.post('/training/:id/complete', visitRequestController.completeTraining);
-
-module.exports = router;
diff --git a/system1-factory/web/components/mobile-nav.html b/system1-factory/web/components/mobile-nav.html
deleted file mode 100644
index 7d72119..0000000
--- a/system1-factory/web/components/mobile-nav.html
+++ /dev/null
@@ -1,147 +0,0 @@
-
-
-
-
-
-
-
diff --git a/system1-factory/web/components/navbar.html b/system1-factory/web/components/navbar.html
deleted file mode 100644
index a656d69..0000000
--- a/system1-factory/web/components/navbar.html
+++ /dev/null
@@ -1,764 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/system1-factory/web/components/sidebar-nav.html b/system1-factory/web/components/sidebar-nav.html
deleted file mode 100644
index 0a555f5..0000000
--- a/system1-factory/web/components/sidebar-nav.html
+++ /dev/null
@@ -1,482 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/system1-factory/web/components/sidebar.html b/system1-factory/web/components/sidebar.html
deleted file mode 100644
index 532fd6a..0000000
--- a/system1-factory/web/components/sidebar.html
+++ /dev/null
@@ -1,136 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/system1-factory/web/css/admin-pages.css b/system1-factory/web/css/admin-pages.css
deleted file mode 100644
index fb42bc8..0000000
--- a/system1-factory/web/css/admin-pages.css
+++ /dev/null
@@ -1,1555 +0,0 @@
-/**
- * 관리자 페이지 공통 스타일
- * 사무적이고 전문적인 디자인 시스템
- *
- * 적용 페이지:
- * - projects.html (프로젝트 관리)
- * - workers.html (작업자 관리)
- * - codes.html (코드 관리)
- */
-
-/* ============================================
- 1. 전역 변수 및 기본 설정
- ============================================ */
-:root {
- /* 색상 시스템 - 사무적 느낌의 중성 색상 */
- --color-primary: #2563eb;
- --color-primary-dark: #1e40af;
- --color-primary-light: #dbeafe;
-
- --color-secondary: #64748b;
- --color-secondary-dark: #475569;
- --color-secondary-light: #f1f5f9;
-
- --color-success: #10b981;
- --color-warning: #f59e0b;
- --color-error: #ef4444;
- --color-info: #3b82f6;
-
- /* 배경 색상 */
- --bg-body: #f8fafc;
- --bg-card: #ffffff;
- --bg-hover: #f1f5f9;
-
- /* 텍스트 색상 */
- --text-primary: #0f172a;
- --text-secondary: #64748b;
- --text-muted: #94a3b8;
-
- /* 테두리 색상 */
- --border-color: #e2e8f0;
- --border-focus: #2563eb;
-
- /* 그림자 */
- --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
- --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
- --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
-
- /* 간격 */
- --space-xs: 0.25rem;
- --space-sm: 0.5rem;
- --space-md: 1rem;
- --space-lg: 1.5rem;
- --space-xl: 2rem;
- --space-2xl: 3rem;
-
- /* 폰트 크기 */
- --font-xs: 0.75rem;
- --font-sm: 0.875rem;
- --font-base: 1rem;
- --font-lg: 1.125rem;
- --font-xl: 1.25rem;
- --font-2xl: 1.5rem;
- --font-3xl: 1.875rem;
-
- /* Border Radius */
- --radius-sm: 0.25rem;
- --radius-md: 0.5rem;
- --radius-lg: 0.75rem;
- --radius-xl: 1rem;
-}
-
-/* ============================================
- 2. 레이아웃 구조 (2단 레이아웃: 사이드바 + 메인)
- ============================================ */
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans KR', Roboto, sans-serif;
- background: var(--bg-body);
- color: var(--text-primary);
- line-height: 1.6;
- margin: 0;
- padding: 0;
-}
-
-/* 페이지 컨테이너: 사이드바 + 메인 콘텐츠 */
-.page-container {
- display: flex;
- min-height: calc(100vh - 80px); /* 네비바 높이 제외 */
- background: var(--bg-body);
-}
-
-/* 사이드바 */
-.sidebar {
- width: 240px;
- min-width: 240px;
- flex-shrink: 0;
- background: #ffffff;
- border-right: 1px solid var(--border-color);
- box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
- overflow-y: auto;
-}
-
-.sidebar-nav {
- padding: var(--space-lg) 0;
-}
-
-.sidebar-header {
- padding: 0 var(--space-lg) var(--space-md);
- border-bottom: 1px solid var(--border-color);
- margin-bottom: var(--space-md);
-}
-
-.sidebar-title {
- font-size: var(--font-base);
- font-weight: 700;
- color: var(--text-primary);
- margin: 0;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.sidebar-menu {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-.menu-item a {
- display: flex;
- align-items: center;
- gap: var(--space-sm);
- padding: var(--space-sm) var(--space-lg);
- color: var(--text-secondary);
- text-decoration: none;
- transition: all 0.2s ease;
- white-space: nowrap;
-}
-
-.menu-item a:hover {
- background: var(--bg-hover);
- color: var(--text-primary);
-}
-
-.menu-item.active a {
- background: var(--color-primary-light);
- color: var(--color-primary);
- font-weight: 600;
- border-right: 3px solid var(--color-primary);
-}
-
-.menu-icon {
- font-size: var(--font-lg);
- flex-shrink: 0;
-}
-
-.menu-text {
- font-size: var(--font-sm);
-}
-
-.menu-divider {
- height: 1px;
- background: var(--border-color);
- margin: var(--space-md) var(--space-lg);
-}
-
-/* 메인 콘텐츠 영역 */
-.main-content {
- flex: 1;
- padding: var(--space-lg);
- padding-left: var(--space-md);
- overflow-x: hidden;
- max-width: 100%;
- box-sizing: border-box;
-}
-
-.dashboard-main {
- width: 100%;
- max-width: 1400px;
- margin: 0 auto;
-}
-
-/* 뒤로가기 버튼 - 사이드바로 대체되어 숨김 */
-.back-button {
- display: none;
-}
-
-/* ============================================
- 3. 페이지 헤더
- ============================================ */
-.page-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: var(--space-xl);
- padding: var(--space-lg);
- background: var(--bg-card);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- box-shadow: var(--shadow-sm);
-}
-
-.page-title-section {
- flex: 1;
-}
-
-.page-title {
- display: flex;
- align-items: center;
- gap: var(--space-md);
- font-size: var(--font-3xl);
- font-weight: 700;
- color: var(--text-primary);
- margin: 0 0 var(--space-sm) 0;
- white-space: nowrap; /* 텍스트 줄바꿈 방지 */
-}
-
-.title-icon {
- font-size: var(--font-2xl);
- filter: grayscale(30%);
-}
-
-.page-description {
- font-size: var(--font-sm);
- color: var(--text-secondary);
- margin: 0;
- line-height: 1.5;
- max-width: 100%;
- word-wrap: break-word;
-}
-
-.page-actions {
- display: flex;
- gap: var(--space-sm);
- flex-shrink: 0;
-}
-
-/* ============================================
- 4. 버튼 스타일
- ============================================ */
-.btn {
- display: inline-flex;
- align-items: center;
- gap: var(--space-sm);
- padding: 0.625rem 1.25rem;
- font-size: var(--font-sm);
- font-weight: 600;
- border: none;
- border-radius: var(--radius-md);
- cursor: pointer;
- transition: all 0.2s ease;
- white-space: nowrap;
-}
-
-.btn-primary {
- background: var(--color-primary);
- color: white;
- box-shadow: var(--shadow-sm);
-}
-
-.btn-primary:hover {
- background: var(--color-primary-dark);
- box-shadow: var(--shadow-md);
- transform: translateY(-1px);
-}
-
-.btn-secondary {
- background: var(--bg-card);
- color: var(--text-secondary);
- border: 1px solid var(--border-color);
-}
-
-.btn-secondary:hover {
- background: var(--bg-hover);
- color: var(--text-primary);
- border-color: var(--color-secondary);
-}
-
-.btn-icon {
- font-size: var(--font-base);
- filter: grayscale(20%);
-}
-
-/* ============================================
- 5. 검색 섹션
- ============================================ */
-.search-section {
- background: var(--bg-card);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- padding: var(--space-lg);
- margin-bottom: var(--space-xl);
- box-shadow: var(--shadow-sm);
-}
-
-.search-bar {
- display: flex;
- gap: var(--space-md);
- margin-bottom: var(--space-md);
-}
-
-.search-input {
- flex: 1;
- padding: 0.625rem 1rem;
- font-size: var(--font-sm);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- background: var(--bg-body);
- transition: all 0.2s ease;
-}
-
-.search-input:focus {
- outline: none;
- border-color: var(--border-focus);
- background: white;
- box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
-}
-
-.search-btn {
- padding: 0.625rem 1.25rem;
- background: var(--color-primary);
- color: white;
- border: none;
- border-radius: var(--radius-md);
- font-size: var(--font-sm);
- font-weight: 600;
- cursor: pointer;
- white-space: nowrap;
- transition: all 0.2s ease;
-}
-
-.search-btn:hover {
- background: var(--color-primary-dark);
- transform: translateY(-1px);
-}
-
-/* 필터 영역 */
-.filter-group {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-md);
- align-items: center;
-}
-
-.filter-label {
- font-size: var(--font-sm);
- font-weight: 600;
- color: var(--text-secondary);
- margin-right: var(--space-sm);
-}
-
-.filter-btn {
- padding: 0.5rem 1rem;
- font-size: var(--font-sm);
- background: var(--bg-body);
- color: var(--text-secondary);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.filter-btn:hover {
- background: var(--bg-hover);
- color: var(--text-primary);
-}
-
-.filter-btn.active {
- background: var(--color-primary);
- color: white;
- border-color: var(--color-primary);
-}
-
-/* ============================================
- 6. 프로젝트 섹션
- ============================================ */
-.projects-section {
- background: var(--bg-card);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- padding: var(--space-lg);
- box-shadow: var(--shadow-sm);
- width: 100%;
- max-width: 100%;
- overflow: hidden;
- box-sizing: border-box;
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-wrap: wrap;
- gap: var(--space-md);
- margin-bottom: var(--space-lg);
- padding-bottom: var(--space-md);
- border-bottom: 1px solid var(--border-color);
-}
-
-.section-title {
- font-size: var(--font-xl);
- font-weight: 700;
- color: var(--text-primary);
- margin: 0;
-}
-
-/* 통계 카드 */
-.project-stats {
- display: flex;
- gap: var(--space-sm);
- flex-wrap: wrap;
-}
-
-.stat-item {
- display: flex;
- align-items: center;
- gap: var(--space-sm);
- padding: 0.625rem 1rem;
- background: var(--bg-card);
- border: 2px solid var(--border-color);
- border-radius: var(--radius-md);
- font-size: var(--font-sm);
- font-weight: 600;
- cursor: pointer;
- transition: all 0.2s ease;
- white-space: nowrap;
-}
-
-.stat-item:hover {
- transform: translateY(-2px);
- box-shadow: var(--shadow-md);
-}
-
-.stat-item.active {
- border-width: 2px;
- box-shadow: var(--shadow-md);
- transform: scale(1.02);
-}
-
-.stat-icon {
- font-size: var(--font-lg);
-}
-
-/* 상태별 통계 색상 */
-.active-stat {
- background: rgba(16, 185, 129, 0.05);
- color: var(--color-success);
- border-color: var(--color-success);
-}
-
-.inactive-stat {
- background: rgba(239, 68, 68, 0.05);
- color: var(--color-error);
- border-color: var(--color-error);
-}
-
-.total-stat {
- background: rgba(37, 99, 235, 0.05);
- color: var(--color-primary);
- border-color: var(--color-primary);
-}
-
-/* ============================================
- 7. 그리드 레이아웃 (중앙 정렬)
- ============================================ */
-.projects-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: var(--space-lg);
- width: 100%;
- max-width: 100%;
-}
-
-/* ============================================
- 8. 카드 스타일
- ============================================ */
-.project-card,
-.worker-card {
- background: var(--bg-card);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- padding: var(--space-lg);
- transition: all 0.2s ease;
- cursor: pointer;
- position: relative;
- display: flex;
- flex-direction: column;
- height: 420px;
- min-height: 420px;
- max-height: 420px;
- max-width: 100%;
- overflow: hidden;
- box-sizing: border-box;
- word-wrap: break-word;
-}
-
-.project-card:hover,
-.worker-card:hover {
- border-color: var(--color-primary);
- box-shadow: var(--shadow-lg);
- transform: translateY(-4px);
-}
-
-.project-card.inactive,
-.worker-card.inactive {
- opacity: 0.75;
- background: var(--bg-body);
-}
-
-/* 카드 헤더 */
-.project-header {
- display: flex;
- flex-direction: column;
- flex: 1;
- min-height: 0;
-}
-
-.project-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- gap: var(--space-sm);
- margin-bottom: var(--space-md);
-}
-
-.project-job-no {
- font-size: var(--font-xs);
- font-weight: 600;
- color: var(--text-muted);
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.project-name {
- font-size: var(--font-lg);
- font-weight: 700;
- color: var(--text-primary);
- margin: 0;
- line-height: 1.3;
-}
-
-.project-badge {
- padding: 0.25rem 0.75rem;
- font-size: var(--font-xs);
- font-weight: 600;
- border-radius: var(--radius-sm);
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.badge-active {
- background: rgba(16, 185, 129, 0.1);
- color: var(--color-success);
-}
-
-.badge-inactive {
- background: rgba(239, 68, 68, 0.1);
- color: var(--color-error);
-}
-
-/* 카드 메타 정보 */
-.project-meta {
- display: grid;
- grid-template-columns: 1fr;
- gap: var(--space-xs);
- font-size: var(--font-sm);
- color: var(--text-secondary);
- padding: var(--space-md);
- background: var(--bg-body);
- border-radius: var(--radius-md);
- margin-bottom: var(--space-md);
-}
-
-.project-meta > span {
- display: flex;
- align-items: center;
- gap: var(--space-xs);
- padding: var(--space-xs) 0;
- line-height: 1.5;
-}
-
-.project-meta > span:empty::after {
- content: '정보 없음';
- color: var(--text-muted);
- font-style: italic;
-}
-
-.meta-row {
- display: grid;
- grid-template-columns: 100px 1fr;
- align-items: center;
- gap: var(--space-sm);
- font-size: var(--font-sm);
- padding: var(--space-xs) 0;
-}
-
-.meta-label {
- font-weight: 600;
- color: var(--text-muted);
- font-size: var(--font-xs);
- text-transform: uppercase;
- letter-spacing: 0.3px;
-}
-
-.meta-value {
- color: var(--text-primary);
- font-weight: 500;
-}
-
-.meta-value:empty::after {
- content: '-';
- color: var(--text-muted);
-}
-
-/* 카드 액션 */
-.project-actions,
-.worker-actions {
- display: flex;
- gap: var(--space-sm);
- margin-top: auto;
- padding-top: var(--space-md);
- border-top: 1px solid var(--border-color);
-}
-
-.btn-edit,
-.btn-delete,
-.action-btn {
- flex: 1;
- padding: 0.5rem 1rem;
- font-size: var(--font-sm);
- font-weight: 600;
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- background: white;
- color: var(--text-secondary);
- cursor: pointer;
- transition: all 0.2s ease;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: var(--space-xs);
-}
-
-.btn-edit:hover {
- background: var(--color-primary);
- color: white;
- border-color: var(--color-primary);
- transform: translateY(-1px);
-}
-
-.btn-delete:hover,
-.action-btn.danger:hover {
- background: var(--color-error);
- color: white;
- border-color: var(--color-error);
- transform: translateY(-1px);
-}
-
-/* 작업자 카드 특별 스타일 */
-.worker-card .project-info {
- display: flex;
- align-items: flex-start;
- gap: var(--space-md);
- margin-bottom: var(--space-md);
-}
-
-.worker-avatar {
- width: 60px;
- height: 60px;
- border-radius: 50%;
- background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- box-shadow: var(--shadow-md);
-}
-
-.avatar-initial {
- color: white;
- font-size: var(--font-xl);
- font-weight: 700;
-}
-
-.worker-card.inactive .worker-avatar {
- background: linear-gradient(135deg, var(--color-secondary), var(--color-secondary-dark));
- opacity: 0.7;
-}
-
-.worker-details {
- flex: 1;
- min-width: 0;
-}
-
-/* 비활성화 오버레이 및 라벨 */
-.inactive-overlay {
- position: absolute;
- top: var(--space-md);
- right: var(--space-md);
- z-index: 10;
-}
-
-.inactive-badge {
- display: inline-flex;
- align-items: center;
- gap: var(--space-xs);
- padding: 0.375rem 0.75rem;
- background: rgba(239, 68, 68, 0.9);
- color: white;
- border-radius: var(--radius-md);
- font-size: var(--font-xs);
- font-weight: 700;
- box-shadow: var(--shadow-md);
-}
-
-.inactive-label {
- color: var(--color-error);
- font-size: var(--font-sm);
- font-weight: 600;
- margin-left: var(--space-xs);
-}
-
-.inactive-notice {
- color: var(--color-warning) !important;
- font-weight: 600 !important;
-}
-
-/* ============================================
- 9. 코드 관리 탭
- ============================================ */
-.code-tabs {
- display: flex;
- gap: var(--space-sm);
- margin-bottom: var(--space-xl);
- padding: var(--space-sm);
- background: var(--bg-card);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- overflow-x: auto;
-}
-
-.tab-btn {
- display: flex;
- align-items: center;
- gap: var(--space-sm);
- padding: 0.75rem 1.25rem;
- font-size: var(--font-sm);
- font-weight: 600;
- color: var(--text-secondary);
- background: transparent;
- border: none;
- border-radius: var(--radius-md);
- cursor: pointer;
- transition: all 0.2s ease;
- white-space: nowrap;
-}
-
-.tab-btn:hover {
- background: var(--bg-hover);
- color: var(--text-primary);
-}
-
-.tab-btn.active {
- color: var(--color-primary);
- background: var(--color-primary-light);
- border-bottom: 3px solid var(--color-primary);
- font-weight: 600;
-}
-
-.tab-icon {
- font-size: var(--font-base);
-}
-
-/* ============================================
- 10. 테이블 스타일
- ============================================ */
-.table-container {
- background: var(--bg-card);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- overflow: hidden;
-}
-
-table {
- width: 100%;
- border-collapse: collapse;
-}
-
-thead {
- background: var(--bg-body);
- border-bottom: 2px solid var(--border-color);
-}
-
-th {
- padding: 1rem;
- font-size: var(--font-sm);
- font-weight: 700;
- color: var(--text-secondary);
- text-align: left;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-td {
- padding: 1rem;
- font-size: var(--font-sm);
- color: var(--text-primary);
- border-bottom: 1px solid var(--border-color);
-}
-
-tr:hover {
- background: var(--bg-hover);
-}
-
-tr:last-child td {
- border-bottom: none;
-}
-
-/* 테이블 내 버튼 스타일 */
-.data-table .btn-icon {
- padding: 0.375rem 0.5rem;
- background: transparent;
- border: none;
- cursor: pointer;
- font-size: 1rem;
- transition: all 0.2s ease;
- border-radius: var(--radius-sm);
-}
-
-.data-table .btn-icon:hover {
- background: var(--bg-hover);
- transform: scale(1.1);
-}
-
-/* ============================================
- 11. 모달
- ============================================ */
-.modal-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1000;
- backdrop-filter: blur(4px);
-}
-
-.modal-container {
- background: var(--bg-card);
- border-radius: var(--radius-xl);
- width: 90%;
- max-width: 600px;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
-}
-
-.modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: var(--space-lg);
- border-bottom: 1px solid var(--border-color);
-}
-
-.modal-title {
- font-size: var(--font-xl);
- font-weight: 700;
- color: var(--text-primary);
- margin: 0;
-}
-
-.modal-close {
- padding: 0.5rem;
- background: none;
- border: none;
- font-size: var(--font-xl);
- color: var(--text-secondary);
- cursor: pointer;
- border-radius: var(--radius-md);
- transition: all 0.2s ease;
-}
-
-.modal-close:hover {
- background: var(--bg-hover);
- color: var(--text-primary);
-}
-
-.modal-body {
- padding: var(--space-lg);
-}
-
-.modal-footer {
- display: flex;
- gap: var(--space-md);
- justify-content: flex-end;
- padding: var(--space-lg);
- border-top: 1px solid var(--border-color);
-}
-
-/* ============================================
- 12. 폼 요소
- ============================================ */
-.form-group {
- margin-bottom: var(--space-lg);
-}
-
-.form-label {
- display: block;
- margin-bottom: var(--space-sm);
- font-size: var(--font-sm);
- font-weight: 600;
- color: var(--text-primary);
-}
-
-.form-label.required::after {
- content: '*';
- color: var(--color-error);
- margin-left: var(--space-xs);
-}
-
-.form-input,
-.form-select,
-.form-textarea {
- width: 100%;
- padding: 0.625rem 1rem;
- font-size: var(--font-sm);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- background: white;
- transition: all 0.2s ease;
- box-sizing: border-box;
-}
-
-.form-input:focus,
-.form-select:focus,
-.form-textarea:focus {
- outline: none;
- border-color: var(--border-focus);
- box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
-}
-
-.form-textarea {
- resize: vertical;
- min-height: 100px;
-}
-
-.form-help {
- margin-top: var(--space-xs);
- font-size: var(--font-xs);
- color: var(--text-muted);
-}
-
-/* ============================================
- 13. 반응형 디자인
- ============================================ */
-
-/* 대형 데스크탑 (1400px 이상) */
-@media (min-width: 1400px) {
- .projects-grid {
- grid-template-columns: repeat(3, 1fr);
- }
-}
-
-/* 일반 데스크탑 (1200px ~ 1399px) */
-@media (max-width: 1399px) and (min-width: 1200px) {
- .projects-grid {
- grid-template-columns: repeat(3, 1fr);
- }
-}
-
-/* 중간 화면 (1024px ~ 1199px) - 2열 */
-@media (max-width: 1199px) and (min-width: 1024px) {
- .projects-grid {
- grid-template-columns: repeat(2, 1fr);
- }
-}
-
-/* 태블릿 (768px ~ 1023px) */
-@media (max-width: 1023px) and (min-width: 768px) {
- .sidebar {
- width: 200px;
- min-width: 200px;
- }
-
- .main-content {
- padding: var(--space-md);
- }
-
- .page-header {
- flex-direction: column;
- align-items: flex-start;
- gap: var(--space-md);
- }
-
- .page-actions {
- width: 100%;
- justify-content: flex-start;
- }
-
- .projects-grid {
- grid-template-columns: repeat(2, 1fr);
- }
-
- .search-bar {
- flex-direction: column;
- }
-
- .project-stats {
- flex-wrap: wrap;
- gap: var(--space-sm);
- }
-
- .stat-item {
- font-size: var(--font-xs);
- padding: 0.375rem 0.625rem;
- }
-}
-
-/* 모바일 (767px 이하) */
-@media (max-width: 767px) {
- .page-container {
- flex-direction: column;
- }
-
- .sidebar {
- display: none; /* 모바일에서는 사이드바 숨김 */
- }
-
- .main-content {
- padding: var(--space-sm);
- }
-
- .page-title {
- font-size: var(--font-xl);
- flex-direction: column;
- align-items: flex-start;
- gap: var(--space-xs);
- }
-
- .title-icon {
- font-size: var(--font-xl);
- }
-
- .page-actions {
- width: 100%;
- flex-direction: column;
- }
-
- .btn {
- width: 100%;
- justify-content: center;
- }
-
- .search-section,
- .projects-section {
- padding: var(--space-md);
- }
-
- .search-bar {
- flex-direction: column;
- }
-
- .projects-grid {
- grid-template-columns: 1fr;
- gap: var(--space-md);
- }
-
- .project-card {
- min-height: auto;
- }
-
- .project-stats {
- flex-direction: column;
- width: 100%;
- }
-
- .stat-item {
- width: 100%;
- justify-content: space-between;
- }
-
- .code-tabs {
- flex-direction: column;
- }
-
- .tab-btn {
- justify-content: center;
- }
-
- .meta-row {
- grid-template-columns: 80px 1fr;
- gap: var(--space-xs);
- }
-
- .meta-label {
- font-size: 0.625rem;
- }
-
- .modal-container {
- width: 95%;
- margin: var(--space-sm);
- max-height: 95vh;
- }
-}
-
-/* 초소형 모바일 (480px 이하) */
-@media (max-width: 480px) {
- .work-report-main {
- padding: var(--space-xs);
- }
-
- .page-title {
- font-size: var(--font-lg);
- }
-
- .page-description {
- font-size: var(--font-xs);
- }
-
- .search-section,
- .projects-section {
- padding: var(--space-sm);
- }
-
- .project-card {
- padding: var(--space-md);
- }
-
- .btn {
- padding: 0.5rem 0.875rem;
- font-size: var(--font-xs);
- }
-}
-
-/* ============================================
- 14. Empty State
- ============================================ */
-.empty-state {
- text-align: center;
- padding: var(--space-2xl) var(--space-lg);
- color: var(--text-secondary);
-}
-
-.empty-icon {
- font-size: 4rem;
- margin-bottom: var(--space-lg);
- opacity: 0.5;
-}
-
-.empty-state h3 {
- font-size: var(--font-xl);
- font-weight: 600;
- color: var(--text-primary);
- margin: 0 0 var(--space-sm) 0;
-}
-
-.empty-state p {
- font-size: var(--font-sm);
- color: var(--text-secondary);
- margin-bottom: var(--space-lg);
-}
-
-/* ============================================
- 15. 로딩 및 스켈레톤
- ============================================ */
-.skeleton {
- background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
- background-size: 200% 100%;
- animation: skeleton-loading 1.5s ease-in-out infinite;
- border-radius: var(--radius-md);
-}
-
-@keyframes skeleton-loading {
- 0% {
- background-position: 200% 0;
- }
- 100% {
- background-position: -200% 0;
- }
-}
-
-.skeleton-card {
- height: 280px;
-}
-
-.skeleton-text {
- height: 1rem;
- margin-bottom: var(--space-sm);
-}
-
-/* ============================================
- 16. 유틸리티 클래스
- ============================================ */
-.text-center {
- text-align: center;
-}
-
-.text-muted {
- color: var(--text-muted);
-}
-
-.text-success {
- color: var(--color-success);
-}
-
-.text-error {
- color: var(--color-error);
-}
-
-.mt-0 { margin-top: 0; }
-.mt-1 { margin-top: var(--space-sm); }
-.mt-2 { margin-top: var(--space-md); }
-.mt-3 { margin-top: var(--space-lg); }
-
-.mb-0 { margin-bottom: 0; }
-.mb-1 { margin-bottom: var(--space-sm); }
-.mb-2 { margin-bottom: var(--space-md); }
-.mb-3 { margin-bottom: var(--space-lg); }
-
-.hidden {
- display: none !important;
-}
-
-.loading {
- opacity: 0.6;
- pointer-events: none;
-}
-
-/* 코드 상세 정보 */
-.code-detail {
- display: flex;
- flex-direction: column;
- gap: var(--space-xs);
-}
-
-.code-name {
- font-size: var(--font-base);
- font-weight: 600;
- color: var(--text-primary);
-}
-
-.code-description {
- font-size: var(--font-sm);
- color: var(--text-secondary);
- line-height: 1.5;
-}
-
-/* ============================================
- 17. 코드 관리 페이지 전용 스타일
- ============================================ */
-
-/* 코드 탭 스타일 */
-.code-tabs {
- display: flex;
- gap: var(--space-sm);
- margin-bottom: var(--space-xl);
- border-bottom: 2px solid var(--border-color);
- padding-bottom: 0;
-}
-
-.tab-btn {
- display: flex;
- align-items: center;
- gap: var(--space-sm);
- padding: var(--space-md) var(--space-lg);
- background: transparent;
- border: none;
- border-bottom: 3px solid transparent;
- color: var(--text-secondary);
- font-size: var(--font-base);
- font-weight: 600;
- cursor: pointer;
- transition: all 0.2s ease;
- position: relative;
- margin-bottom: -2px;
-}
-
-.tab-btn:hover {
- color: var(--color-primary);
- background: var(--color-primary-light);
-}
-
-.tab-btn.active {
- color: var(--color-primary);
- border-bottom-color: var(--color-primary);
-}
-
-.tab-icon {
- font-size: var(--font-lg);
-}
-
-/* 탭 콘텐츠 */
-.code-tab-content {
- display: none;
-}
-
-.code-tab-content.active {
- display: block;
- animation: fadeIn 0.3s ease;
-}
-
-@keyframes fadeIn {
- from {
- opacity: 0;
- transform: translateY(10px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/* 코드 섹션 */
-.code-section {
- margin-bottom: var(--space-xl);
-}
-
-/* 코드 통계 */
-.code-stats {
- display: flex;
- gap: var(--space-sm);
- flex-wrap: wrap;
- margin-bottom: var(--space-lg);
-}
-
-.code-stats .stat-item {
- padding: 0.5rem 1rem;
- font-size: var(--font-sm);
-}
-
-/* 코드 그리드 */
-.code-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: var(--space-lg);
- width: 100%;
-}
-
-/* 코드 카드 */
-.code-card {
- background: var(--bg-card);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- padding: var(--space-lg);
- transition: all 0.2s ease;
- cursor: pointer;
- position: relative;
- display: flex;
- flex-direction: column;
- min-height: 200px;
-}
-
-.code-card:hover {
- border-color: var(--color-primary);
- box-shadow: var(--shadow-lg);
- transform: translateY(-2px);
-}
-
-/* 코드 카드 헤더 */
-.code-header {
- display: flex;
- align-items: flex-start;
- gap: var(--space-md);
- margin-bottom: var(--space-md);
-}
-
-.code-icon {
- font-size: 2rem;
- flex-shrink: 0;
- width: 48px;
- height: 48px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: var(--bg-body);
- border-radius: var(--radius-md);
-}
-
-.code-info {
- flex: 1;
- min-width: 0;
-}
-
-.code-name {
- font-size: var(--font-lg);
- font-weight: 700;
- color: var(--text-primary);
- margin: 0 0 var(--space-xs) 0;
- word-break: break-word;
-}
-
-.code-label {
- display: inline-block;
- padding: 0.25rem 0.75rem;
- background: var(--bg-body);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-sm);
- font-size: var(--font-xs);
- font-weight: 600;
- color: var(--text-secondary);
-}
-
-.code-actions {
- display: flex;
- gap: var(--space-xs);
- flex-shrink: 0;
-}
-
-.btn-small {
- padding: 0.375rem 0.625rem;
- font-size: var(--font-sm);
- background: white;
- border: 1px solid var(--border-color);
- border-radius: var(--radius-sm);
- cursor: pointer;
- transition: all 0.2s ease;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.btn-small:hover {
- transform: scale(1.1);
-}
-
-.btn-small.btn-edit:hover {
- background: var(--color-primary);
- border-color: var(--color-primary);
- color: white;
-}
-
-.btn-small.btn-delete:hover {
- background: var(--color-error);
- border-color: var(--color-error);
- color: white;
-}
-
-/* 코드 설명 */
-.code-description {
- font-size: var(--font-sm);
- color: var(--text-secondary);
- line-height: 1.6;
- margin-bottom: var(--space-md);
- flex: 1;
-}
-
-/* 해결 가이드 */
-.solution-guide {
- background: #fef3c7;
- border-left: 3px solid #f59e0b;
- padding: var(--space-md);
- border-radius: var(--radius-sm);
- font-size: var(--font-sm);
- margin-bottom: var(--space-md);
- line-height: 1.6;
-}
-
-.solution-guide strong {
- color: #92400e;
- display: block;
- margin-bottom: var(--space-xs);
-}
-
-/* 코드 메타 정보 */
-.code-meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-md);
- padding-top: var(--space-md);
- border-top: 1px solid var(--border-color);
- margin-top: auto;
-}
-
-.code-date {
- font-size: var(--font-xs);
- color: var(--text-muted);
-}
-
-/* 상태별 카드 스타일 */
-.normal-status {
- border-left: 4px solid #10b981;
-}
-
-.error-status {
- border-left: 4px solid #ef4444;
-}
-
-/* 심각도별 카드 스타일 */
-.severity-low {
- border-left: 4px solid #10b981;
-}
-
-.severity-low .code-icon {
- background: #d1fae5;
-}
-
-.severity-medium {
- border-left: 4px solid #f59e0b;
-}
-
-.severity-medium .code-icon {
- background: #fef3c7;
-}
-
-.severity-high {
- border-left: 4px solid #f97316;
-}
-
-.severity-high .code-icon {
- background: #ffedd5;
-}
-
-.severity-critical {
- border-left: 4px solid #ef4444;
-}
-
-.severity-critical .code-icon {
- background: #fee2e2;
-}
-
-/* 작업 유형 카드 */
-.work-type-card {
- border-left: 4px solid #3b82f6;
-}
-
-.work-type-card .code-icon {
- background: #dbeafe;
-}
-
-/* 반응형 - 코드 그리드 */
-@media (max-width: 1199px) {
- .code-grid {
- grid-template-columns: repeat(2, 1fr);
- }
-}
-
-@media (max-width: 767px) {
- .code-grid {
- grid-template-columns: 1fr;
- }
-
- .code-tabs {
- overflow-x: auto;
- flex-wrap: nowrap;
- }
-
- .tab-btn {
- white-space: nowrap;
- padding: var(--space-sm) var(--space-md);
- font-size: var(--font-sm);
- }
-}
diff --git a/system1-factory/web/css/admin-settings.css b/system1-factory/web/css/admin-settings.css
deleted file mode 100644
index 8013870..0000000
--- a/system1-factory/web/css/admin-settings.css
+++ /dev/null
@@ -1,1320 +0,0 @@
-/* admin-settings.css */
-
-/* 기본 레이아웃 */
-.work-report-container {
- min-height: 100vh;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
-}
-
-.work-report-header {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- text-align: center;
- padding: 3rem 2rem;
- margin-bottom: 0;
-}
-
-.work-report-header h1 {
- font-size: 2.5rem;
- font-weight: 700;
- margin: 0 0 1rem 0;
- text-shadow: 0 2px 4px rgba(0,0,0,0.3);
-}
-
-.work-report-header .subtitle {
- font-size: 1.1rem;
- opacity: 0.9;
- margin: 0;
- font-weight: 300;
-}
-
-.work-report-main {
- background: #f8f9fa;
- min-height: calc(100vh - 200px);
- padding-top: 2rem;
-}
-
-.back-button {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.75rem 1.5rem;
- background: rgba(255, 255, 255, 0.9);
- color: #495057;
- text-decoration: none;
- border-radius: 8px;
- font-weight: 500;
- margin: 0 2rem 2rem 2rem;
- transition: all 0.3s ease;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
-}
-
-.back-button:hover {
- background: white;
- color: #007bff;
- transform: translateY(-1px);
- box-shadow: 0 4px 8px rgba(0,0,0,0.15);
-}
-
-.dashboard-main {
- padding: 0 2rem 2rem 2rem;
- max-width: 1400px;
- margin: 0 auto;
-}
-
-.page-header {
- margin-bottom: 2rem;
-}
-
-.page-title-section {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
-}
-
-.page-title {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- font-size: 2rem;
- font-weight: 700;
- color: #1a1a1a;
- margin: 0;
-}
-
-.title-icon {
- font-size: 2.25rem;
-}
-
-.page-description {
- font-size: 1rem;
- color: #666;
- margin: 0;
-}
-
-/* 설정 섹션 */
-.settings-section {
- background: white;
- border-radius: 12px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
- overflow: hidden;
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1.5rem 2rem;
- background: #f8f9fa;
- border-bottom: 1px solid #e9ecef;
-}
-
-.section-title {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- font-size: 1.25rem;
- font-weight: 600;
- color: #1a1a1a;
- margin: 0;
-}
-
-.section-icon {
- font-size: 1.5rem;
-}
-
-/* 사용자 컨테이너 */
-.users-container {
- padding: 2rem;
-}
-
-.users-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
- gap: 1rem;
-}
-
-/* 검색 박스 */
-.search-box {
- position: relative;
- flex: 1;
- max-width: 300px;
-}
-
-.search-input {
- width: 100%;
- padding: 0.75rem 1rem 0.75rem 2.5rem;
- border: 2px solid #e9ecef;
- border-radius: 8px;
- font-size: 0.9rem;
- transition: all 0.2s ease;
-}
-
-.search-input:focus {
- outline: none;
- border-color: #007bff;
- box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
-}
-
-.search-icon {
- position: absolute;
- left: 0.75rem;
- top: 50%;
- transform: translateY(-50%);
- font-size: 1rem;
- color: #666;
-}
-
-/* 필터 버튼 */
-.filter-buttons {
- display: flex;
- gap: 0.5rem;
-}
-
-.filter-btn {
- padding: 0.5rem 1rem;
- border: 2px solid #e9ecef;
- background: white;
- border-radius: 6px;
- font-size: 0.85rem;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.filter-btn:hover {
- border-color: #007bff;
- color: #007bff;
-}
-
-.filter-btn.active {
- background: #007bff;
- border-color: #007bff;
- color: white;
-}
-
-/* 사용자 테이블 */
-.users-table-container {
- border: 1px solid #e9ecef;
- border-radius: 8px;
- overflow: hidden;
-}
-
-.users-table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.9rem;
-}
-
-.users-table th {
- background: #f8f9fa;
- padding: 1rem;
- text-align: left;
- font-weight: 600;
- color: #495057;
- border-bottom: 2px solid #e9ecef;
-}
-
-.users-table td {
- padding: 1rem;
- border-bottom: 1px solid #e9ecef;
- vertical-align: middle;
-}
-
-.users-table tbody tr:hover {
- background: #f8f9fa;
-}
-
-/* 사용자 정보 */
-.user-info {
- display: flex;
- align-items: center;
- gap: 0.75rem;
-}
-
-.user-avatar-small {
- width: 36px;
- height: 36px;
- background: #007bff;
- color: white;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: 600;
- font-size: 0.9rem;
-}
-
-.user-details h4 {
- margin: 0;
- font-size: 0.9rem;
- font-weight: 600;
- color: #1a1a1a;
-}
-
-.user-details p {
- margin: 0;
- font-size: 0.8rem;
- color: #666;
-}
-
-/* 역할 배지 */
-.role-badge {
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.25rem 0.75rem;
- border-radius: 12px;
- font-size: 0.75rem;
- font-weight: 600;
-}
-
-.role-badge.admin {
- background: #dc3545;
- color: white;
-}
-
-.role-badge.leader {
- background: #fd7e14;
- color: white;
-}
-
-.role-badge.user {
- background: #28a745;
- color: white;
-}
-
-/* 상태 배지 */
-.status-badge {
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.25rem 0.75rem;
- border-radius: 12px;
- font-size: 0.75rem;
- font-weight: 600;
-}
-
-.status-badge.active {
- background: #d4edda;
- color: #155724;
-}
-
-.status-badge.inactive {
- background: #f8d7da;
- color: #721c24;
-}
-
-/* 액션 버튼 */
-.action-buttons {
- display: flex;
- gap: 0.5rem;
-}
-
-.action-btn {
- padding: 0.4rem 0.8rem;
- border: none;
- border-radius: 4px;
- font-size: 0.8rem;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.action-btn.edit {
- background: #007bff;
- color: white;
-}
-
-.action-btn.edit:hover {
- background: #0056b3;
-}
-
-.action-btn.delete {
- background: #dc3545;
- color: white;
-}
-
-.action-btn.delete:hover {
- background: #c82333;
-}
-
-.action-btn.toggle {
- background: #6c757d;
- color: white;
-}
-
-.action-btn.toggle:hover {
- background: #545b62;
-}
-
-/* 빈 상태 */
-.empty-state {
- text-align: center;
- padding: 3rem 2rem;
- color: #666;
-}
-
-.empty-icon {
- font-size: 4rem;
- margin-bottom: 1rem;
-}
-
-.empty-state h3 {
- font-size: 1.25rem;
- font-weight: 600;
- margin-bottom: 0.5rem;
- color: #1a1a1a;
-}
-
-.empty-state p {
- font-size: 0.9rem;
- margin: 0;
-}
-
-/* 모달 스타일 */
-.modal-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1000;
-}
-
-.modal-container {
- background: white;
- border-radius: 12px;
- box-shadow: 0 20px 25px rgba(0, 0, 0, 0.1);
- width: 90%;
- max-width: 500px;
- max-height: 90vh;
- overflow-y: auto;
-}
-
-.modal-container.small {
- max-width: 400px;
-}
-
-.modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1.5rem 2rem;
- border-bottom: 1px solid #e9ecef;
-}
-
-.modal-header h2 {
- margin: 0;
- font-size: 1.25rem;
- font-weight: 600;
- color: #1a1a1a;
-}
-
-.modal-close-btn {
- background: none;
- border: none;
- font-size: 1.5rem;
- color: #666;
- cursor: pointer;
- padding: 0;
- width: 32px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 4px;
- transition: all 0.2s ease;
-}
-
-.modal-close-btn:hover {
- background: #f8f9fa;
- color: #1a1a1a;
-}
-
-.modal-body {
- padding: 2rem;
-}
-
-.modal-footer {
- display: flex;
- justify-content: flex-end;
- gap: 1rem;
- padding: 1.5rem 2rem;
- border-top: 1px solid #e9ecef;
- background: #f8f9fa;
-}
-
-/* 폼 스타일 */
-.form-group {
- margin-bottom: 1.5rem;
-}
-
-.form-label {
- display: block;
- margin-bottom: 0.5rem;
- font-weight: 600;
- color: #1a1a1a;
- font-size: 0.9rem;
-}
-
-.form-control {
- width: 100%;
- padding: 0.75rem;
- border: 2px solid #e9ecef;
- border-radius: 6px;
- font-size: 0.9rem;
- transition: all 0.2s ease;
-}
-
-.form-control:focus {
- outline: none;
- border-color: #007bff;
- box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
-}
-
-.form-help {
- display: block;
- margin-top: 0.25rem;
- font-size: 0.8rem;
- color: #666;
-}
-
-/* 삭제 경고 */
-.delete-warning {
- text-align: center;
- padding: 1rem 0;
-}
-
-.warning-icon {
- font-size: 3rem;
- margin-bottom: 1rem;
-}
-
-.delete-warning p {
- margin-bottom: 0.5rem;
- font-size: 1rem;
- color: #1a1a1a;
-}
-
-.warning-text {
- font-size: 0.9rem;
- color: #dc3545;
- font-weight: 500;
-}
-
-/* 버튼 스타일 */
-.btn {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.75rem 1.5rem;
- border: none;
- border-radius: 6px;
- font-size: 0.9rem;
- font-weight: 500;
- text-decoration: none;
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.btn-primary {
- background: #007bff;
- color: white;
-}
-
-.btn-primary:hover {
- background: #0056b3;
- transform: translateY(-1px);
-}
-
-.btn-secondary {
- background: #6c757d;
- color: white;
-}
-
-.btn-secondary:hover {
- background: #545b62;
-}
-
-.btn-danger {
- background: #dc3545;
- color: white;
-}
-
-.btn-danger:hover {
- background: #c82333;
-}
-
-.btn-icon {
- font-size: 1rem;
-}
-
-/* 토스트 알림 */
-.toast-container {
- position: fixed;
- top: 20px;
- right: 20px;
- z-index: 1100;
-}
-
-.toast {
- background: white;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
- padding: 1rem 1.5rem;
- margin-bottom: 0.5rem;
- display: flex;
- align-items: center;
- gap: 0.75rem;
- min-width: 300px;
- animation: slideIn 0.3s ease;
-}
-
-.toast.success {
- border-left: 4px solid #28a745;
-}
-
-.toast.error {
- border-left: 4px solid #dc3545;
-}
-
-.toast.warning {
- border-left: 4px solid #ffc107;
-}
-
-.toast-icon {
- font-size: 1.25rem;
-}
-
-.toast-message {
- flex: 1;
- font-size: 0.9rem;
- color: #1a1a1a;
-}
-
-.toast-close {
- background: none;
- border: none;
- font-size: 1.25rem;
- color: #666;
- cursor: pointer;
- padding: 0;
-}
-
-@keyframes slideIn {
- from {
- transform: translateX(100%);
- opacity: 0;
- }
- to {
- transform: translateX(0);
- opacity: 1;
- }
-}
-
-/* 반응형 */
-@media (max-width: 1024px) {
- .dashboard-main {
- padding: 1.5rem;
- }
-
- .users-header {
- flex-direction: column;
- align-items: stretch;
- gap: 1rem;
- }
-
- .search-box {
- max-width: none;
- }
-}
-
-@media (max-width: 768px) {
- .dashboard-main {
- padding: 1rem;
- }
-
- .section-header {
- flex-direction: column;
- align-items: stretch;
- gap: 1rem;
- }
-
- .users-table-container {
- overflow-x: auto;
- }
-
- .users-table {
- min-width: 600px;
- }
-
- .modal-container {
- width: 95%;
- margin: 1rem;
- }
-
- .modal-body {
- padding: 1.5rem;
- }
-}
-
-@media (max-width: 480px) {
- .filter-buttons {
- flex-wrap: wrap;
- }
-
- .action-buttons {
- flex-direction: column;
- }
-}
-
-/* 페이지 권한 관리 스타일 */
-.page-access-list {
- max-height: 300px;
- overflow-y: auto;
- border: 1px solid var(--border-light);
- border-radius: var(--radius-md);
- padding: var(--space-3);
- background: var(--bg-secondary);
-}
-
-.page-access-category {
- margin-bottom: var(--space-4);
-}
-
-.page-access-category:last-child {
- margin-bottom: 0;
-}
-
-.page-access-category-title {
- font-size: var(--text-sm);
- font-weight: var(--font-semibold);
- color: var(--text-secondary);
- margin-bottom: var(--space-2);
- padding-bottom: var(--space-2);
- border-bottom: 1px solid var(--border-light);
- text-transform: uppercase;
-}
-
-.page-access-item {
- display: flex;
- align-items: center;
- padding: var(--space-2);
- border-radius: var(--radius-sm);
- transition: var(--transition-normal);
-}
-
-.page-access-item:hover {
- background: var(--bg-hover);
-}
-
-.page-access-item label {
- display: flex;
- align-items: center;
- cursor: pointer;
- flex: 1;
- margin: 0;
-}
-
-.page-access-item input[type="checkbox"] {
- margin-right: var(--space-2);
- width: 18px;
- height: 18px;
- cursor: pointer;
-}
-
-.page-access-item .page-name {
- font-size: var(--text-sm);
- color: var(--text-primary);
- font-weight: var(--font-medium);
-}
-
-/* 권한 관리 버튼 스타일 */
-.action-btn.permissions {
- background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
- color: white;
-}
-
-.action-btn.permissions:hover {
- background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
-}
-
-/* 비밀번호 초기화 버튼 스타일 */
-.action-btn.reset-pw {
- background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
- color: white;
-}
-
-.action-btn.reset-pw:hover {
- background: linear-gradient(135deg, #d97706 0%, #b45309 100%);
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
-}
-
-/* 페이지 권한 모달 사용자 정보 */
-.page-access-user-info {
- display: flex;
- align-items: center;
- gap: var(--space-3);
- padding: var(--space-4);
- background: var(--bg-secondary);
- border-radius: var(--radius-lg);
- margin-bottom: var(--space-4);
-}
-
-.page-access-user-info h3 {
- margin: 0;
- font-size: var(--text-lg);
- font-weight: var(--font-semibold);
- color: var(--text-primary);
-}
-
-.page-access-user-info p {
- margin: 0;
- font-size: var(--text-sm);
- color: var(--text-secondary);
-}
-
-/* 폴더 트리 스타일 */
-.folder-tree {
- padding: 0;
-}
-
-.folder-group {
- margin-bottom: 0.5rem;
- border: 1px solid #e9ecef;
- border-radius: 8px;
- overflow: hidden;
-}
-
-.folder-header {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.75rem 1rem;
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
- cursor: pointer;
- transition: all 0.2s ease;
- user-select: none;
-}
-
-.folder-header:hover {
- background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
-}
-
-.folder-icon {
- font-size: 1.25rem;
-}
-
-.folder-name {
- font-weight: 600;
- color: #1a1a1a;
- flex: 1;
-}
-
-.folder-count {
- font-size: 0.75rem;
- color: #6c757d;
- background: white;
- padding: 0.125rem 0.5rem;
- border-radius: 10px;
-}
-
-.folder-toggle {
- font-size: 0.75rem;
- color: #6c757d;
- transition: transform 0.2s ease;
-}
-
-.folder-content {
- padding: 0.5rem;
- background: white;
-}
-
-.page-item {
- padding: 0.5rem 0.75rem;
- margin-left: 1rem;
- border-radius: 6px;
- transition: all 0.2s ease;
-}
-
-.page-item:hover {
- background: #f8f9fa;
-}
-
-.page-label {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- cursor: pointer;
- margin: 0;
- width: 100%;
-}
-
-.page-label input[type="checkbox"] {
- width: 18px;
- height: 18px;
- cursor: pointer;
- accent-color: #007bff;
-}
-
-.page-label input[type="checkbox"]:disabled {
- cursor: not-allowed;
- opacity: 0.6;
-}
-
-.file-icon {
- font-size: 1rem;
- opacity: 0.7;
-}
-
-.page-label .page-name {
- flex: 1;
- font-size: 0.875rem;
- color: #495057;
-}
-
-.always-access-badge {
- font-size: 0.65rem;
- background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
- color: white;
- padding: 0.125rem 0.5rem;
- border-radius: 10px;
- font-weight: 500;
-}
-
-/* 활성화/비활성화 버튼 스타일 */
-.action-btn.activate {
- background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
- color: white;
-}
-
-.action-btn.activate:hover {
- background: linear-gradient(135deg, #20c997 0%, #17a2b8 100%);
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3);
-}
-
-.action-btn.deactivate {
- background: linear-gradient(135deg, #6c757d 0%, #495057 100%);
- color: white;
-}
-
-.action-btn.deactivate:hover {
- background: linear-gradient(135deg, #495057 0%, #343a40 100%);
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(108, 117, 125, 0.3);
-}
-
-.action-btn.danger {
- background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
- color: white;
-}
-
-.action-btn.danger:hover {
- background: linear-gradient(135deg, #c82333 0%, #a71d2a 100%);
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(220, 53, 69, 0.3);
-}
-
-/* 작업자 연결 스타일 */
-.worker-link-container {
- display: flex;
- align-items: center;
- gap: 1rem;
- padding: 0.75rem;
- background: #f8f9fa;
- border-radius: 8px;
- border: 1px solid #e9ecef;
-}
-
-.linked-worker-info {
- flex: 1;
- display: flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.linked-worker-info .no-worker {
- color: #6c757d;
- font-style: italic;
-}
-
-.linked-worker-info .worker-badge {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.375rem 0.75rem;
- background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
- color: white;
- border-radius: 20px;
- font-size: 0.875rem;
- font-weight: 500;
-}
-
-.linked-worker-info .worker-badge .dept-name {
- opacity: 0.9;
- font-size: 0.75rem;
-}
-
-/* 작업자 선택 모달 */
-.worker-select-layout {
- display: grid;
- grid-template-columns: 200px 1fr;
- gap: 1rem;
- min-height: 400px;
-}
-
-.department-list-panel,
-.worker-list-panel {
- border: 1px solid #e9ecef;
- border-radius: 8px;
- overflow: hidden;
-}
-
-.panel-title {
- margin: 0;
- padding: 0.75rem 1rem;
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
- font-size: 0.875rem;
- font-weight: 600;
- color: #495057;
- border-bottom: 1px solid #e9ecef;
-}
-
-.department-list {
- max-height: 350px;
- overflow-y: auto;
-}
-
-.department-item {
- padding: 0.75rem 1rem;
- cursor: pointer;
- border-bottom: 1px solid #f0f0f0;
- transition: all 0.2s ease;
- display: flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.department-item:hover {
- background: #f8f9fa;
-}
-
-.department-item.active {
- background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
- color: white;
-}
-
-.department-item .dept-icon {
- font-size: 1rem;
-}
-
-.department-item .dept-name {
- flex: 1;
- font-size: 0.875rem;
-}
-
-.department-item .dept-count {
- font-size: 0.75rem;
- background: rgba(0,0,0,0.1);
- padding: 0.125rem 0.5rem;
- border-radius: 10px;
-}
-
-.department-item.active .dept-count {
- background: rgba(255,255,255,0.2);
-}
-
-.worker-list {
- max-height: 350px;
- overflow-y: auto;
- padding: 0.5rem;
-}
-
-.worker-list .empty-message {
- text-align: center;
- padding: 2rem;
- color: #6c757d;
- font-style: italic;
-}
-
-.worker-select-item {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 0.75rem;
- border-radius: 8px;
- cursor: pointer;
- transition: all 0.2s ease;
- border: 2px solid transparent;
-}
-
-.worker-select-item:hover {
- background: #f8f9fa;
- border-color: #e9ecef;
-}
-
-.worker-select-item.selected {
- background: #e7f3ff;
- border-color: #007bff;
-}
-
-.worker-select-item .worker-avatar {
- width: 40px;
- height: 40px;
- background: linear-gradient(135deg, #007bff 0%, #6610f2 100%);
- color: white;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: 600;
- font-size: 1rem;
-}
-
-.worker-select-item .worker-info {
- flex: 1;
-}
-
-.worker-select-item .worker-name {
- font-weight: 600;
- color: #1a1a1a;
- font-size: 0.9rem;
-}
-
-.worker-select-item .worker-role {
- font-size: 0.75rem;
- color: #6c757d;
-}
-
-.worker-select-item .select-indicator {
- width: 24px;
- height: 24px;
- border: 2px solid #dee2e6;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.2s ease;
-}
-
-.worker-select-item.selected .select-indicator {
- background: #007bff;
- border-color: #007bff;
- color: white;
-}
-
-.worker-select-item .already-linked {
- font-size: 0.7rem;
- background: #ffc107;
- color: #000;
- padding: 0.125rem 0.5rem;
- border-radius: 10px;
-}
-
-/* 버튼 크기 조정 */
-.btn-sm {
- padding: 0.375rem 0.75rem;
- font-size: 0.8rem;
-}
-
-/* ========================================
- 알림 수신자 설정 섹션
- ======================================== */
-#notificationRecipientsSection {
- margin-top: 2rem;
-}
-
-#notificationRecipientsSection .section-header {
- flex-direction: column;
- align-items: flex-start;
- gap: 0.5rem;
-}
-
-.section-description {
- font-size: 0.875rem;
- color: #6c757d;
- margin: 0;
-}
-
-.notification-recipients-container {
- padding: 1.5rem 2rem;
-}
-
-.notification-type-cards {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
- gap: 1rem;
-}
-
-.notification-type-card {
- background: #f8f9fa;
- border: 2px solid #e9ecef;
- border-radius: 12px;
- padding: 1.25rem;
- transition: all 0.2s ease;
-}
-
-.notification-type-card:hover {
- border-color: #007bff;
- box-shadow: 0 4px 12px rgba(0, 123, 255, 0.1);
-}
-
-.notification-type-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1rem;
-}
-
-.notification-type-title {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- font-weight: 600;
- font-size: 1rem;
- color: #1a1a1a;
-}
-
-.notification-type-icon {
- font-size: 1.25rem;
-}
-
-.notification-type-card.repair .notification-type-icon { color: #fd7e14; }
-.notification-type-card.safety .notification-type-icon { color: #dc3545; }
-.notification-type-card.nonconformity .notification-type-icon { color: #6f42c1; }
-.notification-type-card.equipment .notification-type-icon { color: #17a2b8; }
-.notification-type-card.maintenance .notification-type-icon { color: #28a745; }
-.notification-type-card.system .notification-type-icon { color: #6c757d; }
-
-.edit-recipients-btn {
- padding: 0.375rem 0.75rem;
- background: white;
- border: 1px solid #dee2e6;
- border-radius: 6px;
- font-size: 0.75rem;
- color: #495057;
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.edit-recipients-btn:hover {
- background: #007bff;
- border-color: #007bff;
- color: white;
-}
-
-.recipient-list {
- display: flex;
- flex-wrap: wrap;
- gap: 0.5rem;
- min-height: 32px;
-}
-
-.recipient-tag {
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.25rem 0.625rem;
- background: white;
- border: 1px solid #dee2e6;
- border-radius: 16px;
- font-size: 0.75rem;
- color: #495057;
-}
-
-.recipient-tag .tag-icon {
- font-size: 0.875rem;
-}
-
-.no-recipients {
- font-size: 0.8rem;
- color: #adb5bd;
- font-style: italic;
-}
-
-/* 알림 수신자 편집 모달 */
-.modal-description {
- font-size: 0.875rem;
- color: #6c757d;
- margin-bottom: 1rem;
-}
-
-.recipient-search-box {
- margin-bottom: 1rem;
-}
-
-.recipient-user-list {
- max-height: 350px;
- overflow-y: auto;
- border: 1px solid #e9ecef;
- border-radius: 8px;
- background: #f8f9fa;
-}
-
-.recipient-user-item {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 0.75rem 1rem;
- border-bottom: 1px solid #e9ecef;
- cursor: pointer;
- transition: all 0.15s ease;
-}
-
-.recipient-user-item:last-child {
- border-bottom: none;
-}
-
-.recipient-user-item:hover {
- background: #e9ecef;
-}
-
-.recipient-user-item.selected {
- background: #e7f3ff;
-}
-
-.recipient-user-item input[type="checkbox"] {
- width: 18px;
- height: 18px;
- cursor: pointer;
- accent-color: #007bff;
-}
-
-.recipient-user-item .user-avatar-small {
- width: 32px;
- height: 32px;
- font-size: 0.8rem;
-}
-
-.recipient-user-info {
- flex: 1;
-}
-
-.recipient-user-name {
- font-weight: 500;
- font-size: 0.875rem;
- color: #1a1a1a;
-}
-
-.recipient-user-role {
- font-size: 0.75rem;
- color: #6c757d;
-}
-
-@media (max-width: 768px) {
- .notification-type-cards {
- grid-template-columns: 1fr;
- }
-}
diff --git a/system1-factory/web/css/admin.css b/system1-factory/web/css/admin.css
deleted file mode 100644
index 145f0a6..0000000
--- a/system1-factory/web/css/admin.css
+++ /dev/null
@@ -1,50 +0,0 @@
-body {
- font-family: 'Malgun Gothic', sans-serif;
- margin: 0;
- background: #f0f2f5;
-}
-.main-layout {
- display: flex;
-}
-#sidebar-container {
- width: 250px;
- background: #1a237e;
- color: white;
- min-height: 100vh;
-}
-#content-container {
- flex: 1;
- padding: 30px;
-}
-h1, h2 {
- color: #1976d2;
-}
-a {
- color: #1976d2;
- text-decoration: none;
-}
-
-/* Admin 권한 배지 스타일 */
-.admin-badge {
- background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%);
- color: white;
- font-size: 0.7rem;
- font-weight: bold;
- padding: 2px 6px;
- border-radius: 10px;
- margin-left: 8px;
- text-transform: uppercase;
- letter-spacing: 0.5px;
- box-shadow: 0 2px 4px rgba(255,107,53,0.3);
- display: inline-block;
- vertical-align: middle;
-}
-
-.admin-only-link {
- position: relative;
-}
-
-.admin-only-link:hover .admin-badge {
- background: linear-gradient(135deg, #ff5722 0%, #ff9800 100%);
- box-shadow: 0 3px 6px rgba(255,107,53,0.4);
-}
\ No newline at end of file
diff --git a/system1-factory/web/css/annual-vacation-overview.css b/system1-factory/web/css/annual-vacation-overview.css
deleted file mode 100644
index 3d1730f..0000000
--- a/system1-factory/web/css/annual-vacation-overview.css
+++ /dev/null
@@ -1,348 +0,0 @@
-/**
- * annual-vacation-overview.css
- * 연간 연차 현황 페이지 스타일
- */
-
-.page-container {
- min-height: 100vh;
- background: var(--color-bg-primary);
-}
-
-.main-content {
- padding: 2rem 0;
-}
-
-.content-wrapper {
- max-width: 1400px;
- margin: 0 auto;
- padding: 0 2rem;
-}
-
-/* 페이지 헤더 */
-.page-header {
- margin-bottom: 2rem;
-}
-
-.page-title {
- font-size: 2rem;
- font-weight: 700;
- color: var(--color-text-primary);
- margin-bottom: 0.5rem;
-}
-
-.page-description {
- font-size: 1rem;
- color: var(--color-text-secondary);
- margin: 0;
-}
-
-/* 필터 섹션 */
-.filter-section {
- margin-bottom: 2rem;
-}
-
-.filter-controls {
- display: flex;
- gap: 1rem;
- align-items: flex-end;
- flex-wrap: wrap;
-}
-
-.form-group {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
- min-width: 200px;
-}
-
-.form-group label {
- font-size: 0.875rem;
- font-weight: 600;
- color: var(--color-text-primary);
-}
-
-.form-select {
- padding: 0.625rem 1rem;
- border: 1px solid var(--color-border);
- border-radius: 8px;
- background: white;
- font-size: 0.875rem;
- color: var(--color-text-primary);
- transition: all 0.2s;
-}
-
-.form-select:focus {
- outline: none;
- border-color: var(--color-primary);
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-/* 탭 네비게이션 */
-.tabs-section {
- margin-bottom: 2rem;
-}
-
-.tabs-nav {
- display: flex;
- gap: 0.5rem;
- border-bottom: 2px solid var(--color-border);
- padding: 0;
- margin: 0;
-}
-
-.tab-btn {
- padding: 1rem 2rem;
- border: none;
- background: none;
- color: var(--color-text-secondary);
- font-size: 1rem;
- font-weight: 600;
- cursor: pointer;
- position: relative;
- transition: all 0.2s;
- border-radius: 8px 8px 0 0;
-}
-
-.tab-btn:hover {
- color: var(--color-primary);
- background: rgba(59, 130, 246, 0.05);
-}
-
-.tab-btn.active {
- color: var(--color-primary);
- background: white;
-}
-
-.tab-btn.active::after {
- content: '';
- position: absolute;
- bottom: -2px;
- left: 0;
- right: 0;
- height: 2px;
- background: var(--color-primary);
-}
-
-/* 탭 컨텐츠 */
-.tab-content {
- display: none;
-}
-
-.tab-content.active {
- display: block;
-}
-
-/* 월 선택 컨트롤 */
-.month-controls {
- display: flex;
- gap: 1rem;
- align-items: center;
-}
-
-.month-controls .form-select {
- min-width: 120px;
-}
-
-/* 차트 섹션 */
-.chart-section {
- margin-bottom: 2rem;
-}
-
-.card-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1.5rem;
- border-bottom: 1px solid var(--color-border);
-}
-
-.card-title {
- font-size: 1.25rem;
- font-weight: 600;
- color: var(--color-text-primary);
- margin: 0;
-}
-
-.chart-controls {
- display: flex;
- gap: 0.5rem;
-}
-
-.btn-outline {
- background: white;
- border: 1px solid var(--color-border);
- color: var(--color-text-secondary);
-}
-
-.btn-outline:hover {
- background: var(--color-bg-secondary);
- border-color: var(--color-primary);
- color: var(--color-primary);
-}
-
-.btn-outline.active {
- background: var(--color-primary);
- border-color: var(--color-primary);
- color: white;
-}
-
-.chart-container {
- position: relative;
- height: 500px;
- padding: 1.5rem;
-}
-
-/* 테이블 섹션 */
-.table-section {
- margin-bottom: 2rem;
-}
-
-.table-responsive {
- overflow-x: auto;
-}
-
-.data-table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.875rem;
-}
-
-.data-table thead {
- background: var(--color-bg-secondary);
-}
-
-.data-table th {
- padding: 1rem;
- text-align: left;
- font-weight: 600;
- color: var(--color-text-primary);
- border-bottom: 2px solid var(--color-border);
- white-space: nowrap;
-}
-
-.data-table tbody tr {
- border-bottom: 1px solid var(--color-border);
- transition: background 0.2s;
-}
-
-.data-table tbody tr:hover {
- background: var(--color-bg-secondary);
-}
-
-.data-table td {
- padding: 1rem;
- color: var(--color-text-primary);
-}
-
-.loading-state {
- padding: 3rem 1rem !important;
- text-align: center;
-}
-
-.loading-state .spinner {
- margin: 0 auto 1rem;
- width: 40px;
- height: 40px;
- border: 4px solid var(--color-border);
- border-top-color: var(--color-primary);
- border-radius: 50%;
- animation: spin 1s linear infinite;
-}
-
-.loading-state p {
- margin: 0;
- color: var(--color-text-secondary);
-}
-
-@keyframes spin {
- to {
- transform: rotate(360deg);
- }
-}
-
-/* 사용률 프로그레스 바 */
-.usage-rate-cell {
- display: flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.progress-bar {
- flex: 1;
- height: 8px;
- background: var(--color-bg-secondary);
- border-radius: 4px;
- overflow: hidden;
-}
-
-.progress-fill {
- height: 100%;
- border-radius: 4px;
- transition: width 0.3s ease;
-}
-
-.progress-fill.low {
- background: linear-gradient(90deg, #10b981 0%, #059669 100%);
-}
-
-.progress-fill.medium {
- background: linear-gradient(90deg, #f59e0b 0%, #d97706 100%);
-}
-
-.progress-fill.high {
- background: linear-gradient(90deg, #ef4444 0%, #dc2626 100%);
-}
-
-.usage-rate-text {
- font-weight: 600;
- min-width: 45px;
- text-align: right;
-}
-
-/* 반응형 */
-@media (max-width: 768px) {
- .content-wrapper {
- padding: 0 1rem;
- }
-
- .page-title {
- font-size: 1.5rem;
- }
-
- .tabs-nav {
- flex-direction: column;
- gap: 0;
- }
-
- .tab-btn {
- border-radius: 0;
- }
-
- .filter-controls {
- flex-direction: column;
- align-items: stretch;
- }
-
- .form-group {
- width: 100%;
- min-width: auto;
- }
-
- .chart-container {
- height: 400px;
- }
-
- .card-header {
- flex-direction: column;
- gap: 1rem;
- align-items: flex-start;
- }
-
- .chart-controls {
- width: 100%;
- }
-
- .chart-controls button {
- flex: 1;
- }
-}
diff --git a/system1-factory/web/css/attendance-validation.css b/system1-factory/web/css/attendance-validation.css
deleted file mode 100644
index 15184a3..0000000
--- a/system1-factory/web/css/attendance-validation.css
+++ /dev/null
@@ -1,883 +0,0 @@
-/* 근태 검증 관리 시스템 - 개선된 스타일 */
-
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
- color: #333;
- line-height: 1.6;
- min-height: 100vh;
-}
-
-/* 뒤로가기 버튼 */
-.back-btn {
- background: rgba(255,255,255,0.95);
- color: #667eea;
- border: 3px solid #667eea;
- padding: 12px 24px;
- border-radius: 12px;
- text-decoration: none;
- font-weight: 700;
- font-size: 16px;
- display: inline-flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 24px;
- transition: all 0.3s ease;
- box-shadow: 0 3px 12px rgba(102, 126, 234, 0.2);
-}
-
-.back-btn:hover {
- background: #667eea;
- color: white;
- transform: translateY(-2px);
- box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3);
-}
-
-/* 페이지 헤더 */
-.page-header {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- border-radius: 16px;
- padding: 2.5rem;
- margin-bottom: 2rem;
- box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
- border: 1px solid rgba(255, 255, 255, 0.1);
-}
-
-/* 메인 카드 */
-.main-card {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- margin-bottom: 2rem;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
- border: 1px solid rgba(255, 255, 255, 0.8);
- backdrop-filter: blur(10px);
- transition: all 0.3s ease;
-}
-
-.main-card:hover {
- transform: translateY(-2px);
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
-}
-
-.loading-card {
- background: white;
- border-radius: 16px;
- padding: 3rem;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
- text-align: center;
-}
-
-/* 캘린더 헤더 */
-.calendar-header {
- display: flex;
- align-items: center;
- justify-content: between;
- margin-bottom: 2rem;
- padding-bottom: 1rem;
- border-bottom: 2px solid #f0f0f0;
-}
-
-.nav-btn {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border: none;
- border-radius: 12px;
- width: 48px;
- height: 48px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- transition: all 0.3s ease;
- box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
-}
-
-.nav-btn:hover {
- transform: translateY(-2px) scale(1.05);
- box-shadow: 0 6px 24px rgba(102, 126, 234, 0.4);
-}
-
-/* 월간 요약 */
-.summary-section {
- margin-bottom: 2rem;
- padding: 1.5rem;
- background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
- border-radius: 16px;
- border: 1px solid rgba(102, 126, 234, 0.2);
-}
-
-.summary-title {
- text-align: center;
- font-size: 1.25rem;
- font-weight: 700;
- color: #333;
- margin-bottom: 1rem;
-}
-
-.summary-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 1.5rem;
-}
-
-.summary-card {
- background: white;
- border-radius: 12px;
- padding: 1.5rem;
- text-align: center;
- transition: all 0.3s ease;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
- border: 2px solid transparent;
-}
-
-.summary-card:hover {
- transform: translateY(-4px);
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
-}
-
-.summary-card.normal {
- border-color: #10b981;
-}
-
-.summary-card.warning {
- border-color: #f59e0b;
-}
-
-.summary-card.error {
- border-color: #ef4444;
-}
-
-.summary-number {
- font-size: 2rem;
- font-weight: 800;
- margin-bottom: 0.5rem;
-}
-
-.summary-card.normal .summary-number {
- color: #10b981;
-}
-
-.summary-card.warning .summary-number {
- color: #f59e0b;
-}
-
-.summary-card.error .summary-number {
- color: #ef4444;
-}
-
-.summary-label {
- font-size: 0.875rem;
- font-weight: 600;
- color: #666;
-}
-
-/* 요일 헤더 */
-.weekday-header {
- display: grid;
- grid-template-columns: repeat(7, 1fr);
- gap: 0.5rem;
- margin-bottom: 1rem;
-}
-
-.weekday {
- padding: 1rem;
- text-align: center;
- font-size: 0.875rem;
- font-weight: 700;
- color: #64748b;
- background: #f8fafc;
- border-radius: 8px;
-}
-
-.weekday.sunday {
- color: #ef4444;
-}
-
-.weekday.saturday {
- color: #3b82f6;
-}
-
-/* 캘린더 그리드 */
-.calendar-grid {
- display: grid;
- grid-template-columns: repeat(7, 1fr);
- gap: 0.5rem;
- margin-bottom: 2rem;
-}
-
-.calendar-day {
- position: relative;
- min-height: 80px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 12px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s ease;
- background: white;
- border: 2px solid #e2e8f0;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
-}
-
-.calendar-day.hover-enabled:hover {
- transform: translateY(-3px);
- box-shadow: 0 6px 24px rgba(0, 0, 0, 0.15);
- border-color: #3b82f6;
-}
-
-.calendar-day.selected {
- transform: scale(1.05);
- z-index: 10;
- border-color: #3b82f6;
- box-shadow: 0 8px 32px rgba(59, 130, 246, 0.3);
-}
-
-.calendar-day.loading-state {
- background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
- border-color: #3b82f6;
- animation: loading-pulse 1.5s infinite;
-}
-
-@keyframes loading-pulse {
- 0%, 100% { opacity: 1; }
- 50% { opacity: 0.7; }
-}
-
-.calendar-day.error-state {
- background: linear-gradient(135deg, #fecaca 0%, #fca5a5 100%);
- border-color: #ef4444;
- color: #991b1b;
-}
-
-.calendar-day.normal {
- background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
- border-color: #10b981;
- color: #064e3b;
-}
-
-.calendar-day.needs-review {
- background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
- border-color: #f59e0b;
- color: #92400e;
-}
-
-.calendar-day.missing {
- background: linear-gradient(135deg, #fecaca 0%, #fca5a5 100%);
- border-color: #ef4444;
- color: #991b1b;
-}
-
-.calendar-day.no-data {
- background: #f9fafb;
- border-color: #e5e7eb;
- color: #9ca3af;
- position: relative;
-}
-
-.calendar-day.no-data::after {
- content: "클릭하여 확인";
- position: absolute;
- bottom: 4px;
- font-size: 10px;
- color: #6b7280;
- opacity: 0;
- transition: opacity 0.3s;
-}
-
-.calendar-day.no-data.hover-enabled:hover::after {
- opacity: 1;
-}
-
-.status-dot {
- position: absolute;
- top: 8px;
- right: 8px;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
- transition: all 0.3s ease;
-}
-
-.status-dot.pulse {
- animation: pulse 1s infinite;
-}
-
-@keyframes pulse {
- 0%, 100% { transform: scale(1); }
- 50% { transform: scale(1.2); }
-}
-
-.status-dot.normal {
- background: #10b981;
-}
-
-.status-dot.warning {
- background: #f59e0b;
-}
-
-.status-dot.error {
- background: #ef4444;
-}
-
-/* 범례 */
-.legend {
- display: flex;
- justify-content: center;
- gap: 2rem;
- flex-wrap: wrap;
-}
-
-.legend-item {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- font-size: 0.875rem;
- font-weight: 600;
- color: #64748b;
-}
-
-.legend-dot {
- width: 16px;
- height: 16px;
- border-radius: 50%;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
-}
-
-.legend-dot.normal {
- background: #10b981;
-}
-
-.legend-dot.warning {
- background: #f59e0b;
-}
-
-.legend-dot.error {
- background: #ef4444;
-}
-
-/* 빈 상태 */
-.empty-state {
- text-align: center;
- padding: 4rem 2rem;
-}
-
-.empty-icon {
- font-size: 4rem;
- margin-bottom: 1.5rem;
-}
-
-.empty-title {
- font-size: 1.5rem;
- font-weight: 700;
- color: #374151;
- margin-bottom: 1rem;
-}
-
-.empty-description {
- color: #6b7280;
- font-size: 1rem;
- max-width: 500px;
- margin: 0 auto;
-}
-
-/* 작업자 카드 */
-.worker-card {
- background: white;
- border-radius: 16px;
- padding: 1.5rem;
- margin-bottom: 1.5rem;
- border: 2px solid transparent;
- transition: all 0.3s ease;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
-}
-
-.worker-card:hover {
- transform: translateY(-2px);
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
-}
-
-.worker-card.normal {
- background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
- border-color: #10b981;
-}
-
-.worker-card.needs-review {
- background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
- border-color: #f59e0b;
-}
-
-.worker-card.missing {
- background: linear-gradient(135deg, #fef2f2 0%, #fecaca 100%);
- border-color: #ef4444;
-}
-
-.worker-header {
- display: flex;
- justify-content: between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 2px solid rgba(0, 0, 0, 0.1);
-}
-
-.worker-info {
- display: flex;
- align-items: center;
- gap: 1rem;
-}
-
-.worker-avatar {
- width: 48px;
- height: 48px;
- background: white;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: 700;
- font-size: 1.25rem;
- color: #374151;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-}
-
-.worker-name {
- font-size: 1.25rem;
- font-weight: 700;
- color: #374151;
-}
-
-.worker-id {
- font-size: 0.875rem;
- color: #6b7280;
- margin-top: 0.25rem;
-}
-
-.status-badge {
- font-size: 1.5rem;
- filter: drop-shadow(2px 2px 4px rgba(0, 0, 0, 0.1));
-}
-
-/* 데이터 행 */
-.data-section {
- background: rgba(255, 255, 255, 0.7);
- border-radius: 12px;
- padding: 1.5rem;
- margin-bottom: 1rem;
-}
-
-.data-row {
- display: flex;
- justify-content: between;
- align-items: center;
- padding: 0.75rem 0;
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
-}
-
-.data-row:last-child {
- border-bottom: none;
-}
-
-.data-label {
- font-weight: 600;
- color: #4b5563;
-}
-
-.data-value {
- font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
- font-weight: 700;
- font-size: 1rem;
-}
-
-.difference-positive {
- color: #dc2626;
- background: rgba(220, 38, 38, 0.1);
- padding: 0.25rem 0.75rem;
- border-radius: 6px;
- font-weight: 700;
-}
-
-.difference-negative {
- color: #2563eb;
- background: rgba(37, 99, 235, 0.1);
- padding: 0.25rem 0.75rem;
- border-radius: 6px;
- font-weight: 700;
-}
-
-/* 버튼 */
-.btn-primary {
- background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
- color: white;
- border: none;
- padding: 0.75rem 1.5rem;
- border-radius: 12px;
- font-weight: 700;
- cursor: pointer;
- transition: all 0.3s ease;
- box-shadow: 0 4px 16px rgba(59, 130, 246, 0.3);
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.btn-primary:hover {
- transform: translateY(-2px);
- box-shadow: 0 6px 24px rgba(59, 130, 246, 0.4);
-}
-
-.btn-secondary {
- background: #6b7280;
- color: white;
- border: none;
- padding: 0.75rem 1.5rem;
- border-radius: 12px;
- font-weight: 700;
- cursor: pointer;
- transition: all 0.3s ease;
- box-shadow: 0 4px 16px rgba(107, 114, 128, 0.3);
-}
-
-.btn-secondary:hover {
- background: #4b5563;
- transform: translateY(-2px);
-}
-
-.edit-btn {
- background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
- color: white;
- border: none;
- padding: 0.75rem 1.5rem;
- border-radius: 8px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s ease;
- font-size: 0.875rem;
- width: 100%;
- margin-top: 1rem;
-}
-
-.edit-btn:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 16px rgba(59, 130, 246, 0.3);
-}
-
-.delete-btn {
- background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
- color: white;
- border: none;
- padding: 0.5rem 1rem;
- border-radius: 6px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s ease;
- font-size: 0.75rem;
- margin-left: 0.5rem;
-}
-
-.delete-btn:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 16px rgba(239, 68, 68, 0.3);
-}
-
-/* 필터 */
-.filter-container {
- display: flex;
- justify-content: between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 2px solid #f0f0f0;
-}
-
-.filter-select {
- background: white;
- border: 2px solid #e5e7eb;
- border-radius: 8px;
- padding: 0.75rem 1rem;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s ease;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
-}
-
-.filter-select:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-/* 모달 */
-.modal {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0, 0, 0, 0.75);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 1000;
- animation: fadeIn 0.3s ease;
-}
-
-.modal.hidden {
- display: none;
-}
-
-@keyframes fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
-
-.modal-content {
- background: white;
- border-radius: 20px;
- width: 90%;
- max-width: 500px;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
- animation: slideIn 0.3s ease;
-}
-
-@keyframes slideIn {
- from {
- opacity: 0;
- transform: translateY(-50px) scale(0.9);
- }
- to {
- opacity: 1;
- transform: translateY(0) scale(1);
- }
-}
-
-.modal-header {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- padding: 1.5rem;
- border-radius: 20px 20px 0 0;
- display: flex;
- justify-content: between;
- align-items: center;
-}
-
-.modal-header h3 {
- margin: 0;
- font-size: 1.25rem;
- font-weight: 700;
-}
-
-.close-btn {
- background: rgba(255, 255, 255, 0.2);
- color: white;
- border: none;
- border-radius: 50%;
- width: 36px;
- height: 36px;
- cursor: pointer;
- font-size: 1.25rem;
- font-weight: 700;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.3s ease;
-}
-
-.close-btn:hover {
- background: rgba(255, 255, 255, 0.3);
- transform: rotate(90deg);
-}
-
-.modal-body {
- padding: 1.5rem;
-}
-
-.modal-footer {
- display: flex;
- justify-content: flex-end;
- gap: 1rem;
- padding: 1.5rem;
- border-top: 2px solid #f0f0f0;
- background: #f8fafc;
- border-radius: 0 0 20px 20px;
-}
-
-/* 폼 요소 */
-.form-group {
- margin-bottom: 1.5rem;
-}
-
-.form-group label {
- display: block;
- margin-bottom: 0.5rem;
- font-weight: 700;
- color: #374151;
- font-size: 0.875rem;
-}
-
-.form-input {
- width: 100%;
- padding: 0.75rem 1rem;
- border: 2px solid #e5e7eb;
- border-radius: 8px;
- font-size: 1rem;
- transition: all 0.3s ease;
-}
-
-.form-input:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-.form-textarea {
- width: 100%;
- padding: 0.75rem 1rem;
- border: 2px solid #e5e7eb;
- border-radius: 8px;
- font-size: 1rem;
- resize: vertical;
- min-height: 80px;
- transition: all 0.3s ease;
-}
-
-.form-textarea:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-/* 메시지 */
-.message {
- padding: 1rem 1.5rem;
- border-radius: 12px;
- margin-bottom: 1.5rem;
- font-weight: 600;
- border: 2px solid transparent;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
-}
-
-.message.success {
- background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
- color: #065f46;
- border-color: #10b981;
-}
-
-.message.error {
- background: linear-gradient(135deg, #fecaca 0%, #fca5a5 100%);
- color: #991b1b;
- border-color: #ef4444;
-}
-
-.message.warning {
- background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
- color: #92400e;
- border-color: #f59e0b;
-}
-
-.message.loading {
- background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
- color: #1e40af;
- border-color: #3b82f6;
-}
-
-/* 로딩 스피너 */
-.loading-spinner {
- width: 32px;
- height: 32px;
- border: 3px solid #e5e7eb;
- border-top: 3px solid #3b82f6;
- border-radius: 50%;
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
-}
-
-/* 애니메이션 */
-.fade-in {
- animation: fadeInUp 0.5s ease-out;
-}
-
-@keyframes fadeInUp {
- from {
- opacity: 0;
- transform: translateY(20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/* 반응형 디자인 */
-@media (max-width: 768px) {
- .summary-grid {
- grid-template-columns: 1fr;
- gap: 1rem;
- }
-
- .calendar-day {
- min-height: 60px;
- font-size: 0.875rem;
- }
-
- .worker-header {
- flex-direction: column;
- gap: 1rem;
- text-align: center;
- }
-
- .legend {
- flex-direction: column;
- gap: 1rem;
- }
-
- .modal-content {
- width: 95%;
- margin: 1rem;
- }
-
- .main-card {
- padding: 1.5rem;
- }
-
- .page-header {
- padding: 2rem;
- }
-}
-
-@media (max-width: 480px) {
- .calendar-day {
- min-height: 50px;
- font-size: 0.75rem;
- }
-
- .summary-card {
- padding: 1rem;
- }
-
- .summary-number {
- font-size: 1.5rem;
- }
-
- .worker-card {
- padding: 1rem;
- }
-
- .modal-body, .modal-footer {
- padding: 1rem;
- }
-}
\ No newline at end of file
diff --git a/system1-factory/web/css/attendance.css b/system1-factory/web/css/attendance.css
deleted file mode 100644
index 0b77e15..0000000
--- a/system1-factory/web/css/attendance.css
+++ /dev/null
@@ -1,72 +0,0 @@
-body {
- font-family: Arial, sans-serif;
- margin: 20px;
- background: #f8f9fa;
-}
-h2 {
- text-align: center;
- color: #343a40;
-}
-.controls {
- display: flex;
- flex-wrap: wrap;
- gap: 12px;
- justify-content: center;
- align-items: center;
- margin-bottom: 16px;
-}
-.controls label {
- font-weight: bold;
-}
-.controls select,
-.controls button {
- padding: 6px 10px;
- border-radius: 4px;
- border: 1px solid #ccc;
- font-weight: bold;
- cursor: pointer;
-}
-button#loadAttendance {
- background-color: #4CAF50;
- color: white;
- border: none;
-}
-button#downloadPdf {
- background-color: #007BFF;
- color: white;
- border: none;
-}
-#attendanceTableContainer {
- max-height: 600px;
- overflow: auto;
-}
-table {
- width: 100%;
- border-collapse: collapse;
- margin-top: 10px;
- font-size: 14px;
-}
-th, td {
- border: 1px solid #ddd;
- padding: 6px;
- text-align: center;
- background: white;
-}
-th {
- background: #f2f2f2;
-}
-.divider {
- border-left: 3px solid #333 !important;
-}
-tr.separator td {
- border-bottom: 2px solid #999;
- padding: 0;
- height: 4px;
- background: transparent;
-}
-.overtime-cell { background: #e9e5ff !important; }
-.leave { background: #f5e0d6 !important; }
-.holiday { background: #ffd6d6 !important; }
-.paid-leave { background: #d6f0ff !important; }
-.no-data { background: #ddd !important; }
-.overtime-sum { background: #e9e5ff !important; }
\ No newline at end of file
diff --git a/system1-factory/web/css/common.css b/system1-factory/web/css/common.css
deleted file mode 100644
index eb1a24c..0000000
--- a/system1-factory/web/css/common.css
+++ /dev/null
@@ -1,300 +0,0 @@
-/* Common CSS - 공통 스타일 */
-
-/* ========== 통일된 헤더 스타일 ========== */
-.work-report-container {
- min-height: 100vh;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
-}
-
-.work-report-header {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- text-align: center;
- padding: 2rem 1.5rem;
- margin-bottom: 0;
-}
-
-.work-report-header h1 {
- font-size: clamp(1.5rem, 4vw, 2.5rem);
- font-weight: 700;
- margin: 0 0 0.75rem 0;
- text-shadow: 0 0.125rem 0.25rem rgba(0,0,0,0.3);
- word-wrap: break-word;
- overflow-wrap: break-word;
-}
-
-.work-report-header .subtitle {
- font-size: clamp(0.875rem, 2vw, 1.1rem);
- opacity: 0.9;
- margin: 0;
- font-weight: 300;
- word-wrap: break-word;
- overflow-wrap: break-word;
- max-width: 90%;
- margin-left: auto;
- margin-right: auto;
-}
-
-.work-report-main {
- background: #f8f9fa;
- min-height: calc(100vh - 12rem);
- padding-top: 2rem;
-}
-
-.back-button {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.75rem 1.5rem;
- background: rgba(255, 255, 255, 0.9);
- color: #495057;
- text-decoration: none;
- border-radius: 0.5rem;
- font-weight: 500;
- margin: 0 1.5rem 1.5rem 1.5rem;
- transition: all 0.3s ease;
- box-shadow: 0 0.125rem 0.25rem rgba(0,0,0,0.1);
- white-space: nowrap;
-}
-
-.back-button:hover {
- background: white;
- color: #007bff;
- transform: translateY(-0.0625rem);
- box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.15);
-}
-
-/* 반응형 헤더 */
-@media (max-width: 768px) {
- .work-report-header {
- padding: 1.5rem 1rem;
- }
-
- .work-report-header h1 {
- margin-bottom: 0.5rem;
- }
-
- .back-button {
- margin: 0 1rem 1rem 1rem;
- padding: 0.625rem 1.25rem;
- font-size: 0.875rem;
- }
-}
-
-@media (max-width: 480px) {
- .work-report-header {
- padding: 1.25rem 0.75rem;
- }
-
- .work-report-header .subtitle {
- font-size: 0.8125rem;
- }
-
- .back-button {
- margin: 0 0.75rem 0.75rem 0.75rem;
- padding: 0.5rem 1rem;
- font-size: 0.8125rem;
- }
-}
-
-/* Reset and Base Styles */
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
- line-height: 1.6;
- color: #333;
- background-color: #f8fafc;
-}
-
-/* Typography */
-h1, h2, h3, h4, h5, h6 {
- font-weight: 600;
- line-height: 1.25;
- margin-bottom: 0.5rem;
-}
-
-h1 { font-size: 2rem; }
-h2 { font-size: 1.5rem; }
-h3 { font-size: 1.25rem; }
-h4 { font-size: 1.125rem; }
-h5 { font-size: 1rem; }
-h6 { font-size: 0.875rem; }
-
-/* ========== 헤더 액션 버튼 ========== */
-.header-actions {
- display: flex;
- align-items: center;
- gap: 1rem;
- margin-right: 1rem;
-}
-
-.dashboard-btn {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.6rem 1.2rem;
- background: rgba(255, 255, 255, 0.15);
- color: white;
- border: 1px solid rgba(255, 255, 255, 0.3);
- border-radius: 8px;
- font-size: 0.9rem;
- font-weight: 500;
- text-decoration: none;
- cursor: pointer;
- transition: all 0.3s ease;
- backdrop-filter: blur(10px);
-}
-
-.dashboard-btn:hover {
- background: rgba(255, 255, 255, 0.25);
- border-color: rgba(255, 255, 255, 0.5);
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
-}
-
-.dashboard-btn .btn-icon {
- font-size: 1rem;
-}
-
-/* Buttons */
-.btn {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: 0.5rem 1rem;
- border: none;
- border-radius: 0.375rem;
- font-size: 0.875rem;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s ease;
- text-decoration: none;
-}
-
-.btn-primary {
- background-color: #3b82f6;
- color: white;
-}
-
-.btn-primary:hover {
- background-color: #2563eb;
-}
-
-.btn-secondary {
- background-color: #6b7280;
- color: white;
-}
-
-.btn-secondary:hover {
- background-color: #4b5563;
-}
-
-/* Utilities */
-.text-center { text-align: center; }
-.text-left { text-align: left; }
-.text-right { text-align: right; }
-
-.mb-1 { margin-bottom: 0.25rem; }
-.mb-2 { margin-bottom: 0.5rem; }
-.mb-3 { margin-bottom: 0.75rem; }
-.mb-4 { margin-bottom: 1rem; }
-.mb-5 { margin-bottom: 1.25rem; }
-.mb-6 { margin-bottom: 1.5rem; }
-
-.mt-1 { margin-top: 0.25rem; }
-.mt-2 { margin-top: 0.5rem; }
-.mt-3 { margin-top: 0.75rem; }
-.mt-4 { margin-top: 1rem; }
-.mt-5 { margin-top: 1.25rem; }
-.mt-6 { margin-top: 1.5rem; }
-
-.p-1 { padding: 0.25rem; }
-.p-2 { padding: 0.5rem; }
-.p-3 { padding: 0.75rem; }
-.p-4 { padding: 1rem; }
-.p-5 { padding: 1.25rem; }
-.p-6 { padding: 1.5rem; }
-
-/* Container */
-.container {
- max-width: 1200px;
- margin: 0 auto;
- padding: 0 1rem;
-}
-
-/* Cards */
-.card {
- background: white;
- border-radius: 0.5rem;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
- border: 1px solid #e5e7eb;
-}
-
-.card-header {
- padding: 1rem;
- border-bottom: 1px solid #e5e7eb;
-}
-
-.card-body {
- padding: 1rem;
-}
-
-/* Forms */
-.form-group {
- margin-bottom: 1rem;
-}
-
-.form-label {
- display: block;
- font-weight: 500;
- margin-bottom: 0.25rem;
- color: #374151;
-}
-
-.form-control {
- width: 100%;
- padding: 0.5rem 0.75rem;
- border: 1px solid #d1d5db;
- border-radius: 0.375rem;
- font-size: 0.875rem;
- transition: border-color 0.2s ease;
-}
-
-.form-control:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-/* Loading */
-.loading {
- display: inline-block;
- width: 20px;
- height: 20px;
- border: 3px solid #f3f3f3;
- border-top: 3px solid #3b82f6;
- border-radius: 50%;
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-/* Responsive */
-@media (max-width: 768px) {
- .container {
- padding: 0 0.5rem;
- }
-
- h1 { font-size: 1.5rem; }
- h2 { font-size: 1.25rem; }
- h3 { font-size: 1.125rem; }
-}
diff --git a/system1-factory/web/css/daily-issue.css b/system1-factory/web/css/daily-issue.css
deleted file mode 100644
index 827e7c7..0000000
--- a/system1-factory/web/css/daily-issue.css
+++ /dev/null
@@ -1,90 +0,0 @@
-/* /css/daily-issue.css */
-
-body {
- font-family: Arial, sans-serif;
- background: #f5f7fa;
- margin: 0;
- padding: 40px 20px;
-}
-
-.container {
- max-width: 500px;
- margin: auto;
- background: #fff;
- border-radius: 12px;
- box-shadow: 0 0 10px rgba(0,0,0,0.05);
- padding: 32px;
-}
-
-h2 {
- text-align: center;
- color: #333;
- margin-bottom: 24px;
-}
-
-label {
- display: block;
- margin-top: 20px;
- font-weight: bold;
- color: #333;
-}
-
-select, input[type="date"], button {
- width: 100%;
- padding: 10px;
- margin-top: 6px;
- border: 1px solid #ccc;
- border-radius: 6px;
- box-sizing: border-box;
- font-size: 1rem;
-}
-
-button#submitBtn {
- margin-top: 30px;
- background: #1976d2;
- color: white;
- border: none;
- font-size: 1rem;
- border-radius: 6px;
- cursor: pointer;
- transition: background 0.2s;
-}
-
-button#submitBtn:hover {
- background: #125cb1;
-}
-
-.multi-select-box {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- margin-top: 8px;
-}
-
-.multi-select-box .btn {
- flex: 1 0 30%;
- padding: 8px;
- border: 1px solid #1976d2;
- border-radius: 4px;
- background: white;
- color: #1976d2;
- text-align: center;
- cursor: pointer;
- transition: background 0.2s, color 0.2s;
-}
-
-.multi-select-box .btn.selected {
- background: #1976d2;
- color: white;
-}
-
-.time-range {
- display: flex;
- gap: 8px;
- align-items: center;
- margin-top: 6px;
-}
-
-.time-range select {
- flex: 1;
-}
diff --git a/system1-factory/web/css/design-system.css b/system1-factory/web/css/design-system.css
deleted file mode 100644
index ee1b15c..0000000
--- a/system1-factory/web/css/design-system.css
+++ /dev/null
@@ -1,477 +0,0 @@
-/* ✅ design-system.css - 한글 기반 모던 디자인 시스템 */
-
-/* ========== 색상 시스템 ========== */
-:root {
- /* 주요 브랜드 색상 (하늘색 계열) */
- --primary-50: #f0f9ff;
- --primary-100: #e0f2fe;
- --primary-200: #bae6fd;
- --primary-300: #7dd3fc;
- --primary-400: #38bdf8;
- --primary-500: #0ea5e9;
- --primary-600: #0284c7;
- --primary-700: #0369a1;
- --primary-800: #075985;
- --primary-900: #0c4a6e;
-
- /* 헤더 그라디언트 */
- --header-gradient: linear-gradient(135deg, #0ea5e9 0%, #38bdf8 50%, #7dd3fc 100%);
-
- /* 보조 색상 */
- --secondary-50: #f3e5f5;
- --secondary-100: #e1bee7;
- --secondary-200: #ce93d8;
- --secondary-300: #ba68c8;
- --secondary-400: #ab47bc;
- --secondary-500: #9c27b0;
- --secondary-600: #8e24aa;
- --secondary-700: #7b1fa2;
- --secondary-800: #6a1b9a;
- --secondary-900: #4a148c;
-
- /* 그레이 스케일 */
- --gray-50: #fafafa;
- --gray-100: #f5f5f5;
- --gray-200: #eeeeee;
- --gray-300: #e0e0e0;
- --gray-400: #bdbdbd;
- --gray-500: #9e9e9e;
- --gray-600: #757575;
- --gray-700: #616161;
- --gray-800: #424242;
- --gray-900: #212121;
-
- /* 상태 색상 */
- --success-50: #e8f5e8;
- --success-500: #4caf50;
- --success-700: #388e3c;
-
- --warning-50: #fff8e1;
- --warning-500: #ff9800;
- --warning-700: #f57c00;
-
- --error-50: #ffebee;
- --error-500: #f44336;
- --error-700: #d32f2f;
-
- --info-50: #e1f5fe;
- --info-500: #03a9f4;
- --info-700: #0288d1;
-
- /* 따뜻한 중성 색상 (베이지/크림) */
- --warm-50: #fafaf9; /* 매우 밝은 크림 */
- --warm-100: #f5f5f4; /* 밝은 크림 */
- --warm-200: #e7e5e4; /* 베이지 */
- --warm-300: #d6d3d1; /* 중간 베이지 */
- --warm-400: #a8a29e; /* 진한 베이지 */
- --warm-500: #78716c; /* 그레이 베이지 */
-
- /* 부드러운 작업 상태 색상 (눈이 편한 톤) */
- --status-success-bg: #dcfce7; /* 부드러운 초록 배경 */
- --status-success-text: #16a34a; /* 부드러운 초록 텍스트 */
- --status-info-bg: #e0f2fe; /* 부드러운 하늘색 배경 */
- --status-info-text: #0284c7; /* 부드러운 하늘색 텍스트 */
- --status-warning-bg: #fef3c7; /* 부드러운 노랑 배경 */
- --status-warning-text: #ca8a04; /* 부드러운 노랑 텍스트 */
- --status-error-bg: #fee2e2; /* 부드러운 빨강 배경 */
- --status-error-text: #dc2626; /* 부드러운 빨강 텍스트 */
- --status-critical-bg: #fecaca; /* 진한 빨강 배경 */
- --status-critical-text: #b91c1c; /* 진한 빨강 텍스트 */
- --status-vacation-bg: #fed7aa; /* 부드러운 주황 배경 */
- --status-vacation-text: #ea580c; /* 부드러운 주황 텍스트 */
-
- /* 배경 색상 */
- --bg-primary: #ffffff;
- --bg-secondary: #f8fafc;
- --bg-tertiary: #f1f5f9;
- --bg-overlay: rgba(0, 0, 0, 0.5);
-
- /* 텍스트 색상 */
- --text-primary: #1a202c;
- --text-secondary: #4a5568;
- --text-tertiary: #718096;
- --text-inverse: #ffffff;
-
- /* 경계선 */
- --border-light: #e2e8f0;
- --border-medium: #cbd5e0;
- --border-dark: #a0aec0;
-
- /* 그림자 */
- --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
- --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
- --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
- --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
-
- /* 반경 */
- --radius-sm: 4px;
- --radius-md: 8px;
- --radius-lg: 12px;
- --radius-xl: 16px;
- --radius-full: 9999px;
-
- /* 간격 */
- --space-1: 4px;
- --space-2: 8px;
- --space-3: 12px;
- --space-4: 16px;
- --space-5: 20px;
- --space-6: 24px;
- --space-8: 32px;
- --space-10: 40px;
- --space-12: 48px;
- --space-16: 64px;
- --space-20: 80px;
- --space-24: 96px;
-
- /* 폰트 크기 */
- --text-xs: 12px;
- --text-sm: 14px;
- --text-base: 16px;
- --text-lg: 18px;
- --text-xl: 20px;
- --text-2xl: 24px;
- --text-3xl: 30px;
- --text-4xl: 36px;
- --text-5xl: 48px;
-
- /* 폰트 두께 */
- --font-light: 300;
- --font-normal: 400;
- --font-medium: 500;
- --font-semibold: 600;
- --font-bold: 700;
- --font-extrabold: 800;
-
- /* 애니메이션 */
- --transition-fast: 150ms ease-in-out;
- --transition-normal: 250ms ease-in-out;
- --transition-slow: 350ms ease-in-out;
-}
-
-/* ========== 기본 리셋 ========== */
-* {
- box-sizing: border-box;
-}
-
-body {
- margin: 0;
- padding: 0;
- font-family: 'Pretendard', 'Malgun Gothic', 'Apple SD Gothic Neo', system-ui, sans-serif;
- font-size: var(--text-base);
- line-height: 1.6;
- color: var(--text-primary);
- background-color: var(--bg-secondary);
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-/* ========== 타이포그래피 ========== */
-.text-xs { font-size: var(--text-xs); }
-.text-sm { font-size: var(--text-sm); }
-.text-base { font-size: var(--text-base); }
-.text-lg { font-size: var(--text-lg); }
-.text-xl { font-size: var(--text-xl); }
-.text-2xl { font-size: var(--text-2xl); }
-.text-3xl { font-size: var(--text-3xl); }
-.text-4xl { font-size: var(--text-4xl); }
-.text-5xl { font-size: var(--text-5xl); }
-
-.font-light { font-weight: var(--font-light); }
-.font-normal { font-weight: var(--font-normal); }
-.font-medium { font-weight: var(--font-medium); }
-.font-semibold { font-weight: var(--font-semibold); }
-.font-bold { font-weight: var(--font-bold); }
-.font-extrabold { font-weight: var(--font-extrabold); }
-
-.text-primary { color: var(--text-primary); }
-.text-secondary { color: var(--text-secondary); }
-.text-tertiary { color: var(--text-tertiary); }
-.text-inverse { color: var(--text-inverse); }
-
-/* ========== 카드 컴포넌트 ========== */
-.card {
- background: var(--bg-primary);
- border-radius: var(--radius-lg);
- box-shadow: var(--shadow-sm);
- border: 1px solid var(--border-light);
- transition: var(--transition-normal);
-}
-
-.card:hover {
- box-shadow: var(--shadow-md);
- transform: translateY(-1px);
-}
-
-.card-header {
- padding: var(--space-6);
- border-bottom: 1px solid var(--border-light);
-}
-
-.card-body {
- padding: var(--space-6);
-}
-
-.card-footer {
- padding: var(--space-6);
- border-top: 1px solid var(--border-light);
- background: var(--bg-tertiary);
- border-radius: 0 0 var(--radius-lg) var(--radius-lg);
-}
-
-/* ========== 버튼 컴포넌트 ========== */
-.btn {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--space-2);
- padding: var(--space-3) var(--space-4);
- font-size: var(--text-sm);
- font-weight: var(--font-medium);
- border-radius: var(--radius-md);
- border: none;
- cursor: pointer;
- transition: var(--transition-fast);
- text-decoration: none;
- white-space: nowrap;
-}
-
-.btn:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
-
-.btn-primary {
- background: var(--primary-500);
- color: var(--text-inverse);
-}
-
-.btn-primary:hover:not(:disabled) {
- background: var(--primary-600);
- transform: translateY(-1px);
- box-shadow: var(--shadow-md);
-}
-
-.btn-secondary {
- background: var(--gray-100);
- color: var(--text-primary);
- border: 1px solid var(--border-medium);
-}
-
-.btn-secondary:hover:not(:disabled) {
- background: var(--gray-200);
-}
-
-.btn-success {
- background: var(--success-500);
- color: var(--text-inverse);
-}
-
-.btn-success:hover:not(:disabled) {
- background: var(--success-700);
-}
-
-.btn-warning {
- background: var(--warning-500);
- color: var(--text-inverse);
-}
-
-.btn-warning:hover:not(:disabled) {
- background: var(--warning-700);
-}
-
-.btn-error {
- background: var(--error-500);
- color: var(--text-inverse);
-}
-
-.btn-error:hover:not(:disabled) {
- background: var(--error-700);
-}
-
-.btn-sm {
- padding: var(--space-2) var(--space-3);
- font-size: var(--text-xs);
-}
-
-.btn-lg {
- padding: var(--space-4) var(--space-6);
- font-size: var(--text-lg);
-}
-
-/* ========== 배지 컴포넌트 ========== */
-.badge {
- display: inline-flex;
- align-items: center;
- gap: var(--space-1);
- padding: var(--space-1) var(--space-2);
- font-size: var(--text-xs);
- font-weight: var(--font-medium);
- border-radius: var(--radius-full);
- white-space: nowrap;
-}
-
-.badge-primary {
- background: var(--primary-100);
- color: var(--primary-800);
-}
-
-.badge-success {
- background: var(--success-50);
- color: var(--success-700);
-}
-
-.badge-warning {
- background: var(--warning-50);
- color: var(--warning-700);
-}
-
-.badge-error {
- background: var(--error-50);
- color: var(--error-700);
-}
-
-.badge-gray {
- background: var(--gray-100);
- color: var(--gray-700);
-}
-
-/* ========== 상태 표시기 ========== */
-.status-dot {
- display: inline-block;
- width: 8px;
- height: 8px;
- border-radius: var(--radius-full);
- margin-right: var(--space-2);
-}
-
-.status-dot.active {
- background: var(--success-500);
- box-shadow: 0 0 0 2px var(--success-100);
-}
-
-.status-dot.inactive {
- background: var(--gray-400);
-}
-
-.status-dot.warning {
- background: var(--warning-500);
- box-shadow: 0 0 0 2px var(--warning-100);
-}
-
-.status-dot.error {
- background: var(--error-500);
- box-shadow: 0 0 0 2px var(--error-100);
-}
-
-/* ========== 그리드 시스템 ========== */
-.grid {
- display: grid;
- gap: var(--space-6);
-}
-
-.grid-cols-1 { grid-template-columns: repeat(1, 1fr); }
-.grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
-.grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
-.grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
-
-@media (max-width: 768px) {
- .grid-cols-2,
- .grid-cols-3,
- .grid-cols-4 {
- grid-template-columns: 1fr;
- }
-}
-
-/* ========== 플렉스 유틸리티 ========== */
-.flex { display: flex; }
-.flex-col { flex-direction: column; }
-.items-center { align-items: center; }
-.items-start { align-items: flex-start; }
-.items-end { align-items: flex-end; }
-.justify-center { justify-content: center; }
-.justify-between { justify-content: space-between; }
-.justify-start { justify-content: flex-start; }
-.justify-end { justify-content: flex-end; }
-.gap-1 { gap: var(--space-1); }
-.gap-2 { gap: var(--space-2); }
-.gap-3 { gap: var(--space-3); }
-.gap-4 { gap: var(--space-4); }
-.gap-6 { gap: var(--space-6); }
-
-/* ========== 간격 유틸리티 ========== */
-.p-1 { padding: var(--space-1); }
-.p-2 { padding: var(--space-2); }
-.p-3 { padding: var(--space-3); }
-.p-4 { padding: var(--space-4); }
-.p-6 { padding: var(--space-6); }
-.p-8 { padding: var(--space-8); }
-
-.m-1 { margin: var(--space-1); }
-.m-2 { margin: var(--space-2); }
-.m-3 { margin: var(--space-3); }
-.m-4 { margin: var(--space-4); }
-.m-6 { margin: var(--space-6); }
-.m-8 { margin: var(--space-8); }
-
-.mb-2 { margin-bottom: var(--space-2); }
-.mb-4 { margin-bottom: var(--space-4); }
-.mb-6 { margin-bottom: var(--space-6); }
-.mt-4 { margin-top: var(--space-4); }
-.mt-6 { margin-top: var(--space-6); }
-
-/* ========== 반응형 유틸리티 ========== */
-@media (max-width: 640px) {
- .sm\:hidden { display: none; }
- .sm\:text-sm { font-size: var(--text-sm); }
- .sm\:p-4 { padding: var(--space-4); }
-}
-
-@media (max-width: 768px) {
- .md\:hidden { display: none; }
- .md\:flex-col { flex-direction: column; }
-}
-
-@media (max-width: 1024px) {
- .lg\:hidden { display: none; }
-}
-
-/* ========== 애니메이션 ========== */
-.fade-in {
- animation: fadeIn var(--transition-normal) ease-in-out;
-}
-
-.slide-up {
- animation: slideUp var(--transition-normal) ease-out;
-}
-
-@keyframes fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
-
-@keyframes slideUp {
- from {
- opacity: 0;
- transform: translateY(20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/* ========== 로딩 스피너 ========== */
-.spinner {
- width: 20px;
- height: 20px;
- border: 2px solid var(--gray-200);
- border-top: 2px solid var(--primary-500);
- border-radius: var(--radius-full);
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
diff --git a/system1-factory/web/css/factory.css b/system1-factory/web/css/factory.css
deleted file mode 100644
index e7dcd68..0000000
--- a/system1-factory/web/css/factory.css
+++ /dev/null
@@ -1,61 +0,0 @@
-body {
- font-family: 'Segoe UI', sans-serif;
- background-color: #f9f9f9;
- margin: 0;
- padding: 0;
-}
-
-.container {
- max-width: 600px;
- margin: 50px auto;
- background: #fff;
- border-radius: 12px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
- padding: 30px;
-}
-
-h2 {
- text-align: center;
- margin-bottom: 20px;
- color: #333;
-}
-
-form label {
- display: block;
- margin-bottom: 6px;
- font-weight: bold;
- color: #444;
-}
-
-form input[type="text"],
-form input[type="file"],
-form textarea {
- width: 100%;
- padding: 10px;
- margin-bottom: 16px;
- border: 1px solid #ccc;
- border-radius: 8px;
- font-size: 14px;
- box-sizing: border-box;
-}
-
-form textarea {
- resize: vertical;
- min-height: 100px;
-}
-
-button {
- width: 100%;
- background-color: #007bff;
- color: white;
- border: none;
- padding: 12px;
- font-size: 16px;
- border-radius: 8px;
- cursor: pointer;
- transition: background-color 0.3s ease;
-}
-
-button:hover {
- background-color: #0056b3;
-}
\ No newline at end of file
diff --git a/system1-factory/web/css/login.css b/system1-factory/web/css/login.css
deleted file mode 100644
index 3f9061e..0000000
--- a/system1-factory/web/css/login.css
+++ /dev/null
@@ -1,54 +0,0 @@
-body {
- margin: 0;
- padding: 0;
- background: url('/img/login-bg.jpeg') no-repeat center center fixed;
- background-size: cover;
- font-family: 'Malgun Gothic', sans-serif;
-}
-
-.login-container {
- background: rgba(0, 0, 0, 0.65);
- width: 400px;
- padding: 40px;
- margin: 100px auto;
- border-radius: 12px;
- text-align: center;
- color: white;
- box-shadow: 0 0 20px rgba(0,0,0,0.3);
-}
-
-.logo {
- width: 200px;
- margin-bottom: 20px;
-}
-
-input {
- display: block;
- width: 100%;
- margin: 15px 0;
- padding: 12px;
- font-size: 1rem;
- border-radius: 6px;
- border: none;
-}
-
-button {
- padding: 12px 20px;
- font-size: 1rem;
- cursor: pointer;
- border: none;
- background-color: #1976d2;
- color: white;
- border-radius: 6px;
- transition: background-color 0.3s;
-}
-
-button:hover {
- background-color: #1565c0;
-}
-
-.error-message {
- margin-top: 10px;
- color: #ff6b6b;
- font-weight: bold;
-}
\ No newline at end of file
diff --git a/system1-factory/web/css/main-layout.css b/system1-factory/web/css/main-layout.css
deleted file mode 100644
index 6467328..0000000
--- a/system1-factory/web/css/main-layout.css
+++ /dev/null
@@ -1,160 +0,0 @@
-/* ✅ /css/main-layout.css - 공통 레이아웃 스타일 */
-
-* {
- box-sizing: border-box;
-}
-
-body {
- margin: 0;
- padding: 0;
- font-family: 'Malgun Gothic', 'Apple SD Gothic Neo', sans-serif;
- background-color: #f5f5f5;
-}
-
-/* 메인 레이아웃 구조 */
-.main-layout {
- display: flex;
- min-height: 100vh;
- flex-direction: column;
-}
-
-#navbar-container {
- position: sticky;
- top: 0;
- z-index: 1000;
-}
-
-.content-wrapper {
- display: flex;
- flex: 1;
-}
-
-#sidebar-container {
- flex-shrink: 0;
-}
-
-#content-container,
-#sections-container,
-#admin-sections,
-#user-sections {
- flex: 1;
- padding: 24px;
- max-width: 1200px;
- margin: 0 auto;
- width: 100%;
-}
-
-/* 카드 스타일 */
-.card {
- background: white;
- border-radius: 8px;
- padding: 24px;
- margin-bottom: 24px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.08);
-}
-
-/* 섹션 스타일 */
-section {
- background: white;
- border-radius: 8px;
- padding: 20px;
- margin-bottom: 20px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.08);
-}
-
-section h2 {
- font-size: 18px;
- margin: 0 0 16px 0;
- color: #333;
- border-bottom: 2px solid #1976d2;
- padding-bottom: 8px;
-}
-
-section ul {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-section li {
- padding: 8px 0;
- border-bottom: 1px solid #f0f0f0;
-}
-
-section li:last-child {
- border-bottom: none;
-}
-
-section a {
- color: #1976d2;
- text-decoration: none;
- display: block;
- padding: 4px 0;
- transition: all 0.3s;
-}
-
-section a:hover {
- color: #0d47a1;
- padding-left: 8px;
-}
-
-/* 로딩 상태 */
-.loading {
- text-align: center;
- padding: 60px 20px;
- color: #666;
-}
-
-.loading::after {
- content: '.';
- animation: dots 1.5s steps(3, end) infinite;
-}
-
-@keyframes dots {
- 0%, 20% { content: '.'; }
- 40% { content: '..'; }
- 60%, 100% { content: '...'; }
-}
-
-/* 에러 상태 */
-.error-state {
- text-align: center;
- padding: 60px 20px;
- color: #d32f2f;
-}
-
-.error-state button {
- margin-top: 16px;
- padding: 8px 24px;
- background: #1976d2;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
-}
-
-.error-state button:hover {
- background: #1565c0;
-}
-
-/* 반응형 디자인 */
-@media (max-width: 1024px) {
- #content-container,
- #sections-container {
- padding: 16px;
- }
-}
-
-@media (max-width: 768px) {
- .content-wrapper {
- flex-direction: column;
- }
-
- #sidebar-container {
- order: -1;
- }
-
- section h2 {
- font-size: 16px;
- }
-}
\ No newline at end of file
diff --git a/system1-factory/web/css/management-dashboard.css b/system1-factory/web/css/management-dashboard.css
deleted file mode 100644
index 08524ef..0000000
--- a/system1-factory/web/css/management-dashboard.css
+++ /dev/null
@@ -1,1005 +0,0 @@
-/* management-dashboard.css - 관리자 대시보드 전용 스타일 */
-
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: 'Segoe UI', 'Noto Sans KR', Tahoma, Geneva, Verdana, sans-serif;
- background-color: #f5f7fa;
- color: #333;
- line-height: 1.6;
-}
-
-/* 메인 레이아웃 */
-.main-layout-with-navbar {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
-}
-
-.content-wrapper {
- flex: 1;
- padding: 20px;
-}
-
-.dashboard-container {
- max-width: 1400px;
- margin: 0 auto;
-}
-
-/* 페이지 헤더 */
-.page-header {
- text-align: center;
- margin-bottom: 2.5rem;
- padding: 3rem 2rem;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border-radius: 16px;
- box-shadow: 0 6px 24px rgba(0,0,0,0.12);
- position: relative;
-}
-
-.page-header h1 {
- font-size: 2.5rem;
- margin-bottom: 0.8rem;
- font-weight: 700;
-}
-
-.subtitle {
- font-size: 1.1rem;
- opacity: 0.9;
- margin-bottom: 1rem;
-}
-
-.permission-badge {
- display: inline-block;
- background: rgba(255,255,255,0.2);
- color: white;
- padding: 8px 20px;
- border-radius: 25px;
- font-size: 14px;
- font-weight: 600;
- border: 2px solid rgba(255,255,255,0.3);
-}
-
-/* 뒤로가기 버튼 */
-.back-btn {
- background: rgba(255,255,255,0.95);
- color: #667eea;
- border: 3px solid #667eea;
- padding: 16px 32px;
- border-radius: 12px;
- text-decoration: none;
- font-weight: 700;
- font-size: 18px;
- display: inline-flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 24px;
- transition: all 0.3s ease;
- box-shadow: 0 3px 12px rgba(102, 126, 234, 0.2);
-}
-
-.back-btn:hover {
- background: #667eea;
- color: white;
- transform: translateY(-2px);
- box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3);
-}
-
-/* 메시지 스타일 */
-.message {
- padding: 20px 32px;
- border-radius: 12px;
- margin-bottom: 32px;
- font-weight: 600;
- font-size: 18px;
- box-shadow: 0 3px 12px rgba(0,0,0,0.1);
-}
-
-.message.warning {
- background: #fff3cd;
- color: #856404;
- border: 2px solid #ffeaa7;
-}
-
-.message.error {
- background: #f8d7da;
- color: #721c24;
- border: 2px solid #f5c6cb;
-}
-
-.message.success {
- background: #d4edda;
- color: #155724;
- border: 2px solid #c3e6cb;
-}
-
-.message.loading {
- background: #cce5ff;
- color: #0066cc;
- border: 2px solid #99d6ff;
-}
-
-/* 날짜 선택 카드 */
-.date-selection-card {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- box-shadow: 0 6px 24px rgba(0,0,0,0.08);
- margin-bottom: 2rem;
-}
-
-.date-selection-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 2px solid #f0f0f0;
-}
-
-.date-selection-header h3 {
- margin: 0;
- color: #333;
- font-size: 1.4rem;
-}
-
-.refresh-btn {
- background: #28a745;
- color: white;
- border: none;
- border-radius: 8px;
- padding: 12px 20px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 600;
- transition: all 0.3s;
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.refresh-btn:hover {
- background: #1e7e34;
- transform: translateY(-1px);
-}
-
-.date-selection-body {
- display: flex;
- gap: 20px;
- align-items: center;
- justify-content: center;
-}
-
-.date-input {
- padding: 15px 20px;
- font-size: 18px;
- border: 3px solid #e1e5e9;
- border-radius: 12px;
- background: white;
- transition: border-color 0.3s;
- min-width: 200px;
-}
-
-.date-input:focus {
- outline: none;
- border-color: #007bff;
- box-shadow: 0 0 0 4px rgba(0, 123, 255, 0.15);
-}
-
-/* 버튼 스타일 */
-.btn {
- padding: 15px 30px;
- border: none;
- border-radius: 12px;
- font-size: 16px;
- font-weight: 700;
- cursor: pointer;
- transition: all 0.3s;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- text-decoration: none;
- box-shadow: 0 3px 12px rgba(0,0,0,0.1);
-}
-
-.btn-primary {
- background: #007bff;
- color: white;
-}
-
-.btn-primary:hover {
- background: #0056b3;
- transform: translateY(-2px);
- box-shadow: 0 6px 20px rgba(0, 123, 255, 0.3);
-}
-
-.btn-secondary {
- background: #6c757d;
- color: white;
-}
-
-.btn-secondary:hover {
- background: #545b62;
- transform: translateY(-2px);
-}
-
-/* 요약 섹션 */
-.summary-section {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- box-shadow: 0 6px 24px rgba(0,0,0,0.08);
- margin-bottom: 2rem;
-}
-
-.summary-section h3 {
- margin-bottom: 1.5rem;
- color: #333;
- font-size: 1.4rem;
-}
-
-.summary-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 20px;
-}
-
-.summary-card {
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
- border-radius: 12px;
- padding: 1.5rem;
- display: flex;
- align-items: center;
- gap: 15px;
- border: 2px solid #dee2e6;
- transition: all 0.3s ease;
-}
-
-.summary-card:hover {
- transform: translateY(-3px);
- box-shadow: 0 8px 25px rgba(0,0,0,0.1);
-}
-
-.summary-icon {
- font-size: 2rem;
- width: 60px;
- height: 60px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 50%;
- background: rgba(255,255,255,0.8);
-}
-
-.summary-content {
- flex: 1;
-}
-
-.summary-number {
- font-size: 2rem;
- font-weight: 700;
- color: #333;
- line-height: 1;
-}
-
-.summary-label {
- font-size: 0.9rem;
- color: #666;
- margin-top: 4px;
-}
-
-/* 개별 요약 카드 색상 */
-.summary-card.total-workers {
- background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
- border-color: #2196f3;
-}
-
-.summary-card.completed-workers {
- background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
- border-color: #4caf50;
-}
-
-.summary-card.missing-workers {
- background: linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%);
- border-color: #f44336;
-}
-
-.summary-card.total-hours {
- background: linear-gradient(135deg, #f3e5f5 0%, #e1bee7 100%);
- border-color: #9c27b0;
-}
-
-.summary-card.total-entries {
- background: linear-gradient(135deg, #fff3e0 0%, #ffcc02 100%);
- border-color: #ff9800;
-}
-
-.summary-card.error-count {
- background: linear-gradient(135deg, #fce4ec 0%, #f8bbd9 100%);
- border-color: #e91e63;
-}
-
-/* 액션 바 */
-.action-bar {
- background: white;
- border-radius: 12px;
- padding: 1.5rem;
- box-shadow: 0 4px 16px rgba(0,0,0,0.06);
- margin-bottom: 2rem;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.filter-section {
- display: flex;
- gap: 20px;
- align-items: center;
-}
-
-.filter-checkbox {
- display: flex;
- align-items: center;
- gap: 10px;
- cursor: pointer;
- font-weight: 600;
- font-size: 16px;
- color: #333;
-}
-
-.filter-checkbox input[type="checkbox"] {
- display: none;
-}
-
-.checkmark {
- width: 20px;
- height: 20px;
- border: 2px solid #007bff;
- border-radius: 4px;
- position: relative;
- transition: all 0.3s ease;
-}
-
-.filter-checkbox input[type="checkbox"]:checked + .checkmark {
- background: #007bff;
-}
-
-.filter-checkbox input[type="checkbox"]:checked + .checkmark::after {
- content: "✓";
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- color: white;
- font-weight: bold;
- font-size: 12px;
-}
-
-/* 작업자 섹션 */
-.workers-section {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- box-shadow: 0 6px 24px rgba(0,0,0,0.08);
- margin-bottom: 2rem;
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 2px solid #f0f0f0;
-}
-
-.section-header h3 {
- margin: 0;
- color: #333;
- font-size: 1.4rem;
-}
-
-.legend {
- display: flex;
- gap: 15px;
-}
-
-.legend-item {
- font-size: 14px;
- font-weight: 600;
- padding: 6px 12px;
- border-radius: 20px;
- border: 2px solid;
-}
-
-.legend-item.completed {
- color: #28a745;
- border-color: #28a745;
- background: rgba(40, 167, 69, 0.1);
-}
-
-.legend-item.missing {
- color: #dc3545;
- border-color: #dc3545;
- background: rgba(220, 53, 69, 0.1);
-}
-
-.legend-item.partial {
- color: #ffc107;
- border-color: #ffc107;
- background: rgba(255, 193, 7, 0.1);
-}
-
-/* 작업자 테이블 스타일 */
-.table-container {
- background: white;
- border-radius: 12px;
- overflow: hidden;
- box-shadow: 0 4px 16px rgba(0,0,0,0.06);
-}
-
-.workers-table {
- width: 100%;
- border-collapse: collapse;
- font-size: 14px;
-}
-
-.workers-table thead {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
-}
-
-.workers-table th {
- padding: 16px 12px;
- text-align: left;
- font-weight: 700;
- font-size: 14px;
- border-bottom: 2px solid rgba(255,255,255,0.2);
-}
-
-.workers-table th:first-child {
- padding-left: 20px;
-}
-
-.workers-table th:last-child {
- padding-right: 20px;
-}
-
-.workers-table tbody tr {
- border-bottom: 1px solid #e9ecef;
- transition: all 0.3s ease;
-}
-
-.workers-table tbody tr:hover {
- background: #f8f9fa;
- transform: scale(1.01);
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
-}
-
-.workers-table tbody tr:last-child {
- border-bottom: none;
-}
-
-.workers-table td {
- padding: 16px 12px;
- vertical-align: middle;
- line-height: 1.4;
-}
-
-.workers-table td:first-child {
- padding-left: 20px;
-}
-
-.workers-table td:last-child {
- padding-right: 20px;
-}
-
-/* 작업자 이름 스타일 */
-.worker-name-cell {
- font-weight: 700;
- color: #333;
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-/* 상태 배지 스타일 */
-.status-badge {
- padding: 6px 12px;
- border-radius: 20px;
- font-size: 12px;
- font-weight: 700;
- color: white;
- white-space: nowrap;
- text-align: center;
- min-width: 70px;
-}
-
-.status-badge.completed {
- background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
-}
-
-.status-badge.missing {
- background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
-}
-
-.status-badge.partial {
- background: linear-gradient(135deg, #ffc107 0%, #e0a800 100%);
- color: #333;
-}
-
-/* 시간 표시 스타일 */
-.hours-cell {
- font-weight: 700;
- font-size: 16px;
- color: #495057;
-}
-
-.hours-cell.zero {
- color: #dc3545;
- opacity: 0.7;
-}
-
-.hours-cell.partial {
- color: #ffc107;
-}
-
-.hours-cell.full {
- color: #28a745;
-}
-
-/* 작업 유형 태그 */
-.work-types-container {
- display: flex;
- flex-wrap: wrap;
- gap: 4px;
- max-width: 120px;
-}
-
-.work-type-tag {
- background: #e3f2fd;
- color: #1565c0;
- padding: 4px 8px;
- border-radius: 12px;
- font-size: 11px;
- font-weight: 600;
- white-space: nowrap;
- border: 1px solid #bbdefb;
-}
-
-/* 프로젝트 태그 */
-.projects-container {
- display: flex;
- flex-wrap: wrap;
- gap: 4px;
- max-width: 150px;
-}
-
-.project-tag {
- background: #f3e5f5;
- color: #7b1fa2;
- padding: 4px 8px;
- border-radius: 12px;
- font-size: 11px;
- font-weight: 600;
- white-space: nowrap;
- border: 1px solid #e1bee7;
-}
-
-/* 기여자 태그 */
-.contributors-container {
- display: flex;
- flex-wrap: wrap;
- gap: 4px;
- max-width: 120px;
-}
-
-.contributor-tag {
- background: #e8f5e8;
- color: #2e7d32;
- padding: 4px 8px;
- border-radius: 12px;
- font-size: 11px;
- font-weight: 600;
- white-space: nowrap;
- border: 1px solid #c8e6c9;
-}
-
-/* 업데이트 시간 스타일 */
-.update-time {
- font-size: 12px;
- color: #666;
- white-space: nowrap;
-}
-
-.update-time.recent {
- color: #28a745;
- font-weight: 600;
-}
-
-.update-time.old {
- color: #dc3545;
-}
-
-/* 상세 버튼 */
-.detail-btn {
- background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
- color: white;
- border: none;
- border-radius: 20px;
- padding: 8px 16px;
- cursor: pointer;
- font-size: 12px;
- font-weight: 600;
- transition: all 0.3s;
- white-space: nowrap;
-}
-
-.detail-btn:hover {
- background: linear-gradient(135deg, #0056b3 0%, #004085 100%);
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
-}
-
-/* 데이터 없음 행 */
-.no-data-row {
- text-align: center;
- padding: 40px 20px;
- color: #666;
- font-style: italic;
-}
-
-/* 테이블 반응형 */
-@media (max-width: 1200px) {
- .workers-table {
- font-size: 13px;
- }
-
- .workers-table th,
- .workers-table td {
- padding: 12px 8px;
- }
-
- .work-types-container,
- .projects-container,
- .contributors-container {
- max-width: 100px;
- }
-}
-
-@media (max-width: 992px) {
- .table-container {
- overflow-x: auto;
- }
-
- .workers-table {
- min-width: 800px;
- font-size: 12px;
- }
-
- .workers-table th,
- .workers-table td {
- padding: 10px 6px;
- }
-
- .work-types-container,
- .projects-container,
- .contributors-container {
- max-width: 80px;
- }
-
- .work-type-tag,
- .project-tag,
- .contributor-tag {
- font-size: 10px;
- padding: 3px 6px;
- }
-}
-
-@media (max-width: 768px) {
- .workers-table {
- min-width: 700px;
- font-size: 11px;
- }
-
- .workers-table th,
- .workers-table td {
- padding: 8px 4px;
- }
-
- .status-badge {
- font-size: 10px;
- padding: 4px 8px;
- min-width: 60px;
- }
-
- .detail-btn {
- font-size: 10px;
- padding: 6px 12px;
- }
-}
-
-/* 로딩 스피너 */
-.loading-spinner {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 4rem 2rem;
- background: white;
- border-radius: 16px;
- box-shadow: 0 6px 24px rgba(0,0,0,0.08);
-}
-
-.spinner {
- width: 50px;
- height: 50px;
- border: 4px solid #f3f3f3;
- border-top: 4px solid #007bff;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- margin-bottom: 1rem;
-}
-
-@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-.loading-spinner p {
- color: #666;
- font-size: 1.1rem;
- font-weight: 600;
-}
-
-/* 데이터 없음 메시지 */
-.no-data-message {
- text-align: center;
- padding: 4rem 2rem;
- background: white;
- border-radius: 16px;
- box-shadow: 0 6px 24px rgba(0,0,0,0.08);
-}
-
-.no-data-icon {
- font-size: 4rem;
- margin-bottom: 1rem;
-}
-
-.no-data-message h3 {
- color: #333;
- margin-bottom: 1rem;
- font-size: 1.5rem;
-}
-
-.no-data-message p {
- color: #666;
- font-size: 1.1rem;
- line-height: 1.6;
-}
-
-/* 작업자 상세 모달 */
-.worker-detail-modal {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0,0,0,0.7);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 1000;
- animation: fadeIn 0.3s ease;
-}
-
-.modal-content {
- background: white;
- border-radius: 16px;
- width: 90%;
- max-width: 800px;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 10px 40px rgba(0,0,0,0.3);
- animation: slideIn 0.3s ease;
-}
-
-.modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 24px;
- border-bottom: 2px solid #f0f0f0;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border-radius: 16px 16px 0 0;
-}
-
-.modal-header h3 {
- margin: 0;
- font-size: 20px;
- font-weight: 700;
-}
-
-.close-modal-btn {
- background: rgba(255,255,255,0.2);
- color: white;
- border: none;
- border-radius: 50%;
- width: 32px;
- height: 32px;
- cursor: pointer;
- font-size: 18px;
- font-weight: 700;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.3s;
-}
-
-.close-modal-btn:hover {
- background: rgba(255,255,255,0.3);
- transform: rotate(90deg);
-}
-
-.modal-body {
- padding: 24px;
-}
-
-/* 사용법 안내 */
-.guide-section {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- box-shadow: 0 6px 24px rgba(0,0,0,0.08);
- margin-top: 2rem;
-}
-
-.guide-section h3 {
- margin-bottom: 1.5rem;
- color: #333;
- font-size: 1.4rem;
- text-align: center;
-}
-
-.guide-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 20px;
-}
-
-.guide-item {
- text-align: center;
- padding: 20px;
- background: #f8f9fa;
- border-radius: 12px;
- border: 2px solid #e9ecef;
- transition: all 0.3s ease;
-}
-
-.guide-item:hover {
- transform: translateY(-2px);
- box-shadow: 0 6px 20px rgba(0,0,0,0.1);
- border-color: #667eea;
-}
-
-.guide-icon {
- font-size: 28px;
- margin-bottom: 12px;
-}
-
-.guide-item strong {
- display: block;
- font-size: 16px;
- font-weight: 700;
- margin-bottom: 8px;
- color: #333;
-}
-
-/* 애니메이션 */
-@keyframes fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
-
-@keyframes slideIn {
- from {
- opacity: 0;
- transform: translateY(-50px) scale(0.9);
- }
- to {
- opacity: 1;
- transform: translateY(0) scale(1);
- }
-}
-
-/* 수정 모달 스타일 */
-.edit-modal {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0,0,0,0.7);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 1001; /* 상세 모달보다 위에 */
- animation: fadeIn 0.3s ease;
-}
-
-.edit-modal-content {
- background: white;
- border-radius: 16px;
- width: 90%;
- max-width: 600px;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 10px 40px rgba(0,0,0,0.3);
- animation: slideIn 0.3s ease;
-}
-
-.edit-modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 24px;
- border-bottom: 2px solid #f0f0f0;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border-radius: 16px 16px 0 0;
-}
-
-.edit-modal-header h3 {
- margin: 0;
- font-size: 20px;
- font-weight: 700;
-}
-
-.edit-modal-body {
- padding: 24px;
-}
-
-.edit-form-group {
- margin-bottom: 20px;
-}
-
-.edit-form-group label {
- display: block;
- margin-bottom: 8px;
- font-weight: 700;
- color: #555;
- font-size: 14px;
-}
-
-.edit-select, .edit-input {
- width: 100%;
- padding: 12px 16px;
- border: 2px solid #e1e5e9;
- border-radius: 8px;
- font-size: 16px;
- background: white;
- transition: border-color 0.3s;
-}
-
-.edit-select:focus, .edit-input:focus {
- outline: none;
- border-color: #007bff;
- box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
-}
-
-.edit-modal-footer {
- display: flex;
- justify-content: flex-end;
- gap: 12px;
- padding: 24px;
- border-top: 2px solid #f0f0f0;
- background: #f8f9fa;
- border-radius: 0 0 16px 16px;
-}
\ No newline at end of file
diff --git a/system1-factory/web/css/my-attendance.css b/system1-factory/web/css/my-attendance.css
deleted file mode 100644
index a984fb8..0000000
--- a/system1-factory/web/css/my-attendance.css
+++ /dev/null
@@ -1,583 +0,0 @@
-/**
- * 나의 출근 현황 페이지 스타일
- */
-
-/* 페이지 헤더 */
-.page-header {
- margin-bottom: 24px;
-}
-
-.page-title {
- font-size: 28px;
- font-weight: 700;
- color: #1a1a1a;
- margin: 0 0 8px 0;
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.title-icon {
- font-size: 32px;
-}
-
-.page-description {
- font-size: 14px;
- color: #666;
- margin: 0;
-}
-
-/* 통계 카드 섹션 */
-.stats-section {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 16px;
- margin-bottom: 24px;
-}
-
-.stat-card {
- background: white;
- border-radius: 12px;
- padding: 20px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
- display: flex;
- align-items: center;
- gap: 16px;
- transition: transform 0.2s, box-shadow 0.2s;
-}
-
-.stat-card:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
-}
-
-.stat-icon {
- font-size: 36px;
- width: 56px;
- height: 56px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f8f9fa;
- border-radius: 12px;
-}
-
-.stat-info {
- flex: 1;
-}
-
-.stat-value {
- font-size: 24px;
- font-weight: 700;
- color: #1a1a1a;
- margin-bottom: 4px;
-}
-
-.stat-label {
- font-size: 13px;
- color: #666;
- font-weight: 500;
-}
-
-/* 탭 컨테이너 */
-.tab-container {
- display: flex;
- gap: 8px;
- margin-bottom: 20px;
- border-bottom: 2px solid #e9ecef;
-}
-
-.tab-btn {
- background: none;
- border: none;
- padding: 12px 24px;
- font-size: 14px;
- font-weight: 600;
- color: #6c757d;
- cursor: pointer;
- border-bottom: 3px solid transparent;
- transition: all 0.2s;
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.tab-btn:hover {
- color: #495057;
- background: #f8f9fa;
-}
-
-.tab-btn.active {
- color: #007bff;
- border-bottom-color: #007bff;
-}
-
-.tab-icon {
- font-size: 16px;
-}
-
-/* 탭 컨텐츠 */
-.tab-content {
- display: none;
-}
-
-.tab-content.active {
- display: block;
-}
-
-/* 테이블 스타일 */
-#attendanceTable {
- background: white;
- border-radius: 8px;
- overflow: hidden;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-}
-
-#attendanceTable thead {
- background: #f8f9fa;
-}
-
-#attendanceTable th {
- padding: 16px 12px;
- font-weight: 600;
- color: #495057;
- text-align: center;
- border-bottom: 2px solid #dee2e6;
-}
-
-#attendanceTable td {
- padding: 14px 12px;
- text-align: center;
- border-bottom: 1px solid #f1f3f5;
-}
-
-#attendanceTable tbody tr {
- transition: background-color 0.2s;
- cursor: pointer;
-}
-
-#attendanceTable tbody tr:hover {
- background-color: #f8f9fa;
-}
-
-.loading-cell,
-.empty-cell,
-.error-cell {
- text-align: center;
- padding: 40px 20px;
- color: #6c757d;
- font-size: 14px;
-}
-
-.error-cell {
- color: #dc3545;
-}
-
-.notes-cell {
- max-width: 200px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- text-align: left;
- color: #6c757d;
- font-size: 13px;
-}
-
-/* 상태 배지 */
-.status-badge {
- display: inline-block;
- padding: 4px 12px;
- border-radius: 12px;
- font-size: 12px;
- font-weight: 600;
- text-transform: capitalize;
-}
-
-.status-badge.normal {
- background: #d4edda;
- color: #155724;
-}
-
-.status-badge.late {
- background: #fff3cd;
- color: #856404;
-}
-
-.status-badge.early {
- background: #ffe5b5;
- color: #a56200;
-}
-
-.status-badge.absent {
- background: #f8d7da;
- color: #721c24;
-}
-
-.status-badge.vacation {
- background: #cce5ff;
- color: #004085;
-}
-
-/* 달력 스타일 */
-#calendarContainer {
- background: white;
- border-radius: 12px;
- padding: 24px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-}
-
-.calendar-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 24px;
-}
-
-.calendar-header h3 {
- font-size: 20px;
- font-weight: 700;
- color: #1a1a1a;
- margin: 0;
-}
-
-.calendar-nav-btn {
- background: #f8f9fa;
- border: 1px solid #dee2e6;
- border-radius: 8px;
- width: 40px;
- height: 40px;
- font-size: 18px;
- cursor: pointer;
- transition: all 0.2s;
-}
-
-.calendar-nav-btn:hover {
- background: #e9ecef;
- border-color: #adb5bd;
-}
-
-.calendar-grid {
- display: grid;
- grid-template-columns: repeat(7, 1fr);
- gap: 8px;
-}
-
-.calendar-day-header {
- text-align: center;
- font-weight: 600;
- font-size: 13px;
- color: #495057;
- padding: 12px 8px;
- background: #f8f9fa;
- border-radius: 4px;
-}
-
-.calendar-day {
- aspect-ratio: 1;
- border: 1px solid #e9ecef;
- border-radius: 8px;
- padding: 8px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- transition: all 0.2s;
- background: white;
-}
-
-.calendar-day.empty {
- background: #f8f9fa;
- border-color: #f1f3f5;
-}
-
-.calendar-day.has-record {
- cursor: pointer;
- font-weight: 600;
-}
-
-.calendar-day.has-record:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
-}
-
-/* 달력 날짜 상태별 색상 */
-.calendar-day.normal {
- background: #d4edda;
- border-color: #c3e6cb;
- color: #155724;
-}
-
-.calendar-day.late {
- background: #fff3cd;
- border-color: #ffeaa7;
- color: #856404;
-}
-
-.calendar-day.early {
- background: #ffe5b5;
- border-color: #ffd98a;
- color: #a56200;
-}
-
-.calendar-day.absent {
- background: #f8d7da;
- border-color: #f5c6cb;
- color: #721c24;
-}
-
-.calendar-day.vacation {
- background: #cce5ff;
- border-color: #b8daff;
- color: #004085;
-}
-
-.calendar-day-number {
- font-size: 14px;
- margin-bottom: 4px;
-}
-
-.calendar-day-status {
- font-size: 16px;
-}
-
-/* 달력 범례 */
-.calendar-legend {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- justify-content: center;
- margin-top: 24px;
- padding-top: 20px;
- border-top: 1px solid #e9ecef;
-}
-
-.legend-item {
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 13px;
- color: #495057;
-}
-
-.legend-dot {
- width: 16px;
- height: 16px;
- border-radius: 50%;
- border: 2px solid #dee2e6;
-}
-
-.legend-dot.normal {
- background: #d4edda;
- border-color: #c3e6cb;
-}
-
-.legend-dot.late {
- background: #fff3cd;
- border-color: #ffeaa7;
-}
-
-.legend-dot.early {
- background: #ffe5b5;
- border-color: #ffd98a;
-}
-
-.legend-dot.absent {
- background: #f8d7da;
- border-color: #f5c6cb;
-}
-
-.legend-dot.vacation {
- background: #cce5ff;
- border-color: #b8daff;
-}
-
-/* 모달 스타일 */
-.modal {
- position: fixed;
- z-index: 1000;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.modal-content {
- background-color: white;
- border-radius: 12px;
- width: 90%;
- max-width: 500px;
- max-height: 80vh;
- overflow-y: auto;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
-}
-
-.modal-header {
- padding: 20px 24px;
- border-bottom: 1px solid #e9ecef;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.modal-header h2 {
- margin: 0;
- font-size: 20px;
- font-weight: 700;
- color: #1a1a1a;
-}
-
-.modal-close-btn {
- background: none;
- border: none;
- font-size: 28px;
- color: #6c757d;
- cursor: pointer;
- width: 32px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 4px;
- transition: all 0.2s;
-}
-
-.modal-close-btn:hover {
- background: #f8f9fa;
- color: #343a40;
-}
-
-.modal-body {
- padding: 24px;
-}
-
-.modal-footer {
- padding: 16px 24px;
- border-top: 1px solid #e9ecef;
- display: flex;
- justify-content: flex-end;
- gap: 12px;
-}
-
-/* 상세 정보 그리드 */
-.detail-grid {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: 20px;
-}
-
-.detail-item {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.detail-item.full-width {
- grid-column: 1 / -1;
-}
-
-.detail-item label {
- font-size: 13px;
- font-weight: 600;
- color: #6c757d;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.detail-item div {
- font-size: 15px;
- color: #1a1a1a;
-}
-
-/* 버튼 스타일 */
-.btn-primary {
- background-color: #007bff;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 6px;
- font-weight: 600;
- cursor: pointer;
- transition: background-color 0.2s;
-}
-
-.btn-primary:hover {
- background-color: #0056b3;
-}
-
-.btn-secondary {
- background-color: #6c757d;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 6px;
- font-weight: 600;
- cursor: pointer;
- transition: background-color 0.2s;
-}
-
-.btn-secondary:hover {
- background-color: #5a6268;
-}
-
-/* 반응형 디자인 */
-@media (max-width: 768px) {
- .stats-section {
- grid-template-columns: 1fr;
- }
-
- .stat-card {
- padding: 16px;
- }
-
- .stat-icon {
- width: 48px;
- height: 48px;
- font-size: 28px;
- }
-
- .stat-value {
- font-size: 20px;
- }
-
- .tab-btn {
- padding: 10px 16px;
- font-size: 13px;
- }
-
- .calendar-grid {
- gap: 4px;
- }
-
- .calendar-day {
- padding: 4px;
- }
-
- .calendar-day-number {
- font-size: 12px;
- }
-
- .calendar-day-status {
- font-size: 14px;
- }
-
- .detail-grid {
- grid-template-columns: 1fr;
- }
-
- #attendanceTable {
- font-size: 12px;
- }
-
- #attendanceTable th,
- #attendanceTable td {
- padding: 10px 8px;
- }
-
- .notes-cell {
- max-width: 120px;
- }
-}
diff --git a/system1-factory/web/css/my-dashboard.css b/system1-factory/web/css/my-dashboard.css
deleted file mode 100644
index 89e545d..0000000
--- a/system1-factory/web/css/my-dashboard.css
+++ /dev/null
@@ -1,350 +0,0 @@
-/* My Dashboard CSS */
-
-.dashboard-container {
- max-width: 1200px;
- margin: 0 auto;
- padding: 2rem 1.5rem;
- background: #f8f9fa;
- min-height: 100vh;
-}
-
-.back-button {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.75rem 1.5rem;
- background: rgba(255, 255, 255, 0.9);
- color: #495057;
- text-decoration: none;
- border-radius: 0.5rem;
- font-weight: 500;
- margin-bottom: 1.5rem;
- transition: all 0.3s ease;
- box-shadow: 0 0.125rem 0.25rem rgba(0,0,0,0.1);
-}
-
-.back-button:hover {
- background: white;
- color: #007bff;
- transform: translateY(-0.0625rem);
-}
-
-.page-header {
- text-align: center;
- margin-bottom: 2rem;
-}
-
-.page-header h1 {
- font-size: 2rem;
- color: #333;
- margin-bottom: 0.5rem;
-}
-
-.page-header p {
- color: #666;
- font-size: 1.1rem;
-}
-
-/* 사용자 정보 카드 */
-.user-info-card {
- background: white;
- border-radius: 0.75rem;
- padding: 1.5rem;
- margin-bottom: 2rem;
- box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.1);
-}
-
-.info-row {
- display: flex;
- gap: 2rem;
- flex-wrap: wrap;
-}
-
-.info-item {
- display: flex;
- gap: 0.5rem;
-}
-
-.info-item .label {
- font-weight: 600;
- color: #555;
-}
-
-/* 연차 정보 위젯 */
-.vacation-widget {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border-radius: 0.75rem;
- padding: 2rem;
- margin-bottom: 2rem;
- box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.15);
-}
-
-.vacation-widget h2 {
- margin-bottom: 1.5rem;
-}
-
-.vacation-summary {
- display: flex;
- justify-content: space-around;
- margin-bottom: 1.5rem;
-}
-
-.vacation-summary .stat {
- text-align: center;
-}
-
-.vacation-summary .label {
- display: block;
- font-size: 0.9rem;
- opacity: 0.9;
- margin-bottom: 0.5rem;
-}
-
-.vacation-summary .value {
- display: block;
- font-size: 2rem;
- font-weight: 700;
-}
-
-.progress-bar {
- height: 1.5rem;
- background: rgba(255,255,255,0.2);
- border-radius: 0.75rem;
- overflow: hidden;
-}
-
-.progress {
- height: 100%;
- background: rgba(255,255,255,0.8);
- transition: width 0.5s ease;
-}
-
-/* 캘린더 섹션 */
-.calendar-section {
- background: white;
- border-radius: 0.75rem;
- padding: 2rem;
- margin-bottom: 2rem;
- box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.1);
-}
-
-.calendar-section h2 {
- margin-bottom: 1rem;
-}
-
-.calendar-controls {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 2rem;
- margin-bottom: 1.5rem;
-}
-
-.calendar-controls button {
- background: #667eea;
- color: white;
- border: none;
- border-radius: 0.5rem;
- padding: 0.5rem 1rem;
- cursor: pointer;
- font-size: 1rem;
-}
-
-.calendar-controls button:hover {
- background: #764ba2;
-}
-
-.calendar-grid {
- display: grid;
- grid-template-columns: repeat(7, 1fr);
- gap: 0.5rem;
-}
-
-.calendar-header {
- text-align: center;
- font-weight: 600;
- padding: 0.5rem;
- background: #f8f9fa;
- border-radius: 0.25rem;
-}
-
-.calendar-day {
- aspect-ratio: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 0.25rem;
- background: #f8f9fa;
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.calendar-day:hover:not(.empty) {
- transform: scale(1.05);
-}
-
-.calendar-day.empty {
- background: transparent;
-}
-
-.calendar-day.normal {
- background: #d4edda;
- color: #155724;
-}
-
-.calendar-day.late {
- background: #fff3cd;
- color: #856404;
-}
-
-.calendar-day.vacation {
- background: #d1ecf1;
- color: #0c5460;
-}
-
-.calendar-day.absent {
- background: #f8d7da;
- color: #721c24;
-}
-
-.calendar-legend {
- display: flex;
- justify-content: center;
- gap: 1.5rem;
- margin-top: 1.5rem;
- flex-wrap: wrap;
-}
-
-.calendar-legend span {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- font-size: 0.9rem;
-}
-
-.dot {
- width: 1rem;
- height: 1rem;
- border-radius: 50%;
-}
-
-.dot.normal {
- background: #d4edda;
-}
-
-.dot.late {
- background: #fff3cd;
-}
-
-.dot.vacation {
- background: #d1ecf1;
-}
-
-.dot.absent {
- background: #f8d7da;
-}
-
-/* 근무 시간 통계 */
-.work-hours-stats {
- background: white;
- border-radius: 0.75rem;
- padding: 2rem;
- margin-bottom: 2rem;
- box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.1);
-}
-
-.stats-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 1.5rem;
- margin-top: 1.5rem;
-}
-
-.stat-card {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- padding: 1.5rem;
- border-radius: 0.75rem;
- text-align: center;
-}
-
-.stat-card .label {
- display: block;
- font-size: 0.9rem;
- opacity: 0.9;
- margin-bottom: 0.5rem;
-}
-
-.stat-card .value {
- display: block;
- font-size: 2rem;
- font-weight: 700;
-}
-
-/* 최근 작업 보고서 */
-.recent-reports {
- background: white;
- border-radius: 0.75rem;
- padding: 2rem;
- margin-bottom: 2rem;
- box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.1);
-}
-
-.recent-reports h2 {
- margin-bottom: 1.5rem;
-}
-
-.report-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1rem;
- border-bottom: 1px solid #e9ecef;
-}
-
-.report-item:last-child {
- border-bottom: none;
-}
-
-.report-item .date {
- color: #666;
- font-size: 0.9rem;
-}
-
-.report-item .project {
- flex: 1;
- margin: 0 1rem;
- font-weight: 500;
-}
-
-.report-item .hours {
- color: #667eea;
- font-weight: 600;
-}
-
-.empty-message {
- text-align: center;
- color: #999;
- padding: 2rem;
-}
-
-/* 반응형 */
-@media (max-width: 768px) {
- .dashboard-container {
- padding: 1rem;
- }
-
- .vacation-summary {
- flex-direction: column;
- gap: 1rem;
- }
-
- .calendar-grid {
- gap: 0.25rem;
- }
-
- .calendar-legend {
- gap: 0.75rem;
- }
-}
diff --git a/system1-factory/web/css/project-management.css b/system1-factory/web/css/project-management.css
deleted file mode 100644
index a0ee6a5..0000000
--- a/system1-factory/web/css/project-management.css
+++ /dev/null
@@ -1,1570 +0,0 @@
-/* 프로젝트 관리 페이지 스타일 */
-
-/* 기본 레이아웃 */
-body {
- margin: 0;
- padding: 0;
- font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- min-height: 100vh;
-}
-
-/* 헤더 스타일은 navbar 컴포넌트가 관리 */
-/* 필요한 경우 navbar.html에서 수정하세요 */
-
-.logo {
- height: 40px;
- width: auto;
-}
-
-.company-info {
- display: flex;
- flex-direction: column;
-}
-
-.company-name {
- font-size: 1.25rem;
- font-weight: 700;
- color: #1f2937;
- margin: 0;
- line-height: 1.2;
-}
-
-.company-subtitle {
- font-size: 0.875rem;
- color: #6b7280;
- font-weight: 500;
-}
-
-.header-center {
- display: flex;
- align-items: center;
-}
-
-.current-time {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 0.5rem 1rem;
- background: rgba(59, 130, 246, 0.1);
- border-radius: 0.5rem;
- border: 1px solid rgba(59, 130, 246, 0.2);
-}
-
-.time-label {
- font-size: 0.75rem;
- color: #6b7280;
- margin-bottom: 0.125rem;
-}
-
-.time-value {
- font-size: 1rem;
- font-weight: 600;
- color: #1f2937;
- font-family: 'Courier New', monospace;
-}
-
-.header-right {
- display: flex;
- align-items: center;
- gap: 1rem;
-}
-
-.header-actions {
- display: flex;
- align-items: center;
- gap: 0.75rem;
-}
-
-.back-btn, .dashboard-btn {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.5rem 1rem;
- background: rgba(255, 255, 255, 0.15);
- color: #374151;
- text-decoration: none;
- border-radius: 1.25rem;
- font-size: 0.85rem;
- font-weight: 500;
- transition: all 0.3s ease;
- border: 1px solid rgba(255, 255, 255, 0.3);
- backdrop-filter: blur(10px);
-}
-
-.back-btn:hover, .dashboard-btn:hover {
- background: rgba(255, 255, 255, 0.25);
- transform: translateY(-1px);
- text-decoration: none;
- color: #1f2937;
-}
-
-.user-profile {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 0.5rem 1rem;
- background: rgba(255, 255, 255, 0.1);
- border-radius: 2rem;
- cursor: pointer;
- transition: all 0.3s ease;
- position: relative;
-}
-
-.user-profile:hover {
- background: rgba(255, 255, 255, 0.2);
-}
-
-.user-avatar {
- width: 2.5rem;
- height: 2.5rem;
- background: linear-gradient(135deg, #3b82f6, #1d4ed8);
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- color: white;
- font-weight: 600;
- font-size: 1rem;
-}
-
-.user-info {
- display: flex;
- flex-direction: column;
-}
-
-.user-name {
- font-size: 0.875rem;
- font-weight: 600;
- color: #1f2937;
- line-height: 1.2;
-}
-
-.user-role {
- font-size: 0.75rem;
- color: #6b7280;
-}
-
-/* 메인 콘텐츠 */
-.dashboard-main {
- flex: 1;
- padding: 2rem;
- min-height: calc(100vh - 80px);
- max-width: 1600px;
- margin: 0 auto;
- width: 100%;
-}
-
-.page-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-end;
- margin-bottom: 2rem;
-}
-
-.page-title-section {
- flex: 1;
-}
-
-.page-title {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- font-size: 2.5rem;
- font-weight: 700;
- color: white;
- margin: 0 0 0.5rem 0;
- text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.title-icon {
- font-size: 2.5rem;
-}
-
-.page-description {
- font-size: 1.125rem;
- color: rgba(255, 255, 255, 0.9);
- margin: 0;
- font-weight: 400;
-}
-
-.page-actions {
- display: flex;
- gap: 1rem;
-}
-
-.btn {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.75rem 1.5rem;
- border: none;
- border-radius: 0.75rem;
- font-size: 0.875rem;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.3s ease;
- text-decoration: none;
-}
-
-.btn-primary {
- background: #3b82f6;
- color: white;
- box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
-}
-
-.btn-primary:hover {
- background: #2563eb;
- transform: translateY(-2px);
- box-shadow: 0 6px 16px rgba(59, 130, 246, 0.4);
-}
-
-.btn-secondary {
- background: rgba(255, 255, 255, 0.9);
- color: #374151;
- border: 1px solid rgba(255, 255, 255, 0.3);
-}
-
-.btn-secondary:hover {
- background: white;
- transform: translateY(-2px);
-}
-
-.btn-danger {
- background: #ef4444;
- color: white;
-}
-
-.btn-danger:hover {
- background: #dc2626;
- transform: translateY(-2px);
-}
-
-/* 검색 및 필터 섹션 */
-.search-section {
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(20px);
- border-radius: 1rem;
- padding: 1.5rem;
- margin-bottom: 2rem;
- border: 1px solid rgba(255, 255, 255, 0.2);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
-}
-
-.search-bar {
- display: flex;
- gap: 1rem;
- margin-bottom: 1rem;
-}
-
-.search-input {
- flex: 1;
- padding: 0.75rem 1rem;
- border: 1px solid #d1d5db;
- border-radius: 0.5rem;
- font-size: 0.875rem;
- transition: all 0.3s ease;
-}
-
-.search-input:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-.search-btn {
- padding: 0.75rem 1rem;
- background: #3b82f6;
- color: white;
- border: none;
- border-radius: 0.5rem;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-
-.search-btn:hover {
- background: #2563eb;
-}
-
-.filter-options {
- display: flex;
- gap: 1rem;
-}
-
-.filter-select {
- padding: 0.5rem 1rem;
- border: 1px solid #d1d5db;
- border-radius: 0.5rem;
- font-size: 0.875rem;
- background: white;
- cursor: pointer;
-}
-
-/* 프로젝트 섹션 */
-.projects-section {
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(20px);
- border-radius: 1rem;
- padding: 1.5rem;
- border: 1px solid rgba(255, 255, 255, 0.2);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 1px solid #e5e7eb;
-}
-
-.section-title {
- font-size: 1.25rem;
- font-weight: 600;
- color: #1f2937;
- margin: 0;
-}
-
-.project-stats {
- display: flex;
- gap: 1.5rem;
- font-size: 0.875rem;
- align-items: center;
-}
-
-.stat-item {
- display: flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.5rem 0.75rem;
- border-radius: 0.5rem;
- font-weight: 500;
- transition: all 0.3s ease;
- cursor: pointer;
- position: relative;
-}
-
-.stat-item:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-}
-
-.stat-item.active {
- transform: scale(1.05);
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
- z-index: 10;
-}
-
-.stat-item .stat-icon {
- font-size: 1rem;
-}
-
-.stat-item span:not(.stat-icon) {
- font-weight: 600;
-}
-
-/* 활성 프로젝트 통계 */
-.active-stat {
- background: rgba(16, 185, 129, 0.1);
- color: #065f46;
- border: 1px solid rgba(16, 185, 129, 0.2);
-}
-
-.active-stat span:not(.stat-icon) {
- color: #10b981;
-}
-
-.active-stat.active {
- background: rgba(16, 185, 129, 0.2);
- border: 2px solid #10b981;
-}
-
-.active-stat:hover {
- background: rgba(16, 185, 129, 0.15);
-}
-
-/* 비활성 프로젝트 통계 */
-.inactive-stat {
- background: rgba(239, 68, 68, 0.1);
- color: #7f1d1d;
- border: 1px solid rgba(239, 68, 68, 0.2);
-}
-
-.inactive-stat span:not(.stat-icon) {
- color: #ef4444;
-}
-
-.inactive-stat.active {
- background: rgba(239, 68, 68, 0.2);
- border: 2px solid #ef4444;
-}
-
-.inactive-stat:hover {
- background: rgba(239, 68, 68, 0.15);
-}
-
-/* 전체 프로젝트 통계 */
-.total-stat {
- background: rgba(59, 130, 246, 0.1);
- color: #1e3a8a;
- border: 1px solid rgba(59, 130, 246, 0.2);
-}
-
-.total-stat span:not(.stat-icon) {
- color: #3b82f6;
-}
-
-.total-stat.active {
- background: rgba(59, 130, 246, 0.2);
- border: 2px solid #3b82f6;
-}
-
-.total-stat:hover {
- background: rgba(59, 130, 246, 0.15);
-}
-
-/* 프로젝트 그리드 */
-.projects-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
- gap: 1.5rem;
- justify-content: center;
-}
-
-/* 작업자 카드 전용 스타일 */
-.worker-card .project-info {
- display: flex;
- align-items: flex-start;
- gap: 1rem;
-}
-
-.worker-avatar {
- width: 60px;
- height: 60px;
- border-radius: 50%;
- background: linear-gradient(135deg, #3b82f6, #1d4ed8);
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
-}
-
-.avatar-initial {
- color: white;
- font-size: 1.5rem;
- font-weight: 700;
-}
-
-.worker-card .project-name {
- margin-top: 0.25rem;
-}
-
-.worker-card .project-meta {
- margin-top: 0.5rem;
-}
-
-.worker-card.inactive .worker-avatar {
- background: linear-gradient(135deg, #9ca3af, #6b7280);
- box-shadow: 0 4px 12px rgba(156, 163, 175, 0.3);
-}
-
-/* 작업 유형 트리 뷰 스타일 */
-.task-tree-container {
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(20px);
- border-radius: 1rem;
- padding: 1.5rem;
- border: 1px solid rgba(255, 255, 255, 0.2);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
-}
-
-.tree-header {
- display: flex;
- gap: 1rem;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 1px solid #e5e7eb;
-}
-
-.btn-outline {
- background: transparent;
- border: 1px solid #d1d5db;
- color: #374151;
- padding: 0.5rem 1rem;
- border-radius: 0.5rem;
- font-size: 0.875rem;
- cursor: pointer;
- transition: all 0.3s ease;
- display: flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.btn-outline:hover {
- background: #f3f4f6;
- border-color: #9ca3af;
-}
-
-.task-tree {
- max-height: 600px;
- overflow-y: auto;
-}
-
-/* 카테고리 (대분류) 스타일 */
-.tree-category {
- margin-bottom: 1rem;
- border: 1px solid #e5e7eb;
- border-radius: 0.75rem;
- overflow: hidden;
-}
-
-.category-header {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 1rem 1.25rem;
- background: linear-gradient(135deg, #f8fafc, #e2e8f0);
- cursor: pointer;
- transition: all 0.3s ease;
- border-bottom: 1px solid #e5e7eb;
-}
-
-.category-header:hover {
- background: linear-gradient(135deg, #f1f5f9, #cbd5e1);
-}
-
-.category-toggle {
- font-size: 0.875rem;
- color: #6b7280;
- transition: transform 0.3s ease;
-}
-
-.category-icon {
- font-size: 1.25rem;
-}
-
-.category-name {
- font-size: 1.125rem;
- font-weight: 600;
- color: #1f2937;
- flex: 1;
-}
-
-.category-count {
- font-size: 0.875rem;
- color: #6b7280;
- background: rgba(107, 114, 128, 0.1);
- padding: 0.25rem 0.5rem;
- border-radius: 0.375rem;
-}
-
-.category-actions {
- display: flex;
- gap: 0.5rem;
-}
-
-.category-content {
- background: #ffffff;
-}
-
-/* 서브카테고리 (중분류) 스타일 */
-.tree-subcategory {
- border-bottom: 1px solid #f3f4f6;
-}
-
-.tree-subcategory:last-child {
- border-bottom: none;
-}
-
-.subcategory-header {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 0.875rem 1.25rem;
- background: #f8fafc;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-
-.subcategory-header:hover {
- background: #f1f5f9;
-}
-
-.subcategory-toggle {
- font-size: 0.75rem;
- color: #6b7280;
- margin-left: 1rem;
-}
-
-.subcategory-icon {
- font-size: 1rem;
-}
-
-.subcategory-name {
- font-size: 1rem;
- font-weight: 500;
- color: #374151;
- flex: 1;
-}
-
-.subcategory-count {
- font-size: 0.75rem;
- color: #6b7280;
- background: rgba(107, 114, 128, 0.1);
- padding: 0.125rem 0.375rem;
- border-radius: 0.25rem;
-}
-
-.subcategory-actions {
- display: flex;
- gap: 0.25rem;
-}
-
-.subcategory-content {
- background: #ffffff;
-}
-
-/* 작업 (상세) 스타일 */
-.tree-task {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0.75rem 1.25rem 0.75rem 2.5rem;
- border-bottom: 1px solid #f9fafb;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-
-.tree-task:hover {
- background: #f9fafb;
-}
-
-.tree-task:last-child {
- border-bottom: none;
-}
-
-.task-info {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- flex: 1;
-}
-
-.task-icon {
- font-size: 0.875rem;
- color: #6b7280;
-}
-
-.task-name {
- font-size: 0.875rem;
- font-weight: 500;
- color: #1f2937;
-}
-
-.task-description {
- font-size: 0.75rem;
- color: #6b7280;
- margin-left: 0.5rem;
- font-style: italic;
-}
-
-.task-actions {
- display: flex;
- gap: 0.25rem;
- opacity: 0;
- transition: opacity 0.3s ease;
-}
-
-.tree-task:hover .task-actions {
- opacity: 1;
-}
-
-/* 작은 버튼 스타일 */
-.btn-small {
- padding: 0.25rem 0.5rem;
- border: none;
- border-radius: 0.25rem;
- font-size: 0.75rem;
- cursor: pointer;
- transition: all 0.3s ease;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.btn-small.btn-primary {
- background: #3b82f6;
- color: white;
-}
-
-.btn-small.btn-primary:hover {
- background: #2563eb;
-}
-
-.btn-small.btn-secondary {
- background: #6b7280;
- color: white;
-}
-
-.btn-small.btn-secondary:hover {
- background: #4b5563;
-}
-
-.btn-small.btn-edit {
- background: #f59e0b;
- color: white;
-}
-
-.btn-small.btn-edit:hover {
- background: #d97706;
-}
-
-.btn-small.btn-delete {
- background: #ef4444;
- color: white;
-}
-
-.btn-small.btn-delete:hover {
- background: #dc2626;
-}
-
-/* 코드 관리 전용 스타일 */
-.code-tabs {
- display: flex;
- gap: 0.5rem;
- margin-bottom: 2rem;
- border-bottom: 3px solid #d1d5db;
- padding-bottom: 0;
- background: rgba(255, 255, 255, 0.9);
- border-radius: 1rem 1rem 0 0;
- padding: 0.5rem 0.5rem 0 0.5rem;
-}
-
-.tab-btn {
- background: rgba(255, 255, 255, 0.7);
- border: 2px solid #e5e7eb;
- padding: 1rem 1.5rem;
- border-radius: 0.75rem;
- cursor: pointer;
- transition: all 0.3s ease;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- font-size: 0.95rem;
- font-weight: 600;
- color: #4b5563;
- border-bottom: 3px solid transparent;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.tab-btn:hover {
- background: rgba(59, 130, 246, 0.1);
- color: #1e40af;
- border-color: #3b82f6;
- transform: translateY(-1px);
-}
-
-.tab-btn.active {
- background: linear-gradient(135deg, #3b82f6, #1d4ed8);
- color: #ffffff;
- border-color: #1d4ed8;
- box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
- transform: translateY(-2px);
-}
-
-.tab-icon {
- font-size: 1rem;
-}
-
-.code-tab-content {
- display: none;
-}
-
-.code-tab-content.active {
- display: block;
-}
-
-.code-section {
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 250, 252, 0.95));
- backdrop-filter: blur(20px);
- border-radius: 1rem;
- padding: 2rem;
- border: 2px solid rgba(59, 130, 246, 0.2);
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 1px solid #e5e7eb;
-}
-
-.section-title {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- font-size: 1.25rem;
- font-weight: 600;
- color: #1f2937;
- margin: 0;
-}
-
-.section-icon {
- font-size: 1.5rem;
-}
-
-.section-actions {
- display: flex;
- gap: 0.75rem;
-}
-
-.code-stats {
- display: flex;
- gap: 1rem;
- margin-bottom: 1.5rem;
- flex-wrap: wrap;
-}
-
-.code-stats .stat-item {
- background: linear-gradient(135deg, rgba(59, 130, 246, 0.15), rgba(59, 130, 246, 0.05));
- border: 2px solid rgba(59, 130, 246, 0.3);
- color: #1e40af;
- padding: 0.75rem 1.25rem;
- border-radius: 0.75rem;
- font-size: 0.9rem;
- font-weight: 600;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- box-shadow: 0 4px 12px rgba(59, 130, 246, 0.2);
-}
-
-.code-stats .critical-stat {
- background: linear-gradient(135deg, rgba(239, 68, 68, 0.2), rgba(239, 68, 68, 0.1));
- border-color: rgba(239, 68, 68, 0.4);
- color: #dc2626;
- box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
-}
-
-.code-stats .high-stat {
- background: linear-gradient(135deg, rgba(249, 115, 22, 0.2), rgba(249, 115, 22, 0.1));
- border-color: rgba(249, 115, 22, 0.4);
- color: #ea580c;
- box-shadow: 0 4px 12px rgba(249, 115, 22, 0.3);
-}
-
-.code-stats .medium-stat {
- background: linear-gradient(135deg, rgba(245, 158, 11, 0.2), rgba(245, 158, 11, 0.1));
- border-color: rgba(245, 158, 11, 0.4);
- color: #d97706;
- box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
-}
-
-.code-stats .low-stat {
- background: linear-gradient(135deg, rgba(16, 185, 129, 0.2), rgba(16, 185, 129, 0.1));
- border-color: rgba(16, 185, 129, 0.4);
- color: #059669;
- box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
-}
-
-.code-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
- gap: 1.5rem;
-}
-
-.code-card {
- background: linear-gradient(135deg, #ffffff, #f8fafc);
- border: 2px solid #e5e7eb;
- border-radius: 1rem;
- padding: 1.5rem;
- cursor: pointer;
- transition: all 0.3s ease;
- position: relative;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-}
-
-.code-card:hover {
- transform: translateY(-4px);
- box-shadow: 0 12px 35px rgba(0, 0, 0, 0.2);
- border-color: #3b82f6;
- background: linear-gradient(135deg, #ffffff, #f0f9ff);
-}
-
-.code-card.normal-status {
- border-left: 6px solid #10b981;
- background: linear-gradient(135deg, #ffffff, #f0fdf4);
-}
-
-.code-card.normal-status:hover {
- background: linear-gradient(135deg, #f0fdf4, #dcfce7);
- box-shadow: 0 12px 35px rgba(16, 185, 129, 0.3);
-}
-
-.code-card.error-status {
- border-left: 6px solid #ef4444;
- background: linear-gradient(135deg, #ffffff, #fef2f2);
-}
-
-.code-card.error-status:hover {
- background: linear-gradient(135deg, #fef2f2, #fee2e2);
- box-shadow: 0 12px 35px rgba(239, 68, 68, 0.3);
-}
-
-.code-card.error-type-card.severity-low {
- border-left: 6px solid #10b981;
- background: linear-gradient(135deg, #ffffff, #f0fdf4);
-}
-
-.code-card.error-type-card.severity-low:hover {
- background: linear-gradient(135deg, #f0fdf4, #dcfce7);
- box-shadow: 0 12px 35px rgba(16, 185, 129, 0.3);
-}
-
-.code-card.error-type-card.severity-medium {
- border-left: 6px solid #f59e0b;
- background: linear-gradient(135deg, #ffffff, #fffbeb);
-}
-
-.code-card.error-type-card.severity-medium:hover {
- background: linear-gradient(135deg, #fffbeb, #fef3c7);
- box-shadow: 0 12px 35px rgba(245, 158, 11, 0.3);
-}
-
-.code-card.error-type-card.severity-high {
- border-left: 6px solid #f97316;
- background: linear-gradient(135deg, #ffffff, #fff7ed);
-}
-
-.code-card.error-type-card.severity-high:hover {
- background: linear-gradient(135deg, #fff7ed, #fed7aa);
- box-shadow: 0 12px 35px rgba(249, 115, 22, 0.3);
-}
-
-.code-card.error-type-card.severity-critical {
- border-left: 6px solid #ef4444;
- background: linear-gradient(135deg, #ffffff, #fef2f2);
-}
-
-.code-card.error-type-card.severity-critical:hover {
- background: linear-gradient(135deg, #fef2f2, #fee2e2);
- box-shadow: 0 12px 35px rgba(239, 68, 68, 0.3);
-}
-
-.code-card.work-type-card {
- border-left: 6px solid #6366f1;
- background: linear-gradient(135deg, #ffffff, #faf5ff);
-}
-
-.code-card.work-type-card:hover {
- background: linear-gradient(135deg, #faf5ff, #f3e8ff);
- box-shadow: 0 12px 35px rgba(99, 102, 241, 0.3);
-}
-
-.code-header {
- display: flex;
- align-items: flex-start;
- justify-content: space-between;
- margin-bottom: 1rem;
-}
-
-.code-icon {
- font-size: 1.5rem;
- margin-right: 0.75rem;
-}
-
-.code-info {
- flex: 1;
-}
-
-.code-name {
- font-size: 1.25rem;
- font-weight: 700;
- color: #111827;
- margin: 0 0 0.5rem 0;
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
-}
-
-.code-label {
- font-size: 0.8rem;
- font-weight: 600;
- color: #374151;
- background: linear-gradient(135deg, #f3f4f6, #e5e7eb);
- padding: 0.25rem 0.75rem;
- border-radius: 0.5rem;
- border: 1px solid #d1d5db;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-}
-
-.code-description {
- color: #6b7280;
- font-size: 0.875rem;
- line-height: 1.5;
- margin: 0 0 1rem 0;
-}
-
-.solution-guide {
- background: #f0f9ff;
- border: 1px solid #bae6fd;
- border-radius: 0.5rem;
- padding: 0.75rem;
- margin: 1rem 0;
- font-size: 0.875rem;
- color: #0c4a6e;
-}
-
-.code-meta {
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-size: 0.75rem;
- color: #9ca3af;
- margin-top: 1rem;
- padding-top: 0.75rem;
- border-top: 1px solid #f3f4f6;
-}
-
-.code-date {
- font-size: 0.75rem;
- color: #9ca3af;
-}
-
-.code-actions {
- display: flex;
- gap: 0.25rem;
- opacity: 0;
- transition: opacity 0.3s ease;
-}
-
-.code-card:hover .code-actions {
- opacity: 1;
-}
-
-.form-checkbox {
- margin-right: 0.5rem;
-}
-
-.form-help {
- display: block;
- margin-top: 0.25rem;
- font-size: 0.75rem;
- color: #6b7280;
-}
-
-/* 프로필 드롭다운 스타일 개선 */
-.profile-dropdown {
- position: relative;
-}
-
-.profile-dropdown .dropdown-item {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 0.75rem 1rem;
- color: #374151;
- text-decoration: none;
- transition: all 0.3s ease;
- border: none;
- background: transparent;
- width: 100%;
- text-align: left;
- font-size: 0.875rem;
- cursor: pointer;
- font-family: inherit;
- border-radius: 0.5rem;
- margin: 0.25rem;
-}
-
-.profile-dropdown .dropdown-item:hover {
- background: linear-gradient(135deg, #f3f4f6, #e5e7eb);
- color: #1f2937;
- transform: translateX(2px);
-}
-
-.profile-dropdown .dropdown-item.logout-btn {
- color: #dc2626;
- border-top: 1px solid #e5e7eb;
- margin-top: 0.5rem;
- padding-top: 0.75rem;
-}
-
-.profile-dropdown .dropdown-item.logout-btn:hover {
- background: linear-gradient(135deg, #fef2f2, #fee2e2);
- color: #b91c1c;
-}
-
-.profile-dropdown .dropdown-icon {
- font-size: 1.1rem;
- width: 1.5rem;
- text-align: center;
- opacity: 0.8;
-}
-
-.profile-dropdown .dropdown-item:hover .dropdown-icon {
- opacity: 1;
-}
-
-/* 헤더 사용자 프로필 스타일 개선 */
-.user-profile {
- position: relative;
- cursor: pointer;
-}
-
-.user-profile .profile-dropdown {
- position: absolute;
- top: calc(100% + 0.5rem);
- right: 0;
- background: linear-gradient(135deg, #ffffff, #f8fafc);
- border: 2px solid rgba(59, 130, 246, 0.2);
- border-radius: 1rem;
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
- min-width: 200px;
- opacity: 0;
- visibility: hidden;
- transform: translateY(-10px);
- transition: all 0.3s ease;
- overflow: hidden;
- z-index: 1000;
- backdrop-filter: blur(20px);
-}
-
-.user-profile .profile-dropdown[style*="block"] {
- opacity: 1;
- visibility: visible;
- transform: translateY(0);
-}
-
-/* 반응형 디자인 */
-@media (max-width: 768px) {
- .code-tabs {
- flex-direction: column;
- gap: 0;
- }
-
- .tab-btn {
- border-radius: 0;
- border-bottom: 1px solid #e5e7eb;
- }
-
- .tab-btn.active {
- border-bottom-color: #3b82f6;
- }
-
- .section-header {
- flex-direction: column;
- align-items: flex-start;
- gap: 1rem;
- }
-
- .code-stats {
- justify-content: center;
- }
-
- .code-grid {
- grid-template-columns: 1fr;
- }
-
- .user-profile .profile-dropdown {
- right: -1rem;
- min-width: 180px;
- }
-}
-
-.project-card {
- background: #f8fafc;
- border: 1px solid #e2e8f0;
- border-radius: 0.75rem;
- padding: 1.5rem;
- transition: all 0.3s ease;
- cursor: pointer;
-}
-
-.project-card:hover {
- background: #f1f5f9;
- border-color: #cbd5e1;
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-}
-
-.project-card.inactive {
- opacity: 0.8;
- background: #f8f9fa;
- border-color: #e9ecef;
- border-left: 4px solid #ef4444;
- position: relative;
-}
-
-.project-card.inactive:hover {
- background: #f1f3f4;
- border-color: #dee2e6;
-}
-
-/* 비활성화 오버레이 */
-.inactive-overlay {
- position: absolute;
- top: 0;
- right: 0;
- z-index: 10;
-}
-
-.inactive-badge {
- background: linear-gradient(135deg, #ef4444, #dc2626);
- color: white;
- padding: 0.25rem 0.75rem;
- border-radius: 0 0.75rem 0 0.5rem;
- font-size: 0.75rem;
- font-weight: 600;
- box-shadow: 0 2px 4px rgba(239, 68, 68, 0.3);
-}
-
-/* 비활성 라벨 */
-.inactive-label {
- color: #ef4444;
- font-size: 0.8rem;
- font-weight: 600;
- margin-left: 0.5rem;
- background: rgba(239, 68, 68, 0.1);
- padding: 0.125rem 0.5rem;
- border-radius: 0.25rem;
-}
-
-/* 비활성 안내 */
-.inactive-notice {
- color: #f59e0b;
- font-size: 0.75rem;
- font-weight: 500;
- background: rgba(245, 158, 11, 0.1);
- padding: 0.25rem 0.5rem;
- border-radius: 0.25rem;
- border: 1px solid rgba(245, 158, 11, 0.2);
- display: inline-block;
- margin-top: 0.25rem;
-}
-
-.project-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 1rem;
-}
-
-.project-info {
- flex: 1;
-}
-
-.project-job-no {
- font-size: 0.75rem;
- color: #6b7280;
- font-weight: 500;
- margin-bottom: 0.25rem;
-}
-
-.project-name {
- font-size: 1rem;
- font-weight: 600;
- color: #1f2937;
- margin: 0 0 0.5rem 0;
- line-height: 1.4;
-}
-
-.project-meta {
- display: flex;
- flex-direction: column;
- gap: 0.25rem;
- font-size: 0.75rem;
- color: #6b7280;
-}
-
-.project-actions {
- display: flex;
- gap: 0.5rem;
-}
-
-.btn-edit, .btn-delete {
- padding: 0.375rem 0.75rem;
- border: none;
- border-radius: 0.375rem;
- font-size: 0.75rem;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-
-.btn-edit {
- background: #3b82f6;
- color: white;
-}
-
-.btn-edit:hover {
- background: #2563eb;
-}
-
-.btn-delete {
- background: #ef4444;
- color: white;
-}
-
-.btn-delete:hover {
- background: #dc2626;
-}
-
-/* Empty State */
-.empty-state {
- text-align: center;
- padding: 3rem 2rem;
- color: #6b7280;
-}
-
-.empty-state .empty-icon {
- font-size: 4rem;
- margin-bottom: 1rem;
- opacity: 0.5;
-}
-
-.empty-state h3 {
- margin: 0 0 0.5rem 0;
- color: #374151;
- font-size: 1.25rem;
-}
-
-.empty-state p {
- margin: 0 0 1.5rem 0;
- font-size: 0.875rem;
-}
-
-/* 모달 스타일 */
-.modal-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1000;
- padding: 1rem;
-}
-
-.modal-container {
- background: white;
- border-radius: 1rem;
- max-width: 600px;
- width: 100%;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 20px 25px rgba(0, 0, 0, 0.1);
-}
-
-.modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1.5rem;
- border-bottom: 1px solid #e5e7eb;
-}
-
-.modal-header h2 {
- margin: 0;
- font-size: 1.25rem;
- font-weight: 600;
- color: #1f2937;
-}
-
-.modal-close-btn {
- background: none;
- border: none;
- font-size: 1.5rem;
- color: #6b7280;
- cursor: pointer;
- padding: 0.25rem;
- border-radius: 0.25rem;
- transition: all 0.3s ease;
-}
-
-.modal-close-btn:hover {
- background: #f3f4f6;
- color: #374151;
-}
-
-.modal-body {
- padding: 1.5rem;
-}
-
-.modal-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1.5rem;
- border-top: 1px solid #e5e7eb;
- gap: 1rem;
-}
-
-/* 폼 스타일 */
-.form-row {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 1rem;
- margin-bottom: 1rem;
-}
-
-.form-group {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
-}
-
-.form-label {
- font-size: 0.875rem;
- font-weight: 500;
- color: #374151;
-}
-
-.form-control {
- padding: 0.75rem;
- border: 1px solid #d1d5db;
- border-radius: 0.5rem;
- font-size: 0.875rem;
- transition: all 0.3s ease;
-}
-
-.form-control:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-/* 반응형 디자인 */
-@media (max-width: 1024px) {
- .dashboard-header {
- padding: 1rem;
- }
-
- .dashboard-main {
- padding: 1.5rem;
- }
-
- .page-header {
- flex-direction: column;
- align-items: flex-start;
- gap: 1rem;
- }
-
- .projects-grid {
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- }
-}
-
-@media (max-width: 768px) {
- .header-center {
- display: none;
- }
-
- .company-info {
- display: none;
- }
-
- .page-title {
- font-size: 2rem;
- }
-
- .page-actions {
- flex-direction: column;
- }
-
- .search-bar {
- flex-direction: column;
- }
-
- .filter-options {
- flex-direction: column;
- }
-
- .projects-grid {
- grid-template-columns: 1fr;
- }
-
- .form-row {
- grid-template-columns: 1fr;
- }
-
- .project-stats {
- flex-direction: column;
- gap: 0.75rem;
- align-items: stretch;
- }
-
- .stat-item {
- justify-content: center;
- }
-}
-
-@media (max-width: 480px) {
- .dashboard-header {
- padding: 0.75rem;
- }
-
- .dashboard-main {
- padding: 1rem;
- }
-
- .page-title {
- font-size: 1.75rem;
- }
-
- .search-section,
- .projects-section {
- padding: 1rem;
- }
-
- .modal-container {
- margin: 0.5rem;
- max-height: 95vh;
- }
-}
-
-/* 작업자 상태 토글 버튼 스타일 */
-.btn-toggle {
- background: none;
- border: 2px solid;
- border-radius: 50%;
- width: 36px;
- height: 36px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- font-size: 1rem;
- transition: all 0.2s ease;
- margin-right: 0.25rem;
-}
-
-.btn-deactivate {
- border-color: #ef4444;
- color: #ef4444;
- background: rgba(239, 68, 68, 0.1);
-}
-
-.btn-deactivate:hover {
- background: #ef4444;
- color: white;
- transform: scale(1.05);
-}
-
-.btn-activate {
- border-color: #10b981;
- color: #10b981;
- background: rgba(16, 185, 129, 0.1);
-}
-
-.btn-activate:hover {
- background: #10b981;
- color: white;
- transform: scale(1.05);
-}
diff --git a/system1-factory/web/css/system-dashboard.css b/system1-factory/web/css/system-dashboard.css
deleted file mode 100644
index 9b8a723..0000000
--- a/system1-factory/web/css/system-dashboard.css
+++ /dev/null
@@ -1,953 +0,0 @@
-/* 시스템 대시보드 전용 스타일 */
-
-/* 시스템 대시보드 배경 - 깔끔한 흰색 */
-.main-layout .content-wrapper {
- background: #ffffff;
- min-height: calc(100vh - 80px);
- padding: 0;
- border-left: 1px solid #e0e0e0;
-}
-
-/* 시스템 관리자 배너 */
-.system-banner {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- padding: 2rem;
- margin-bottom: 2rem;
- position: relative;
- overflow: hidden;
-}
-
-.system-banner::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: url('data:image/svg+xml,');
- opacity: 0.3;
-}
-
-.banner-content {
- display: flex;
- justify-content: space-between;
- align-items: center;
- position: relative;
- z-index: 1;
-}
-
-.banner-left {
- display: flex;
- align-items: center;
- gap: 1.5rem;
-}
-
-.system-icon {
- font-size: 3rem;
- background: rgba(255,255,255,0.2);
- padding: 1rem;
- border-radius: 50%;
- backdrop-filter: blur(10px);
- border: 2px solid rgba(255,255,255,0.3);
-}
-
-.banner-text h1 {
- margin: 0 0 0.5rem 0;
- font-size: 2.2rem;
- font-weight: 700;
- text-shadow: 0 2px 4px rgba(0,0,0,0.2);
-}
-
-.banner-text p {
- margin: 0;
- font-size: 1.1rem;
- opacity: 0.9;
- font-weight: 300;
-}
-
-.banner-right {
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 1rem;
-}
-
-.system-status {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- background: rgba(255,255,255,0.15);
- padding: 0.5rem 1rem;
- border-radius: 20px;
- backdrop-filter: blur(10px);
- border: 1px solid rgba(255,255,255,0.2);
-}
-
-.quick-actions {
- display: flex;
- gap: 0.5rem;
-}
-
-.quick-btn {
- background: rgba(255,255,255,0.2);
- border: 1px solid rgba(255,255,255,0.3);
- border-radius: 50%;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- transition: all 0.3s ease;
- backdrop-filter: blur(10px);
- font-size: 1.2rem;
-}
-
-.quick-btn:hover {
- background: rgba(255,255,255,0.3);
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0,0,0,0.2);
-}
-
-.status-dot {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- animation: pulse 2s infinite;
-}
-
-.status-dot.online {
- background: #2ecc71;
- box-shadow: 0 0 10px rgba(46,204,113,0.5);
-}
-
-@keyframes pulse {
- 0% { opacity: 1; }
- 50% { opacity: 0.5; }
- 100% { opacity: 1; }
-}
-
-/* 메인 컨텐츠 패딩 조정 */
-.main-content {
- padding: 0 2rem 2rem 2rem;
-}
-
-/* 반응형 배너 */
-@media (max-width: 768px) {
- .system-banner {
- padding: 1.5rem;
- }
-
- .banner-content {
- flex-direction: column;
- gap: 1.5rem;
- text-align: center;
- }
-
- .banner-left {
- flex-direction: column;
- gap: 1rem;
- }
-
- .system-icon {
- font-size: 2.5rem;
- padding: 0.8rem;
- }
-
- .banner-text h1 {
- font-size: 1.8rem;
- }
-
- .banner-text p {
- font-size: 1rem;
- }
-
- .banner-right {
- align-items: center;
- }
-
- .main-content {
- padding: 0 1rem 2rem 1rem;
- }
-}
-
-.page-header {
- display: flex;
- align-items: center;
- gap: 1rem;
- margin-bottom: 2rem;
- color: #333;
- border-bottom: 2px solid #f0f0f0;
- padding-bottom: 1rem;
-}
-
-.page-header h1 {
- margin: 0;
- font-size: 1.8rem;
- font-weight: 500;
- color: #2c3e50;
-}
-
-/* 시스템 배지 */
-
-.system-badge {
- background: #e74c3c;
- color: white;
- padding: 0.2rem 0.6rem;
- border-radius: 4px;
- font-size: 0.75rem;
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.5px;
- border: 1px solid #c0392b;
-}
-
-.header-right {
- display: flex;
- align-items: center;
-}
-
-.user-info {
- display: flex;
- align-items: center;
- gap: 1rem;
-}
-
-.logout-btn {
- background: #e74c3c;
- color: white;
- border: none;
- padding: 0.5rem 1rem;
- border-radius: 8px;
- cursor: pointer;
- font-size: 0.9rem;
- transition: all 0.3s ease;
-}
-
-.logout-btn:hover {
- background: #c0392b;
- transform: translateY(-2px);
- box-shadow: 0 4px 15px rgba(231, 76, 60, 0.3);
-}
-
-/* 메인 컨텐츠 */
-.main-content {
- max-width: 1200px;
- margin: 0 auto;
- padding: 0;
- display: flex;
- flex-direction: column;
- gap: 2rem;
- width: 100%;
-}
-
-/* 시스템 상태 개요 */
-.system-overview {
- margin-bottom: 2rem;
-}
-
-.system-overview h2 {
- color: #2c3e50;
- margin-bottom: 1.5rem;
- font-size: 1.4rem;
- font-weight: 500;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- border-bottom: 1px solid #ecf0f1;
- padding-bottom: 0.5rem;
-}
-
-.status-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
- gap: 1rem;
- margin-bottom: 2rem;
-}
-
-.status-card {
- background: #ffffff;
- border: 1px solid #e0e0e0;
- border-radius: 8px;
- padding: 1.5rem;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- transition: box-shadow 0.2s ease;
-}
-
-.status-card:hover {
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-}
-
-.status-icon {
- width: 60px;
- height: 60px;
- border-radius: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 1.5rem;
- background: linear-gradient(45deg, #3498db, #2980b9);
- color: white;
-}
-
-.status-info h3 {
- margin: 0 0 0.5rem 0;
- color: #2c3e50;
- font-size: 1rem;
- font-weight: 500;
-}
-
-.status-value {
- font-size: 1.3rem;
- font-weight: 600;
- margin: 0.5rem 0;
-}
-
-.status-value.online {
- color: #27ae60;
-}
-
-.status-value.warning {
- color: #f39c12;
-}
-
-.status-value.error {
- color: #e74c3c;
-}
-
-.status-info small {
- color: #7f8c8d;
- font-size: 0.85rem;
-}
-
-/* 관리 섹션 */
-.management-section {
- margin-bottom: 2rem;
-}
-
-.management-section h2 {
- color: #2c3e50;
- margin-bottom: 1.5rem;
- font-size: 1.4rem;
- font-weight: 500;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- border-bottom: 1px solid #ecf0f1;
- padding-bottom: 0.5rem;
-}
-
-.management-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
- gap: 1rem;
-}
-
-.management-card {
- background: #ffffff;
- border: 1px solid #e0e0e0;
- border-radius: 8px;
- padding: 1.5rem;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- transition: box-shadow 0.2s ease;
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-
-.management-card:hover {
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-}
-
-.management-card.primary {
- border-left: 4px solid #3498db;
-}
-
-.card-header {
- display: flex;
- align-items: center;
- gap: 0.8rem;
- margin-bottom: 1rem;
- padding-bottom: 0.5rem;
- border-bottom: 1px solid #f0f0f0;
-}
-
-.card-header i {
- font-size: 1.2rem;
- color: #3498db;
-}
-
-.card-header h3 {
- margin: 0;
- color: #2c3e50;
- font-size: 1.1rem;
- font-weight: 500;
-}
-
-.card-content {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-
-.card-content p {
- color: #7f8c8d;
- margin-bottom: 1.5rem;
- line-height: 1.5;
- font-size: 0.9rem;
- flex: 1;
-}
-
-.card-actions {
- display: flex;
- gap: 0.8rem;
- margin-top: auto;
-}
-
-.btn {
- padding: 0.6rem 1rem;
- border: 1px solid #ddd;
- border-radius: 4px;
- cursor: pointer;
- font-size: 0.9rem;
- font-weight: 500;
- transition: all 0.2s ease;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- background: #ffffff;
- text-decoration: none;
-}
-
-.btn-primary {
- background: #3498db;
- color: white;
- border-color: #2980b9;
-}
-
-.btn-primary:hover {
- background: #2980b9;
-}
-
-.btn-secondary {
- background: #95a5a6;
- color: white;
- border-color: #7f8c8d;
-}
-
-.btn-secondary:hover {
- background: #7f8c8d;
-}
-
-/* 최근 활동 */
-.recent-activity {
- margin-bottom: 2rem;
-}
-
-.recent-activity h2 {
- color: white;
- margin-bottom: 1.5rem;
- font-size: 1.8rem;
- font-weight: 600;
- display: flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.activity-container {
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(10px);
- border-radius: 16px;
- padding: 1.5rem;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
- border: 1px solid rgba(255, 255, 255, 0.2);
-}
-
-.activity-list {
- max-height: 400px;
- overflow-y: auto;
-}
-
-.activity-item {
- display: flex;
- align-items: center;
- gap: 1rem;
- padding: 1rem;
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
- transition: background-color 0.3s ease;
-}
-
-.activity-item:hover {
- background: rgba(52, 152, 219, 0.05);
-}
-
-.activity-item:last-child {
- border-bottom: none;
-}
-
-.activity-icon {
- width: 40px;
- height: 40px;
- border-radius: 8px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: linear-gradient(45deg, #3498db, #2980b9);
- color: white;
- font-size: 1rem;
-}
-
-.activity-info h4 {
- margin: 0 0 0.3rem 0;
- color: #2c3e50;
- font-size: 1rem;
- font-weight: 600;
-}
-
-.activity-info p {
- margin: 0;
- color: #7f8c8d;
- font-size: 0.9rem;
-}
-
-.activity-time {
- margin-left: auto;
- color: #95a5a6;
- font-size: 0.8rem;
-}
-
-/* 모달 */
-.modal {
- display: none;
- position: fixed;
- z-index: 2000;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- backdrop-filter: blur(5px);
-}
-
-.modal-content {
- background: white;
- margin: 5% auto;
- padding: 0;
- border-radius: 16px;
- width: 90%;
- max-width: 800px;
- max-height: 80vh;
- overflow: hidden;
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
-}
-
-.modal-header {
- background: linear-gradient(45deg, #3498db, #2980b9);
- color: white;
- padding: 1.5rem;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.modal-header h3 {
- margin: 0;
- font-size: 1.3rem;
- font-weight: 600;
-}
-
-.close-btn {
- background: none;
- border: none;
- color: white;
- font-size: 1.5rem;
- cursor: pointer;
- padding: 0;
- width: 30px;
- height: 30px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 50%;
- transition: background-color 0.3s ease;
-}
-
-.close-btn:hover {
- background: rgba(255, 255, 255, 0.2);
-}
-
-.modal-body {
- padding: 2rem;
- max-height: 60vh;
- overflow-y: auto;
-}
-
-/* 반응형 디자인 */
-@media (max-width: 1200px) {
- .status-grid {
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- }
-
- .management-grid {
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
- }
-}
-
-@media (max-width: 768px) {
- .main-layout .content-wrapper {
- padding: 1rem;
- }
-
- .page-header {
- flex-direction: column;
- align-items: flex-start;
- gap: 0.5rem;
- }
-
- .page-header h1 {
- font-size: 1.5rem;
- }
-
- .status-grid,
- .management-grid {
- grid-template-columns: 1fr;
- gap: 0.8rem;
- }
-
- .status-card,
- .management-card {
- padding: 1rem;
- }
-
- .modal-content {
- width: 95%;
- margin: 5% auto;
- }
-
- .system-overview h2,
- .management-section h2,
- .recent-activity h2 {
- font-size: 1.2rem;
- }
-}
-
-@media (max-width: 480px) {
- .main-layout .content-wrapper {
- padding: 0.5rem;
- }
-
- .status-card,
- .management-card {
- padding: 0.8rem;
- }
-
- .btn {
- padding: 0.5rem 0.8rem;
- font-size: 0.8rem;
- }
-}
-
-/* 계정 관리 스타일 */
-.account-management {
- padding: 1rem;
-}
-
-.account-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 2px solid #ecf0f1;
-}
-
-.account-header h4 {
- margin: 0;
- color: #2c3e50;
- font-size: 1.3rem;
- font-weight: 600;
-}
-
-.account-filters {
- display: flex;
- gap: 1rem;
- margin-bottom: 1.5rem;
- flex-wrap: wrap;
-}
-
-.account-filters input,
-.account-filters select {
- padding: 0.7rem;
- border: 2px solid #ecf0f1;
- border-radius: 8px;
- font-size: 0.9rem;
- transition: border-color 0.3s ease;
-}
-
-.account-filters input:focus,
-.account-filters select:focus {
- outline: none;
- border-color: #3498db;
-}
-
-.users-table {
- overflow-x: auto;
- border-radius: 12px;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
-}
-
-.users-table table {
- width: 100%;
- border-collapse: collapse;
- background: white;
-}
-
-.users-table th,
-.users-table td {
- padding: 1rem;
- text-align: left;
- border-bottom: 1px solid #ecf0f1;
-}
-
-.users-table th {
- background: linear-gradient(45deg, #3498db, #2980b9);
- color: white;
- font-weight: 600;
- font-size: 0.9rem;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.users-table tr:hover {
- background: rgba(52, 152, 219, 0.05);
-}
-
-.role-badge {
- padding: 0.3rem 0.8rem;
- border-radius: 20px;
- font-size: 0.75rem;
- font-weight: bold;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.role-badge.role-system {
- background: linear-gradient(45deg, #e74c3c, #c0392b);
- color: white;
-}
-
-.role-badge.role-admin {
- background: linear-gradient(45deg, #f39c12, #e67e22);
- color: white;
-}
-
-.role-badge.role-leader {
- background: linear-gradient(45deg, #9b59b6, #8e44ad);
- color: white;
-}
-
-.role-badge.role-user {
- background: linear-gradient(45deg, #95a5a6, #7f8c8d);
- color: white;
-}
-
-.status-badge {
- padding: 0.3rem 0.8rem;
- border-radius: 20px;
- font-size: 0.75rem;
- font-weight: bold;
- text-transform: uppercase;
-}
-
-.status-badge.active {
- background: linear-gradient(45deg, #27ae60, #2ecc71);
- color: white;
-}
-
-.status-badge.inactive {
- background: linear-gradient(45deg, #e74c3c, #c0392b);
- color: white;
-}
-
-.action-buttons {
- display: flex;
- gap: 0.5rem;
-}
-
-.btn-small {
- padding: 0.4rem 0.6rem;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-size: 0.8rem;
- transition: all 0.3s ease;
-}
-
-.btn-edit {
- background: linear-gradient(45deg, #3498db, #2980b9);
- color: white;
-}
-
-.btn-edit:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
-}
-
-.btn-delete {
- background: linear-gradient(45deg, #e74c3c, #c0392b);
- color: white;
-}
-
-.btn-delete:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(231, 76, 60, 0.3);
-}
-
-.loading-spinner {
- text-align: center;
- padding: 3rem;
- color: #7f8c8d;
-}
-
-.loading-spinner i {
- font-size: 2rem;
- margin-bottom: 1rem;
-}
-
-.error-message {
- text-align: center;
- padding: 3rem;
- color: #e74c3c;
-}
-
-.error-message i {
- font-size: 3rem;
- margin-bottom: 1rem;
-}
-
-.error-message p {
- margin: 1rem 0;
- font-size: 1.1rem;
-}
-
-/* 알림 스타일 */
-.notification {
- position: fixed;
- top: 20px;
- right: 20px;
- padding: 1rem 1.5rem;
- border-radius: 8px;
- color: white;
- font-weight: 500;
- z-index: 3000;
- animation: slideIn 0.3s ease;
-}
-
-.notification-info {
- background: linear-gradient(45deg, #3498db, #2980b9);
-}
-
-.notification-success {
- background: linear-gradient(45deg, #27ae60, #2ecc71);
-}
-
-.notification-warning {
- background: linear-gradient(45deg, #f39c12, #e67e22);
-}
-
-.notification-error {
- background: linear-gradient(45deg, #e74c3c, #c0392b);
-}
-
-@keyframes slideIn {
- from {
- transform: translateX(100%);
- opacity: 0;
- }
- to {
- transform: translateX(0);
- opacity: 1;
- }
-}
-
-/* 사용자 폼 스타일 */
-.user-edit-form,
-.user-create-form {
- padding: 1.5rem;
-}
-
-.user-edit-form h4,
-.user-create-form h4 {
- margin: 0 0 2rem 0;
- color: #2c3e50;
- font-size: 1.3rem;
- font-weight: 600;
- display: flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.form-group {
- margin-bottom: 1.5rem;
-}
-
-.form-group label {
- display: block;
- margin-bottom: 0.5rem;
- color: #2c3e50;
- font-weight: 500;
- font-size: 0.9rem;
-}
-
-.form-group input,
-.form-group select {
- width: 100%;
- padding: 0.8rem;
- border: 2px solid #ecf0f1;
- border-radius: 8px;
- font-size: 0.9rem;
- transition: border-color 0.3s ease;
- box-sizing: border-box;
-}
-
-.form-group input:focus,
-.form-group select:focus {
- outline: none;
- border-color: #3498db;
- box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
-}
-
-.form-group input:disabled {
- background: #f8f9fa;
- color: #6c757d;
- cursor: not-allowed;
-}
-
-.form-actions {
- display: flex;
- gap: 1rem;
- justify-content: flex-end;
- margin-top: 2rem;
- padding-top: 1.5rem;
- border-top: 2px solid #ecf0f1;
-}
-
-/* 스크롤바 스타일링 */
-::-webkit-scrollbar {
- width: 8px;
-}
-
-::-webkit-scrollbar-track {
- background: rgba(0, 0, 0, 0.1);
- border-radius: 4px;
-}
-
-::-webkit-scrollbar-thumb {
- background: linear-gradient(45deg, #3498db, #2980b9);
- border-radius: 4px;
-}
-
-::-webkit-scrollbar-thumb:hover {
- background: linear-gradient(45deg, #2980b9, #3498db);
-}
diff --git a/system1-factory/web/css/user.css b/system1-factory/web/css/user.css
deleted file mode 100644
index c6a4562..0000000
--- a/system1-factory/web/css/user.css
+++ /dev/null
@@ -1,57 +0,0 @@
-body {
- font-family: 'Malgun Gothic', sans-serif;
- background-color: #f5f5f5;
- margin: 0;
- padding: 0;
-}
-
-header {
- background: linear-gradient(135deg, #4caf50 0%, #45a049 100%);
- color: white;
- padding: 30px;
- text-align: center;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
-}
-
-main {
- padding: 30px;
- max-width: 1200px;
- margin: auto;
-}
-
-.card {
- background: white;
- padding: 24px;
- border-radius: 12px;
- margin-bottom: 24px;
- box-shadow: 0 2px 8px rgba(0,0,0,0.08);
-}
-
-.quick-menu {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 16px;
- margin-top: 16px;
-}
-
-.menu-item {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 16px;
- background: #f8f9fa;
- border-radius: 8px;
- text-decoration: none;
- color: #333;
- transition: all 0.3s ease;
-}
-
-.menu-item:hover {
- background: #e8f5e9;
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
-}
-
-.icon {
- font-size: 24px;
-}
\ No newline at end of file
diff --git a/system1-factory/web/css/work-management.css b/system1-factory/web/css/work-management.css
deleted file mode 100644
index 5261e5f..0000000
--- a/system1-factory/web/css/work-management.css
+++ /dev/null
@@ -1,431 +0,0 @@
-/* 작업 관리 페이지 스타일 */
-
-/* 기본 레이아웃 */
-body {
- margin: 0;
- padding: 0;
- font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- min-height: 100vh;
-}
-
-/* 헤더 스타일은 navbar.html에서 관리됨 */
-
-/* 메인 콘텐츠 */
-.dashboard-main {
- flex: 1;
- padding: 2rem;
- min-height: calc(100vh - 80px);
-}
-
-.page-header {
- margin-bottom: 2rem;
-}
-
-.page-title-section {
- text-align: center;
- margin-bottom: 2rem;
-}
-
-.page-title {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 0.75rem;
- font-size: 2.5rem;
- font-weight: 700;
- color: white;
- margin: 0 0 0.5rem 0;
- text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.title-icon {
- font-size: 2.5rem;
-}
-
-.page-description {
- font-size: 1.125rem;
- color: rgba(255, 255, 255, 0.9);
- margin: 0;
- font-weight: 400;
-}
-
-/* 관리 메뉴 그리드 */
-.management-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
- gap: 1.5rem;
- margin-bottom: 3rem;
-}
-
-.management-card {
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(20px);
- border-radius: 1rem;
- padding: 1.5rem;
- border: 1px solid rgba(255, 255, 255, 0.2);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
- cursor: pointer;
- transition: all 0.3s ease;
- position: relative;
- overflow: hidden;
-}
-
-.management-card::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 4px;
- background: linear-gradient(90deg, #3b82f6, #8b5cf6);
- transform: scaleX(0);
- transition: transform 0.3s ease;
-}
-
-.management-card:hover::before {
- transform: scaleX(1);
-}
-
-.management-card:hover {
- transform: translateY(-4px);
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
-}
-
-.card-header {
- display: flex;
- align-items: center;
- gap: 1rem;
- margin-bottom: 1rem;
-}
-
-.card-icon {
- font-size: 2rem;
- width: 3rem;
- height: 3rem;
- display: flex;
- align-items: center;
- justify-content: center;
- background: linear-gradient(135deg, #f3f4f6, #e5e7eb);
- border-radius: 0.75rem;
-}
-
-.card-title {
- font-size: 1.25rem;
- font-weight: 600;
- color: #1f2937;
- margin: 0;
-}
-
-.card-content {
- margin-bottom: 1.5rem;
-}
-
-.card-description {
- font-size: 0.875rem;
- color: #6b7280;
- line-height: 1.5;
- margin: 0 0 1rem 0;
-}
-
-.card-stats {
- display: flex;
- gap: 1rem;
-}
-
-.stat-item {
- display: flex;
- flex-direction: column;
- gap: 0.25rem;
-}
-
-.stat-label {
- font-size: 0.75rem;
- color: #9ca3af;
- font-weight: 500;
-}
-
-.stat-value {
- font-size: 1.5rem;
- font-weight: 700;
- color: #3b82f6;
-}
-
-.card-footer {
- display: flex;
- justify-content: flex-end;
-}
-
-.card-action {
- font-size: 0.875rem;
- color: #3b82f6;
- font-weight: 500;
- transition: color 0.3s ease;
-}
-
-.management-card:hover .card-action {
- color: #1d4ed8;
-}
-
-/* 최근 활동 섹션 */
-.recent-activity-section {
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(20px);
- border-radius: 1rem;
- padding: 1.5rem;
- border: 1px solid rgba(255, 255, 255, 0.2);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
- padding-bottom: 1rem;
- border-bottom: 1px solid #e5e7eb;
-}
-
-.section-title {
- font-size: 1.25rem;
- font-weight: 600;
- color: #1f2937;
- margin: 0;
-}
-
-.refresh-btn {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.5rem 1rem;
- background: #3b82f6;
- color: white;
- border: none;
- border-radius: 0.5rem;
- font-size: 0.875rem;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-
-.refresh-btn:hover {
- background: #2563eb;
- transform: translateY(-1px);
-}
-
-.activity-list {
- display: flex;
- flex-direction: column;
- gap: 1rem;
-}
-
-.activity-item {
- display: flex;
- align-items: flex-start;
- gap: 1rem;
- padding: 1rem;
- background: #f8fafc;
- border-radius: 0.75rem;
- border: 1px solid #e2e8f0;
- transition: all 0.3s ease;
-}
-
-.activity-item:hover {
- background: #f1f5f9;
- border-color: #cbd5e1;
-}
-
-.activity-icon {
- font-size: 1.25rem;
- width: 2.5rem;
- height: 2.5rem;
- display: flex;
- align-items: center;
- justify-content: center;
- background: white;
- border-radius: 0.5rem;
- border: 1px solid #e2e8f0;
- flex-shrink: 0;
-}
-
-.activity-content {
- flex: 1;
-}
-
-.activity-title {
- font-size: 0.875rem;
- font-weight: 500;
- color: #1f2937;
- margin-bottom: 0.25rem;
- line-height: 1.4;
-}
-
-.activity-meta {
- display: flex;
- gap: 1rem;
- font-size: 0.75rem;
- color: #6b7280;
-}
-
-.activity-user {
- font-weight: 500;
-}
-
-/* 반응형 디자인 */
-@media (max-width: 1024px) {
- .dashboard-main {
- padding: 1.5rem;
- }
-
- .management-grid {
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
- gap: 1rem;
- }
-}
-
-@media (max-width: 768px) {
- .page-title {
- font-size: 2rem;
- }
-
- .management-grid {
- grid-template-columns: 1fr;
- }
-
- .section-header {
- flex-direction: column;
- gap: 1rem;
- align-items: flex-start;
- }
-}
-
-@media (max-width: 480px) {
- .dashboard-main {
- padding: 1rem;
- }
-
- .page-title {
- font-size: 1.75rem;
- }
-
- .management-card {
- padding: 1rem;
- }
-
- .recent-activity-section {
- padding: 1rem;
- }
-}
-
-/* ========== 빠른 액세스 섹션 ========== */
-.quick-access-section {
- margin-bottom: 3rem;
-}
-
-.section-title {
- font-size: 1.5rem;
- font-weight: 700;
- color: #1f2937;
- margin-bottom: 1.5rem;
- display: flex;
- align-items: center;
- gap: 0.5rem;
-}
-
-.quick-actions-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
- gap: 1rem;
- max-width: 800px;
-}
-
-.quick-action-btn {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 0.75rem;
- padding: 1.5rem 1rem;
- background: rgba(255, 255, 255, 0.95);
- border: 2px solid rgba(59, 130, 246, 0.1);
- border-radius: 12px;
- cursor: pointer;
- transition: all 0.3s ease;
- text-decoration: none;
- color: inherit;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
- backdrop-filter: blur(10px);
- min-height: 120px;
- justify-content: center;
-}
-
-.quick-action-btn:hover {
- transform: translateY(-2px);
- box-shadow: 0 8px 25px rgba(59, 130, 246, 0.15);
- border-color: rgba(59, 130, 246, 0.3);
- background: rgba(255, 255, 255, 1);
-}
-
-.quick-icon {
- font-size: 2rem;
- line-height: 1;
-}
-
-.quick-text {
- font-size: 0.875rem;
- font-weight: 600;
- color: #374151;
- text-align: center;
- white-space: nowrap;
-}
-
-/* ========== 관리 섹션 ========== */
-.management-section {
- margin-bottom: 3rem;
-}
-
-/* ========== 시스템 상태 섹션 ========== */
-.system-status-section {
- margin-bottom: 3rem;
-}
-
-.status-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 1rem;
- margin-top: 1.5rem;
-}
-
-.status-card {
- display: flex;
- align-items: center;
- gap: 1rem;
- padding: 1.5rem;
- background: rgba(255, 255, 255, 0.95);
- border-radius: 12px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
- backdrop-filter: blur(10px);
- border: 1px solid rgba(255, 255, 255, 0.2);
-}
-
-.status-icon {
- font-size: 2rem;
- line-height: 1;
-}
-
-.status-info {
- display: flex;
- flex-direction: column;
- gap: 0.25rem;
-}
-
-.status-label {
- font-size: 0.875rem;
- color: #6b7280;
- font-weight: 500;
-}
-
-.status-value {
- font-size: 1.5rem;
- font-weight: 700;
- color: #1f2937;
-}
diff --git a/system1-factory/web/css/work-review.css b/system1-factory/web/css/work-review.css
deleted file mode 100644
index daaec2c..0000000
--- a/system1-factory/web/css/work-review.css
+++ /dev/null
@@ -1,839 +0,0 @@
-/* work-review.css - 작업 검토 페이지 전용 스타일 (개선된 버전) */
-
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- background-color: #f5f7fa;
- color: #333;
- line-height: 1.4;
-}
-
-.main-layout-with-navbar {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
-}
-
-.content-wrapper {
- flex: 1;
- padding: 20px;
-}
-
-.review-container {
- max-width: 1400px;
- margin: 0 auto;
-}
-
-/* 페이지 헤더 */
-.page-header {
- text-align: center;
- margin-bottom: 2rem;
- padding: 2rem;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border-radius: 16px;
- box-shadow: 0 6px 24px rgba(0,0,0,0.12);
-}
-
-.page-header h1 {
- font-size: 2.2rem;
- margin-bottom: 0.5rem;
- font-weight: 700;
-}
-
-.subtitle {
- font-size: 1rem;
- opacity: 0.9;
-}
-
-/* 뒤로가기 버튼 */
-.back-btn {
- background: rgba(255,255,255,0.95);
- color: #667eea;
- border: 3px solid #667eea;
- padding: 12px 24px;
- border-radius: 12px;
- text-decoration: none;
- font-weight: 700;
- font-size: 16px;
- display: inline-flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 20px;
- transition: all 0.3s ease;
-}
-
-.back-btn:hover {
- background: #667eea;
- color: white;
- transform: translateY(-2px);
-}
-
-/* 컨트롤 패널 */
-.control-panel {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- margin-bottom: 2rem;
- box-shadow: 0 4px 16px rgba(0,0,0,0.08);
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-wrap: wrap;
- gap: 1rem;
-}
-
-.month-navigation {
- display: flex;
- align-items: center;
- gap: 1rem;
-}
-
-.nav-btn, .today-btn {
- background: #007bff;
- color: white;
- border: none;
- border-radius: 8px;
- padding: 12px 16px;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.3s;
- font-size: 16px;
-}
-
-.nav-btn:hover, .today-btn:hover {
- background: #0056b3;
- transform: translateY(-2px);
-}
-
-.today-btn {
- background: #28a745;
-}
-
-.today-btn:hover {
- background: #1e7e34;
-}
-
-.current-month {
- font-size: 1.5rem;
- font-weight: 700;
- color: #333;
- min-width: 200px;
- text-align: center;
-}
-
-.control-actions {
- display: flex;
- gap: 12px;
-}
-
-/* 사용법 안내 */
-.usage-guide {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- margin-bottom: 2rem;
- box-shadow: 0 4px 16px rgba(0,0,0,0.08);
-}
-
-.usage-guide h3 {
- margin-bottom: 1.5rem;
- color: #333;
- font-size: 1.3rem;
- text-align: center;
-}
-
-.guide-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
- gap: 1.5rem;
-}
-
-.guide-item {
- display: flex;
- align-items: center;
- gap: 15px;
- padding: 1rem;
- border-radius: 12px;
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
- border: 2px solid #dee2e6;
- transition: all 0.3s ease;
-}
-
-.guide-item:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
-}
-
-.guide-icon {
- font-size: 2rem;
- width: 50px;
- text-align: center;
-}
-
-.guide-text {
- flex: 1;
-}
-
-.guide-text strong {
- color: #007bff;
- font-size: 1.1rem;
-}
-
-/* 캘린더 */
-.calendar-container {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- box-shadow: 0 4px 16px rgba(0,0,0,0.08);
- margin-bottom: 2rem;
-}
-
-.calendar-container h3 {
- color: #333;
- font-size: 1.3rem;
-}
-
-.calendar-grid {
- display: grid;
- grid-template-columns: repeat(7, 1fr);
- gap: 2px;
- border: 3px solid #dee2e6;
- border-radius: 12px;
- overflow: hidden;
-}
-
-.day-header {
- background: #343a40;
- color: white;
- padding: 15px;
- text-align: center;
- font-weight: 700;
- font-size: 1.1rem;
-}
-
-.day-cell {
- background: white;
- border: 1px solid #dee2e6;
- min-height: 80px;
- padding: 8px;
- position: relative;
- transition: all 0.3s ease;
- display: flex;
- flex-direction: column;
- justify-content: flex-start;
- align-items: center;
-}
-
-.day-cell:hover {
- transform: scale(1.05);
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
- z-index: 10;
-}
-
-.day-cell.other-month {
- background: #f8f9fa;
- color: #6c757d;
- cursor: not-allowed;
-}
-
-.day-cell.today {
- border: 3px solid #007bff;
- background: #e7f3ff;
-}
-
-.day-cell.selected {
- background: #d4edda;
- border: 3px solid #28a745;
- transform: scale(1.02);
-}
-
-.day-cell.selected .day-number {
- color: #155724;
- font-weight: 800;
-}
-
-.day-number {
- font-size: 1.2rem;
- font-weight: 700;
- margin-bottom: 5px;
-}
-
-/* 선택된 날짜 정보 패널 */
-.day-info-panel {
- background: white;
- border-radius: 16px;
- padding: 2rem;
- box-shadow: 0 4px 16px rgba(0,0,0,0.08);
- margin-bottom: 2rem;
-}
-
-.day-info-placeholder {
- text-align: center;
- padding: 3rem;
- color: #6c757d;
-}
-
-.day-info-placeholder h3 {
- font-size: 1.5rem;
- margin-bottom: 1rem;
- color: #495057;
-}
-
-.day-info-content {
- animation: fadeIn 0.3s ease;
-}
-
-@keyframes fadeIn {
- from { opacity: 0; transform: translateY(20px); }
- to { opacity: 1; transform: translateY(0); }
-}
-
-.day-info-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 2rem;
- padding-bottom: 1rem;
- border-bottom: 3px solid #dee2e6;
-}
-
-.day-info-header h3 {
- color: #333;
- font-size: 1.5rem;
- margin: 0;
-}
-
-.day-info-actions {
- display: flex;
- gap: 12px;
-}
-
-.review-toggle, .refresh-day-btn {
- padding: 10px 20px;
- border: none;
- border-radius: 8px;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.3s;
- font-size: 14px;
-}
-
-.review-toggle {
- background: #007bff;
- color: white;
-}
-
-.review-toggle.reviewed {
- background: #28a745;
-}
-
-.review-toggle:hover {
- transform: translateY(-2px);
-}
-
-.refresh-day-btn {
- background: #6c757d;
- color: white;
-}
-
-.refresh-day-btn:hover {
- background: #545b62;
- transform: translateY(-2px);
-}
-
-/* 일별 요약 정보 */
-.day-summary {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 1rem;
- margin-bottom: 2rem;
- padding: 1.5rem;
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
- border-radius: 12px;
- border: 2px solid #dee2e6;
-}
-
-.summary-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 8px;
-}
-
-.summary-label {
- font-weight: 600;
- color: #6c757d;
- font-size: 0.9rem;
-}
-
-.summary-value {
- font-size: 1.3rem;
- font-weight: 700;
- color: #333;
-}
-
-.summary-value.normal-work {
- color: #28a745;
-}
-
-.summary-value.overtime {
- color: #6f42c1;
-}
-
-.summary-value.vacation {
- color: #ffc107;
-}
-
-.summary-value.reviewed {
- color: #28a745;
-}
-
-.summary-value.unreviewed {
- color: #fd7e14;
-}
-
-/* 작업자별 상세 섹션 */
-.workers-detail-container h4 {
- margin-bottom: 1rem;
- color: #333;
- font-size: 1.2rem;
-}
-
-.worker-detail-section {
- border: 2px solid #dee2e6;
- border-radius: 12px;
- margin-bottom: 1rem;
- overflow: hidden;
- box-shadow: 0 2px 8px rgba(0,0,0,0.05);
-}
-
-.worker-header-detail {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- padding: 1rem;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.delete-worker-btn {
- background: rgba(220, 53, 69, 0.9);
- color: white;
- border: none;
- border-radius: 6px;
- padding: 8px 16px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 600;
- transition: all 0.3s;
-}
-
-.delete-worker-btn:hover {
- background: #c82333;
- transform: translateY(-1px);
-}
-
-.worker-work-items {
- padding: 1rem;
- background: white;
-}
-
-.work-item-detail {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1rem;
- margin-bottom: 0.5rem;
- background: #f8f9fa;
- border-radius: 8px;
- border-left: 4px solid #007bff;
- transition: all 0.3s ease;
-}
-
-.work-item-detail:hover {
- background: #e9ecef;
- transform: translateX(5px);
-}
-
-.work-item-info {
- flex: 1;
-}
-
-.work-item-actions {
- display: flex;
- gap: 8px;
-}
-
-.edit-work-btn, .delete-work-btn {
- padding: 8px 16px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 600;
- transition: all 0.3s;
- white-space: nowrap;
-}
-
-.edit-work-btn {
- background: #007bff;
- color: white;
-}
-
-.edit-work-btn:hover {
- background: #0056b3;
- transform: translateY(-1px);
-}
-
-.delete-work-btn {
- background: #dc3545;
- color: white;
-}
-
-.delete-work-btn:hover {
- background: #c82333;
- transform: translateY(-1px);
-}
-
-/* 메시지 */
-.message {
- padding: 15px 20px;
- border-radius: 8px;
- margin-bottom: 20px;
- font-weight: 600;
- animation: slideInDown 0.3s ease;
-}
-
-@keyframes slideInDown {
- from {
- opacity: 0;
- transform: translateY(-20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-.message.loading {
- background: #cce5ff;
- color: #0066cc;
- border: 2px solid #99d6ff;
-}
-
-.message.success {
- background: #d4edda;
- color: #155724;
- border: 2px solid #c3e6cb;
-}
-
-.message.error {
- background: #f8d7da;
- color: #721c24;
- border: 2px solid #f5c6cb;
-}
-
-.message.warning {
- background: #fff3cd;
- color: #856404;
- border: 2px solid #ffeaa7;
-}
-
-/* 수정 모달 스타일 */
-.edit-modal {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0,0,0,0.7);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 1001;
- animation: fadeIn 0.3s ease;
-}
-
-.edit-modal-content {
- background: white;
- border-radius: 16px;
- width: 90%;
- max-width: 500px;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 10px 40px rgba(0,0,0,0.3);
- animation: slideInUp 0.3s ease;
-}
-
-@keyframes slideInUp {
- from {
- opacity: 0;
- transform: translateY(50px) scale(0.9);
- }
- to {
- opacity: 1;
- transform: translateY(0) scale(1);
- }
-}
-
-.edit-modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 24px;
- border-bottom: 2px solid #f0f0f0;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border-radius: 16px 16px 0 0;
-}
-
-.edit-modal-header h3 {
- margin: 0;
- font-size: 18px;
- font-weight: 700;
-}
-
-.close-modal-btn {
- background: rgba(255,255,255,0.2);
- color: white;
- border: none;
- border-radius: 50%;
- width: 30px;
- height: 30px;
- cursor: pointer;
- font-size: 16px;
- font-weight: 700;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.3s;
-}
-
-.close-modal-btn:hover {
- background: rgba(255,255,255,0.3);
- transform: rotate(90deg);
-}
-
-.edit-modal-body {
- padding: 24px;
-}
-
-.edit-form-group {
- margin-bottom: 20px;
-}
-
-.edit-form-group label {
- display: block;
- margin-bottom: 8px;
- font-weight: 700;
- color: #555;
- font-size: 14px;
-}
-
-.edit-select, .edit-input {
- width: 100%;
- padding: 12px 16px;
- border: 2px solid #e1e5e9;
- border-radius: 8px;
- font-size: 14px;
- background: white;
- transition: border-color 0.3s;
-}
-
-.edit-select:focus, .edit-input:focus {
- outline: none;
- border-color: #007bff;
- box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
-}
-
-.edit-modal-footer {
- display: flex;
- justify-content: flex-end;
- gap: 12px;
- padding: 24px;
- border-top: 2px solid #f0f0f0;
- background: #f8f9fa;
- border-radius: 0 0 16px 16px;
-}
-
-/* 확인 모달 */
-.confirm-modal {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0,0,0,0.8);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 1002;
- animation: fadeIn 0.3s ease;
-}
-
-.confirm-modal-content {
- background: white;
- border-radius: 16px;
- width: 90%;
- max-width: 400px;
- box-shadow: 0 10px 40px rgba(0,0,0,0.3);
- animation: slideInUp 0.3s ease;
-}
-
-.confirm-modal-header {
- padding: 24px 24px 16px;
- border-bottom: 2px solid #f0f0f0;
-}
-
-.confirm-modal-header h3 {
- margin: 0;
- font-size: 18px;
- font-weight: 700;
- color: #dc3545;
-}
-
-.confirm-modal-body {
- padding: 16px 24px;
-}
-
-.confirm-modal-footer {
- display: flex;
- justify-content: flex-end;
- gap: 12px;
- padding: 16px 24px 24px;
- border-top: 2px solid #f0f0f0;
- background: #f8f9fa;
- border-radius: 0 0 16px 16px;
-}
-
-/* 버튼 스타일 */
-.btn {
- padding: 10px 20px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.3s;
- font-size: 14px;
-}
-
-.btn-secondary {
- background: #6c757d;
- color: white;
-}
-
-.btn-secondary:hover {
- background: #545b62;
- transform: translateY(-1px);
-}
-
-.btn-success {
- background: #28a745;
- color: white;
-}
-
-.btn-success:hover {
- background: #1e7e34;
- transform: translateY(-1px);
-}
-
-.btn-danger {
- background: #dc3545;
- color: white;
-}
-
-.btn-danger:hover {
- background: #c82333;
- transform: translateY(-1px);
-}
-
-/* 반응형 */
-@media (max-width: 768px) {
- .content-wrapper {
- padding: 10px;
- }
-
- .control-panel {
- flex-direction: column;
- text-align: center;
- }
-
- .month-navigation {
- flex-direction: column;
- gap: 0.5rem;
- }
-
- .guide-grid {
- grid-template-columns: 1fr;
- }
-
- .guide-item {
- flex-direction: column;
- text-align: center;
- }
-
- .day-cell {
- min-height: 60px;
- padding: 5px;
- }
-
- .day-number {
- font-size: 1rem;
- }
-
- .day-summary {
- grid-template-columns: 1fr 1fr;
- }
-
- .day-info-header {
- flex-direction: column;
- gap: 15px;
- text-align: center;
- }
-
- .day-info-actions {
- flex-direction: column;
- width: 100%;
- }
-
- .review-toggle, .refresh-day-btn {
- width: 100%;
- }
-
- .work-item-detail {
- flex-direction: column;
- align-items: stretch;
- gap: 12px;
- }
-
- .work-item-actions {
- justify-content: center;
- }
-
- .worker-header-detail {
- flex-direction: column;
- gap: 10px;
- text-align: center;
- }
-
- .edit-modal-content {
- width: 95%;
- margin: 20px;
- }
-
- .edit-modal-footer, .confirm-modal-footer {
- flex-direction: column;
- }
-
- .edit-work-btn, .delete-work-btn {
- flex: 1;
- padding: 12px;
- font-size: 14px;
- }
-}
\ No newline at end of file
diff --git a/system1-factory/web/index.html b/system1-factory/web/index.html
index 7b93a9a..af33734 100644
--- a/system1-factory/web/index.html
+++ b/system1-factory/web/index.html
@@ -16,10 +16,10 @@
var token = window.getSSOToken ? window.getSSOToken() : (localStorage.getItem('sso_token') || localStorage.getItem('token'));
if (token && token !== 'undefined' && token !== 'null') {
// 이미 로그인된 경우 대시보드로 이동
- window.location.replace('/pages/dashboard.html');
+ window.location.replace('/pages/dashboard-new.html');
} else {
// SSO 로그인 페이지로 리다이렉트 (gateway의 /login)
- window.location.replace('/login?redirect=' + encodeURIComponent('/pages/dashboard.html'));
+ window.location.replace('/login?redirect=' + encodeURIComponent('/pages/dashboard-new.html'));
}
diff --git a/system1-factory/web/js/admin-settings.js b/system1-factory/web/js/admin-settings.js
deleted file mode 100644
index 4c87cce..0000000
--- a/system1-factory/web/js/admin-settings.js
+++ /dev/null
@@ -1,1224 +0,0 @@
-// admin-settings.js - 관리자 설정 페이지
-
-// 전역 변수
-let currentUser = null;
-let users = [];
-let filteredUsers = [];
-let currentEditingUser = null;
-
-// DOM 요소
-const elements = {
- // 시간
- timeValue: document.getElementById('timeValue'),
-
- // 사용자 정보
- userName: document.getElementById('userName'),
- userRole: document.getElementById('userRole'),
- userInitial: document.getElementById('userInitial'),
-
- // 검색 및 필터
- userSearch: document.getElementById('userSearch'),
- filterButtons: document.querySelectorAll('.filter-btn'),
-
- // 테이블
- usersTableBody: document.getElementById('usersTableBody'),
- emptyState: document.getElementById('emptyState'),
-
- // 버튼
- addUserBtn: document.getElementById('addUserBtn'),
- saveUserBtn: document.getElementById('saveUserBtn'),
- confirmDeleteBtn: document.getElementById('confirmDeleteBtn'),
-
- // 모달
- userModal: document.getElementById('userModal'),
- deleteModal: document.getElementById('deleteModal'),
- modalTitle: document.getElementById('modalTitle'),
-
- // 폼
- userForm: document.getElementById('userForm'),
- userNameInput: document.getElementById('userName'),
- userIdInput: document.getElementById('userId'),
- userPasswordInput: document.getElementById('userPassword'),
- userRoleSelect: document.getElementById('userRole'),
- userEmailInput: document.getElementById('userEmail'),
- userPhoneInput: document.getElementById('userPhone'),
- passwordGroup: document.getElementById('passwordGroup'),
-
- // 토스트
- toastContainer: document.getElementById('toastContainer')
-};
-
-// ========== 초기화 ========== //
-document.addEventListener('DOMContentLoaded', async () => {
-
- try {
- await initializePage();
- } catch (error) {
- console.error(' 페이지 초기화 오류:', error);
- showToast('페이지를 불러오는 중 오류가 발생했습니다.', 'error');
- }
-});
-
-async function initializePage() {
- // 이벤트 리스너 설정
- setupEventListeners();
-
- // 사용자 목록 로드
- await loadUsers();
-}
-
-// ========== 사용자 정보 설정 ========== //
-// navbar/sidebar는 app-init.js에서 공통 처리
-function setupUserInfo() {
- const authData = getAuthData();
- if (authData && authData.user) {
- currentUser = authData.user;
- }
-}
-
-function getAuthData() {
- const token = localStorage.getItem('sso_token');
- const user = localStorage.getItem('sso_user');
- return {
- token,
- user: user ? JSON.parse(user) : null
- };
-}
-
-// ========== 시간 업데이트 ========== //
-function updateCurrentTime() {
- const now = new Date();
- const hours = String(now.getHours()).padStart(2, '0');
- const minutes = String(now.getMinutes()).padStart(2, '0');
- const seconds = String(now.getSeconds()).padStart(2, '0');
- if (elements.timeValue) {
- elements.timeValue.textContent = `${hours}시 ${minutes}분 ${seconds}초`;
- }
-}
-
-// ========== 이벤트 리스너 ========== //
-function setupEventListeners() {
- // 검색
- if (elements.userSearch) {
- elements.userSearch.addEventListener('input', handleSearch);
- }
-
- // 필터 버튼
- elements.filterButtons.forEach(btn => {
- btn.addEventListener('click', handleFilter);
- });
-
- // 사용자 추가 버튼
- if (elements.addUserBtn) {
- elements.addUserBtn.addEventListener('click', openAddUserModal);
- }
-
- // 사용자 저장 버튼
- if (elements.saveUserBtn) {
- elements.saveUserBtn.addEventListener('click', saveUser);
- }
-
- // 삭제 확인 버튼
- if (elements.confirmDeleteBtn) {
- elements.confirmDeleteBtn.addEventListener('click', confirmDeleteUser);
- }
-
- // 로그아웃 버튼
- const logoutBtn = document.getElementById('logoutBtn');
- if (logoutBtn) {
- logoutBtn.addEventListener('click', handleLogout);
- }
-
- // 프로필 드롭다운
- const userProfile = document.getElementById('userProfile');
- const profileMenu = document.getElementById('profileMenu');
- if (userProfile && profileMenu) {
- userProfile.addEventListener('click', (e) => {
- e.stopPropagation();
- profileMenu.style.display = profileMenu.style.display === 'block' ? 'none' : 'block';
- });
-
- document.addEventListener('click', () => {
- profileMenu.style.display = 'none';
- });
- }
-}
-
-// ========== 사용자 관리 ========== //
-async function loadUsers() {
- try {
-
- // 실제 API에서 사용자 데이터 가져오기
- const response = await window.apiCall('/users');
- users = Array.isArray(response) ? response : (response.data || []);
-
-
- // 필터링된 사용자 목록 초기화
- filteredUsers = [...users];
-
- // 테이블 렌더링
- renderUsersTable();
-
- } catch (error) {
- console.error(' 사용자 목록 로딩 오류:', error);
- showToast('사용자 목록을 불러오는 중 오류가 발생했습니다.', 'error');
- users = [];
- filteredUsers = [];
- renderUsersTable();
- }
-}
-
-function renderUsersTable() {
- if (!elements.usersTableBody) return;
-
- if (filteredUsers.length === 0) {
- elements.usersTableBody.innerHTML = '';
- if (elements.emptyState) {
- elements.emptyState.style.display = 'block';
- }
- return;
- }
-
- if (elements.emptyState) {
- elements.emptyState.style.display = 'none';
- }
-
- elements.usersTableBody.innerHTML = filteredUsers.map(user => `
-
-
-
- ${(user.name || user.username).charAt(0)}
-
- ${user.name || user.username}
- ${user.email || '이메일 없음'}
-
-
- |
- ${user.username} |
-
-
- ${getRoleIcon(user.role)} ${getRoleName(user.role)}
-
- |
-
-
- ${user.is_active ? '활성' : '비활성'}
-
- |
- ${formatDate(user.last_login) || '로그인 기록 없음'} |
-
-
-
- ${user.role !== 'Admin' && user.role !== 'admin' ? `
-
- ` : ''}
-
-
-
-
- |
-
- `).join('');
-}
-
-function getRoleIcon(role) {
- const icons = {
- admin: '👑',
- leader: '👨💼',
- user: '👤'
- };
- return icons[role] || '👤';
-}
-
-function getRoleName(role) {
- const names = {
- admin: '관리자',
- leader: '그룹장',
- user: '작업자'
- };
- return names[role] || '작업자';
-}
-
-function formatDate(dateString) {
- if (!dateString) return null;
-
- const date = new Date(dateString);
- return date.toLocaleDateString('ko-KR', {
- year: 'numeric',
- month: 'short',
- day: 'numeric',
- hour: '2-digit',
- minute: '2-digit'
- });
-}
-
-// ========== 검색 및 필터링 ========== //
-function handleSearch(e) {
- const searchTerm = e.target.value.toLowerCase();
-
- filteredUsers = users.filter(user => {
- return (user.name && user.name.toLowerCase().includes(searchTerm)) ||
- (user.username && user.username.toLowerCase().includes(searchTerm)) ||
- (user.email && user.email.toLowerCase().includes(searchTerm));
- });
-
- renderUsersTable();
-}
-
-function handleFilter(e) {
- const filterType = e.target.dataset.filter;
-
- // 활성 버튼 변경
- elements.filterButtons.forEach(btn => btn.classList.remove('active'));
- e.target.classList.add('active');
-
- // 필터링
- if (filterType === 'all') {
- filteredUsers = [...users];
- } else {
- filteredUsers = users.filter(user => user.role === filterType);
- }
-
- renderUsersTable();
-}
-
-// ========== 모달 관리 ========== //
-function openAddUserModal() {
- currentEditingUser = null;
-
- if (elements.modalTitle) {
- elements.modalTitle.textContent = '새 사용자 추가';
- }
-
- // 폼 초기화
- if (elements.userForm) {
- elements.userForm.reset();
- }
-
- // 비밀번호 필드 표시
- if (elements.passwordGroup) {
- elements.passwordGroup.style.display = 'block';
- }
-
- if (elements.userPasswordInput) {
- elements.userPasswordInput.required = true;
- }
-
- // 작업자 연결 섹션 숨기기 (새 사용자 추가 시)
- const workerLinkGroup = document.getElementById('workerLinkGroup');
- if (workerLinkGroup) {
- workerLinkGroup.style.display = 'none';
- }
-
- if (elements.userModal) {
- elements.userModal.style.display = 'flex';
- }
-}
-
-function editUser(userId) {
- const user = users.find(u => u.user_id === userId);
- if (!user) return;
-
- currentEditingUser = user;
-
- if (elements.modalTitle) {
- elements.modalTitle.textContent = '사용자 정보 수정';
- }
-
- // 역할 이름을 HTML select option value로 변환
- const roleToValueMap = {
- 'Admin': 'admin',
- 'System Admin': 'admin',
- 'User': 'user',
- 'Guest': 'user'
- };
-
- // 폼에 데이터 채우기
- if (elements.userNameInput) elements.userNameInput.value = user.name || '';
- if (elements.userIdInput) elements.userIdInput.value = user.username || '';
- if (elements.userRoleSelect) elements.userRoleSelect.value = roleToValueMap[user.role] || 'user';
- if (elements.userEmailInput) elements.userEmailInput.value = user.email || '';
- if (elements.userPhoneInput) elements.userPhoneInput.value = user.phone || '';
-
- // 비밀번호 필드 숨기기 (수정 시에는 선택사항)
- if (elements.passwordGroup) {
- elements.passwordGroup.style.display = 'none';
- }
-
- if (elements.userPasswordInput) {
- elements.userPasswordInput.required = false;
- }
-
- // 작업자 연결 섹션 표시 (수정 시에만)
- const workerLinkGroup = document.getElementById('workerLinkGroup');
- if (workerLinkGroup) {
- workerLinkGroup.style.display = 'block';
- updateLinkedWorkerDisplay(user);
- }
-
- if (elements.userModal) {
- elements.userModal.style.display = 'flex';
- }
-}
-
-function closeUserModal() {
- if (elements.userModal) {
- elements.userModal.style.display = 'none';
- }
- currentEditingUser = null;
-}
-
-// 영구 삭제 (Hard Delete)
-async function permanentDeleteUser(userId, username) {
- if (!confirm(`⚠️ 경고: "${username}" 사용자를 영구 삭제하시겠습니까?\n\n이 작업은 되돌릴 수 없습니다!\n관련된 모든 데이터(로그인 기록, 권한 설정 등)도 함께 삭제됩니다.`)) {
- return;
- }
-
- // 이중 확인
- if (!confirm(`정말로 "${username}"을(를) 영구 삭제하시겠습니까?\n\n[확인]을 누르면 즉시 삭제됩니다.`)) {
- return;
- }
-
- try {
- const response = await window.apiCall(`/users/${userId}/permanent`, 'DELETE');
-
- if (response.success) {
- showToast(`"${username}" 사용자가 영구 삭제되었습니다.`, 'success');
- await loadUsers();
- } else {
- throw new Error(response.message || '사용자 삭제에 실패했습니다.');
- }
- } catch (error) {
- console.error('사용자 영구 삭제 오류:', error);
- showToast(`사용자 삭제 중 오류가 발생했습니다: ${error.message}`, 'error');
- }
-}
-
-function closeDeleteModal() {
- if (elements.deleteModal) {
- elements.deleteModal.style.display = 'none';
- }
- currentEditingUser = null;
-}
-
-// ========== 비밀번호 초기화 ========== //
-async function resetPassword(userId, username) {
- if (!confirm(`${username} 사용자의 비밀번호를 000000으로 초기화하시겠습니까?`)) {
- return;
- }
-
- try {
- const response = await window.apiCall(`/users/${userId}/reset-password`, 'POST');
-
- if (response.success) {
- showToast(`${username}의 비밀번호가 000000으로 초기화되었습니다.`, 'success');
- } else {
- showToast(response.message || '비밀번호 초기화에 실패했습니다.', 'error');
- }
- } catch (error) {
- console.error('비밀번호 초기화 오류:', error);
- showToast('비밀번호 초기화 중 오류가 발생했습니다.', 'error');
- }
-}
-window.resetPassword = resetPassword;
-
-// ========== 사용자 CRUD ========== //
-async function saveUser() {
- try {
- const formData = {
- name: elements.userNameInput?.value,
- username: elements.userIdInput?.value,
- role: elements.userRoleSelect?.value, // HTML select value는 이미 'admin' 또는 'user'
- email: elements.userEmailInput?.value
- };
-
- console.log('저장할 데이터:', formData);
-
- // 유효성 검사
- if (!formData.name || !formData.username || !formData.role) {
- showToast('필수 항목을 모두 입력해주세요.', 'error');
- return;
- }
-
- // 비밀번호 처리
- if (!currentEditingUser && elements.userPasswordInput?.value) {
- formData.password = elements.userPasswordInput.value;
- } else if (currentEditingUser && elements.userPasswordInput?.value) {
- formData.password = elements.userPasswordInput.value;
- }
-
- let response;
- if (currentEditingUser) {
- // 수정
- response = await window.apiCall(`/users/${currentEditingUser.user_id}`, 'PUT', formData);
- } else {
- // 생성
- response = await window.apiCall('/users', 'POST', formData);
- }
-
- if (response.success || response.user_id) {
- const action = currentEditingUser ? '수정' : '생성';
- showToast(`사용자가 성공적으로 ${action}되었습니다.`, 'success');
-
- closeUserModal();
- await loadUsers();
- } else {
- throw new Error(response.message || '사용자 저장에 실패했습니다.');
- }
-
- } catch (error) {
- console.error('사용자 저장 오류:', error);
- showToast(`사용자 저장 중 오류가 발생했습니다: ${error.message}`, 'error');
- }
-}
-
-async function confirmDeleteUser() {
- if (!currentEditingUser) return;
-
- try {
- const response = await window.apiCall(`/users/${currentEditingUser.user_id}`, 'DELETE');
-
- if (response.success) {
- showToast('사용자가 성공적으로 삭제되었습니다.', 'success');
- closeDeleteModal();
- await loadUsers();
- } else {
- throw new Error(response.message || '사용자 삭제에 실패했습니다.');
- }
-
- } catch (error) {
- console.error('사용자 삭제 오류:', error);
- showToast(`사용자 삭제 중 오류가 발생했습니다: ${error.message}`, 'error');
- }
-}
-
-async function toggleUserStatus(userId) {
- try {
- const user = users.find(u => u.user_id === userId);
- if (!user) return;
-
- const newStatus = !user.is_active;
- const response = await window.apiCall(`/users/${userId}/status`, 'PUT', { is_active: newStatus });
-
- if (response.success) {
- const action = newStatus ? '활성화' : '비활성화';
- showToast(`사용자가 성공적으로 ${action}되었습니다.`, 'success');
- await loadUsers();
- } else {
- throw new Error(response.message || '사용자 상태 변경에 실패했습니다.');
- }
-
- } catch (error) {
- console.error('사용자 상태 변경 오류:', error);
- showToast(`사용자 상태 변경 중 오류가 발생했습니다: ${error.message}`, 'error');
- }
-}
-
-// ========== 로그아웃 ========== //
-function handleLogout() {
- if (confirm('로그아웃하시겠습니까?')) {
- localStorage.clear();
- if (window.clearSSOAuth) window.clearSSOAuth();
- window.location.href = window.getLoginUrl ? window.getLoginUrl() : '/login';
- }
-}
-
-// showToast → api-base.js 전역 사용
-
-// ========== 전역 함수 (HTML에서 호출) ========== //
-window.editUser = editUser;
-window.toggleUserStatus = toggleUserStatus;
-window.closeUserModal = closeUserModal;
-window.closeDeleteModal = closeDeleteModal;
-window.permanentDeleteUser = permanentDeleteUser;
-
-// ========== 페이지 권한 관리 ========== //
-let allPages = [];
-let userPageAccess = [];
-
-// 모든 페이지 목록 로드
-async function loadAllPages() {
- try {
- const response = await apiCall('/pages');
- allPages = response.data || response || [];
- } catch (error) {
- console.error(' 페이지 목록 로드 오류:', error);
- allPages = [];
- }
-}
-
-// 사용자의 페이지 권한 로드
-async function loadUserPageAccess(userId) {
- try {
- const response = await apiCall(`/users/${userId}/page-access`);
- userPageAccess = response.data?.pageAccess || [];
- } catch (error) {
- console.error(' 사용자 페이지 권한 로드 오류:', error);
- userPageAccess = [];
- }
-}
-
-
-// 페이지 권한 저장
-async function savePageAccess(userId, containerId = null) {
- try {
- // 특정 컨테이너가 지정되면 그 안에서만 체크박스 선택
- const container = containerId ? document.getElementById(containerId) : document;
- const checkboxes = container.querySelectorAll('.page-access-checkbox:not([disabled])');
-
- // 중복 page_id 제거 (Map 사용)
- const pageAccessMap = new Map();
- checkboxes.forEach(checkbox => {
- const pageId = parseInt(checkbox.dataset.pageId);
- pageAccessMap.set(pageId, {
- page_id: pageId,
- can_access: checkbox.checked ? 1 : 0
- });
- });
-
- const pageAccessData = Array.from(pageAccessMap.values());
-
-
- await apiCall(`/users/${userId}/page-access`, 'PUT', {
- pageAccess: pageAccessData
- });
-
- } catch (error) {
- console.error(' 페이지 권한 저장 오류:', error);
- throw error;
- }
-}
-
-
-
-
-// ========== 페이지 권한 관리 모달 ========== //
-let currentPageAccessUser = null;
-
-// 페이지 권한 관리 모달 열기
-async function managePageAccess(userId) {
- try {
- // 페이지 목록이 없으면 로드
- if (allPages.length === 0) {
- await loadAllPages();
- }
-
- // 사용자 정보 가져오기
- const user = users.find(u => u.user_id === userId);
- if (!user) {
- showToast('사용자를 찾을 수 없습니다.', 'error');
- return;
- }
-
- currentPageAccessUser = user;
-
- // 사용자의 페이지 권한 로드
- await loadUserPageAccess(userId);
-
- // 모달 정보 업데이트
- const userName = user.name || user.username;
- document.getElementById('pageAccessModalTitle').textContent = userName + ' - 페이지 권한 관리';
- document.getElementById('pageAccessUserName').textContent = userName;
- document.getElementById('pageAccessUserRole').textContent = getRoleName(user.role);
- document.getElementById('pageAccessUserAvatar').textContent = userName.charAt(0);
-
- // 페이지 권한 체크박스 렌더링
- renderPageAccessModalList();
-
- // 모달 표시
- document.getElementById('pageAccessModal').style.display = 'flex';
- } catch (error) {
- console.error(' 페이지 권한 관리 모달 오류:', error);
- showToast('페이지 권한 관리를 열 수 없습니다.', 'error');
- }
-}
-
-// 페이지 권한 모달 닫기
-function closePageAccessModal() {
- document.getElementById('pageAccessModal').style.display = 'none';
- currentPageAccessUser = null;
-}
-
-// 페이지 권한 체크박스 렌더링 (모달용) - 폴더 구조 형태
-function renderPageAccessModalList() {
- const pageAccessList = document.getElementById('pageAccessModalList');
- if (!pageAccessList) return;
-
- // 폴더 구조 정의 (page_key 패턴 기준)
- const folderStructure = {
- 'dashboard': { name: '대시보드', icon: '📊', pages: [] },
- 'work': { name: '작업 관리', icon: '📋', pages: [] },
- 'safety': { name: '안전 관리', icon: '🛡️', pages: [] },
- 'attendance': { name: '근태 관리', icon: '📅', pages: [] },
- 'admin': { name: '시스템 관리', icon: '⚙️', pages: [] },
- 'profile': { name: '내 정보', icon: '👤', pages: [] }
- };
-
- // 페이지를 폴더별로 분류
- allPages.forEach(page => {
- const pageKey = page.page_key || '';
-
- if (pageKey === 'dashboard') {
- folderStructure['dashboard'].pages.push(page);
- } else if (pageKey.startsWith('work.')) {
- folderStructure['work'].pages.push(page);
- } else if (pageKey.startsWith('safety.')) {
- folderStructure['safety'].pages.push(page);
- } else if (pageKey.startsWith('attendance.')) {
- folderStructure['attendance'].pages.push(page);
- } else if (pageKey.startsWith('admin.')) {
- folderStructure['admin'].pages.push(page);
- } else if (pageKey.startsWith('profile.')) {
- folderStructure['profile'].pages.push(page);
- }
- });
-
- // HTML 생성 - 폴더 트리 형태
- let html = '';
-
- Object.keys(folderStructure).forEach(folderKey => {
- const folder = folderStructure[folderKey];
- if (folder.pages.length === 0) return;
-
- const folderId = 'folder-' + folderKey;
-
- html += '
';
- html += '';
-
- html += '
';
-
- folder.pages.forEach(page => {
- // 프로필과 대시보드는 모든 사용자가 접근 가능
- const isAlwaysAccessible = page.page_key === 'dashboard' || page.page_key.startsWith('profile.');
- const isChecked = userPageAccess.find(p => p.page_id === page.id && p.can_access === 1) || isAlwaysAccessible;
-
- // 파일명만 추출 (page_key에서)
- const fileName = page.page_key.split('.').pop() || page.page_key;
-
- html += '
';
- html += '';
- html += '
';
- });
-
- html += '
'; // folder-content
- html += '
'; // folder-group
- });
-
- html += '
'; // folder-tree
-
- pageAccessList.innerHTML = html;
-}
-
-// 폴더 접기/펼치기
-function toggleFolder(folderId) {
- const content = document.getElementById(folderId);
- const toggle = document.getElementById('toggle-' + folderId);
-
- if (content && toggle) {
- const isExpanded = content.style.display !== 'none';
- content.style.display = isExpanded ? 'none' : 'block';
- toggle.textContent = isExpanded ? '▶' : '▼';
- }
-}
-window.toggleFolder = toggleFolder;
-
-// 페이지 권한 저장 (모달용)
-async function savePageAccessFromModal() {
- if (!currentPageAccessUser) {
- showToast('사용자 정보가 없습니다.', 'error');
- return;
- }
-
- try {
- // 모달 컨테이너 지정
- await savePageAccess(currentPageAccessUser.user_id, 'pageAccessModalList');
- showToast('페이지 권한이 저장되었습니다.', 'success');
-
- // 캐시 삭제 (사용자가 다시 로그인하거나 페이지 새로고침 필요)
- localStorage.removeItem('userPageAccess');
-
- closePageAccessModal();
- } catch (error) {
- console.error(' 페이지 권한 저장 오류:', error);
- showToast('페이지 권한 저장에 실패했습니다.', 'error');
- }
-}
-
-// 전역 함수로 등록
-window.managePageAccess = managePageAccess;
-window.closePageAccessModal = closePageAccessModal;
-
-// 저장 버튼 이벤트 리스너
-document.addEventListener('DOMContentLoaded', () => {
- const saveBtn = document.getElementById('savePageAccessBtn');
- if (saveBtn) {
- saveBtn.addEventListener('click', savePageAccessFromModal);
- }
-});
-
-// ========== 작업자 연결 기능 ========== //
-let departments = [];
-let selectedUserId = null;
-
-// 연결된 작업자 정보 표시 업데이트
-function updateLinkedWorkerDisplay(user) {
- const linkedWorkerInfo = document.getElementById('linkedWorkerInfo');
- if (!linkedWorkerInfo) return;
-
- if (user.user_id && user.worker_name) {
- linkedWorkerInfo.innerHTML = `
-
- 👤 ${user.worker_name}
- ${user.department_name ? `(${user.department_name})` : ''}
-
- `;
- } else {
- linkedWorkerInfo.innerHTML = '연결된 작업자 없음';
- }
-}
-
-// 작업자 선택 모달 열기
-async function openWorkerSelectModal() {
- if (!currentEditingUser) {
- showToast('사용자 정보가 없습니다.', 'error');
- return;
- }
-
- selectedUserId = currentEditingUser.user_id || null;
-
- // 부서 목록 로드
- await loadDepartmentsForSelect();
-
- // 모달 표시
- document.getElementById('workerSelectModal').style.display = 'flex';
-}
-window.openWorkerSelectModal = openWorkerSelectModal;
-
-// 작업자 선택 모달 닫기
-function closeWorkerSelectModal() {
- document.getElementById('workerSelectModal').style.display = 'none';
- selectedUserId = null;
-}
-window.closeWorkerSelectModal = closeWorkerSelectModal;
-
-// 부서 목록 로드
-async function loadDepartmentsForSelect() {
- try {
- const response = await window.apiCall('/departments');
- departments = response.data || response || [];
-
- renderDepartmentList();
- } catch (error) {
- console.error('부서 목록 로드 실패:', error);
- showToast('부서 목록을 불러오는데 실패했습니다.', 'error');
- }
-}
-
-// 부서 목록 렌더링
-function renderDepartmentList() {
- const container = document.getElementById('departmentList');
- if (!container) return;
-
- if (departments.length === 0) {
- container.innerHTML = '등록된 부서가 없습니다
';
- return;
- }
-
- container.innerHTML = departments.map(dept => `
-
- 📁
- ${dept.department_name}
- ${dept.worker_count || 0}명
-
- `).join('');
-}
-
-// 부서 선택
-async function selectDepartment(departmentId) {
- // 활성 상태 업데이트
- document.querySelectorAll('.department-item').forEach(item => {
- item.classList.remove('active');
- });
- document.querySelector(`.department-item[data-dept-id="${departmentId}"]`)?.classList.add('active');
-
- // 해당 부서의 작업자 목록 로드
- await loadWorkersForSelect(departmentId);
-}
-window.selectDepartment = selectDepartment;
-
-// 부서별 작업자 목록 로드
-async function loadWorkersForSelect(departmentId) {
- try {
- const response = await window.apiCall(`/departments/${departmentId}/workers`);
- const workers = response.data || response || [];
-
- renderWorkerListForSelect(workers);
- } catch (error) {
- console.error('작업자 목록 로드 실패:', error);
- showToast('작업자 목록을 불러오는데 실패했습니다.', 'error');
- }
-}
-
-// 작업자 목록 렌더링 (선택용)
-function renderWorkerListForSelect(workers) {
- const container = document.getElementById('workerListForSelect');
- if (!container) return;
-
- if (workers.length === 0) {
- container.innerHTML = '이 부서에 작업자가 없습니다
';
- return;
- }
-
- // 이미 다른 계정에 연결된 작업자 확인을 위해 users 배열 사용
- const linkedUserIds = users
- .filter(u => u.user_id && u.user_id !== currentEditingUser?.user_id)
- .map(u => u.user_id);
-
- container.innerHTML = workers.map(worker => {
- const isSelected = selectedUserId === worker.user_id;
- const isLinkedToOther = linkedUserIds.includes(worker.user_id);
- const linkedUser = isLinkedToOther ? users.find(u => u.user_id === worker.user_id) : null;
-
- return `
-
-
${worker.worker_name.charAt(0)}
-
-
${worker.worker_name}
-
${getJobTypeName(worker.job_type)}
-
- ${isLinkedToOther ? `
${linkedUser?.username} 연결됨` : ''}
-
${isSelected ? '✓' : ''}
-
- `;
- }).join('');
-}
-
-// 직책 한글 변환
-function getJobTypeName(jobType) {
- const names = {
- leader: '그룹장',
- worker: '작업자',
- admin: '관리자'
- };
- return names[jobType] || jobType || '-';
-}
-
-// 작업자 선택
-async function selectWorker(userId, workerName) {
- selectedUserId = userId;
-
- // UI 업데이트
- document.querySelectorAll('.worker-select-item').forEach(item => {
- item.classList.remove('selected');
- item.querySelector('.select-indicator').textContent = '';
- });
-
- const selectedItem = document.querySelector(`.worker-select-item[onclick*="${userId}"]`);
- if (selectedItem) {
- selectedItem.classList.add('selected');
- selectedItem.querySelector('.select-indicator').textContent = '✓';
- }
-
- // 서버에 저장
- try {
- const response = await window.apiCall(`/users/${currentEditingUser.user_id}`, 'PUT', {
- user_id: userId
- });
-
- if (response.success) {
- // currentEditingUser 업데이트
- currentEditingUser.user_id = userId;
- currentEditingUser.worker_name = workerName;
-
- // 부서 정보도 업데이트
- const dept = departments.find(d =>
- document.querySelector(`.department-item.active`)?.dataset.deptId == d.department_id
- );
- if (dept) {
- currentEditingUser.department_name = dept.department_name;
- }
-
- // users 배열 업데이트
- const userIndex = users.findIndex(u => u.user_id === currentEditingUser.user_id);
- if (userIndex !== -1) {
- users[userIndex] = { ...users[userIndex], ...currentEditingUser };
- }
-
- // 표시 업데이트
- updateLinkedWorkerDisplay(currentEditingUser);
-
- showToast(`${workerName} 작업자가 연결되었습니다.`, 'success');
- closeWorkerSelectModal();
- } else {
- throw new Error(response.message || '작업자 연결에 실패했습니다.');
- }
- } catch (error) {
- console.error('작업자 연결 오류:', error);
- showToast(`작업자 연결 중 오류가 발생했습니다: ${error.message}`, 'error');
- }
-}
-window.selectWorker = selectWorker;
-
-// 작업자 연결 해제
-async function unlinkWorker() {
- if (!currentEditingUser) {
- showToast('사용자 정보가 없습니다.', 'error');
- return;
- }
-
- if (!currentEditingUser.user_id) {
- showToast('연결된 작업자가 없습니다.', 'warning');
- closeWorkerSelectModal();
- return;
- }
-
- if (!confirm('작업자 연결을 해제하시겠습니까?')) {
- return;
- }
-
- try {
- const response = await window.apiCall(`/users/${currentEditingUser.user_id}`, 'PUT', {
- user_id: null
- });
-
- if (response.success) {
- // currentEditingUser 업데이트
- currentEditingUser.user_id = null;
- currentEditingUser.worker_name = null;
- currentEditingUser.department_name = null;
-
- // users 배열 업데이트
- const userIndex = users.findIndex(u => u.user_id === currentEditingUser.user_id);
- if (userIndex !== -1) {
- users[userIndex] = { ...users[userIndex], user_id: null, worker_name: null, department_name: null };
- }
-
- // 표시 업데이트
- updateLinkedWorkerDisplay(currentEditingUser);
-
- showToast('작업자 연결이 해제되었습니다.', 'success');
- closeWorkerSelectModal();
- } else {
- throw new Error(response.message || '연결 해제에 실패했습니다.');
- }
- } catch (error) {
- console.error('작업자 연결 해제 오류:', error);
- showToast(`연결 해제 중 오류가 발생했습니다: ${error.message}`, 'error');
- }
-}
-window.unlinkWorker = unlinkWorker;
-
-// ========== 알림 수신자 관리 ========== //
-let notificationRecipients = {};
-let allUsersForRecipient = [];
-let currentNotificationType = null;
-
-const NOTIFICATION_TYPE_CONFIG = {
- repair: { name: '설비 수리', icon: '🔧', description: '설비 수리 신청 시 알림을 받을 사용자' },
- safety: { name: '안전 신고', icon: '⚠️', description: '안전 관련 신고 시 알림을 받을 사용자' },
- nonconformity: { name: '부적합 신고', icon: '🚫', description: '부적합 사항 신고 시 알림을 받을 사용자' },
- equipment: { name: '설비 관련', icon: '🔩', description: '설비 관련 알림을 받을 사용자' },
- maintenance: { name: '정기점검', icon: '🛠️', description: '정기점검 알림을 받을 사용자' },
- system: { name: '시스템', icon: '📢', description: '시스템 알림을 받을 사용자' }
-};
-
-// 알림 수신자 목록 로드
-async function loadNotificationRecipients() {
- try {
- const response = await window.apiCall('/notification-recipients');
- if (response.success) {
- notificationRecipients = response.data || {};
- renderNotificationTypeCards();
- }
- } catch (error) {
- console.error('알림 수신자 로드 오류:', error);
- }
-}
-
-// 알림 유형 카드 렌더링
-function renderNotificationTypeCards() {
- const container = document.getElementById('notificationTypeCards');
- if (!container) return;
-
- let html = '';
-
- Object.keys(NOTIFICATION_TYPE_CONFIG).forEach(type => {
- const config = NOTIFICATION_TYPE_CONFIG[type];
- const recipients = notificationRecipients[type]?.recipients || [];
-
- html += `
-
-
-
- ${recipients.length > 0
- ? recipients.map(r => `
-
- 👤
- ${r.user_name || r.username}
-
- `).join('')
- : '지정된 수신자 없음'
- }
-
-
- `;
- });
-
- container.innerHTML = html;
-}
-
-// 수신자 편집 모달 열기
-async function openRecipientModal(notificationType) {
- currentNotificationType = notificationType;
- const config = NOTIFICATION_TYPE_CONFIG[notificationType];
-
- // 모달 정보 업데이트
- document.getElementById('recipientModalTitle').textContent = config.name + ' 알림 수신자';
- document.getElementById('recipientModalDesc').textContent = config.description;
-
- // 사용자 목록 로드 (users가 이미 로드되어 있으면 사용)
- if (users.length === 0) {
- await loadUsers();
- }
- allUsersForRecipient = users.filter(u => u.is_active);
-
- // 현재 수신자 목록
- const currentRecipients = notificationRecipients[notificationType]?.recipients || [];
- const currentRecipientIds = currentRecipients.map(r => r.user_id);
-
- // 사용자 목록 렌더링
- renderRecipientUserList(currentRecipientIds);
-
- // 검색 이벤트
- const searchInput = document.getElementById('recipientSearchInput');
- searchInput.value = '';
- searchInput.oninput = (e) => {
- renderRecipientUserList(currentRecipientIds, e.target.value);
- };
-
- // 모달 표시
- document.getElementById('notificationRecipientModal').style.display = 'flex';
-}
-window.openRecipientModal = openRecipientModal;
-
-// 수신자 사용자 목록 렌더링
-function renderRecipientUserList(selectedIds, searchTerm = '') {
- const container = document.getElementById('recipientUserList');
- if (!container) return;
-
- let filteredUsers = allUsersForRecipient;
-
- if (searchTerm) {
- const term = searchTerm.toLowerCase();
- filteredUsers = filteredUsers.filter(u =>
- (u.name && u.name.toLowerCase().includes(term)) ||
- (u.username && u.username.toLowerCase().includes(term))
- );
- }
-
- if (filteredUsers.length === 0) {
- container.innerHTML = '사용자가 없습니다
';
- return;
- }
-
- container.innerHTML = filteredUsers.map(user => {
- const isSelected = selectedIds.includes(user.user_id);
- return `
-
-
-
${(user.name || user.username).charAt(0)}
-
-
${user.name || user.username}
-
${getRoleName(user.role)}
-
-
- `;
- }).join('');
-}
-
-// 수신자 토글
-function toggleRecipientUser(userId, element) {
- const checkbox = element.querySelector('input[type="checkbox"]');
- checkbox.checked = !checkbox.checked;
- element.classList.toggle('selected', checkbox.checked);
-}
-window.toggleRecipientUser = toggleRecipientUser;
-
-// 수신자 모달 닫기
-function closeRecipientModal() {
- document.getElementById('notificationRecipientModal').style.display = 'none';
- currentNotificationType = null;
-}
-window.closeRecipientModal = closeRecipientModal;
-
-// 알림 수신자 저장
-async function saveNotificationRecipients() {
- if (!currentNotificationType) {
- showToast('알림 유형이 선택되지 않았습니다.', 'error');
- return;
- }
-
- try {
- const checkboxes = document.querySelectorAll('#recipientUserList input[type="checkbox"]:checked');
- const userIds = Array.from(checkboxes).map(cb => parseInt(cb.dataset.userId));
-
- const response = await window.apiCall(`/notification-recipients/${currentNotificationType}`, 'PUT', {
- user_ids: userIds
- });
-
- if (response.success) {
- showToast('알림 수신자가 저장되었습니다.', 'success');
- closeRecipientModal();
- await loadNotificationRecipients();
- } else {
- throw new Error(response.message || '저장에 실패했습니다.');
- }
- } catch (error) {
- console.error('알림 수신자 저장 오류:', error);
- showToast(`저장 중 오류가 발생했습니다: ${error.message}`, 'error');
- }
-}
-window.saveNotificationRecipients = saveNotificationRecipients;
-
-// 초기화 시 알림 수신자 로드
-const originalInitializePage = initializePage;
-initializePage = async function() {
- await originalInitializePage();
- await loadNotificationRecipients();
-};
diff --git a/system1-factory/web/js/admin.js b/system1-factory/web/js/admin.js
deleted file mode 100644
index 1a6a5c5..0000000
--- a/system1-factory/web/js/admin.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// ✅ /js/admin.js (수정됨 - 중복 로딩 제거)
-async function initDashboard() {
- // 로그인 토큰 확인
- const token = localStorage.getItem('sso_token') || (window.getSSOToken ? window.getSSOToken() : null);
- if (!token) {
- location.href = window.getLoginUrl ? window.getLoginUrl() : '/login';
- return;
- }
-
- // ✅ navbar, sidebar는 각각의 모듈에서 처리하도록 변경
- // load-navbar.js, load-sidebar.js가 자동으로 처리함
-
- // ✅ 콘텐츠만 직접 로딩 (admin-sections.html이 자동 로딩됨)
- console.log('관리자 대시보드 초기화 완료');
-}
-
-// ✅ 보조 함수 - 필요시 수동 컴포넌트 로딩용
-async function loadComponent(id, url) {
- try {
- const res = await fetch(url);
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
- const html = await res.text();
- const element = document.getElementById(id);
- if (element) {
- element.innerHTML = html;
- } else {
- console.warn(`요소를 찾을 수 없습니다: ${id}`);
- }
- } catch (err) {
- console.error(`컴포넌트 로딩 실패 (${url}):`, err);
- }
-}
-
-document.addEventListener('DOMContentLoaded', initDashboard);
\ No newline at end of file
diff --git a/system1-factory/web/js/api-helper.js b/system1-factory/web/js/api-helper.js
deleted file mode 100644
index b5acf6f..0000000
--- a/system1-factory/web/js/api-helper.js
+++ /dev/null
@@ -1,139 +0,0 @@
-// /public/js/api-helper.js
-// ES6 모듈 의존성 제거 - 브라우저 호환성 개선
-
-// API 설정 (window 객체에서 가져오기)
-const API_BASE_URL = window.API_BASE_URL || 'http://localhost:30005/api';
-
-// 인증 관련 함수들 (직접 구현)
-function getToken() {
- // SSO 토큰 우선, 기존 token 폴백
- if (window.getSSOToken) return window.getSSOToken();
- const token = localStorage.getItem('sso_token');
- return token && token !== 'undefined' && token !== 'null' ? token : null;
-}
-
-function clearAuthData() {
- if (window.clearSSOAuth) { window.clearSSOAuth(); return; }
- localStorage.removeItem('sso_token');
- localStorage.removeItem('sso_user');
-}
-
-/**
- * 로그인 API를 호출합니다. (인증이 필요 없는 public 요청)
- * @param {string} username - 사용자 아이디
- * @param {string} password - 사용자 비밀번호
- * @returns {Promise