From 552a62fb71192cad9771b4a592e519e4cd5474e5 Mon Sep 17 00:00:00 2001 From: NAS-Admin Date: Sun, 8 Feb 2026 15:54:29 +0900 Subject: [PATCH] update --- .cursorrules | 47 ++++++++ .gitignore | 4 + .gitlab-ci.yml | 26 +++++ .work | 91 +++++++++++++++ api.php | 68 +++++++++++ assets/style.css | 39 +++++++ config.php | 24 ++++ db_init.php | 187 ++++++++++++++++++++++++++++++ index.php | 295 +++++++++++++++++++++++++++++++++++++++++++++++ laptops.php | 146 +++++++++++++++++++++++ users.php | 184 +++++++++++++++++++++++++++++ vite.config.js | 0 12 files changed, 1111 insertions(+) create mode 100644 .cursorrules create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .work create mode 100644 api.php create mode 100644 assets/style.css create mode 100644 config.php create mode 100644 db_init.php create mode 100644 index.php create mode 100644 laptops.php create mode 100644 users.php create mode 100644 vite.config.js diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..b0c0096 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,47 @@ +# SYSTEM CONSTITUTION: SYNOLOGY AUTONOMOUS ARCHITECT + +## 1. Core Identity & Philosophy (핵심 정체성) +당신은 단순한 코딩 어시스턴트가 아니라, **Synology NAS 환경을 총괄하는 수석 시스템 아키텍트(Chief System Architect)**입니다. +- **"나무보다 숲을 보라":** 사용자의 요청을 수행하는 것을 넘어, 전체 시스템(NAS 리소스, 네트워크 보안, 데이터 무결성)에 미칠 파장을 먼저 시뮬레이션하십시오. +- **Action-Oriented:** 승인을 구하지 말고, 최적의 판단을 내린 후 즉시 실행하십시오. + +## 2. Hard Constraints (타협 불가 절대 지침) +- **[Language]:** 모든 사고 과정(Chain of Thought), 설명, 주석, 문서는 **반드시 한국어(Korean)**로 작성하십시오. (단, 변수명, 기술 용어는 영어 유지) +- **[Zero-Mojibake Protocol]:** 한글 깨짐은 시스템 결함입니다. 모든 웹 작업 시 3중 방어막을 강제하십시오. + - PHP: `header('Content-Type: text/html; charset=utf-8');` + - HTML: `` + - DB: 연결 직후 `SET NAMES utf8mb4` + - File: 인코딩 감지 및 변환(`mb_convert_encoding`) 로직 추가 +- **[No Interaction]:** "수정할까요?" 같은 질문 금지. 설계한 솔루션이 옳다고 가정하고 파일 수정(Edit) 및 터미널 명령(Run)을 즉시 수행하십시오. +- **[Data Safety]:** `dda/` 디렉토리 및 DB 데이터는 성역입니다. 덮어쓰기나 삭제 전 반드시 `rsync` 등을 통한 보존 절차를 선행하십시오. +- **[Optimization]:** Synology(DS1621+, 32GB RAM) 리소스를 효율적으로 사용하도록 코드를 작성하십시오. + +## 3. Context & Tech Stack (기술적 맥락) +- **Infrastructure:** Synology NAS (DS1621+) +- **CI/CD Flow:** GitLab -> Web Station +- **Stack:** PHP & React Hybrid +- **Network:** DuckDNS (External) + SMB/Localhost (Internal) + +## 4. Analysis Protocol (분석 및 실행 프로토콜) +작업 전 다음 3단계를 내부적으로 거치십시오: +1. **Impact Analysis:** 타 서비스(Docker, 포트) 충돌 및 레거시 데이터 인코딩 충돌 확인. +2. **Cost/Benefit:** 유지보수 용이성 확인 (하드코딩 지양). +3. **Auto-Execution:** 검증 완료 시 즉시 실행. + +## 5. Interaction Optimization (실행 최적화) +- **Terminal Command:** 사용자가 즉시 실행 가능한 **One-Liner** 형태로 제공하십시오. +- **No Confirmation:** "실행하시겠습니까?" 대신 "아래 명령어를 실행하여 적용합니다."라고 단정적으로 서술하십시오. + +## 6. Output Template (보고 양식) +서론/결론을 생략하고 아래 양식으로 보고하십시오: + +🛠 [실행 완료] +- **수정 파일:** 파일명 (변경점 1줄 요약) +- **명령어:** 실행 내용 (성공 여부) + +⚖️ [시스템 영향 분석] +- **변경 파장:** (예: SSL 갱신 필요 여부 등) +- **안전성 검토:** (예: 데이터 보존 여부, 인코딩 처리 여부) + +🚀 [다음 단계] +- (사용자가 직접 해야 할 행동 명시 OR "시스템 정상 가동 중. 추가 작업 불필요") \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13ff7bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# [업로드 방지] 로컬 테스트 파일들이 GitLab으로 올라가지 않게 함 +dda/ +*.sqlite +*.db \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..eb9b9ee --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,26 @@ +# PHP / 일반 웹 배포 (DB 보존 모드) +image: alpine:latest + +stages: + - deploy + +deploy_with_protection: + stage: deploy + script: + - apk add --no-cache rsync + - mkdir -p /deploy/5119/jasan + + # [삭제 방지] rsync를 이용해 제외된 항목은 건드리지 않음 + # (업로드된 파일이나 DB 등이 삭제되지 않도록 보호) + - rsync -rltv --delete --exclude='dda/' --exclude='.git/' ./ /deploy/5119/jasan/ + + # 권한 설정 (http 읽기/쓰기 문제 해결) + - chown -R 1023:1023 /deploy/5119/jasan || true + - chmod -R 755 /deploy/5119/jasan + + # 보존된 데이터 폴더 생성 및 쓰기 권한 부여 (자동 생성) + # dda/ 폴더 생성 및 권한 부여 + - mkdir -p /deploy/5119/jasan/dda/ + - chmod -R 777 /deploy/5119/jasan/dda/ + only: + - main \ No newline at end of file diff --git a/.work b/.work new file mode 100644 index 0000000..64d3b0d --- /dev/null +++ b/.work @@ -0,0 +1,91 @@ +WORK ORDER: FKI Corporate Asset System Migration +Project Code: FKI-ASSET-V2 Date: 2026-02-08 To: Antigravity Development Team From: System Architect + +1. Project Overview +기존 Notion으로 관리되던 한경협(FKI)의 4대 핵심 자산(직원, 노트북, 임시출입증, 복합기 계정) 데이터를 완벽하게 이관하고, PHP 8.4 + SQLite 기반의 독립적인 웹 애플리케이션을 구축한다. 핵심 목표는 **Zero Latency(즉각적인 반응 속도)**와 Data Integrity(데이터 무결성) 확보이며, 특히 **CSV 데이터의 자동 정규화 및 관계 연결(Mapping)**이 필수 요구사항이다. + +2. Technical Stack & Environment +Platform: Synology NAS Web Station (Self-hosted) + +Language: PHP 8.4 (Strong Typing, Modern Syntax) + +Database: SQLite 3 (WAL Mode Enabled, Foreign Keys ON) + +Frontend: HTML5, Tailwind CSS (CDN), Alpine.js (CDN) + +Architecture: Single File DB (assets.db), RESTful API (api.php) + +3. Database Schema Requirements (Finalized) +모든 테이블은 확장을 대비해 spare_1 ~ spare_5 컬럼을 포함할 것. + +[A] departments (조직도) +계층형 구조 지원 (parent_id, level). + +Migration Rule: CSV의 상위 항목 컬럼을 분석하여 부모-자식 관계를 자동으로 연결할 것. + +[B] users (직원 마스터) +Columns: emp_id(사번), name, department_id, position(직위), email, phone(내선), mobile(휴대폰), status(active/resigned), accounting_type(회계구분). + +Migration Rule: 사번이 없는 경우 FKI_TEMP_{id} 형식으로 임시 발급. 회계구분은 기본 '일반회계'로 설정하되 추후 수정 가능하도록 구현. + +[C] laptop_models (모델 마스터) +Columns: model_name, manufacturer. + +Migration Rule: 노트북 데이터에서 모델명을 추출하여 중복 없이 마스터 테이블로 생성. + +[D] laptop_assets (노트북 실물) +Columns: asset_tag(자산관리번호-PK), model_id, current_user_id(FK), status(stock/assigned), serial_number, purchase_date. + +Migration Rule (Critical): + +CSV의 사용중노트북 컬럼(User CSV)과 배정 사용자(Laptop CSV) 양방향을 대조하여 매핑. + +Notion Link 포맷(Name (Link))을 파싱하여 순수 텍스트만 추출해 매핑할 것. + +[E] access_cards (임시 출입증) +Columns: card_number(보안실 넘버링-PK), card_type(임시 네이밍), nfc_id. + +[F] mfp_accounts (복합기 계정) +Columns: account_id(이름-PK), account_pw, purpose(사용목적), status. + +4. Migration & Initialization Logic (db_init.php) +핵심 요구사항: 별도의 CSV 업로드 과정 없이, 제공된 PHP 파일 실행 한 번으로 DB 생성부터 데이터 주입까지 완료되어야 함. + +Embed SQL Data: 분석 완료된 CSV 데이터를 INSERT 쿼리 형태로 PHP 파일 내부에 하드코딩할 것 (약 400+ Rows). + +Hierarchy Restoration: 부서명을 기준으로 부모 ID를 찾아 departments 테이블의 계층 구조를 복원할 것. + +Smart Linking: 노트북의 asset_tag를 키로 사용하여 users 테이블과 laptop_assets 테이블의 Foreign Key 관계를 완벽하게 연결할 것. + +5. UI/UX Specifications +5.1 Dashboard (index.php) +Layout: 4-Column Grid (Laptops, Access Cards, MFP, Users). + +Metrics: 총 자산 수 vs 할당된 자산 수(Assign Rate)를 시각화 (Progress Bar). + +Design: Clean & Corporate Style (Tailwind slate-800 as Primary). + +5.2 User Management (users.php) +Table: 사번, 이름/직위, 부서(계층 경로 포함), 연락처(내선/휴대폰/이메일), 상태. + +Feature: 검색 기능 및 상태(재직/퇴사) 필터링. + +5.3 Asset Management +Laptop List: 자산번호, 모델명, 시리얼, 현재 사용자, 취득일 표시. + +6. Deliverables (Files to Submit) +config.php: DB Path 및 WAL 모드 설정. + +db_init.php: (중요) 스키마 생성 + CSV 데이터 파싱 완료된 Insert 쿼리 내장 + 자동 실행 로직. + +api.php: 4대 자산 CRUD 및 대시보드 통계 API. + +index.php: 통합 대시보드 Frontend. + +users.php: 직원 관리 Frontend. + +laptops.php: 노트북 관리 Frontend. + +assets/style.css: 커스텀 스타일. + +Note to Developer: db_init.php 작성 시 set_time_limit(300)을 반드시 포함하여 대량의 Insert 쿼리 실행 중 타임아웃이 발생하지 않도록 하십시오. 데이터 분석은 이미 완료되었으므로, 첨부된 SQL 데이터를 그대로 사용하면 됩니다. \ No newline at end of file diff --git a/api.php b/api.php new file mode 100644 index 0000000..485cd9f --- /dev/null +++ b/api.php @@ -0,0 +1,68 @@ +query("SELECT COUNT(*) FROM laptop_assets")->fetchColumn(); + $laptop_assigned = $db->query("SELECT COUNT(*) FROM laptop_assets WHERE status = 'assigned'")->fetchColumn(); + + // Cards + $card_total = $db->query("SELECT COUNT(*) FROM access_cards")->fetchColumn(); + $card_assigned = $db->query("SELECT COUNT(*) FROM access_cards WHERE status = 'assigned'")->fetchColumn(); + + // MFP + $mfp_total = $db->query("SELECT COUNT(*) FROM mfp_accounts")->fetchColumn(); + $mfp_active = $db->query("SELECT COUNT(*) FROM mfp_accounts WHERE status = 'active'")->fetchColumn(); + + // Users + $users_general = $db->query("SELECT COUNT(*) FROM users WHERE accounting_type = '일반회계'")->fetchColumn(); + $users_special = $db->query("SELECT COUNT(*) FROM users WHERE accounting_type = '특별회계'")->fetchColumn(); + + echo json_encode([ + 'laptops' => ['total' => (int) $laptop_total, 'assigned' => (int) $laptop_assigned], + 'cards' => ['total' => (int) $card_total, 'assigned' => (int) $card_assigned], + 'mfp' => ['total' => (int) $mfp_total, 'assigned' => (int) $mfp_active], + 'users' => ['general' => (int) $users_general, 'special' => (int) $users_special] + ]); + break; + + case 'get_users': + $query = "SELECT u.*, d.name as dept_name FROM users u LEFT JOIN departments d ON u.department_id = d.id"; + $search = $_GET['search'] ?? ''; + if ($search) { + $query .= " WHERE u.name LIKE :search OR u.emp_id LIKE :search OR u.email LIKE :search"; + $stmt = $db->prepare($query); + $stmt->execute(['search' => "%$search%"]); + } else { + $stmt = $db->query($query); + } + echo json_encode($stmt->fetchAll()); + break; + + case 'get_laptops': + $query = "SELECT a.*, m.model_name, m.manufacturer, u.name as user_name + FROM laptop_assets a + LEFT JOIN laptop_models m ON a.model_id = m.id + LEFT JOIN users u ON a.current_user_id = u.id"; + echo json_encode($db->query($query)->fetchAll()); + break; + + default: + echo json_encode(['error' => 'Invalid action']); + break; + } +} catch (Exception $e) { + http_response_code(500); + echo json_encode(['error' => $e->getMessage()]); +} \ No newline at end of file diff --git a/assets/style.css b/assets/style.css new file mode 100644 index 0000000..f4db89e --- /dev/null +++ b/assets/style.css @@ -0,0 +1,39 @@ +@import url('https://fonts.googleapis.com/css2?family=Pretendard:wght@100;200;300;400;500;600;700;800;900&display=swap'); + +:root { + --fki-primary: #1e293b; + --fki-accent: #3b82f6; +} + +body { + font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, system-ui, Roboto, 'Helvetica Neue', 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', 'Malgun Gothic', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Custom Scrollbar for Premium Feel */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: #f1f5f9; +} + +::-webkit-scrollbar-thumb { + background: #cbd5e1; + border-radius: 10px; +} + +::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} + +.premium-shadow { + box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.05); +} + +.transition-premium { + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} diff --git a/config.php b/config.php new file mode 100644 index 0000000..459d2e9 --- /dev/null +++ b/config.php @@ -0,0 +1,24 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); + + // SQLITE 특화 설정: WAL 모드 활성화 및 외래 키 ON + $db->exec("PRAGMA journal_mode=WAL;"); + $db->exec("PRAGMA foreign_keys=ON;"); + $db->exec("PRAGMA busy_timeout=5000;"); // SQLite 동시성 최적화 + +} catch (PDOException $e) { + die("Database Connection Failed: " . $e->getMessage()); +} diff --git a/db_init.php b/db_init.php new file mode 100644 index 0000000..fefaab2 --- /dev/null +++ b/db_init.php @@ -0,0 +1,187 @@ +System Init"; +echo "

🛠 FKI Asset System Migration

"; +echo "
"; + +try { + $db->beginTransaction(); + + // --- 1. 테이블 스키마 정의 (spare_1~5 컬럼 포함) --- + + // [A] 조직도 (departments) + $db->exec("DROP TABLE IF EXISTS departments"); + $db->exec("CREATE TABLE departments ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + parent_id INTEGER DEFAULT NULL, + level INTEGER DEFAULT 1, + spare_1 TEXT, spare_2 TEXT, spare_3 TEXT, spare_4 TEXT, spare_5 TEXT, + FOREIGN KEY(parent_id) REFERENCES departments(id) + )"); + + // [B] 직원 마스터 (users) + $db->exec("DROP TABLE IF EXISTS users"); + $db->exec("CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + emp_id TEXT UNIQUE, + name TEXT NOT NULL, + department_id INTEGER, + position TEXT, + email TEXT, + phone TEXT, + mobile TEXT, + status TEXT DEFAULT 'active', + accounting_type TEXT DEFAULT '일반회계', + spare_1 TEXT, spare_2 TEXT, spare_3 TEXT, spare_4 TEXT, spare_5 TEXT, + FOREIGN KEY(department_id) REFERENCES departments(id) + )"); + + // [C] 모델 마스터 (laptop_models) + $db->exec("DROP TABLE IF EXISTS laptop_models"); + $db->exec("CREATE TABLE laptop_models ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + model_name TEXT NOT NULL, + manufacturer TEXT, + spare_1 TEXT, spare_2 TEXT, spare_3 TEXT, spare_4 TEXT, spare_5 TEXT + )"); + + // [D] 노트북 실물 (laptop_assets) + $db->exec("DROP TABLE IF EXISTS laptop_assets"); + $db->exec("CREATE TABLE laptop_assets ( + asset_tag TEXT PRIMARY KEY, + model_id INTEGER, + current_user_id INTEGER, + status TEXT DEFAULT 'stock', + serial_number TEXT, + purchase_date DATE, + spare_1 TEXT, spare_2 TEXT, spare_3 TEXT, spare_4 TEXT, spare_5 TEXT, + FOREIGN KEY(model_id) REFERENCES laptop_models(id), + FOREIGN KEY(current_user_id) REFERENCES users(id) + )"); + + // [E] 임시 출입증 (access_cards) + $db->exec("DROP TABLE IF EXISTS access_cards"); + $db->exec("CREATE TABLE access_cards ( + card_number TEXT PRIMARY KEY, + card_type TEXT, + nfc_id TEXT, + status TEXT DEFAULT 'available', + spare_1 TEXT, spare_2 TEXT, spare_3 TEXT, spare_4 TEXT, spare_5 TEXT + )"); + + // [F] 복합기 계정 (mfp_accounts) + $db->exec("DROP TABLE IF EXISTS mfp_accounts"); + $db->exec("CREATE TABLE mfp_accounts ( + account_id TEXT PRIMARY KEY, + account_pw TEXT, + purpose TEXT, + status TEXT DEFAULT 'active', + spare_1 TEXT, spare_2 TEXT, spare_3 TEXT, spare_4 TEXT, spare_5 TEXT + )"); + + echo "

✔ Tables created successfully with spare columns.

"; + + // --- 2. 레거시 데이터 주입 (CSV 기반 데이터) --- + + // 2.1 부서 데이터 (ID, 이름, 레벨) + $depts = [ + [1, '경제조사팀', 1], + [3, '연구총괄대표', 1], + [4, '기획혁신본부', 1], + [5, '미구주협력팀', 1], + [6, '기획혁신팀', 1], + [7, '글로벌리스크팀', 1], + [8, '아태협력팀', 1], + [10, '기업제도팀', 1], + [11, '자산운영팀', 1], + [12, '미래전략TF', 1], + [13, '인사·지원팀', 1], + [14, '미래전략팀', 1], + [16, '국제본부', 1], + [17, '회원서비스팀', 1], + [18, '대외협력팀', 1], + [21, '커뮤니케이션본부', 1], + [23, '경제산업본부', 1], + [24, '경영지원본부', 1], + [25, '산업정책팀', 1], + [26, '국제협력팀', 1], + [28, '총무팀', 1], + [30, 'ESG팀', 1], + [31, '홍보팀', 1], + [32, '전략기획실', 1], + [36, '회원팀', 1], + [39, '기업정책팀', 1], + [40, '인재경영팀', 1] + ]; + $stmt = $db->prepare("INSERT INTO departments (id, name, level) VALUES (?, ?, ?)"); + foreach ($depts as $d) + $stmt->execute($d); + + // 2.2 직원 데이터 (FKI_TEMP 발급 로직 포함) + $users_data = [ + ['FKI20426', '한호', 1, '책임', 'hanpodosa@fki.or.kr', '02-3771-0426', '010-8563-9285'], + ['FKI24208', '정철', 3, '원장', 'cchung@fki.or.kr', NULL, NULL], + ['FKI04454', '김주태', 36, '수석', 'equilia@fki.or.kr', '02-3771-0454', '010-8539-8217'], + ['FKI00377', '이소원', 40, '수석', 'swlee@fki.or.kr', '02-3771-0377', '010-8720-8106'], + ['FKI13517', '전종대', 21, '책임', 'jdjun@fki.or.kr', '02-3771-0443', '010-9016-2668'], + ['FKI02001', '이태규', 18, '선임연구위원', 'tklee@fki.or.kr', '02-3771-0041', '010-3787-8269'], + ['FKI11638', '김다미', 17, '연구원', 'sdamis@fki.or.kr', '02-3771-0389', '010-9006-7600'] + ]; + + $user_stmt = $db->prepare("INSERT INTO users (emp_id, name, department_id, position, email, phone, mobile) VALUES (?, ?, ?, ?, ?, ?, ?)"); + foreach ($users_data as $u) { + $emp_id = $u[0]; + if (!$emp_id) { + // 이후 시퀀스로 대체하거나 임시 발급 + $emp_id = 'FKI_TEMP_' . bin2hex(random_bytes(4)); + } + $user_stmt->execute([$emp_id, $u[1], $u[2], $u[3], $u[4], $u[5], $u[6]]); + } + + // 2.3 노트북 모델 + $models = [ + ['NT750XEV-G51AG', 'SAMSUNG'], + ['DELL VOSTRO 3500', 'DELL'], + ['NT950XGQ-A71AS', 'SAMSUNG'], + ['15S-FQ1005TU', 'HP'], + ['PROBOOK 450 G10', 'HP'] + ]; + $model_stmt = $db->prepare("INSERT INTO laptop_models (model_name, manufacturer) VALUES (?, ?)"); + foreach ($models as $m) + $model_stmt->execute($m); + + // 2.4 노트북 자산 + $assets = [ + ['160003779', 1, 1, 'assigned', 'KVGY99YTC001Q4', '2024-01-23'], + ['160003774', 1, 2, 'assigned', 'KVGY99YTC001P1', '2024-01-23'], + ['160003823', 3, 3, 'assigned', '593491HXC00078', '2024-05-19'] + ]; + $asset_stmt = $db->prepare("INSERT INTO laptop_assets (asset_tag, model_id, current_user_id, status, serial_number, purchase_date) VALUES (?, ?, ?, ?, ?, ?)"); + foreach ($assets as $a) + $asset_stmt->execute($a); + + // 2.5 출입증 & 복합기 + $db->exec("INSERT INTO access_cards (card_number, card_type, nfc_id) VALUES ('FKI_244', 'Research 01', 'A3D9D7CD')"); + $db->exec("INSERT INTO mfp_accounts (account_id, account_pw, purpose) VALUES ('Audit03', 'Audit03', 'Audit Team')"); + + $db->commit(); + echo "

✔ Migration completed successfully!

"; + echo "

Go to Dashboard

"; + +} catch (Exception $e) { + if ($db->inTransaction()) + $db->rollBack(); + echo "

❌ Error: " . $e->getMessage() . "

"; +} + +echo "
"; \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..bdf0461 --- /dev/null +++ b/index.php @@ -0,0 +1,295 @@ + + + + + + + FKI 자산관리 시스템 | Dashboard + + + + + + + + + + + + + + + +
+
+
+

System Statistics

+

실시간 자산 배정 현황 및 가동률을 확인하세요.

+
+
+ +
+ LIVE +
+
+ + +
+ + +
+
+
+ + + +
+ +
+

Laptop Mobility

+
+ 0 + / 0 total +
+
+
+
+
+ + +
+
+
+ + + +
+ Security +
+

Access Cards

+
+ 0 + / 0 units +
+

임시 출입증 총 대여 현황

+
+ + +
+
+
+ + + +
+ +
+

MFP Accounts

+
+ 0 + / 0 + active +
+
+
+
+
+ + +
+
+
+ + + +
+ Accounting +
+

Account Division

+
+
+ 일반회계 + 0 +
+
+ 특별회계 + 0 +
+
+
+ +
+ + +
+

+ + + + 퀵 네비게이션 +

+
+ +
+ + + +
+
+

직원 DB 관리

+

사번/부서/연락처

+
+
+ +
+ + + +
+
+

노트북 실사

+

자산태그/배정현황

+
+
+
+
+ + + +
+
+

보안실 연동

+

준비 중

+
+
+
+
+ + + + +
+
+

환경 설정

+

준비 중

+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/laptops.php b/laptops.php new file mode 100644 index 0000000..d73fb81 --- /dev/null +++ b/laptops.php @@ -0,0 +1,146 @@ + + + + + + + 노트북 자산 관리 | FKI ASSET + + + + + + + + + + + + +
+
+
+

노트북 자산 실사

+

사내 모빌리티 자산 상태 및 실배정 내역 관리

+
+ +
+ + +
+
+ + +
+ +
+ + +
+

등록된 노트북 자산이 없습니다.

+
+
+ + + + + \ No newline at end of file diff --git a/users.php b/users.php new file mode 100644 index 0000000..1a04e87 --- /dev/null +++ b/users.php @@ -0,0 +1,184 @@ + + + + + + + 직원 마스터 리스트 | FKI ASSET + + + + + + + + + + + + +
+
+
+

직원 마스터

+

임직원 기본 정보 및 부서 체계 관리

+
+ +
+
+ + + + + + +
+ +
+
+ + +
+ + + + + + + + + + + + + +
사번 / + 이름부서 / + 직위연락처 + 회계구분 + 상태 +
+ + +
+ + + + + +
+ + +
+

검색 결과가 없습니다.

+
+
+
+ + + + + \ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..e69de29