diff --git a/.gemini/settings.json b/.gemini/settings.json deleted file mode 100644 index b0948b3..0000000 --- a/.gemini/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "mcpServers": { - "gitea": { - "command": "npx", - "args": [ - "-y", - "@andrebuzeli/git-mcp@latest" - ], - "env": { - "GITEA_HOST": "https://gitea.hmac.kr", - "GITEA_ACCESS_TOKEN": "0318de8265b9cbabc5e70773e94c59807ec3ad8a" - } - } - } -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 40b878d..fb9f602 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ -node_modules/ \ No newline at end of file +node_modules/ +.gemini/ +.env +dist/ +*.log +.DS_Store +Thumbs.db diff --git a/PROJECT_GUIDE.md b/PROJECT_GUIDE.md new file mode 100644 index 0000000..8716dc9 --- /dev/null +++ b/PROJECT_GUIDE.md @@ -0,0 +1,49 @@ +# ๐Ÿ“— ITAM ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ ๋ฐ ํ˜‘์—… ๊ฐ€์ด๋“œ + +๋ณธ ๋ฌธ์„œ๋Š” ITAM(IT Asset Management System)์˜ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ์™€ ๊ณต๋™ ์ž‘์—…์„ ์œ„ํ•œ ๊ฐ€์ด๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. + +## 1. ํ”„๋กœ์ ํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์š” +ITAM์€ **์ค‘์•™ ์ƒํƒœ ๊ด€๋ฆฌ(Centralized State)**์™€ **์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ UI(Component-based UI)** ๊ตฌ์กฐ๋กœ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  UI์™€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ๊ธฐ๋Šฅ๋ณ„๋กœ ๋…๋ฆฝ๋œ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์–ด, ์—ฌ๋Ÿฌ ์ž‘์—…์ž๊ฐ€ ์ถฉ๋Œ ์—†์ด ๋™์‹œ์— ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +## 2. ํ•ต์‹ฌ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ๋ฐ ์—ญํ•  + +### ๐Ÿ—๏ธ ์ œ์–ด ๋กœ์ง (Core) +* **`src/main.ts`**: ์‹œ์Šคํ…œ ๊ด€์ œํƒ‘. ์ „์ฒด ์ปดํฌ๋„ŒํŠธ ์ดˆ๊ธฐํ™” ๋ฐ ๋ฉ”์ธ ๋ Œ๋”๋ง ํ๋ฆ„์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. +* **`src/state.ts`**: **์ „์—ญ ๋ฐ์ดํ„ฐ ์ฐฝ๊ณ **. ์ž์‚ฐ ๋ฐ์ดํ„ฐ(`masterData`)์™€ ํ˜„์žฌ ํƒญ ์ƒํƒœ๋ฅผ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์‹œ ๊ฐ€์žฅ ๋จผ์ € ํ™•์ธํ•ด์•ผ ํ•  ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. + +### ๐Ÿ› ๏ธ ์ƒ์„ธ ํŽ˜์ด์ง€ ๋ฐ ๋ชจ๋‹ฌ (Modals) +๋ชจ๋“  ์ž์‚ฐ์˜ ์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ ๋กœ์ง์€ `src/components/Modal/` ํด๋” ๋‚ด์— ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. + +* **`BaseModal.ts`**: ๋ชจ๋“  ๋ชจ๋‹ฌ์˜ ๊ณตํ†ต ๊ธฐ๋Šฅ(๋‹ซ๊ธฐ, ESC ์ฒ˜๋ฆฌ, ๋ฐฐ๊ฒฝ ํด๋ฆญ)์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. +* **`PCModal.ts`**: ๊ฐœ์ธPC ์ „์šฉ ์ƒ์„ธ ์ •๋ณด ๋ฐ ์‚ฌ์–‘ ๊ด€๋ฆฌ. +* **`HWModal.ts`**: ์„œ๋ฒ„, ์ „์‚ฐ๋น„ํ’ˆ ์ž์‚ฐ ์ƒ์„ธ ์ •๋ณด ๊ด€๋ฆฌ. +* **`StorageModal.ts`**: ์Šคํ† ๋ฆฌ์ง€(NAS/DAS) ํŠนํ™” ํ•„๋“œ ๋ฐ ์ •๋ณด ๊ด€๋ฆฌ. +* **`SWModal.ts`**: ์†Œํ”„ํŠธ์›จ์–ด ๋ผ์ด์„ ์Šค ๊ธฐ๋ณธ ์ •๋ณด ๊ด€๋ฆฌ. +* **`SWUserModal.ts`**: **๋ณต์žกํ•œ ๋กœ์ง ์˜์—ญ**. ์†Œํ”„ํŠธ์›จ์–ด๋ณ„ ์‚ฌ์šฉ์ž ํ• ๋‹น/ํ•ด์ œ ๋ฐ ๋งคํ•‘ ๋กœ์ง์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. + +### ๐Ÿ“Š ํ™”๋ฉด ๋ Œ๋”๋ง (Views) +* **`src/views/DashboardView.ts`**: HW/SW ํ˜„ํ™ฉ ํ†ต๊ณ„ ๋ฐ ์š”์•ฝ ์ฐจํŠธ ํ™”๋ฉด์„ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. +* **`src/views/AssetTableView.ts`**: ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ž์‚ฐ ๋ชฉ๋ก ํ…Œ์ด๋ธ”์„ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. + +## 3. ๊ณต๋™ ์ž‘์—… ๊ฐ€์ด๋“œ (ํ˜‘์—… ์ „๋žต) + +๋ณธ ํ”„๋กœ์ ํŠธ๋Š” ํŒŒ์ผ ๋‹จ์œ„๋กœ ์—ญํ• ์ด ๋ช…ํ™•ํžˆ ๋‚˜๋‰˜์–ด ์žˆ์–ด, **๋‹ด๋‹น ์˜์—ญ์— ๋”ฐ๋ผ ๋…๋ฆฝ์ ์ธ ์ž‘์—…์ด ๊ฐ€๋Šฅ**ํ•ฉ๋‹ˆ๋‹ค. + +### ๐Ÿ‘ค ๋‹ด๋‹น์ž๋ณ„ ๊ถŒ์žฅ ์ž‘์—… ์˜์—ญ +| ์ž‘์—… ๋Œ€์ƒ | ๋‹ด๋‹น ํŒŒ์ผ (Primary) | ์„ค๋ช… | +| :--- | :--- | :--- | +| **ํ•˜๋“œ์›จ์–ด(HW) ๋‹ด๋‹น** | `PCModal.ts`, `HWModal.ts`, `StorageModal.ts` | ํ•˜๋“œ์›จ์–ด ์ƒ์„ธ ํŽ˜์ด์ง€ ๋ฐ ์‚ฌ์–‘ ๊ด€๋ฆฌ ๋กœ์ง ๊ฐœ๋ฐœ | +| **์†Œํ”„ํŠธ์›จ์–ด(SW) ๋‹ด๋‹น** | `SWModal.ts`, `SWUserModal.ts` | ์†Œํ”„ํŠธ์›จ์–ด ์ •๋ณด ๋ฐ ์‚ฌ์šฉ์ž ํ• ๋‹น ์‹œ์Šคํ…œ ๊ฐœ๋ฐœ | + +### ๐Ÿค ๊ณตํ†ต ์˜์—ญ ๋ฐ ์ฃผ์˜์‚ฌํ•ญ +์•„๋ž˜ ํŒŒ์ผ๋“ค์€ ๋‘ ๋‹ด๋‹น์ž๊ฐ€ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์˜์—ญ์ด๋ฏ€๋กœ, ์ˆ˜์ • ์‹œ Git ์ถฉ๋Œ์— ์œ ์˜ํ•˜๊ณ  ์†Œํ†ต์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. +1. **`src/state.ts`**: ๋ฐ์ดํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค(Interface)๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ. +2. **`src/views/AssetTableView.ts`**: ๋ชฉ๋ก ํ…Œ์ด๋ธ”์˜ ๊ณตํ†ต ์Šคํƒ€์ผ์ด๋‚˜ HW/SW ํ…Œ์ด๋ธ” ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ. +3. **`src/views/DashboardView.ts`**: ๋Œ€์‹œ๋ณด๋“œ ํ†ต๊ณ„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ. + +## 4. ๋ฐ์ดํ„ฐ ํ๋ฆ„ (Data Flow) +1. **๋ฐ์ดํ„ฐ ์กฐํšŒ**: `AssetTableView`์—์„œ ํ•ญ๋ชฉ ํด๋ฆญ โ†’ ๋‹ด๋‹น ๋ชจ๋‹ฌ์˜ `openModal(asset)` ํ˜ธ์ถœ โ†’ ํผ ๋ฐ”์ธ๋”ฉ. +2. **๋ฐ์ดํ„ฐ ์ €์žฅ**: ๋ชจ๋‹ฌ์—์„œ '์ €์žฅ' ๋ฒ„ํŠผ ํด๋ฆญ โ†’ `state.ts`์˜ ์ „์—ญ ์ƒํƒœ ์—…๋ฐ์ดํŠธ โ†’ `main.ts`์˜ `renderContent()` ํ˜ธ์ถœ โ†’ ์ „์ฒด ํ™”๋ฉด ์ฆ‰์‹œ ๊ฐฑ์‹ . + +--- +**Tip**: ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ๋Š” `main.ts`์— ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ๋ง๊ณ , ์ ์ ˆํ•œ ํด๋” ์•„๋ž˜์— ์ƒˆ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด `import` ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. diff --git a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_agent.pdf b/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_agent.pdf deleted file mode 100644 index 961f66d..0000000 Binary files a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_agent.pdf and /dev/null differ diff --git a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_app.pdf b/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_app.pdf deleted file mode 100644 index e516327..0000000 Binary files a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_app.pdf and /dev/null differ diff --git a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_web_realassets.pdf b/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_web_realassets.pdf deleted file mode 100644 index 194bb8d..0000000 Binary files a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_web_realassets.pdf and /dev/null differ diff --git a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_web_software.pdf b/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_web_software.pdf deleted file mode 100644 index 2d8d5e3..0000000 Binary files a/Reference/SAMQ ๋งค๋‰ด์–ผ/SAMQ_manual_web_software.pdf and /dev/null differ diff --git a/backup_temp/README.md b/backup_temp/README.md new file mode 100644 index 0000000..3bc41b3 --- /dev/null +++ b/backup_temp/README.md @@ -0,0 +1,57 @@ +# ๐Ÿ› ๏ธ ๊ฐœ๋ฐœ ๋ฐ ๊ด€๋ฆฌ ๊ทœ์น™ (Strict Development Rules) + +1. **์–ธ์–ด ์„ค์ •**: ์˜์–ด๋กœ ์ƒ๊ฐํ•˜๋˜, ๋ชจ๋“  ๋‹ต๋ณ€์€ **ํ•œ๊ตญ์–ด**๋กœ ์ž‘์„ฑํ•œ๋‹ค. +2. **์ž„์˜ ์ˆ˜์ • ์ ˆ๋Œ€ ๊ธˆ์ง€ (Zero-Arbitrary Change)**: + - ์‚ฌ์šฉ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์‹œํ•œ ๋ถ€๋ถ„ ์™ธ์—๋Š” **๋‹จ ํ•œ ์ค„์˜ ์ฝ”๋“œ๋„, ๊ทธ ์–ด๋–ค ํŒŒ์ผ๋„ ์ž„์˜๋กœ ์ˆ˜์ •, ์ •๋ฆฌ, ๋ฆฌํŒฉํ† ๋งํ•˜์ง€ ์•Š๋Š”๋‹ค.** + - ์ง€์‹œ๋ฐ›์ง€ ์•Š์€ ๋‹ค๋ฅธ ํŒŒํŠธ์˜ ์ฝ”๋“œ๋Š” ์ ˆ๋Œ€ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋ฉฐ, ์˜ํ–ฅ ๋ฒ”์œ„๊ฐ€ ์š”์ฒญ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜์ง€ ์•Š๋„๋ก '์™ธ๊ณผ ์ˆ˜์ˆ ์‹(Surgical) ์ˆ˜์ •'์„ ์›์น™์œผ๋กœ ํ•œ๋‹ค. +3. **๊ฐœ์„  ์ž‘์—… ์ ˆ์ฐจ (Test-First Approach)**: + - ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐœ์„ (Refactoring, Optimization ๋“ฑ)์„ ์ง€์‹œํ•œ ๊ฒฝ์šฐ, **์ˆ˜์ • ์ „ ํ˜„์žฌ ์‹œ์Šคํ…œ์ด ์ •์ƒ์ ์œผ๋กœ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€ ๋จผ์ € ์ „์ˆ˜ ํ™•์ธ**ํ•œ๋‹ค. + - ๊ธฐ์กด ๋™์ž‘ ๋ฐฉ์‹๊ณผ ์„ฑ๋Šฅ์„ ๊ธฐ์ค€(Baseline)์œผ๋กœ ์‚ผ๊ณ , ์ˆ˜์ • ํ›„์—๋„ **๊ธฐ์กด์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ๋ฌด๊ฒฐํ•˜๊ฒŒ ์œ ์ง€๋˜๋Š”์ง€ ๋ฐ˜๋“œ์‹œ ํ…Œ์ŠคํŠธํ•˜์—ฌ ์ž…์ฆ**ํ•œ๋‹ค. + - ๊ฒ€์ฆ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ "๋ฌด์—‡์„, ์™œ, ์–ด๋–ป๊ฒŒ" ๋ฐ”๊ฟ€์ง€ ์ƒ์„ธ ๋ณด๊ณ  ํ›„, ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ **'์ง„ํ–‰์‹œ์ผœ'** ์Šน์ธ์„ ์–ป์€ ๋’ค์—๋งŒ ์ง‘ํ–‰ํ•œ๋‹ค. +4. **์„ ๋ณด๊ณ  ํ›„์Šน์ธ**: ๋ชจ๋“  ๊ธฐ๋Šฅ ์ˆ˜์ • ๋ฐ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์ „์—๋Š” ์˜ˆ์ƒ ๋ฐฉ์•ˆ์„ ๋จผ์ € ๋ณด๊ณ ํ•˜๊ณ  ์Šน์ธ ์ ˆ์ฐจ๋ฅผ ๊ฑฐ์นœ๋‹ค. + +--- + +### ๐Ÿš€ ์„œ๋ฒ„ ๊ตฌ๋™ ๋ฐ ์™ธ๋ถ€ ์ ‘์† ๊ทœ์น™ (Server Run & External Access) + +1. **ํฌํŠธ ๊ณ ์ •**: ๊ฐœ๋ฐœ ์„œ๋ฒ„๋Š” ๋ฐ˜๋“œ์‹œ **8080** ํฌํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. (`vite.config.ts` ์„ค์ • ์ค€์ˆ˜) +2. **์™ธ๋ถ€ ์ ‘์† ํ—ˆ์šฉ (Host)**: ์‚ฌ๋ฌด์‹ค ๋‚ด ํƒ€ ์ง์›์ด ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋„๋ก `--host` ๋ชจ๋“œ๋กœ ๊ตฌ๋™ํ•œ๋‹ค. +3. **๊ตฌ๋™ ๋ช…๋ น์–ด**: + ```bash + npm run dev + ``` + * ํ•ด๋‹น ๋ช…๋ น์–ด ์‹คํ–‰ ์‹œ `0.0.0.0` ๋˜๋Š” `Network: http://[๋‚ด-IP]:8080/` ๊ฒฝ๋กœ๋กœ ํƒ€์ธ ์ ‘์†์ด ๊ฐ€๋Šฅํ•˜๋‹ค. +4. **IP ํ™•์ธ ๋ฐฉ๋ฒ•**: + * Windows: `ipconfig` ๋ช…๋ น์–ด๋กœ 'IPv4 ์ฃผ์†Œ' ํ™•์ธ ํ›„ ๊ณต์œ . + +--- + +### ๐ŸŽจ ITAM ์‹œ์Šคํ…œ ๋””์ž์ธ ๊ฐ€์ด๋“œ (Design Guide) + +1. **๋””์ž์ธ ์ฒ ํ•™ (Design Philosophy)** + * **Minimalist & Border-based**: ๋ถˆํ•„์š”ํ•œ ๋ฐ•์Šค(Card) ์‚ฌ์šฉ์„ ์ตœ์†Œํ™”ํ•˜๊ณ , ์ •๋ณด์˜ ๊ตฌ๋ถ„์€ ๊ฐ„๊ฒฐํ•œ ๋ผ์ธ(Border/Divider)์„ ํ™œ์šฉํ•˜์—ฌ ์‹œ๊ฐ์  ํ”ผ๋กœ๋„๋ฅผ ๋‚ฎ์ถฅ๋‹ˆ๋‹ค. + * **Professional Achromatic**: ๋ฌด์ฑ„์ƒ‰(Black, White, Grey)์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜์—ฌ ์ •๋ˆ๋œ ์—…๋ฌด ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. + * **Green Accent**: ๋ธ”๋ฃจ ๋Œ€์‹  ์ง™์€ ๊ทธ๋ฆฐ(`#1E5149`)์„ ํฌ์ธํŠธ ์ปฌ๋Ÿฌ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์ฐจ๋ถ„ํ•œ ์ „๋ฌธ์„ฑ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค. + +2. **ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ (Typography)** + * **Font Family**: `Pretendard` (์ „์—ญ ์ ์šฉ) + * **Letter Spacing**: `-0.02em` (์•ฝ -2%) ์ ์šฉ. ์ž๊ฐ„์„ ์ข๊ฒŒ ์„ค์ •ํ•˜์—ฌ ๋ฐ€๋„ ์žˆ๊ณ  ์„ธ๋ จ๋œ ๊ฐ€๋…์„ฑ์„ ํ™•๋ณดํ•ฉ๋‹ˆ๋‹ค. + * **Weights**: 400(Regular), 500(Medium), 600(SemiBold), 700(Bold). + * **Date Format (๋‚ ์งœ ํ‘œ๊ธฐ ๊ทœ์น™)**: ์‹œ์Šคํ…œ ๋‚ด ๋ชจ๋“  ๋‚ ์งœ๋Š” `YYYY.MM.DD` ํ˜•์‹์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. (์˜ˆ: 2026.04.10) + +3. **์ปฌ๋Ÿฌ ํŒ”๋ ˆํŠธ (Color Palette)** + * **Point Color**: `#1E5149` (Deep Green) - ๊ฐ•์กฐ, ํ™œ์„ฑํ™” ์ƒํƒœ, ์ฃผ์š” ์•ก์…˜ ๋ฒ„ํŠผ. + * **Text**: Main(`#111827` - Near Black), Muted(`#6B7280` - Grey). + * **Border/Divider**: `#E5E7EB` (Light Grey) - ์ •๋ณด ๊ตฌ๋ถ„์„ ์œ„ํ•œ ์–‡์€ ์‹ค์„ . + * **Background**: `#FFFFFF` (White) / `#F9FAFB` (Off White). + +4. **๋ ˆ์ด์•„์›ƒ ๋ฐ ์ปดํฌ๋„ŒํŠธ ๊ทœ์น™ (Layout Rules)** + * **Box-less Design**: ๊ผญ ํ•„์š”ํ•œ ์ •๋ณด ๋ฌถ์Œ(๋ฐ์ดํ„ฐ ๊ทธ๋ฃนํ™” ๋“ฑ)์ด ์•„๋‹ˆ๋ฉด ๋ฐ•์Šค ํ˜•ํƒœ์˜ ํ…Œ๋‘๋ฆฌ๋‚˜ ๋ฐฐ๊ฒฝ ์‚ฌ์šฉ์„ ์ง€์–‘ํ•ฉ๋‹ˆ๋‹ค. + * **Line-based Division**: ์„น์…˜ ๊ฐ„์˜ ๊ตฌ๋ถ„์€ 1px ๋‘๊ป˜์˜ ์–‡์€ ์‹ค์„ (Border)์„ ํ†ตํ•ด ๋ช…ํ™•ํžˆ ํ•ฉ๋‹ˆ๋‹ค. + * **Table**: ๋ฐฐ๊ฒฝ์ƒ‰์ด๋‚˜ ํ™”๋ คํ•œ ํšจ๊ณผ ์—†์ด ํ–‰(Row) ๊ฐ„์˜ ์–‡์€ ๊ตฌ๋ถ„์„ ๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ณธ์—ฐ์— ์ง‘์ค‘ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. + * **Input/Button**: ์ž…๋ ฅ ํ•„๋“œ์™€ ๋ฒ„ํŠผ์€ ์ตœ์†Œํ•œ์˜ ๋ณด๋”์™€ ํฌ์ธํŠธ ์ปฌ๋Ÿฌ๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ์ •๊ฐˆํ•˜๊ฒŒ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. + * **Modal (๋ชจ๋‹ฌ ๊ณตํ†ต ๊ทœ์น™)**: + * **Header**: ์ง™์€ ๊ทธ๋ฆฐ(`#1E5149`) ๋ฐฐ๊ฒฝ์— ํ™”์ดํŠธ ํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์šฐ์ธก ์ƒ๋‹จ์— ๋ช…ํ™•ํ•œ 'X' ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์„ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค. + * **Interaction**: ์‚ฌ์šฉ์ž์˜ ํŽธ์˜๋ฅผ ์œ„ํ•ด `ESC` ํ‚ค๋ฅผ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ ๋ชจ๋‹ฌ ๋ฐ”๊นฅ ์˜์—ญ(Overlay)์„ ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌ์ด ๋‹ซํžˆ๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. + * **Layout**: `detail.png` ๊ธฐ์ค€์˜ 2์—ด ๊ทธ๋ฆฌ๋“œ ์‹œ์Šคํ…œ์„ ๊ถŒ์žฅํ•˜๋ฉฐ, ํ•˜๋‹จ ์šฐ์ธก์— ์•ก์…˜ ๋ฒ„ํŠผ(๋‹ซ๊ธฐ, ์ €์žฅ ๋“ฑ)์„ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค. + diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.HW์š”์•ฝ์ •๋ณด.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.HW์š”์•ฝ์ •๋ณด.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.HW์š”์•ฝ์ •๋ณด.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.HW์š”์•ฝ์ •๋ณด.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.SW์š”์•ฝ์ •๋ณด.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.SW์š”์•ฝ์ •๋ณด.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.SW์š”์•ฝ์ •๋ณด.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/00.SW์š”์•ฝ์ •๋ณด.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/01.SW์ž์‚ฐ ์‚ฌ์šฉ์ž ํ• ๋‹น.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/01.SW์ž์‚ฐ ์‚ฌ์šฉ์ž ํ• ๋‹น.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/01.SW์ž์‚ฐ ์‚ฌ์šฉ์ž ํ• ๋‹น.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/01.SW์ž์‚ฐ ์‚ฌ์šฉ์ž ํ• ๋‹น.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/02.๊ฐœ์ธPCํ”„๋กœ๊ทธ๋žจ์„ค์น˜ํ˜„ํ™ฉ.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/02.๊ฐœ์ธPCํ”„๋กœ๊ทธ๋žจ์„ค์น˜ํ˜„ํ™ฉ.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/02.๊ฐœ์ธPCํ”„๋กœ๊ทธ๋žจ์„ค์น˜ํ˜„ํ™ฉ.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/02.๊ฐœ์ธPCํ”„๋กœ๊ทธ๋žจ์„ค์น˜ํ˜„ํ™ฉ.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/03.๋น„์ธ๊ฐ€ํ”„๋กœ๊ทธ๋žจ์‹คํ–‰์ฐฏ์•ˆ.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/03.๋น„์ธ๊ฐ€ํ”„๋กœ๊ทธ๋žจ์‹คํ–‰์ฐฏ์•ˆ.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/03.๋น„์ธ๊ฐ€ํ”„๋กœ๊ทธ๋žจ์‹คํ–‰์ฐฏ์•ˆ.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/03.๋น„์ธ๊ฐ€ํ”„๋กœ๊ทธ๋žจ์‹คํ–‰์ฐฏ์•ˆ.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/04.๊ฐœ์ธPC์‚ฌ์–‘์ •๋ณด์ˆ˜์ง‘.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/04.๊ฐœ์ธPC์‚ฌ์–‘์ •๋ณด์ˆ˜์ง‘.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/04.๊ฐœ์ธPC์‚ฌ์–‘์ •๋ณด์ˆ˜์ง‘.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/04.๊ฐœ์ธPC์‚ฌ์–‘์ •๋ณด์ˆ˜์ง‘.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.๊ตฌ๋…๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.๊ตฌ๋…๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.๊ตฌ๋…๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.๊ตฌ๋…๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.์˜๊ตฌ๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.์˜๊ตฌ๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.์˜๊ตฌ๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/05.์˜๊ตฌ๋ผ์ด์„ผ์Šค๋“ฑ๋กํŽ˜์ด์ง€.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/06. ํ”„๋กœ๊ทธ๋žจ ํ• ๋‹น ํ˜„ํ™ฉ.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/06. ํ”„๋กœ๊ทธ๋žจ ํ• ๋‹น ํ˜„ํ™ฉ.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/06. ํ”„๋กœ๊ทธ๋žจ ํ• ๋‹น ํ˜„ํ™ฉ.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/06. ํ”„๋กœ๊ทธ๋žจ ํ• ๋‹น ํ˜„ํ™ฉ.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๊ด€๋ฆฌํŽ˜์ด์ง€.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๊ด€๋ฆฌํŽ˜์ด์ง€.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๊ด€๋ฆฌํŽ˜์ด์ง€.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๊ด€๋ฆฌํŽ˜์ด์ง€.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๋“ฑ๋กํŽ˜์ด์ง€.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๋“ฑ๋กํŽ˜์ด์ง€.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๋“ฑ๋กํŽ˜์ด์ง€.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/07.์‹ค๋ฌผ์ž์‚ฐ๋“ฑ๋กํŽ˜์ด์ง€.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/08.๋ณ€๊ฒฝ๋‚ด์—ญํŽ˜์ด์ง€.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/08.๋ณ€๊ฒฝ๋‚ด์—ญํŽ˜์ด์ง€.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/08.๋ณ€๊ฒฝ๋‚ด์—ญํŽ˜์ด์ง€.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/08.๋ณ€๊ฒฝ๋‚ด์—ญํŽ˜์ด์ง€.png diff --git a/Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/09.HW๊ด€๋ฆฌํŽ˜์ด์ง€.png b/backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/09.HW๊ด€๋ฆฌํŽ˜์ด์ง€.png similarity index 100% rename from Reference/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/09.HW๊ด€๋ฆฌํŽ˜์ด์ง€.png rename to backup_temp/SAMQ ๊ธฐ๋Šฅ ์ด๋ฏธ์ง€ ์บก์ณ/09.HW๊ด€๋ฆฌํŽ˜์ด์ง€.png diff --git a/backup_temp/[์ „์‚ฐ์ž์‚ฐ๊ด€๋ฆฌ] ์ž์‚ฐ๋ฒˆํ˜ธ์ฒด๊ณ„ ๋ถ€์—ฌ๋ฐฉ์•ˆ ๊ฒ€ํ†  (2026.04.09).pdf b/backup_temp/[์ „์‚ฐ์ž์‚ฐ๊ด€๋ฆฌ] ์ž์‚ฐ๋ฒˆํ˜ธ์ฒด๊ณ„ ๋ถ€์—ฌ๋ฐฉ์•ˆ ๊ฒ€ํ†  (2026.04.09).pdf new file mode 100644 index 0000000..9ac90c6 Binary files /dev/null and b/backup_temp/[์ „์‚ฐ์ž์‚ฐ๊ด€๋ฆฌ] ์ž์‚ฐ๋ฒˆํ˜ธ์ฒด๊ณ„ ๋ถ€์—ฌ๋ฐฉ์•ˆ ๊ฒ€ํ†  (2026.04.09).pdf differ diff --git a/backup_temp/detail.png b/backup_temp/detail.png new file mode 100644 index 0000000..85fe4f2 Binary files /dev/null and b/backup_temp/detail.png differ diff --git a/backup_temp/index.html b/backup_temp/index.html new file mode 100644 index 0000000..4be2827 --- /dev/null +++ b/backup_temp/index.html @@ -0,0 +1,13 @@ + + + + + + + ITAM - IT Asset Management + + +
+ + + diff --git a/backup_temp/plan.md b/backup_temp/plan.md new file mode 100644 index 0000000..34a17f2 --- /dev/null +++ b/backup_temp/plan.md @@ -0,0 +1,32 @@ +# ๐Ÿ“‘ ITAM ์‹œ์Šคํ…œ ํ†ตํ•ฉ ๊ตฌ์ถ• ๊ธฐํš์„œ (plan.md) + +## 1. ํ”„๋กœ์ ํŠธ ๋ชฉ์  (Objective) +๋ณธ ์‹œ์Šคํ…œ์€ **'์ „์‚ฐ์ž์‚ฐ๋ฒˆํ˜ธ ๋ถ€์—ฌ๋ฐฉ์•ˆ'** ํ‘œ์ค€ ๊ฐ€์ด๋“œ์— ๋”ฐ๋ผ ์‚ฌ๋‚ด ๋ชจ๋“  ์ „์‚ฐ ์ž์‚ฐ์„ ํ†ตํ•ฉ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ชฉ์ ์œผ๋กœ ํ•œ๋‹ค. ๋ถ„์‚ฐ๋œ ์ž์‚ฐ ์ •๋ณด๋ฅผ ์ผ์›ํ™”๋œ ๋ฒˆํ˜ธ ์ฒด๊ณ„๋กœ ์‹œ์Šคํ…œํ™”ํ•˜์—ฌ ์ง๊ด€์ ์ธ ์‹๋ณ„๊ณผ ์ •๋ฐ€ํ•œ ์ด๋ ฅ ์ถ”์ ์ด ๊ฐ€๋Šฅํ•œ ํ”Œ๋žซํผ์„ ์ง€ํ–ฅํ•œ๋‹ค. + +## 2. ์ž์‚ฐ๋ฒˆํ˜ธ ์ฒด๊ณ„ ์ ์šฉ (Standardization) +๊ฒ€ํ† ์•ˆ์— ๋”ฐ๋ผ ๋ชจ๋“  ์ž์‚ฐ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ทœ์น™์œผ๋กœ ๊ณ ์œ  ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌ๋ฐ›์œผ๋ฉฐ, ์‹œ์Šคํ…œ์˜ ํ•ต์‹ฌ Key๋กœ ํ™œ์šฉ๋œ๋‹ค. + +* **๋ฒˆํ˜ธ ์ƒ์„ฑ ๊ทœ์น™**: `[๊ตฌ๋งค๋ฒ•์ธ]-[์„ค์น˜์œ„์น˜]-[์ž์‚ฐ์ข…๋ฅ˜]-[์ผ๋ จ๋ฒˆํ˜ธ(๊ตฌ๋งค์—ฐ์›”+3์ž๋ฆฌ)]` + * *์˜ˆ์‹œ: ์‚ผ์•ˆ์—์„œ 2025๋…„ 4์›”์— ๊ตฌ๋งคํ•œ IDC ์„œ๋ฒ„ โ†’ `SM-IDC-SVR-202504001`* +* **์ฝ”๋“œ ์ •์˜**: + * **๊ตฌ๋งค๋ฒ•์ธ**: BR(๋ฐ”๋ก ), SM(์‚ผ์•ˆ), HM(ํ•œ๋งฅ), JH(์žฅํ—Œ), HL(ํ•œ๋ผ), PTC(PTC) ๋“ฑ + * **์„ค์น˜์œ„์น˜**: TDC(์„ผํ„ฐ ์„œ๋ฒ„์‹ค), HBD(ํ•œ๋งฅ๋นŒ๋”ฉ), IDC(IDC), UBD(์œ ๋‹ˆ์˜จ ๋นŒ๋”ฉ), NBD(๋‰ด์ฝ”์•„ ๋นŒ๋”ฉ) ๋“ฑ + * **์ž์‚ฐ์ข…๋ฅ˜**: SVR(์„œ๋ฒ„), PC(PC), STO(์Šคํ† ๋ฆฌ์ง€), NAS(NAS), DAS(DAS), HDD(ํ•˜๋“œ) ๋“ฑ + +## 3. ๊ธฐํš ์˜๋„ ๋ฐ ์‹œ์Šคํ…œ ๊ฐ€์น˜ (Core Intent) +1. **์‹๋ณ„ ์šฉ์ด์„ฑ ํ™•๋ณด**: ๋ฒˆํ˜ธ๋งŒ์œผ๋กœ๋„ ๋ฒ•์ธ, ์œ„์น˜, ์ข…๋ฅ˜, ๋„์ž… ์‹œ๊ธฐ๋ฅผ ์ฆ‰์‹œ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ UI๋ฅผ ์ œ๊ณตํ•œ๋‹ค. +2. **์ „์‚ฌ ํ†ตํ•ฉ ๊ด€๋ฆฌ ๋กœ๋“œ๋งต**: + * **Phase 1**: IDC ์„œ๋ฒ„ ๋ฐ ์Šคํ† ๋ฆฌ์ง€ ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (ํ˜„์žฌ ์™„๋ฃŒ ๋‹จ๊ณ„) + * **Phase 2**: ์„ผํ„ฐ ์„œ๋ฒ„์‹ค(TDC) ๋ฐ ๋นŒ๋”ฉ๋ณ„ ๋„คํŠธ์›Œํฌ ์žฅ๋น„ ํ™•์žฅ + * **Phase 3**: ์ „์‚ฌ ๊ฐœ์ธ PC(PC) ๋ฐ ํ•˜๋“œ์›จ์–ด ๋ถ€ํ’ˆ(HDD ๋“ฑ) ํ†ตํ•ฉ + * **Phase 4**: ์†Œํ”„ํŠธ์›จ์–ด ๋ผ์ด์„ ์Šค์™€ ํ•˜๋“œ์›จ์–ด ์ž์‚ฐ์˜ ๋งคํ•‘ ๊ด€๋ฆฌ +3. **๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์œ ์ง€**: ์ž์‚ฐ ์œ„์น˜ ๋ณ€๊ฒฝ ์‹œ ๊ธฐ์กด ๋ฒˆํ˜ธ๋ฅผ ํ๊ธฐํ•˜๊ณ  ์‹ ๊ทœ ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ์ด๋ ฅ ๊ด€๋ฆฌ ์›์น™์„ ์‹œ์Šคํ…œ์ƒ์—์„œ ๊ฐ•์ œ ๋ฐ ๊ธฐ๋กํ•œ๋‹ค. + +## 4. ์‹œ์Šคํ…œ ์ฃผ์š” ๊ธฐ๋Šฅ (Key Features) +* **์ž์‚ฐ ์ž๋™ ๋ฒˆํ˜ธ ๋ถ€์—ฌ**: ์ž…๋ ฅ ํผ์—์„œ ๋ฒ•์ธ/์œ„์น˜/์ข…๋ฅ˜ ์„ ํƒ ์‹œ ๊ฐ€์ด๋“œ์— ๋”ฐ๋ฅธ ์ž์‚ฐ๋ฒˆํ˜ธ ์ž๋™ ์ƒ์„ฑ ๊ธฐ๋Šฅ. +* **์ƒ์„ธ ์ด๋ ฅ ์นด๋“œ**: ์ž์‚ฐ๋ฒˆํ˜ธ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ƒ์„ธ ์‚ฌ์–‘, ์ทจ๋“์ผ, ์‚ฌ์šฉ์ž, ํ˜„์žฌ ์ƒํƒœ ๋ฐ ๊ณผ๊ฑฐ ์ด๋™ ์ด๋ ฅ์„ ๋ชจ๋‹ฌ๋กœ ํ‘œ์‹œ. +* **ํ†ตํ•ฉ ํ•„ํ„ฐ๋ง**: ๋ฒ•์ธ๋ณ„, ์œ„์น˜๋ณ„, ์ข…๋ฅ˜๋ณ„๋กœ ์ž์‚ฐ์„ ์ฆ‰์‹œ ๋ถ„๋ฅ˜ํ•˜์—ฌ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ ์„ฑ๋Šฅ ํ…Œ์ด๋ธ” ์ œ๊ณต. + +## 5. ๊ธฐ์ˆ  ๋ฐ ๋””์ž์ธ ์›์น™ (Engineering Standards) +* **Design**: `README.md` ๊ฐ€์ด๋“œ๋ฅผ ์ค€์ˆ˜ํ•˜๋ฉฐ, ์ž์‚ฐ๋ฒˆํ˜ธ๊ฐ€ ๊ฐ€์žฅ ๊ฐ•์กฐ๋˜๋Š” ๋ ˆ์ด์•„์›ƒ์„ ์œ ์ง€ํ•œ๋‹ค. +* **Data Structure**: ํ–ฅํ›„ DB ์ „ํ™˜ ์‹œ ์ž์‚ฐ๋ฒˆํ˜ธ์˜ ๊ฐ ์ฝ”๋“œ(SM, IDC ๋“ฑ)๋ฅผ ์ •๊ทœํ™”ํ•˜์—ฌ ๊ด€๋ฆฌ ํšจ์œจ์„ ๊ทน๋Œ€ํ™”ํ•œ๋‹ค. diff --git a/backup_temp/src/App.css b/backup_temp/src/App.css new file mode 100644 index 0000000..ca88bd1 --- /dev/null +++ b/backup_temp/src/App.css @@ -0,0 +1,295 @@ +:root { + --primary-color: #1E5149; + --primary-hover: #163d37; + --bg-default: #FFFFFF; + --bg-muted: #F9FAFB; + --info-color: #4B5563; /* ๋ฌด์ฑ„์ƒ‰ ๊ณ„์—ด๋กœ ๋ณ€๊ฒฝ */ + --text-main: #111827; + --text-muted: #6B7280; + --border-color: #E5E7EB; +} + +.app-container { + display: flex; + flex-direction: column; + height: 100vh; + width: 100%; + background-color: var(--bg-default); + color: var(--text-main); + letter-spacing: -0.02em; +} + +.top-bar { + height: 50px; + background-color: var(--primary-color); + color: white; + display: flex; + align-items: center; + padding: 0 40px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + box-sizing: border-box; +} + +.top-bar-brand { + font-size: 1rem; + font-weight: 700; + margin-right: 48px; + color: white; +} + +.top-bar-menu { + display: flex; + gap: 4px; + height: 100%; +} + +.menu-item { + display: flex; + align-items: center; + padding: 0 16px; + cursor: pointer; + transition: all 0.2s; + color: rgba(255, 255, 255, 0.7); + font-weight: 500; + font-size: 0.875rem; + height: 100%; + border-bottom: 3px solid transparent; +} + +.menu-item:hover { + color: white; +} + +.menu-item.active { + color: white; + border-bottom: 3px solid white; + background-color: rgba(255, 255, 255, 0.1); +} + +.main-content { + flex: 1; + display: flex; + flex-direction: column; + height: calc(100vh - 50px); + overflow: hidden; /* ์ „์ฒด ํŽ˜์ด์ง€ ์Šคํฌ๋กค ๋ฐฉ์ง€ */ + padding: 0; /* ํŒจ๋”ฉ์€ ๋‚ด๋ถ€ ์š”์†Œ์—์„œ ๊ด€๋ฆฌ */ +} + +.content-header { + padding: 32px 40px 16px 40px; + margin-bottom: 0; + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; + background-color: var(--bg-default); + flex-shrink: 0; +} + +.table-container { + flex: 1; + overflow: auto; + padding: 0 40px 40px 40px; +} + +.content-title { + font-size: 1.5rem; + font-weight: 700; + color: var(--text-main); +} + +/* Common Table Styles */ +.data-table { + width: 100%; + border-collapse: separate; /* sticky border ์œ ์ง€๋ฅผ ์œ„ํ•ด separate ์‚ฌ์šฉ */ + border-spacing: 0; + font-size: 0.875rem; +} + +.data-table th, .data-table td { + padding: 14px 12px; + text-align: left; + border-bottom: 1px solid var(--border-color); + white-space: nowrap; +} + +.data-table th { + font-weight: 600; + color: var(--text-muted); + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.05em; + background-color: #F8FAFC; /* ํ—ค๋” ์ „์šฉ ๋ฐฐ๊ฒฝ์ƒ‰ */ + position: sticky; + top: 0; + z-index: 10; + border-bottom: 2px solid var(--border-color); +} + +.data-table tr:hover { + background-color: var(--bg-muted); +} + +/* Buttons */ +.btn { + padding: 8px 16px; + border-radius: 4px; + cursor: pointer; + border: 1px solid transparent; + font-weight: 600; + font-size: 0.875rem; + transition: all 0.2s; +} + +.btn-primary { + background-color: var(--primary-color); + color: white; +} + +.btn-primary:hover { + background-color: var(--primary-hover); +} + +.btn-outline { + background-color: transparent; + border: 1px solid var(--border-color); + color: var(--text-main); +} + +.btn-outline:hover { + background-color: var(--bg-muted); +} + +/* Dashboard Stats - Border based */ +.dashboard-stats { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 0; + margin-bottom: 48px; + border-top: 1px solid var(--border-color); + border-bottom: 1px solid var(--border-color); +} + +.stat-card { + padding: 24px; + display: flex; + flex-direction: column; + border-right: 1px solid var(--border-color); +} + +.stat-card:last-child { + border-right: none; +} + +.stat-label { + font-size: 0.875rem; + font-weight: 500; + color: var(--text-muted); + margin-bottom: 12px; +} + +.stat-value { + font-size: 2rem; + font-weight: 700; + color: var(--primary-color); +} + +/* Modal Styles */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; + padding: 20px; +} + +.modal-content { + background-color: var(--bg-default); + width: 100%; + max-width: 800px; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + overflow: hidden; + display: flex; + flex-direction: column; + max-height: 90vh; +} + +.modal-header { + background-color: var(--primary-color); + color: white; + padding: 16px 24px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-close-btn { + background: none; + border: none; + color: white; + font-size: 1.5rem; + line-height: 1; + cursor: pointer; + padding: 4px; + opacity: 0.8; + transition: opacity 0.2s; +} + +.modal-close-btn:hover { + opacity: 1; +} + +.modal-body { + padding: 24px; + overflow-y: auto; + flex: 1; +} + +.detail-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px 24px; +} + +.detail-item { + display: flex; + flex-direction: column; + gap: 6px; +} + +.detail-item.full-width { + grid-column: 1 / -1; +} + +.detail-item label { + font-size: 0.8125rem; + font-weight: 600; + color: var(--text-main); +} + +.detail-value { + padding: 10px 12px; + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 0.875rem; + color: var(--text-muted); + background-color: var(--bg-default); + min-height: 20px; +} + +.modal-footer { + padding: 16px 24px; + border-top: 1px solid var(--border-color); + display: flex; + justify-content: flex-end; + background-color: var(--bg-muted); +} + diff --git a/backup_temp/src/App.tsx b/backup_temp/src/App.tsx new file mode 100644 index 0000000..fbaa585 --- /dev/null +++ b/backup_temp/src/App.tsx @@ -0,0 +1,51 @@ +import { useState } from 'react' +import './App.css' +import AssetManagementView from './components/AssetManagementView' +import HardwareManagementView from './components/HardwareManagementView' + +function App() { + const [activeMenu, setActiveMenu] = useState('assets') + + const renderContent = () => { + switch (activeMenu) { + case 'assets': + return + case 'hardware': + return + default: + return + } + } + + return ( +
+
+
+ ITAM System +
+ +
+
+ {renderContent()} +
+
+ ) +} + +export default App diff --git a/backup_temp/src/components/AssetManagementView.tsx b/backup_temp/src/components/AssetManagementView.tsx new file mode 100644 index 0000000..3cc60ce --- /dev/null +++ b/backup_temp/src/components/AssetManagementView.tsx @@ -0,0 +1,168 @@ +import { useState } from 'react' +import { idcServers, idcStorages, IdcServer } from '../data/idcData' +import ServerDetailModal from './ServerDetailModal' + +const AssetManagementView = () => { + const [viewMode, setViewMode] = useState<'server' | 'storage'>('server') + const [selectedServer, setSelectedServer] = useState(null) + + return ( +
+
+
์ „์‚ฐ์ž์‚ฐ๊ด€๋ฆฌ๋Œ€์žฅ (IDC)
+
+ + +
+
+ +
+
+

+ {viewMode === 'server' ? 'IDC ์„œ๋ฒ„ ์ƒ์„ธ ์ •๋ณด' : 'IDC ์Šคํ† ๋ฆฌ์ง€ ์ƒ์„ธ ์ •๋ณด'} +

+
+ + {viewMode === 'server' ? ( + + + + + + + + + + + + + + + + + {idcServers.map((server) => ( + setSelectedServer(server)} style={{ cursor: 'pointer' }}> + + + + + + + + + + + + ))} + +
ํšŒ์‚ฌ์„œ๋ฒ„๋ฒˆํ˜ธ๊ตฌ๋ถ„์„ค์น˜์œ„์น˜๊ด€๋ฆฌ์žIP ์ฃผ์†Œ์ ‘์† ์ •๋ณดH/W ์‚ฌ์–‘OS๊ตฌ๋งค์ผ
{server.company}{server.serverNo} +
{server.category}
+ {server.remarks &&
{server.remarks}
} +
{server.location} +
{server.managerPrimary ? `์ •: ${server.managerPrimary}` : '์ •: -'}
+
{server.managerSecondary ? `๋ถ€: ${server.managerSecondary}` : '๋ถ€: -'}
+
+
{server.ip1}
+ {server.ip2 &&
{server.ip2}
} +
+ {server.remoteAccess.map((access, idx) => ( +
+
+ {access.tool} + {access.id} +
+
+ PW: {access.pw} +
+
+ ))} +
+
{server.model}
+
{server.cpu} / {server.ram}
+
{server.storage.join(' + ')}
+
{server.os}{server.purchaseDate}
+ ) : ( + + + + + + + + + + + + + + + + + {idcStorages.map((storage) => ( + + + + + + + + + + + + + ))} + +
ํšŒ์‚ฌ์„œ๋ฒ„๋ฒˆํ˜ธ๊ตฌ๋ถ„์„ค์น˜์œ„์น˜๊ด€๋ฆฌ์žIP ์ฃผ์†Œ์ ‘์† ์ •๋ณด๋ชจ๋ธ๋ช…์šฉ๋Ÿ‰๊ตฌ๋งค์ผ
{storage.company}{storage.serverNo} +
{storage.category}
+ {storage.remarks &&
{storage.remarks}
} +
{storage.location} + ์ •: {storage.managerPrimary} + ๋ถ€: {storage.managerSecondary} + {storage.ip} + {storage.remoteAccess.map((access, idx) => ( +
+
+ {access.tool} + {access.id} +
+
+ PW: {access.pw} +
+
+ ))} +
{storage.model}{storage.capacity}{storage.purchaseDate}
+ )} +
+ + {selectedServer && ( + setSelectedServer(null)} + /> + )} +
+ ) +} + +export default AssetManagementView diff --git a/backup_temp/src/components/DashboardView.tsx b/backup_temp/src/components/DashboardView.tsx new file mode 100644 index 0000000..d1c98d0 --- /dev/null +++ b/backup_temp/src/components/DashboardView.tsx @@ -0,0 +1,51 @@ +import { mockCategories } from '../data/mockData' + +const DashboardView = () => { + return ( +
+
+
๋Œ€์‹œ๋ณด๋“œ
+
+ +
+
+
์ „์ฒด ์ž์‚ฐ
+
8๊ฐœ
+
+ {mockCategories.map(cat => ( +
+
{cat.name}
+
{cat.count}๊ฐœ
+
+ ))} +
+ +
+

์ตœ๊ทผ ๋ณ€๊ฒฝ ๋‚ด์—ญ

+ + + + + + + + + + + + + + + + + + + + +
๋‚ ์งœ๋‚ด์šฉ์‚ฌ์šฉ์ž
2023-04-11PC ์‹ ๊ทœ ๋“ฑ๋ก์ด๊ด€ํ˜•
2023-04-10๋ชจ๋‹ˆํ„ฐ ๋ถ€์„œ ํ• ๋‹น ๋ณ€๊ฒฝ๊ด€๋ฆฌ์ž
+
+
+ ) +} + +export default DashboardView diff --git a/backup_temp/src/components/HardwareManagementView.tsx b/backup_temp/src/components/HardwareManagementView.tsx new file mode 100644 index 0000000..e23805f --- /dev/null +++ b/backup_temp/src/components/HardwareManagementView.tsx @@ -0,0 +1,87 @@ +import { useState } from 'react' +import { mockHardwareSpecs, HardwareSpec } from '../data/mockData' + +const SpecModal = ({ spec, onClose }: { spec: HardwareSpec, onClose: () => void }) => { + return ( +
+
+
+

์ƒ์„ธ ์‚ฌ์–‘ ์ •๋ณด

+ +
+
+ PC๋ช…: {spec.pcName} + ์‚ฌ์šฉ์ž: {spec.userName} + ๋ถ€์„œ: {spec.department} + OS: {spec.os} + CPU: {spec.cpu} + Memory: {spec.memory} + Disk: {spec.disk} + MAC: {spec.macAddress} + IP: {spec.ipAddress} + Graphic: {spec.graphicCard} +
+
+ +
+
+
+ ) +} + +const HardwareManagementView = () => { + const [selectedSpec, setSelectedSpec] = useState(null) + + return ( +
+
+
H/W ์‚ฌ์–‘ ์ •๋ณด
+
+ + + + + + + + + + + + + + + {mockHardwareSpecs.map(spec => ( + + + + + + + + + + ))} + +
PC๋ช…๋ถ€์„œ์‚ฌ์šฉ์žOSCPUIP์ฃผ์†Œ์ƒ์„ธ
{spec.pcName}{spec.department}{spec.userName}{spec.os.split(' ')[2]}{spec.cpu.split('@')[0]}{spec.ipAddress} + +
+ + {selectedSpec && ( + setSelectedSpec(null)} /> + )} +
+ ) +} + +export default HardwareManagementView diff --git a/backup_temp/src/components/ServerDetailModal.tsx b/backup_temp/src/components/ServerDetailModal.tsx new file mode 100644 index 0000000..39d477b --- /dev/null +++ b/backup_temp/src/components/ServerDetailModal.tsx @@ -0,0 +1,144 @@ +import React, { useEffect } from 'react'; +import { IdcServer } from '../data/idcData'; + +interface ServerDetailModalProps { + server: IdcServer; + onClose: () => void; +} + +const ServerDetailModal: React.FC = ({ server, onClose }) => { + // ESC ํ‚ค๋กœ ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ + useEffect(() => { + const handleEsc = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + onClose(); + } + }; + window.addEventListener('keydown', handleEsc); + return () => { + window.removeEventListener('keydown', handleEsc); + }; + }, [onClose]); + + return ( +
+
e.stopPropagation()}> +
+

{server.category} ({server.serverNo})

+ +
+ +
+
+ {/* Row 1 */} +
+ +
{server.company}
+
+
+ +
{server.serverNo}
+
+ + {/* Row 2 */} +
+ +
{server.category}
+
+
+ +
{server.location}
+
+ + {/* Row 3: ๊ด€๋ฆฌ์ž ์ถ”๊ฐ€ */} +
+ +
+ ์ •: {server.managerPrimary} + ๋ถ€: {server.managerSecondary} +
+
+ + {/* Row 4 */} +
+ +
{server.ip1 || '-'}
+
+
+ +
{server.ip2 || '-'}
+
+ + {/* Row 5 */} +
+ +
+ {server.remoteAccess.length > 0 ? ( +
+ {server.remoteAccess.map((access, idx) => ( +
+ {access.tool} + {access.id} + | + PW: {access.pw} +
+ ))} +
+ ) : '-'} +
+
+ + {/* Row 6 */} +
+ +
{server.model || '-'}
+
+
+ +
{server.os || '-'}
+
+ + {/* Row 7 */} +
+ +
{server.cpu || '-'}
+
+
+ +
{server.ram || '-'}
+
+ + {/* Row 8 */} +
+ +
{server.storage.length > 0 ? server.storage.join(' + ') : '-'}
+
+ + {/* Row 9 */} +
+ +
{server.purchaseDate || '-'}
+
+
+ +
{server.monitoring || '-'}
+
+ + {/* Row 10 */} +
+ +
{server.remarks || '-'}
+
+
+
+ +
+ + +
+
+
+ ); +}; + +export default ServerDetailModal; diff --git a/backup_temp/src/data/idcData.ts b/backup_temp/src/data/idcData.ts new file mode 100644 index 0000000..94fd214 --- /dev/null +++ b/backup_temp/src/data/idcData.ts @@ -0,0 +1,608 @@ +export interface RemoteAccess { + tool: string; + ip?: string; + id: string; + pw: string; +} + +export interface IdcServer { + company: string; + serverNo: string; + category: string; + remarks: string; + location: string; + managerPrimary: string; + managerSecondary: string; + ip1: string; + ip2: string; + remoteAccess: RemoteAccess[]; + monitoring: string; + serverIdMatch: string; + model: string; + os: string; + cpu: string; + ram: string; + storage: string[]; + purchaseDate: string; +} + +export interface IdcStorage { + company: string; + serverNo: string; + category: string; + remarks: string; + location: string; + managerPrimary: string; + managerSecondary: string; + ip: string; + managementIp?: string; + remoteAccess: RemoteAccess[]; + model: string; + capacity: string; + purchaseDate: string; +} + +export const idcServers: IdcServer[] = [ + { + company: "ํ•œ๋งฅ", + serverNo: "hm-idc-001", + category: "ํ•œ๋งฅ ์ธํŠธ๋ผ๋„ท", + remarks: "", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.70", + ip2: "192.168.10.5", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "samanerp1!" }, + { tool: "Remote Util", id: "211.206.127.70", pw: "1234์•„์ดํ‹ฐ!" } + ], + monitoring: "win exp, raid X", + serverIdMatch: "srv07d330084", + model: "HPE ProLiant DL360 Gen10", + os: "Windows Server 2016", + cpu: "intel xeon silver4110 CPU @2.10GHz", + ram: "32GB", + storage: ["280GB", "2.7TB"], + purchaseDate: "2020.12.10" + }, + { + company: "ํ•œ๋งฅ", + serverNo: "hm-idc-002", + category: "ํ•œ๋งฅ ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„", + remarks: "๋‹จ๊ฐ€, ์ž…์‚ฌ์ž์ง€์› ์„œ๋ฒ„ (์Šค๋งˆํŠธ ๊ฑด์„ค ์šฉ๋„ ๊ตฌ๋งค)", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.78", + ip2: "192.168.10.13", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "Hanmac2141!" } + ], + monitoring: "win exp, raid X", + serverIdMatch: "srcff5294c84", + model: "HPE ProLiant DL360 Gen10", + os: "Windows Server 2019", + cpu: "intel xeon silver4214R CPU @2.40GHz", + ram: "32GB", + storage: ["280GB", "2.7TB"], + purchaseDate: "" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-001", + category: "์‚ผ์•ˆ ์ธํŠธ๋ผ๋„ท", + remarks: "", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "118.220.172.237", + ip2: "erp.samaneng.com", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "samanerp1!" }, + { tool: "Remote Util", id: "118.220.172.237", pw: "1234์•„์ดํ‹ฐ!" } + ], + monitoring: "O", + serverIdMatch: "newSmintranet", + model: "HPE ProLiant DL360 Gen10", + os: "Windows Server 2016", + cpu: "intel xeon silver4214R CPU @2.40GHz", + ram: "32GB", + storage: ["280GB", "3.27TB"], + purchaseDate: "2019.12.20" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-002", + category: "์‚ผ์•ˆ ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„", + remarks: "", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "118.220.172.249", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "samanerp1!" }, + { tool: "Remote Util", id: "678-605-383-130", pw: "1234์•„์ดํ‹ฐ!" } + ], + monitoring: "์„ค์น˜ X", + serverIdMatch: "INTRANET", + model: "HPE ProLiant DL360 GEN9", + os: "Windows Server 2008 R2", + cpu: "Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz", + ram: "32GB", + storage: ["279GB", "2.72TB"], + purchaseDate: "" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-003", + category: "SATIS 01", + remarks: "๊ตฌ SATIS ์„œ๋ฒ„, ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ ๋ฐœํ–‰(ํšŒ๊ณ„)", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "118.220.172.228", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "satissg11707808" } + ], + monitoring: "์„ค์น˜ X", + serverIdMatch: "satis01", + model: "HPE ProLiant DL380p GEN8", + os: "Windows Server 2008 R2", + cpu: "Intel(R) Xeon(R) CPU E5-2643 0 @ 3.30GHz", + ram: "20GB", + storage: ["100GB", "458GB"], + purchaseDate: "" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-004", + category: "SATIS 02", + remarks: "SATIS ๋ฆฌ๋‰ด์–ผ ๋ฒ„์ „ (ERP ์„œ๋ฒ„)", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "118.220.172.229", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "satissg11707808" } + ], + monitoring: "์„ค์น˜ X", + serverIdMatch: "satis02", + model: "HPE ProLiant DL380p GEN8", + os: "Windows Server 2008 R2", + cpu: "Intel(R) Xeon(R) CPU E5-2643 0 @ 3.30GHz", + ram: "20GB", + storage: ["100GB", "458GB", "18.1TB"], + purchaseDate: "" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-005", + category: "์›น ์„œ๋ฒ„", + remarks: "๋‚จ์–‘์ฃผ ํ…Œ์ŠคํŠธ ์„œ๋ฒ„ (๋„๋ฉ”์ธ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ ์ œ๊ฑฐ 2026.03.11)", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "samanweb.cafe24.com", + ip2: "118.220.172.195", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "saman+2013+web" } + ], + monitoring: "win exp, ํฌํŠธ ์•ˆ์—ด๋ฆผ", + serverIdMatch: "www", + model: "HPE ProLiant DL380p GEN8", + os: "Windwos Server 2012", + cpu: "Intel(R) Xeon(R) CPU E5-2609 0 @ 2.40GHz", + ram: "16GB", + storage: ["100GB", "230GB", "230GB"], + purchaseDate: "" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-006", + category: "PQ DB ์„œ๋ฒ„", + remarks: "", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "118.220.172.231", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "7013ddj10235!" } + ], + monitoring: "O", + serverIdMatch: "src5dd67f2ed", + model: "HPE ProLiant DL360 Gen10", + os: "Windows Server 2019", + cpu: "intel xeon silver4210R CPU @2.40GHz", + ram: "32GB", + storage: ["278GB", "2.18TB"], + purchaseDate: "2024.12.16" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-007", + category: "Oracle DB ์„œ๋ฒ„", + remarks: "", + location: "์„œ๊ด€ 202๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "118.220.172.225", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "7013ddj10235!" } + ], + monitoring: "win exp, raid X", + serverIdMatch: "SAMAN-DB", + model: "HPE ProLiant DL380 GEN9", + os: "Windows Server 2012", + cpu: "Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz", + ram: "64GB", + storage: ["558GB", "1.09TB", "1.09TB"], + purchaseDate: "" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-008", + category: "์•ˆ์ „๊ด€๋ฆฌ", + remarks: "์‚ผ์•ˆ ๊ฐœ๋ฐœ์„œ๋ฒ„2 - AI, SSL, ์žฅํ—ŒTBM, ๋…ธ๋“œ", + location: "์„œ๊ด€ 202๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "1.234.37.171", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "samanerp1!" } + ], + monitoring: "์—ฐ๊ฒฐ X", + serverIdMatch: "", + model: "HPE ProLiant DL380 GEN10", + os: "Windwos Server 2022", + cpu: "Intel Xeon(R) Silver 4210R CPU @ 2.40GHz", + ram: "128GB", + storage: ["278GB", "3.27TB"], + purchaseDate: "2025.04.10" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-idc-009", + category: "๊ฐ€์กฑ์‚ฌ ๊ณตํ†ต๋ฉ”๋‰ด", + remarks: "์‚ผ์•ˆ ๊ฐœ๋ฐœ์„œ๋ฒ„1 - QNA, ๊ธ‰์—ฌ๋ช…์„ธ์„œ", + location: "์„œ๊ด€ 202๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "118.220.172.233", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "samanerp1!" } + ], + monitoring: "O", + serverIdMatch: "srcc9ac928ee", + model: "HPE ProLiant DL380 GEN10", + os: "Windwos Server 2022", + cpu: "Intel Xeon(R) Silver 4210R CPU @ 2.40GHz", + ram: "128GB", + storage: ["278GB", "3.27TB"], + purchaseDate: "2025.04.10" + }, + { + company: "ํ•œ๋ผ", + serverNo: "hl-idc-001", + category: "ํ•œ๋ผ ์ธํŠธ๋ผ๋„ท", + remarks: "์ธํŠธ๋ผ๋„ท,์•ˆ์ „, ์šด์˜, MISO ์„œ๋ฒ„๋กœ ์šด์˜ ์ค‘(win 2008)", + location: "๋™๊ด€ 54๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "1.234.37.143", + ip2: "", + remoteAccess: [ + { tool: "Remote Util", id: "1.234.37.143", pw: "1234dkdlxl!" } + ], + monitoring: "์„ค์น˜ X", + serverIdMatch: "", + model: "HPE ProLiant DL360 GEN9", + os: "Windows Server 2008 R2", + cpu: "Intel(R) Xeon(R) CPU E5-2603 v4 @ 1.70GHz", + ram: "8GB", + storage: ["299GB", "631GB"], + purchaseDate: "" + }, + { + company: "ํ•œ๋ผ", + serverNo: "hl-idc-002", + category: "์•ˆ์ „์ „์‚ฐํ™” ์„œ๋ฒ„ (๋””์ž์ธํŒ€ ์›น)", + remarks: "์ธํŠธ๋ผ๋„ท ์„œ๋ฒ„ ๋‹ค์šด ์‹œ ๋ฐฑ์—…์šฉ ๋Œ€๊ธฐ", + location: "๋™๊ด€ 54๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "1.234.37.144", + ip2: "192.168.20.49", + remoteAccess: [ + { tool: "Remote Util", id: "1.234.37.144", pw: "1234dkdlxl!" } + ], + monitoring: "O", + serverIdMatch: "", + model: "HPE ProLiant DL360 GEN9", + os: "Windows Server 2012", + cpu: "Intel(R) Xeon(R) CPU E5-2603 v4 @ 1.70GHz", + ram: "8GB", + storage: ["299GB", "631GB"], + purchaseDate: "" + }, + { + company: "ํ•œ๋ผ", + serverNo: "hl-idc-003", + category: "๊ฐœ๋ฐœ์„œ๋ฒ„2", + remarks: "PTC ์—ฐ๊ตฌ๋น„๋กœ ๊ตฌ๋งคํ•œ ์˜ˆ๋น„์„œ๋ฒ„2", + location: "๋™๊ด€ 53๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "192.168.20.171", + ip2: "1.234.37.171", + remoteAccess: [ + { tool: "Remote Util", id: "1.234.37.171", pw: "1234dkdlxl!" } + ], + monitoring: "O", + serverIdMatch: "", + model: "HPE ProLiant DL380 Gen10", + os: "Windows Server 2019 Standard", + cpu: "Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz", + ram: "32GB", + storage: ["280GB", "1TB"], + purchaseDate: "2022.09.21" + }, + { + company: "์žฅํ—Œ", + serverNo: "jh-idc-001", + category: "์žฅํ—Œ์ธํŠธ๋ผ๋„ท", + remarks: "BEPs", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.71", + ip2: "192.168.10.6", + remoteAccess: [ + { tool: "Remote Util", id: "211.206.127.71", pw: "1234dkdlxl!" }, + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "Hanmac2141!%" } + ], + monitoring: "์ž ๊ธˆ ๊ฑธ๋ ค์žˆ์Œ", + serverIdMatch: "src775d3e5df", + model: "HPE ProLiant DL380 GEN10", + os: "Windows Server 2019", + cpu: "Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz", + ram: "32GB", + storage: ["280GB", "1TB"], + purchaseDate: "2022.09.21" + }, + { + company: "์žฅํ—Œ", + serverNo: "jh-idc-002", + category: "์žฅํ—Œ ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„", + remarks: "", + location: "๋™๊ด€ 53๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "1.234.37.170", + ip2: "192.168.20.170", + remoteAccess: [ + { tool: "Remote Util", id: "1.234.37.170", pw: "1234dkdlxl!" }, + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "Administrator", pw: "Hanmac2141!" } + ], + monitoring: "์›๊ฒฉ X, O", + serverIdMatch: "", + model: "HPE ProLiant DL360 Gen10", + os: "Windows Server 2019", + cpu: "Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz", + ram: "32GB", + storage: ["280GB", "1TB"], + purchaseDate: "2022.04.01" + }, + { + company: "์žฅํ—Œ", + serverNo: "jh-idc-003", + category: "์ธํŠธ๋ผ๋„ท(๊ตฌ)", + remarks: "ํ˜„์žฌ๋Š” GIT ๋ฐฑ์—… ์œผ๋กœ ์‚ฌ์šฉ", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.110", + ip2: "192.168.10.40", + remoteAccess: [ + { tool: "Remote Util", id: "211.206.127.110", pw: "1234dkdlxl!" }, + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "User", pw: "Hanmac2141!" } + ], + monitoring: "", + serverIdMatch: "", + model: "", + os: "Windows Server 2019", + cpu: "Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz", + ram: "", + storage: [], + purchaseDate: "" + }, + { + company: "(์ฃผ)์žฅํ—Œ", + serverNo: "jh-idc-004", + category: "(์ฃผ) ์žฅํ—Œ ์ธํŠธ๋ผ๋„ท", + remarks: "2025.12.23 IDC ์ด์ „ ์„ค์น˜", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.76", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "User", pw: "Hanmac2141!%" } + ], + monitoring: "win exp, raid X", + serverIdMatch: "DESKTOP-5IL75B7", + model: "", + os: "Windows 10", + cpu: "12th Gen Intel(R) Core(TM) i7-12700F", + ram: "32GB", + storage: ["465GB", "1.81TB"], + purchaseDate: "" + }, + { + company: "PTC", + serverNo: "ptc-idc-001", + category: "PTC์ธํŠธ๋ผ๋„ท", + remarks: "2024.05.22 ์ธํŠธ๋ผ๋„ท์„œ๋ฒ„๋กœ ๊ต์ฒด", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.72", + ip2: "192.168.10.7", + remoteAccess: [ + { tool: "Remote Util", id: "211.206.127.72", pw: "1234dkdlxl!" } + ], + monitoring: "์„ค์น˜ X", + serverIdMatch: "", + model: "SYSTEM X3650 M2", + os: "Windows Server 2008 R2", + cpu: "Intel(R) Xeon(R) CPU E5520 @ 2.27GHz", + ram: "16GB", + storage: ["556GB"], + purchaseDate: "" + }, + { + company: "PTC", + serverNo: "ptc-idc-002", + category: "์˜ˆ๋น„์„œ๋ฒ„", + remarks: "PTC ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„์„œ๋ฒ„", + location: "์„œ๊ด€ 204๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "192.168.10.8", + ip2: "", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "1234dkdlxl!" } + ], + monitoring: "O", + serverIdMatch: "", + model: "HPE ProLiant DL360 GEN10", + os: "Windows Server 2019", + cpu: "Intel Xeon(R) Silver 4210R CPU @ 2.40GHz", + ram: "32GB", + storage: ["278GB", "1.09TB"], + purchaseDate: "2022.04.01" + }, + { + company: "PTC", + serverNo: "ptc-idc-003", + category: "DB ๋ฐฑ์—… ์„œ๋ฒ„", + remarks: "2024.05.22 ๋ณ€๊ฒฝ (๋ฐ์Šคํฌํƒ‘)", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.74", + ip2: "192.168.10.9", + remoteAccess: [ + { tool: "Remote Util", id: "211.206.127.74", pw: "1234dkdlxl!" } + ], + monitoring: "์„ค์น˜ X", + serverIdMatch: "", + model: "", + os: "Window 7", + cpu: "Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz", + ram: "4GB", + storage: ["593GB", "1.23TB"], + purchaseDate: "" + }, + { + company: "๋ฐ”๋ก ", + serverNo: "br-idc-001", + category: "์ธํŠธ๋ผ๋„ท", + remarks: "", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "211.206.127.75", + ip2: "192.168.10.10", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "Hanmac2141!%" } + ], + monitoring: "O", + serverIdMatch: "srcf0136042d", + model: "HPE ProLiant DL360 GEN10", + os: "Windows Server 2022", + cpu: "Intel Xeon(R) Silver 4210R CPU @ 2.40GHz", + ram: "32GB", + storage: ["280GB", "2.18TB"], + purchaseDate: "2025.04.14" + }, + { + company: "ํ˜„ํƒ€", + serverNo: "ht-idc-001", + category: "์ธํŠธ๋ผ๋„ท", + remarks: "", + location: "๋™๊ด€ 53๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip1: "1.234.37.172", + ip2: "192.168.20.172", + remoteAccess: [ + { tool: "์›๊ฒฉ๋ฐ์Šคํฌํƒ‘", id: "administrator", pw: "Hanmac2141!" } + ], + monitoring: "O", + serverIdMatch: "src901e49933", + model: "HPE ProLiant DL380 GEN10", + os: "Windows Server 2019", + cpu: "Intel Xeon Silver 4210R CPU @ 2.40GHz", + ram: "32GB", + storage: ["280GB", "1TB"], + purchaseDate: "2022.09.21" + } +]; + +export const idcStorages: IdcStorage[] = [ + { + company: "์‚ผ์•ˆ", + serverNo: "sa-nas-001", + category: "์ธํŠธ๋ผ๋„ท ๋ฐฑ์—… ์Šคํ† ๋ฆฌ์ง€", + remarks: "", + location: "์„œ๊ด€ 203๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip: "118.220.172.246", + remoteAccess: [{ tool: "์›๊ฒฉ", id: "administrator", pw: "sg11707808" }], + model: "Promiss R Series", + capacity: "36TB", + purchaseDate: "" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-nas-002", + category: "์„ฑ๊ณผํ’ˆ ์Šคํ† ๋ฆฌ์ง€", + remarks: "๋งค๋‹ˆ์ง€๋จผํŠธ ์ ‘์† ํ™•์ธ ๋ถˆ๊ฐ€", + location: "์„œ๊ด€ 205๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip: "118.220.172.248", + managementIp: "118.220.172.247", + remoteAccess: [{ tool: "์›๊ฒฉ", id: "administrator", pw: "sg11707808" }], + model: "ENC_3U_16BAY_D", + capacity: "23TB", + purchaseDate: "2019.06.03" + }, + { + company: "์‚ผ์•ˆ", + serverNo: "sa-nas-003", + category: "์„ฑ๊ณผํ’ˆ ๋ฐฑ์—… ์Šคํ† ๋ฆฌ์ง€", + remarks: "", + location: "์„œ๊ด€ 202๋ฒˆ", + managerPrimary: "๊น€์ฒ ์ˆ˜", + managerSecondary: "ํ™๊ธธ๋™", + ip: "118.220.172.241", + managementIp: "118.220.172.240", + remoteAccess: [ + { tool: "์›๊ฒฉ", id: "administrator", pw: "saman1!" }, + { tool: "์›๊ฒฉ", id: "admin0", pw: "Root1234" } + ], + model: "Promiss R Series", + capacity: "48TB", + purchaseDate: "2025.03.13" + } +]; diff --git a/backup_temp/src/data/mockData.ts b/backup_temp/src/data/mockData.ts new file mode 100644 index 0000000..d848549 --- /dev/null +++ b/backup_temp/src/data/mockData.ts @@ -0,0 +1,84 @@ +export interface Category { + id: string; + name: string; + count: number; +} + +export interface Asset { + id: string; + categoryName: string; + name: string; + quantity: number; + internalCode: string; + serialNumber: string; + department: string; + user: string; + acquisitionDate: string; + status: string; + location: string; +} + +export interface HardwareSpec { + id: string; + pcName: string; + department: string; + userName: string; + os: string; + cpu: string; + memory: string; + disk: string; + macAddress: string; + ipAddress: string; + graphicCard: string; +} + +export const mockCategories: Category[] = [ + { id: '1', name: 'PC', count: 1 }, + { id: '2', name: '๋ชจ๋‹ˆํ„ฐ', count: 5 }, + { id: '3', name: '๋…ธํŠธ๋ถ', count: 2 }, +]; + +export const mockAssets: Asset[] = [ + { + id: '1', + categoryName: 'PC', + name: 'PC', + quantity: 1, + internalCode: 'PC20230411001', + serialNumber: 'SN-001-A1', + department: 'ํ•œ๋งฅ๊ธฐ์ˆ ', + user: '์ด๊ด€ํ˜•', + acquisitionDate: '2023-04-11', + status: '์ •์ƒ', + location: '๋ณธ์‚ฌ 3์ธต', + }, +]; + +export const mockHardwareSpecs: HardwareSpec[] = [ + { + id: '1', + pcName: 'DESKTOP-G1DVL26', + department: 'ํ•œ๋งฅ๊ธฐ์ˆ ', + userName: '์ด์ค€๊ถŒ', + os: 'Microsoft Windows 10 Pro 10.0.19044', + cpu: 'Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz', + memory: 'Samsung 4 GB / Samsung 4 GB', + disk: 'ST2000DM001-1CH164 1.82 TB / Samsung SSD 850 EVO 120GB', + macAddress: '0862664B98A3', + ipAddress: '172.16.9.68', + graphicCard: 'NVIDIA GeForce GTX 750', + }, + { + id: '2', + pcName: 'DESKTOP-BNBPOUP', + department: 'ํ•œ๋งฅ๊ธฐ์ˆ ', + userName: '์ฃผ์™„๊ธฐ ์—ฐ๊ตฌ์›', + os: 'Microsoft Windows 10 Pro 10.0.19045', + cpu: 'Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz', + memory: 'Samsung 8 GB / Samsung 8 GB', + disk: 'ST1000DM003-1CH162 931.51 GB / Samsung SSD 840 EVO 120GB', + macAddress: 'E03F4948ECC6', + ipAddress: '172.16.9.23', + graphicCard: 'Intel(R) HD Graphics 4600', + }, +]; diff --git a/backup_temp/src/index.css b/backup_temp/src/index.css new file mode 100644 index 0000000..cc457c7 --- /dev/null +++ b/backup_temp/src/index.css @@ -0,0 +1,26 @@ +:root { + font-family: "Pretendard Variable", 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; + line-height: 1.5; + font-weight: 400; + letter-spacing: -0.02em; + + color-scheme: light; + color: #111827; + background-color: #F9FAFB; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + margin: 0; + display: flex; + min-width: 320px; + min-height: 100vh; +} + +#root { + width: 100%; +} diff --git a/backup_temp/src/main.tsx b/backup_temp/src/main.tsx new file mode 100644 index 0000000..3d7150d --- /dev/null +++ b/backup_temp/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/backup_temp/์„œ๋ฒ„๋ชฉ๋ก ๋ฐ IDC ์„œ๋ฒ„ ์œ„์น˜ - ์„œ๋ฒ„ ๋ฐ ์Šคํ† ๋ฆฌ์ง€ ๋ชฉ๋ก(IDC).csv b/backup_temp/์„œ๋ฒ„๋ชฉ๋ก ๋ฐ IDC ์„œ๋ฒ„ ์œ„์น˜ - ์„œ๋ฒ„ ๋ฐ ์Šคํ† ๋ฆฌ์ง€ ๋ชฉ๋ก(IDC).csv new file mode 100644 index 0000000..509bafe --- /dev/null +++ b/backup_temp/์„œ๋ฒ„๋ชฉ๋ก ๋ฐ IDC ์„œ๋ฒ„ ์œ„์น˜ - ์„œ๋ฒ„ ๋ฐ ์Šคํ† ๋ฆฌ์ง€ ๋ชฉ๋ก(IDC).csv @@ -0,0 +1,49 @@ +IDC,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +์„œ๋ฒ„๋ชฉ๋ก,,,,,,,,,,,,,,,,,,,,,,,,,,ํ•œ๋งฅ,LMS ์„œ๋ฒ„,mdf, +ํšŒ์‚ฌ,์„œ๋ฒ„๋ฒˆํ˜ธ,๊ตฌ๋ถ„,๋น„๊ณ ,์„ค์น˜์œ„์น˜,๋‹ด๋‹น์ž,,IP ์ฃผ์†Œ,,์›๊ฒฉ์ ‘์†,,,๋ชจ๋‹ˆํ„ฐ๋ง ์—ฌ๋ถ€,"์„œ๋ฒ„ ์ด๋ฆ„ ID + ์ผ์น˜ ์—ฌ๋ถ€, ์ „ ์„œ๋ฒ„ ์ด๋ฆ„",์ œ์กฐ์‚ฌ ๋ฐ ๋ชจ๋ธ๋ช…,OS,CPU,RAM,Storage1,Storage2,Storage3,๊ณ„์‚ฐ์„œ,,,,,์‚ผ์•ˆ,XRํ”Œ๋ž˜๊ทธ์‹ญ ์Šคํ† ๋ฆฌ์ง€,,20250414 +,,,,,์ •,๋ถ€,IP,IP2,์ ‘์†๋„๊ตฌ,์•„์ด๋””,๋น„๋นŒ๋ฒˆํ˜ธ,,,,,,,,,,,,,,,์žฅํ—Œ,"์Šคํ† ๋ฆฌ์ง€, ์„œ๋ฒ„",mdf ์ถ”์ •, +ํ•œ๋งฅ,hm-idc-001,ํ•œ๋งฅ ์ธํŠธ๋ผ๋„ท,,์„œ๊ด€ 204๋ฒˆ,,,211.206.127.70,192.168.10.5,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,samanerp1!,"win exp, raid X",srv07d330084,HPE ProLiant DL360 Gen10,Windows Server 2016,intel xeon silver4110 CPU @2.10GHz 2.10GHZ,32GB,280GB,2.7TB,,20201210 ์ถ”์ •,ํ•œ๋งฅ,,,,ํ•œ๋ผ,๋ฐฑ์—…์„œ๋ฒ„,mdf, +,,,,,,,,,Remote Util,211.206.127.70,1234์•„์ดํ‹ฐ!,,,,,,,,,,,,,,,,,, +,hm-idc-002,ํ•œ๋งฅ ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„,"๋‹จ๊ฐ€, ์ž…์‚ฌ์ž์ง€์› ์„œ๋ฒ„ (4/1 ์žฅํ—Œ์‚ฐ์—… ์ด๋ฆ„์œผ๋กœ ์Šค๋งˆํŠธ ๊ฑด์„ค ์šฉ๋„ ๊ตฌ๋งค)",์„œ๊ด€ 205๋ฒˆ,,,211.206.127.78,192.168.10.13,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,Hanmac2141!,"win exp, raid X",srcff5294c84,HPE ProLiant DL360 Gen10,Windows Server 2019,intel xeon silver4214R CPU @2.40GHz 2.39GHZ,32GB,280GB,2.7TB,,,,,,,,,, +์‚ผ์•ˆ,sa-idc-001,์‚ผ์•ˆ ์ธํŠธ๋ผ๋„ท,,์„œ๊ด€ 204๋ฒˆ,,,118.220.172.237,erp.samaneng.com,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,samanerp1!,O,newSmintranet,HPE ProLiant DL360 Gen10,Windows Server 2016,intel xeon silver4214R CPU @2.40GHz 2.39GHZ,32GB,280GB,3.27TB,,20191220 ์ถ”์ •,์‚ผ์•ˆ,,,,,,, +,,,,,,,,,Remote Util,118.220.172.237,1234์•„์ดํ‹ฐ!,,,,,,,,,,,,,,,,,, +,sa-idc-002,์‚ผ์•ˆ ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„,,์„œ๊ด€ 204๋ฒˆ,,,118.220.172.249,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,samanerp1!,์„ค์น˜ X,INTRANET,HPE ProLiant DL360 GEN9,Windows Server 2008 R2,Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz 2.40GHz,32GB,279GB,2.72TB,,,,,,,,,, +,,,,,,,,,Remote Util,678-605-383-130,1234์•„์ดํ‹ฐ!,,,,,,,,,,,,,,,,,, +,sa-idc-003,SATIS 01,"๊ตฌ SATIS ์„œ๋ฒ„, ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ ๋ฐœํ–‰(ํšŒ๊ณ„)",์„œ๊ด€ 204๋ฒˆ,,,118.220.172.228,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,satissg11707808,์„ค์น˜ X,satis01,HPE ProLiant DL380p GEN8,Windows Server 2008 R2,Intel(R) Xeon(R) CPU E5-2643 0 @ 3.30GHz 3.30GHz,20GB,100GB,458GB,,,,,,,,,, +,sa-idc-004,SATIS 02,SATIS ๋ฆฌ๋‰ด์–ผ ๋ฒ„์ „ (ERP ์„œ๋ฒ„),์„œ๊ด€ 204๋ฒˆ,,,118.220.172.229,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,satissg11707808,์„ค์น˜ X,satis02,HPE ProLiant DL380p GEN8,Windows Server 2008 R2,Intel(R) Xeon(R) CPU E5-2643 0 @ 3.30GHz 3.30GHz,20GB,100GB,458GB,18.1TB,,,,,,,,, +,sa-idc-005,์›น ์„œ๋ฒ„,๋‚จ์–‘์ฃผ ํ…Œ์ŠคํŠธ ์„œ๋ฒ„ (๋„๋ฉ”์ธ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ ์ œ๊ฑฐ 2026.03.11),์„œ๊ด€ 204๋ฒˆ,,,samanweb.cafe24.com,118.220.172.195,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,saman+2013+web,"win exp, ํฌํŠธ ์•ˆ์—ด๋ฆผ",www,HPE ProLiant DL380p GEN8,Windwos Server 2012,Intel(R) Xeon(R) CPU E5-2609 0 @ 2.40GHz 2.40GHz,16GB,100GB,230GB,230GB,,,,,,,,, +,sa-idc-006,PQ DB ์„œ๋ฒ„,,์„œ๊ด€ 204๋ฒˆ,,,118.220.172.231,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,7013ddj10235!, O,src5dd67f2ed,HPE ProLiant DL360 Gen10,Windows Server 2019,intel xeon silver4210R CPU @2.40GHz 2.39GHZ,32GB,278GB,2.18TB,,20241216 ๊ตฌ๋งค๊ต์ฒด,์‚ผ์•ˆ,,,,,,, +,sa-idc-007,Oracle DB ์„œ๋ฒ„,,์„œ๊ด€ 202๋ฒˆ,,,118.220.172.225,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,7013ddj10235!,"win exp, raid X",SAMAN-DB,HPE ProLiant DL380 GEN9,Windows Server 2012,Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz 2.20GHz,64GB,558GB,1.09TB,1.09TB,,,,,,,,, +,sa-idc-008,์•ˆ์ „๊ด€๋ฆฌ,"์‚ผ์•ˆ ๊ฐœ๋ฐœ์„œ๋ฒ„2 - AI, SSL, ์žฅํ—ŒTBM, ๋…ธ๋“œ",์„œ๊ด€ 202๋ฒˆ,,,1.234.37.171,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,samanerp1!,์—ฐ๊ฒฐ X,,HPE ProLiant DL380 GEN10,Windwos Server 2022,Intel Xeon(R) Silver 4210R CPU @ 2.40GHz,128GB,278GB,3.27TB,,20250410 ์„ค์น˜,์‚ผ์•ˆ,,,,,,, +,sa-idc-009,๊ฐ€์กฑ์‚ฌ ๊ณตํ†ต๋ฉ”๋‰ด,"์‚ผ์•ˆ ๊ฐœ๋ฐœ์„œ๋ฒ„1 - QNA, ๊ธ‰์—ฌ๋ช…์„ธ์„œ",์„œ๊ด€ 202๋ฒˆ,,,118.220.172.233,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,samanerp1!,O,srcc9ac928ee,HPE ProLiant DL380 GEN10,Windwos Server 2022,Intel Xeon(R) Silver 4210R CPU @ 2.40GHz,128GB,278GB,3.27TB,,20250410 ์„ค์น˜,์‚ผ์•ˆ,,,,,,, +ํ•œ๋ผ,hl-idc-001,ํ•œ๋ผ ์ธํŠธ๋ผ๋„ท,"์ธํŠธ๋ผ๋„ท,์•ˆ์ „, ์šด์˜, MISO ์„œ๋ฒ„๋กœ ์šด์˜ ์ค‘(win 2008)",๋™๊ด€ 54๋ฒˆ,,,1.234.37.143,,Remote Util,1.234.37.143,1234dkdlxl!,์„ค์น˜ X,,HPE ProLiant DL360 GEN9,Windows Server 2008 R2,Intel(R) Xeon(R) CPU E5-2603 v4 @ 1.70GHz 1.70GHz,8GB,299GB,631GB,,,,,,,,,, +,hl-idc-002,์•ˆ์ „์ „์‚ฐํ™” ์„œ๋ฒ„ (๋””์ž์ธํŒ€ ์›น),"์ธํŠธ๋ผ๋„ท ์„œ๋ฒ„ ๋‹ค์šด ์‹œ ๋ฐฑ์—…์šฉ ๋Œ€๊ธฐ, (์ž„์‹œ) ๋””์ž์ธํŒ€ ์›น ํผ๋ธ”๋ฆฌ์‹ฑ ์„œ๋ฒ„",๋™๊ด€ 54๋ฒˆ,,,1.234.37.144,192.168.20.49,Remote Util,1.234.37.144,1234dkdlxl!,O,,HPE ProLiant DL360 GEN9,Windows Server 2012,Intel(R) Xeon(R) CPU E5-2603 v4 @ 1.70GHz 1.70GHz,8GB,299GB,631GB,,,,,,,,,, +,hl-idc-003,๊ฐœ๋ฐœ์„œ๋ฒ„2,PTC ์—ฐ๊ตฌ๋น„๋กœ ๊ตฌ๋งคํ•œ ์˜ˆ๋น„์„œ๋ฒ„2 ,๋™๊ด€ 53๋ฒˆ,,,192.168.20.171,1.234.37.171,Remote Util,1.234.37.171,1234dkdlxl!,O,,HPE ProLiant DL380 Gen10,Windows Server 2019 Standard,Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz,32GB,280GB,1TB,,20220921 ์ถ”์ •,ptc,,,,,,, +,,,"์ด์ „ : ํ•˜์ˆ˜๋„์ž์‚ฐ ์†Œ์Šค+ํ”„๋กœ๊ทธ๋žจ ํ˜„์žฌ : ํฐ๊ธธ ์„œ๋น„์Šค์šฉ xampp+ PostgreSQL, BEPs",,,,,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,Hanmac2141!%,,src775d3e5df,,,,,,,,,,,,,,,, +์žฅํ—Œ,jh-idc-001,์žฅํ—Œ์ธํŠธ๋ผ๋„ท,,์„œ๊ด€ 205๋ฒˆ,,,211.206.127.71,192.168.10.6,Remote Util,211.206.127.71,1234dkdlxl!,์ž ๊ธˆ ๊ฑธ๋ ค์žˆ์Œ,,HPE ProLiant DL380 GEN10,Windows Server 2019,Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz 2.39GHz,32GB,280GB,1TB,,20220921 ์ถ”์ •,ptc,,,,,,, +,jh-idc-002,์žฅํ—Œ ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„,,๋™๊ด€ 53๋ฒˆ,,,1.234.37.170,192.168.20.170,Remote Util,1.234.37.170,1234dkdlxl!,"์›๊ฒฉ X, O +",,HPE ProLiant DL360 Gen10,Windows Server 2019,Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz 2.39GHz,32GB,280GB,1TB,,20220401 ์ถ”์ •,์žฅํ—Œ,,,,,,, +,,,,,,,,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,Administrator,Hanmac2141!,,,,,,,,,,,,,,,,,, +,jh-idc-003,์ธํŠธ๋ผ๋„ท(๊ตฌ),ํ˜„์žฌ๋Š” GIT ๋ฐฑ์—… ์œผ๋กœ ์‚ฌ์šฉ,์„œ๊ด€ 205๋ฒˆ,,,211.206.127.110,192.168.10.40,Remote Util,211.206.127.110,1234dkdlxl!,,,,Windows Server 2019,Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz,,,,,,,,,,,,, +,,,,,,,,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,User,Hanmac2141!,,,,,,,,,,,,,,,,,, +(์ฃผ)์žฅํ—Œ,jh-idc-004,(์ฃผ) ์žฅํ—Œ ์ธํŠธ๋ผ๋„ท,2025.12.23 (์ฃผ) ์žฅํ—Œ ์„ผํ„ฐ MDF์—์„œ IDC๋กœ ์ด์ „ ์„ค์น˜,์„œ๊ด€ 205๋ฒˆ,,,211.206.127.76,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,User,Hanmac2141!%,"win exp, raid X",DESKTOP-5IL75B7,,Windows 10,12th Gen Intel(R) Core(TM) i7-12700F,32GB,465GB,1.81TB,,,,,,,,,, +PTC,ptc-idc-001,PTC์ธํŠธ๋ผ๋„ท,"๊ตฌ ํŒŒ์ผ ์„œ๋ฒ„(๋ถ€์„œ์ž๋ฃŒ ๋ฐฑ์—…์šฉ), 2024.05.22 ์ธํŠธ๋ผ๋„ท์„œ๋ฒ„๋กœ ๊ต์ฒด",์„œ๊ด€ 205๋ฒˆ,,,211.206.127.72,192.168.10.7,Remote Util,211.206.127.72,1234dkdlxl!,์„ค์น˜ X,,SYSTEM X3650 M2,Windows Server 2008 R2,Intel(R) Xeon(R) CPU E5520 @ 2.27GHz 2.26GHz,16GB,556GB,,,,,,,,,,, +,ptc-idc-002,์˜ˆ๋น„์„œ๋ฒ„,PTC ์ธํŠธ๋ผ๋„ท ์˜ˆ๋น„์„œ๋ฒ„,์„œ๊ด€ 204๋ฒˆ,,,192.168.10.8,,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,1234dkdlxl!,O,,HPE ProLiant DL360 GEN10,Windows Server 2019,Intel Xeon(R) Silver 4210R CPU @ 2.40GHz,32GB,278GB,1.09TB,,20220401 ์ถ”์ •,์žฅํ—Œ,,,,,,, +,ptc-idc-003,DB ๋ฐฑ์—… ์„œ๋ฒ„,"๊ตฌ ํŒŒ์ผ ์ธํŠธ๋ผ๋„ท, 2024.05.22์— DB ๋ฐฑ์—… ํ…Œ์ŠคํŠธ ์„œ๋ฒ„๋กœ ๋ณ€๊ฒฝ (๋ฐ์Šคํฌํƒ‘)",์„œ๊ด€ 205๋ฒˆ,,,211.206.127.74,192.168.10.9,Remote Util,211.206.127.74,1234dkdlxl!,์„ค์น˜ X,,,Window 7,Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz 2.13GHz,4GB,593GB,1.23TB,,,,,,,,,, +๋ฐ”๋ก ,br-idc-001,์ธํŠธ๋ผ๋„ท,,์„œ๊ด€ 205๋ฒˆ,,,211.206.127.75,192.168.10.10,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,Hanmac2141!%,O,srcf0136042d,HPE ProLiant DL360 GEN10,Windows Server 2022,Intel Xeon(R) Silver 4210R CPU @ 2.40GHz,32GB,280GB,2.18TB,,20250414 ์ถ”์ •,๋ฐ”๋ก ,,,,,,, +ํ˜„ํƒ€,ht-idc-001,์ธํŠธ๋ผ๋„ท,,๋™๊ด€ 53๋ฒˆ,,,1.234.37.172,192.168.20.172,์›๊ฒฉ๋ฐ์Šคํฌํƒ‘,administrator,Hanmac2141!,O,src901e49933,HPE ProLiant DL380 GEN10,Windows Server 2019,Intel Xeon Silver 4210R CPU @ 2.40GHz 2.39GHz,32GB,280GB,1TB,,20220921 ์ถ”์ •,ptc,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +์Šคํ† ๋ฆฌ์ง€ ๋ชฉ๋ก,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ํšŒ์‚ฌ,์„œ๋ฒ„๋ฒˆํ˜ธ,๊ตฌ๋ถ„,๋น„๊ณ ,์„ค์น˜์œ„์น˜,๋‹ด๋‹น์ž,,IP ์ฃผ์†Œ,,์›๊ฒฉ์ ‘์†,,,,,,๋ชจ๋ธ๋ช…,์šฉ๋Ÿ‰,,,,,,,,,,,,, +,,,,,์ •,๋ถ€,,,์ ‘์†๋„๊ตฌ,์•„์ด๋””,๋น„๋นŒ๋ฒˆํ˜ธ,,,,,,,,,,,,,,,,,, +์‚ผ์•ˆ,sa-das-001,,"Satis01, Satis02 ๊ด‘์ผ€์ด๋ธ” ์—ฐ๊ฒฐ (๋ฌผ๋ฆฌ์—ฐ๊ฒฐ)",์„œ๊ด€ 205๋ฒˆ,,,,,,,,,,,,,,,,,,,,,,,,, +,sa-nas-001,์ธํŠธ๋ผ๋„ท ๋ฐฑ์—… ์Šคํ† ๋ฆฌ์ง€,,์„œ๊ด€ 203๋ฒˆ,,,(IDC) 118.220.172.246,,์›๊ฒฉ,administrator,sg11707808,,,,Promiss R Series,36TB,,,,,,,,,,,,, +,sa-nas-002,์„ฑ๊ณผํ’ˆ ์Šคํ† ๋ฆฌ์ง€,,์„œ๊ด€ 205๋ฒˆ,,,(IDC) 118.220.172.248,,์›๊ฒฉ,administrator,sg11707808,,,,ENC_3U_16BAY_D // SEAGATE ST2000NM0045,23TB,,,,,20190603 ์ถ”์ •,์‚ผ์•ˆ,,,,,,, +,,,๋งค๋‹ˆ์ง€๋จผํŠธ ์ ‘์† ํ™•์ธ ๋ถˆ๊ฐ€ (์ฝ˜์†” ์—ฐ๊ฒฐ ํ›„ ํŽ˜์ด์ง€ ์˜คํ”ˆ ํ•„์š”),,,,(๋งค๋‹ˆ์ง€๋จผํŠธ) 118.220.172.247,,์›๊ฒฉ,-,-,,,,,,,,,,,,,,,,,, +,sa-nas-003,์„ฑ๊ณผํ’ˆ ๋ฐฑ์—… ์Šคํ† ๋ฆฌ์ง€,,์„œ๊ด€ 202๋ฒˆ,,,(IDC) 118.220.172.241,,์›๊ฒฉ,administrator,saman1!,,,,Promiss R Series,48TB,,,,,20250313,์‚ผ์•ˆ,,,,,,, +,,,,,,,(๋งค์ง€๋‹ˆ๋จผํŠธ) 118.220.172.240,,์›๊ฒฉ,admin0,Root1234,,,,,,,,,,,,,,,,,, +ํ•œ๋ผ,hl-das-001,,ํŒŒ์ผ์„œ๋ฒ„ ์ •๋ณด ์—†์Œ(์ ‘์† ๋ถˆ๊ฐ€),๋™๊ด€ 54๋ฒˆ,,,,,,,,,,,,,,,,,20190701 ์ถ”์ •,ํ•œ๋ผ,(ํ•œ๋ผ ํŒŒ์ผ์„œ๋ฒ„๋„ ๋™์ผ์ผ์ž ์ถ”์ •),,,,,, +,hl-das-002,,,๋™๊ด€ 54๋ฒˆ,,,,,,,,,,,,,,,,,,,,,,,,, \ No newline at end of file diff --git a/backup_temp/์„œ๋ฒ„๋ชฉ๋ก ๋ฐ IDC ์„œ๋ฒ„ ์œ„์น˜.xlsx b/backup_temp/์„œ๋ฒ„๋ชฉ๋ก ๋ฐ IDC ์„œ๋ฒ„ ์œ„์น˜.xlsx new file mode 100644 index 0000000..8c41508 Binary files /dev/null and b/backup_temp/์„œ๋ฒ„๋ชฉ๋ก ๋ฐ IDC ์„œ๋ฒ„ ์œ„์น˜.xlsx differ diff --git a/package-lock.json b/package-lock.json index 1cdfe37..d08dc5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -499,9 +499,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -516,9 +513,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -533,9 +527,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -550,9 +541,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -567,9 +555,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -584,9 +569,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -601,9 +583,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -618,9 +597,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -635,9 +611,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -652,9 +625,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -669,9 +639,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -686,9 +653,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -703,9 +667,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ diff --git a/src/components/Modal/BaseModal.ts b/src/components/Modal/BaseModal.ts new file mode 100644 index 0000000..8830c5f --- /dev/null +++ b/src/components/Modal/BaseModal.ts @@ -0,0 +1,46 @@ +/** + * ๋ชจ๋“  ๋ชจ๋‹ฌ์˜ ๊ณตํ†ต ๊ธฐ๋Šฅ (๋‹ซ๊ธฐ, ESC ์ฒ˜๋ฆฌ, ๋ฐฐ๊ฒฝ ํด๋ฆญ ๋“ฑ)์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฒ ์ด์Šค ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. + */ +export function initBaseModal() { + const modals = document.querySelectorAll('.modal-overlay'); + const closeButtons = document.querySelectorAll('.btn-icon, [id^="btn-cancel-"]'); + + // ๋ชจ๋“  ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ ํ•จ์ˆ˜ + const closeAllModals = () => { + modals.forEach(modal => modal.classList.add('hidden')); + // SW ๊ด€๋ จ ์ถ”๊ฐ€ ๋ชจ๋‹ฌ ์ฒ˜๋ฆฌ + document.getElementById('sw-user-modal')?.classList.add('hidden'); + document.getElementById('sw-user-edit-modal')?.classList.add('hidden'); + document.getElementById('dashboard-detail-modal')?.classList.add('hidden'); + }; + + // ๋‹ซ๊ธฐ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ + closeButtons.forEach(btn => { + btn.addEventListener('click', closeAllModals); + }); + + // ESC ํ‚ค๋กœ ๋‹ซ๊ธฐ + window.addEventListener('keydown', (e) => { + if (e.key === 'Escape') closeAllModals(); + }); + + // ๋ฐฐ๊ฒฝ(Overlay) ํด๋ฆญ ์‹œ ๋‹ซ๊ธฐ + modals.forEach(modal => { + modal.addEventListener('click', (e) => { + if (e.target === modal) closeAllModals(); + }); + }); + + return { closeAllModals }; +} + +/** + * ํŠน์ • ๋ชจ๋‹ฌ์„ ์—ฝ๋‹ˆ๋‹ค. + * @param modalId ๋ชจ๋‹ฌ ์—˜๋ฆฌ๋จผํŠธ์˜ ID + */ +export function openModal(modalId: string) { + const modal = document.getElementById(modalId); + if (modal) { + modal.classList.remove('hidden'); + } +} diff --git a/src/components/Modal/HWModal.ts b/src/components/Modal/HWModal.ts new file mode 100644 index 0000000..b62ce13 --- /dev/null +++ b/src/components/Modal/HWModal.ts @@ -0,0 +1,112 @@ +import { state } from '../../state'; +import { HardwareAsset } from '../../excelHandler'; +import { openModal } from './BaseModal'; + +/** + * ํ•˜๋“œ์›จ์–ด(์„œ๋ฒ„, ์ „์‚ฐ๋น„ํ’ˆ ๋“ฑ) ๋ชจ๋‹ฌ ์ดˆ๊ธฐํ™” ๋ฐ ๋กœ์ง ์ œ์–ด + */ +export function initHWModal(renderContent: () => void, closeModals: () => void) { + const hwForm = document.getElementById('hw-asset-form') as HTMLFormElement; + const btnSaveHw = document.getElementById('btn-save-hw-asset') as HTMLButtonElement; + const btnDeleteHw = document.getElementById('btn-delete-hw-asset') as HTMLButtonElement; + + // ์ €์žฅ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnSaveHw?.addEventListener('click', (e) => { + e.preventDefault(); + if (!hwForm.checkValidity()) { hwForm.reportValidity(); return; } + + const id = (document.getElementById('hw-asset-id') as HTMLInputElement).value; + const fileInput = document.getElementById('hw-ํ’ˆ์˜์„œ') as HTMLInputElement; + const ํ’ˆ์˜์„œ๋ช… = fileInput.files && fileInput.files.length > 0 ? fileInput.files[0].name : (document.getElementById('hw-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText.replace('๐Ÿ“Ž', ''); + + const newAsset: HardwareAsset = { + id: id || Math.random().toString(36).substring(2, 9), + type: (document.getElementById('hw-asset-type') as HTMLInputElement).value, + ๋ฒ•์ธ: (document.getElementById('hw-๋ฒ•์ธ') as HTMLInputElement).value, + ์ž์‚ฐ์ฝ”๋“œ: (document.getElementById('hw-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value, + ๋ช…์นญ: (document.getElementById('hw-๋ช…์นญ') as HTMLInputElement).value, + ์œ„์น˜: (document.getElementById('hw-์œ„์น˜') as HTMLInputElement).value, + ๊ด€๋ฆฌ์ž: (document.getElementById('hw-๊ด€๋ฆฌ์ž') as HTMLInputElement).value, + IP์ฃผ์†Œ: (document.getElementById('hw-IP์ฃผ์†Œ') as HTMLInputElement).value, + MACaddress: (document.getElementById('hw-MACaddress') as HTMLInputElement).value, + OS: (document.getElementById('hw-OS') as HTMLInputElement).value, + HW์‚ฌ์–‘: (document.getElementById('hw-HW์‚ฌ์–‘') as HTMLTextAreaElement).value, + ๊ตฌ๋งค์ผ: (document.getElementById('hw-๊ตฌ๋งค์ผ') as HTMLInputElement).value, + ๊ธˆ์•ก: (document.getElementById('hw-๊ธˆ์•ก') as HTMLInputElement).value, + ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('hw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, + ํ’ˆ์˜์„œ๋ช…, + ๋น„ํ’ˆ์œ ํ˜•: (document.getElementById('hw-asset-type') as HTMLInputElement).value === '์ „์‚ฐ๋น„ํ’ˆ' + ? (document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•') as HTMLSelectElement).value : undefined + }; + + if (id) { + const idx = state.masterData.hw.findIndex(a => a.id === id); + if(idx !== -1) state.masterData.hw[idx] = newAsset; + } else { + state.masterData.hw.push(newAsset); + } + + closeModals(); + renderContent(); + }); + + // ์‚ญ์ œ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnDeleteHw?.addEventListener('click', (e) => { + e.preventDefault(); + const id = (document.getElementById('hw-asset-id') as HTMLInputElement).value; + if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { + state.masterData.hw = state.masterData.hw.filter(a => a.id !== id); + closeModals(); + renderContent(); + } + }); +} + +/** + * ํ•˜๋“œ์›จ์–ด ์ƒ์„ธ ๋ชจ๋‹ฌ ์—ด๊ธฐ + * @param asset ์ˆ˜์ • ์‹œ ์ž์‚ฐ ๋ฐ์ดํ„ฐ, ์‹ ๊ทœ ์‹œ undefined + */ +export function openHwModal(asset?: HardwareAsset) { + const hwModal = document.getElementById('hw-asset-modal') as HTMLDivElement; + const hwForm = document.getElementById('hw-asset-form') as HTMLFormElement; + const deleteBtn = document.getElementById('btn-delete-hw-asset')!; + + openModal('hw-asset-modal'); + hwForm.reset(); + + if (asset) { + document.getElementById('hw-modal-title')!.textContent = '์ž์‚ฐ ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •'; + deleteBtn.style.display = 'block'; + + (document.getElementById('hw-asset-id') as HTMLInputElement).value = asset.id; + (document.getElementById('hw-asset-type') as HTMLInputElement).value = asset.type; + (document.getElementById('hw-๋ฒ•์ธ') as HTMLInputElement).value = asset.๋ฒ•์ธ; + (document.getElementById('hw-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value = asset.์ž์‚ฐ์ฝ”๋“œ; + (document.getElementById('hw-๋ช…์นญ') as HTMLInputElement).value = asset.๋ช…์นญ; + (document.getElementById('hw-์œ„์น˜') as HTMLInputElement).value = asset.์œ„์น˜; + (document.getElementById('hw-๊ด€๋ฆฌ์ž') as HTMLInputElement).value = asset.๊ด€๋ฆฌ์ž; + (document.getElementById('hw-IP์ฃผ์†Œ') as HTMLInputElement).value = asset.IP์ฃผ์†Œ; + (document.getElementById('hw-MACaddress') as HTMLInputElement).value = asset.MACaddress; + (document.getElementById('hw-OS') as HTMLInputElement).value = asset.OS; + (document.getElementById('hw-HW์‚ฌ์–‘') as HTMLTextAreaElement).value = asset.HW์‚ฌ์–‘; + (document.getElementById('hw-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; + (document.getElementById('hw-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; + (document.getElementById('hw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; + (document.getElementById('hw-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = asset.ํ’ˆ์˜์„œ๋ช… ? `๐Ÿ“Ž${asset.ํ’ˆ์˜์„œ๋ช…}` : ''; + (document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•') as HTMLSelectElement).value = asset.๋น„ํ’ˆ์œ ํ˜• || '๋…ธํŠธ๋ถ'; + } else { + document.getElementById('hw-modal-title')!.textContent = `์ƒˆ ${state.activeSubTab} ์ž์‚ฐ ์ถ”๊ฐ€`; + deleteBtn.style.display = 'none'; + (document.getElementById('hw-asset-id') as HTMLInputElement).value = ''; + (document.getElementById('hw-asset-type') as HTMLInputElement).value = state.activeSubTab; + (document.getElementById('hw-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = ''; + (document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•') as HTMLSelectElement).value = '๋…ธํŠธ๋ถ'; + } + + // ์ „์‚ฐ๋น„ํ’ˆ์ผ ๊ฒฝ์šฐ ์œ ํ˜• ์„ ํƒ ํ•„๋“œ ๋…ธ์ถœ + if (state.activeSubTab === '์ „์‚ฐ๋น„ํ’ˆ') { + document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•-group')!.style.display = 'block'; + } else { + document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•-group')!.style.display = 'none'; + } +} diff --git a/src/components/Modal/PCModal.ts b/src/components/Modal/PCModal.ts new file mode 100644 index 0000000..5185f62 --- /dev/null +++ b/src/components/Modal/PCModal.ts @@ -0,0 +1,111 @@ +import { state } from '../../state'; +import { HardwareAsset } from '../../excelHandler'; +import { openModal } from './BaseModal'; + +/** + * ๊ฐœ์ธPC ๋ชจ๋‹ฌ ์ดˆ๊ธฐํ™” ๋ฐ ๋กœ์ง ์ œ์–ด + */ +export function initPCModal(renderContent: () => void, closeModals: () => void) { + const pcModal = document.getElementById('pc-asset-modal') as HTMLDivElement; + const pcForm = document.getElementById('pc-asset-form') as HTMLFormElement; + const btnSavePc = document.getElementById('btn-save-pc-asset') as HTMLButtonElement; + const btnDeletePc = document.getElementById('btn-delete-pc-asset') as HTMLButtonElement; + + // ์ €์žฅ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnSavePc?.addEventListener('click', (e) => { + e.preventDefault(); + if (!pcForm.checkValidity()) { pcForm.reportValidity(); return; } + + const id = (document.getElementById('pc-asset-id') as HTMLInputElement).value; + const fileInput = document.getElementById('pc-ํ’ˆ์˜์„œ') as HTMLInputElement; + const ํ’ˆ์˜์„œ๋ช… = fileInput.files && fileInput.files.length > 0 ? fileInput.files[0].name : (document.getElementById('pc-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText.replace('๐Ÿ“Ž', ''); + + const newAsset: HardwareAsset = { + id: id || Math.random().toString(36).substring(2, 9), + type: '๊ฐœ์ธPC', + ๋ฒ•์ธ: (document.getElementById('pc-๋ฒ•์ธ') as HTMLSelectElement).value, + ์ž์‚ฐ์ฝ”๋“œ: (document.getElementById('pc-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value, + ๋ช…์นญ: '', + ์œ„์น˜: (document.getElementById('pc-์œ„์น˜') as HTMLInputElement).value, + ๊ด€๋ฆฌ์ž: '', + IP์ฃผ์†Œ: '', + MACaddress: '', + HW์‚ฌ์–‘: '', + OS: '', + ์‚ฌ์šฉ์ž: (document.getElementById('pc-์‚ฌ์šฉ์ž') as HTMLInputElement).value, + CPU: (document.getElementById('pc-CPU') as HTMLInputElement).value, + GPU: (document.getElementById('pc-GPU') as HTMLInputElement).value, + RAM: (document.getElementById('pc-RAM') as HTMLInputElement).value, + SSD1: (document.getElementById('pc-SSD1') as HTMLInputElement).value, + SSD2: (document.getElementById('pc-SSD2') as HTMLInputElement).value, + HDD1: (document.getElementById('pc-HDD1') as HTMLInputElement).value, + HDD2: (document.getElementById('pc-HDD2') as HTMLInputElement).value, + ๊ตฌ๋งค์ผ: (document.getElementById('pc-๊ตฌ๋งค์ผ') as HTMLInputElement).value, + ๊ธˆ์•ก: (document.getElementById('pc-๊ธˆ์•ก') as HTMLInputElement).value, + ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('pc-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, + ํ’ˆ์˜์„œ๋ช… + }; + + if (id) { + const idx = state.masterData.hw.findIndex(a => a.id === id); + if(idx !== -1) state.masterData.hw[idx] = newAsset; + } else { + state.masterData.hw.push(newAsset); + } + + closeModals(); + renderContent(); + }); + + // ์‚ญ์ œ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnDeletePc?.addEventListener('click', (e) => { + e.preventDefault(); + const id = (document.getElementById('pc-asset-id') as HTMLInputElement).value; + if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { + state.masterData.hw = state.masterData.hw.filter(a => a.id !== id); + closeModals(); + renderContent(); + } + }); +} + +/** + * ๊ฐœ์ธPC ์ƒ์„ธ ๋ชจ๋‹ฌ ์—ด๊ธฐ + * @param asset ์ˆ˜์ • ์‹œ ์ž์‚ฐ ๋ฐ์ดํ„ฐ, ์‹ ๊ทœ ์‹œ undefined + */ +export function openPcModal(asset?: HardwareAsset) { + const pcModal = document.getElementById('pc-asset-modal') as HTMLDivElement; + const pcForm = document.getElementById('pc-asset-form') as HTMLFormElement; + const deleteBtn = document.getElementById('btn-delete-pc-asset')!; + + openModal('pc-asset-modal'); + pcForm.reset(); + + if (asset) { + document.getElementById('pc-modal-title')!.textContent = '๊ฐœ์ธPC ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •'; + deleteBtn.style.display = 'block'; + + (document.getElementById('pc-asset-id') as HTMLInputElement).value = asset.id; + (document.getElementById('pc-๋ฒ•์ธ') as HTMLSelectElement).value = asset.๋ฒ•์ธ; + (document.getElementById('pc-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value = asset.์ž์‚ฐ์ฝ”๋“œ; + (document.getElementById('pc-์‚ฌ์šฉ์ž') as HTMLInputElement).value = asset.์‚ฌ์šฉ์ž || ''; + (document.getElementById('pc-์œ„์น˜') as HTMLInputElement).value = asset.์œ„์น˜ || ''; + (document.getElementById('pc-CPU') as HTMLInputElement).value = asset.CPU || ''; + (document.getElementById('pc-GPU') as HTMLInputElement).value = asset.GPU || ''; + (document.getElementById('pc-RAM') as HTMLInputElement).value = asset.RAM || ''; + (document.getElementById('pc-SSD1') as HTMLInputElement).value = asset.SSD1 || ''; + (document.getElementById('pc-SSD2') as HTMLInputElement).value = asset.SSD2 || ''; + (document.getElementById('pc-HDD1') as HTMLInputElement).value = asset.HDD1 || ''; + (document.getElementById('pc-HDD2') as HTMLInputElement).value = asset.HDD2 || ''; + (document.getElementById('pc-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; + (document.getElementById('pc-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; + (document.getElementById('pc-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; + (document.getElementById('pc-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = asset.ํ’ˆ์˜์„œ๋ช… ? `๐Ÿ“Ž${asset.ํ’ˆ์˜์„œ๋ช…}` : ''; + } else { + document.getElementById('pc-modal-title')!.textContent = '์ƒˆ ๊ฐœ์ธPC ์ž์‚ฐ ์ถ”๊ฐ€'; + deleteBtn.style.display = 'none'; + (document.getElementById('pc-asset-id') as HTMLInputElement).value = ''; + (document.getElementById('pc-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; + (document.getElementById('pc-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = ''; + } +} diff --git a/src/components/Modal/SWModal.ts b/src/components/Modal/SWModal.ts new file mode 100644 index 0000000..cb2ccc0 --- /dev/null +++ b/src/components/Modal/SWModal.ts @@ -0,0 +1,102 @@ +import { state } from '../../state'; +import { SoftwareAsset } from '../../excelHandler'; +import { openModal } from './BaseModal'; + +/** + * ์†Œํ”„ํŠธ์›จ์–ด ๋ชจ๋‹ฌ ์ดˆ๊ธฐํ™” ๋ฐ ๋กœ์ง ์ œ์–ด + */ +export function initSWModal(renderContent: () => void, closeModals: () => void) { + const swForm = document.getElementById('sw-asset-form') as HTMLFormElement; + const btnSaveSw = document.getElementById('btn-save-sw-asset') as HTMLButtonElement; + const btnDeleteSw = document.getElementById('btn-delete-sw-asset') as HTMLButtonElement; + + // ์ €์žฅ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnSaveSw?.addEventListener('click', (e) => { + e.preventDefault(); + if (!swForm.checkValidity()) { swForm.reportValidity(); return; } + + const id = (document.getElementById('sw-asset-id') as HTMLInputElement).value; + const newAsset: SoftwareAsset = { + id: id || Math.random().toString(36).substring(2, 9), + type: (document.getElementById('sw-asset-type') as HTMLInputElement).value, + ๋ฒ•์ธ: (document.getElementById('sw-๋ฒ•์ธ') as HTMLSelectElement).value, + ์ œํ’ˆ๋ช…: (document.getElementById('sw-์ œํ’ˆ๋ช…') as HTMLInputElement).value, + ๊ตฌ๋งค์ผ: (document.getElementById('sw-๊ตฌ๋งค์ผ') as HTMLInputElement).value, + ๊ตฌ๋…์ผ: (document.getElementById('sw-๊ตฌ๋…์ผ') as HTMLInputElement).value, + ์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€: (document.getElementById('sw-์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€') as HTMLInputElement).checked, + ๊ธˆ์•ก: (document.getElementById('sw-๊ธˆ์•ก') as HTMLInputElement).value, + ์ˆ˜๋Ÿ‰: parseInt((document.getElementById('sw-์ˆ˜๋Ÿ‰') as HTMLInputElement).value || '1', 10), + ๊ณ„์ •๋ช…: (document.getElementById('sw-๊ณ„์ •๋ช…') as HTMLInputElement).value, + ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('sw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, + ๋น„๊ณ : (document.getElementById('sw-๋น„๊ณ ') as HTMLInputElement).value, + }; + + if (id) { + const idx = state.masterData.sw.findIndex(a => a.id === id); + if(idx !== -1) state.masterData.sw[idx] = newAsset; + } else { + state.masterData.sw.push(newAsset); + } + + closeModals(); + renderContent(); + }); + + // ์‚ญ์ œ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnDeleteSw?.addEventListener('click', (e) => { + e.preventDefault(); + const id = (document.getElementById('sw-asset-id') as HTMLInputElement).value; + if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { + state.masterData.sw = state.masterData.sw.filter(a => a.id !== id); + closeModals(); + renderContent(); + } + }); +} + +/** + * ์†Œํ”„ํŠธ์›จ์–ด ์ƒ์„ธ ๋ชจ๋‹ฌ ์—ด๊ธฐ + * @param asset ์ˆ˜์ • ์‹œ ์ž์‚ฐ ๋ฐ์ดํ„ฐ, ์‹ ๊ทœ ์‹œ undefined + */ +export function openSwModal(asset?: SoftwareAsset) { + const swModal = document.getElementById('sw-asset-modal') as HTMLDivElement; + const swForm = document.getElementById('sw-asset-form') as HTMLFormElement; + const deleteBtn = document.getElementById('btn-delete-sw-asset')!; + + openModal('sw-asset-modal'); + swForm.reset(); + + const subGroup = document.getElementById('sw-๊ตฌ๋…์ผ-group')!; + const permGroup = document.getElementById('sw-์œ ์ง€๋ณด์ˆ˜-group')!; + if (state.activeSubTab === '๊ตฌ๋…SW') { + subGroup.style.display = 'block'; + permGroup.style.display = 'none'; + } else { + subGroup.style.display = 'none'; + permGroup.style.display = 'block'; + } + + if (asset) { + document.getElementById('sw-modal-title')!.textContent = `${state.activeSubTab} ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •`; + deleteBtn.style.display = 'block'; + + (document.getElementById('sw-asset-id') as HTMLInputElement).value = asset.id; + (document.getElementById('sw-asset-type') as HTMLInputElement).value = asset.type; + (document.getElementById('sw-๋ฒ•์ธ') as HTMLSelectElement).value = asset.๋ฒ•์ธ; + (document.getElementById('sw-์ œํ’ˆ๋ช…') as HTMLInputElement).value = asset.์ œํ’ˆ๋ช…; + (document.getElementById('sw-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; + (document.getElementById('sw-๊ตฌ๋…์ผ') as HTMLInputElement).value = asset.๊ตฌ๋…์ผ || ''; + (document.getElementById('sw-์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€') as HTMLInputElement).checked = !!asset.์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€; + (document.getElementById('sw-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; + (document.getElementById('sw-์ˆ˜๋Ÿ‰') as HTMLInputElement).value = String(asset.์ˆ˜๋Ÿ‰); + (document.getElementById('sw-๊ณ„์ •๋ช…') as HTMLInputElement).value = asset.๊ณ„์ •๋ช… || ''; + (document.getElementById('sw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; + (document.getElementById('sw-๋น„๊ณ ') as HTMLInputElement).value = asset.๋น„๊ณ  || ''; + } else { + document.getElementById('sw-modal-title')!.textContent = `์ƒˆ ${state.activeSubTab} ์ž์‚ฐ ์ถ”๊ฐ€`; + deleteBtn.style.display = 'none'; + (document.getElementById('sw-asset-id') as HTMLInputElement).value = ''; + (document.getElementById('sw-asset-type') as HTMLInputElement).value = state.activeSubTab; + (document.getElementById('sw-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; + } +} diff --git a/src/components/Modal/SWUserModal.ts b/src/components/Modal/SWUserModal.ts new file mode 100644 index 0000000..2e67f23 --- /dev/null +++ b/src/components/Modal/SWUserModal.ts @@ -0,0 +1,171 @@ +import { state } from '../../state'; +import { SoftwareAsset, SWUser } from '../../excelHandler'; +import { openModal } from './BaseModal'; +import { createIcons, Edit2, X, Paperclip } from 'lucide'; + +let currentSwUserAssetId: string = ''; +let tempSwUsers: SWUser[] = []; + +/** + * ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ์ž ํ• ๋‹น ๋ชจ๋‹ฌ ์ดˆ๊ธฐํ™” + */ +export function initSWUserModal(renderContent: () => void, closeModals: () => void) { + const btnOpenAddUser = document.getElementById('btn-open-add-user'); + const btnSaveEditUser = document.getElementById('btn-save-edit-user'); + const btnSaveSwUserMapping = document.getElementById('btn-save-sw-user-mapping'); + + btnOpenAddUser?.addEventListener('click', () => { + openUserEditModal(-1); + }); + + btnSaveEditUser?.addEventListener('click', () => { + saveUserEdit(); + }); + + btnSaveSwUserMapping?.addEventListener('click', () => { + // ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ „์—ญ ์ƒํƒœ์— ๋ฐ˜์˜ + state.masterData.swUsers = state.masterData.swUsers.filter(u => u.swId !== currentSwUserAssetId); + state.masterData.swUsers.push(...tempSwUsers); + + document.getElementById('sw-user-modal')?.classList.add('hidden'); + renderContent(); + }); + + // ์ทจ์†Œ ๋ฒ„ํŠผ๋“ค + document.getElementById('btn-cancel-sw-user-edit')?.addEventListener('click', () => { + document.getElementById('sw-user-edit-modal')?.classList.add('hidden'); + }); + document.getElementById('btn-cancel-sw-user-modal')?.addEventListener('click', () => { + document.getElementById('sw-user-modal')?.classList.add('hidden'); + }); +} + +/** + * ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ์ž ๋ชฉ๋ก ๋ Œ๋”๋ง + */ +function renderUserList() { + const tbody = document.getElementById('user-list-body')!; + tbody.innerHTML = ''; + if (tempSwUsers.length === 0) { + tbody.innerHTML = 'ํ• ๋‹น๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + return; + } + + tempSwUsers.forEach((user, idx) => { + const tr = document.createElement('tr'); + tr.style.cssText = 'border-bottom: 1px solid var(--border); transition: background-color 0.2s;'; + + const deptTeam = [user.๋ถ€์„œ, user.ํŒ€].filter(Boolean).join(' / ') || '-'; + const attachIcon = user.์‹ ์ฒญ์„œ๋ช… ? `` : '-'; + + tr.innerHTML = ` + ${user.๋ฒ•์ธ} + ${deptTeam} + ${user.์ง์œ„ || '-'} + ${user.์ด๋ฆ„} + ${user.์‚ฌ์šฉ๊ธฐ๊ฐ„ || '-'} + ${attachIcon} + + + + + `; + tbody.appendChild(tr); + }); + + createIcons({ icons: { Edit2, X, Paperclip } }); + + tbody.querySelectorAll('.btn-edit-user').forEach(btn => { + btn.addEventListener('click', (e) => { + const idx = parseInt((e.currentTarget as HTMLElement).getAttribute('data-idx')!); + openUserEditModal(idx); + }); + }); + + tbody.querySelectorAll('.btn-remove-user').forEach(btn => { + btn.addEventListener('click', (e) => { + e.stopPropagation(); + const idx = parseInt((e.currentTarget as HTMLButtonElement).getAttribute('data-idx')!); + tempSwUsers.splice(idx, 1); + renderUserList(); + }); + }); +} + +/** + * ์‚ฌ์šฉ์ž ํ• ๋‹น ๋ชจ๋‹ฌ ์—ด๊ธฐ + */ +export function openSwUserModal(asset: SoftwareAsset) { + openModal('sw-user-modal'); + currentSwUserAssetId = asset.id; + tempSwUsers = state.masterData.swUsers.filter(u => u.swId === asset.id).map(u => ({...u})); + renderUserList(); +} + +/** + * ์‚ฌ์šฉ์ž ์ถ”๊ฐ€/์ˆ˜์ • ๋ชจ๋‹ฌ ์—ด๊ธฐ + */ +function openUserEditModal(idx: number) { + const editModal = document.getElementById('sw-user-edit-modal')!; + editModal.classList.remove('hidden'); + (document.getElementById('edit-user-idx') as HTMLInputElement).value = String(idx); + + if (idx === -1) { + document.getElementById('sw-user-edit-modal-title')!.innerText = '์ƒˆ ์‚ฌ์šฉ์ž ์ถ”๊ฐ€'; + (document.getElementById('new-user-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; + (document.getElementById('new-user-๋ถ€์„œ') as HTMLInputElement).value = ''; + (document.getElementById('new-user-ํŒ€') as HTMLInputElement).value = ''; + (document.getElementById('new-user-์ง์œ„') as HTMLInputElement).value = ''; + (document.getElementById('new-user-์ด๋ฆ„') as HTMLInputElement).value = ''; + (document.getElementById('new-user-์‚ฌ์šฉ๊ธฐ๊ฐ„') as HTMLInputElement).value = ''; + (document.getElementById('new-user-์‹ ์ฒญ์„œ') as HTMLInputElement).value = ''; + document.getElementById('new-user-์‹ ์ฒญ์„œ๋ช…')!.innerText = ''; + } else { + document.getElementById('sw-user-edit-modal-title')!.innerText = '์‚ฌ์šฉ์ž ์ˆ˜์ •'; + const u = tempSwUsers[idx]; + (document.getElementById('new-user-๋ฒ•์ธ') as HTMLSelectElement).value = u.๋ฒ•์ธ; + (document.getElementById('new-user-๋ถ€์„œ') as HTMLInputElement).value = u.๋ถ€์„œ; + (document.getElementById('new-user-ํŒ€') as HTMLInputElement).value = u.ํŒ€; + (document.getElementById('new-user-์ง์œ„') as HTMLInputElement).value = u.์ง์œ„; + (document.getElementById('new-user-์ด๋ฆ„') as HTMLInputElement).value = u.์ด๋ฆ„; + (document.getElementById('new-user-์‚ฌ์šฉ๊ธฐ๊ฐ„') as HTMLInputElement).value = u.์‚ฌ์šฉ๊ธฐ๊ฐ„; + (document.getElementById('new-user-์‹ ์ฒญ์„œ') as HTMLInputElement).value = ''; + document.getElementById('new-user-์‹ ์ฒญ์„œ๋ช…')!.innerText = u.์‹ ์ฒญ์„œ๋ช… ? `๐Ÿ“Ž${u.์‹ ์ฒญ์„œ๋ช…}` : ''; + } +} + +/** + * ์‚ฌ์šฉ์ž ์ถ”๊ฐ€/์ˆ˜์ • ๋‚ด์šฉ ์ €์žฅ (์ž„์‹œ ๋ชฉ๋ก์— ๋ฐ˜์˜) + */ +function saveUserEdit() { + const idx = parseInt((document.getElementById('edit-user-idx') as HTMLInputElement).value); + const ๋ฒ•์ธ = (document.getElementById('new-user-๋ฒ•์ธ') as HTMLSelectElement).value; + const ๋ถ€์„œ = (document.getElementById('new-user-๋ถ€์„œ') as HTMLInputElement).value; + const ํŒ€ = (document.getElementById('new-user-ํŒ€') as HTMLInputElement).value; + const ์ง์œ„ = (document.getElementById('new-user-์ง์œ„') as HTMLInputElement).value; + const ์ด๋ฆ„ = (document.getElementById('new-user-์ด๋ฆ„') as HTMLInputElement).value.trim(); + const ์‚ฌ์šฉ๊ธฐ๊ฐ„ = (document.getElementById('new-user-์‚ฌ์šฉ๊ธฐ๊ฐ„') as HTMLInputElement).value; + + const fileInput = document.getElementById('new-user-์‹ ์ฒญ์„œ') as HTMLInputElement; + let ์‹ ์ฒญ์„œ๋ช… = ''; + if (fileInput.files && fileInput.files.length > 0) { + ์‹ ์ฒญ์„œ๋ช… = fileInput.files[0].name; + } else if (idx !== -1) { + ์‹ ์ฒญ์„œ๋ช… = tempSwUsers[idx].์‹ ์ฒญ์„œ๋ช…; + } + + if (!์ด๋ฆ„) { alert('์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'); return; } + + if (idx === -1) { + tempSwUsers.push({ + id: Math.random().toString(36).substring(2, 9), + swId: currentSwUserAssetId, + ๋ฒ•์ธ, ๋ถ€์„œ, ํŒ€, ์ง์œ„, ์ด๋ฆ„, ์‚ฌ์šฉ๊ธฐ๊ฐ„, ์‹ ์ฒญ์„œ๋ช… + }); + } else { + tempSwUsers[idx] = { ...tempSwUsers[idx], ๋ฒ•์ธ, ๋ถ€์„œ, ํŒ€, ์ง์œ„, ์ด๋ฆ„, ์‚ฌ์šฉ๊ธฐ๊ฐ„, ์‹ ์ฒญ์„œ๋ช… }; + } + + document.getElementById('sw-user-edit-modal')?.classList.add('hidden'); + renderUserList(); +} diff --git a/src/components/Modal/StorageModal.ts b/src/components/Modal/StorageModal.ts new file mode 100644 index 0000000..1c3a8d9 --- /dev/null +++ b/src/components/Modal/StorageModal.ts @@ -0,0 +1,108 @@ +import { state } from '../../state'; +import { HardwareAsset } from '../../excelHandler'; +import { openModal } from './BaseModal'; + +/** + * ์Šคํ† ๋ฆฌ์ง€ ๋ชจ๋‹ฌ ์ดˆ๊ธฐํ™” ๋ฐ ๋กœ์ง ์ œ์–ด + */ +export function initStorageModal(renderContent: () => void, closeModals: () => void) { + const storageForm = document.getElementById('storage-asset-form') as HTMLFormElement; + const btnSaveStorage = document.getElementById('btn-save-storage-asset') as HTMLButtonElement; + const btnDeleteStorage = document.getElementById('btn-delete-storage-asset') as HTMLButtonElement; + + // ์ €์žฅ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnSaveStorage?.addEventListener('click', (e) => { + e.preventDefault(); + if (!storageForm.checkValidity()) { storageForm.reportValidity(); return; } + + const id = (document.getElementById('storage-asset-id') as HTMLInputElement).value; + const fileInput = document.getElementById('storage-ํ’ˆ์˜์„œ') as HTMLInputElement; + const ํ’ˆ์˜์„œ๋ช… = fileInput.files && fileInput.files.length > 0 ? fileInput.files[0].name : (document.getElementById('storage-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText.replace('๐Ÿ“Ž', ''); + + const newAsset: HardwareAsset = { + id: id || Math.random().toString(36).substring(2, 9), + type: '์Šคํ† ๋ฆฌ์ง€', + ๋ฒ•์ธ: (document.getElementById('storage-๋ฒ•์ธ') as HTMLSelectElement).value, + storage์œ ํ˜•: (document.getElementById('storage-์œ ํ˜•') as HTMLSelectElement).value, + ์ž์‚ฐ์ฝ”๋“œ: (document.getElementById('storage-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value, + ๋ช…์นญ: (document.getElementById('storage-๋ช…์นญ') as HTMLInputElement).value, + ์œ„์น˜: (document.getElementById('storage-์œ„์น˜') as HTMLInputElement).value, + ๊ด€๋ฆฌ์ž: '', + IP์ฃผ์†Œ: (document.getElementById('storage-IP์ฃผ์†Œ') as HTMLInputElement).value, + MACaddress: (document.getElementById('storage-MAC์ฃผ์†Œ') as HTMLInputElement).value, + HW์‚ฌ์–‘: '', + OS: '', + ๋ชจ๋ธ๋ช…: (document.getElementById('storage-๋ชจ๋ธ๋ช…') as HTMLInputElement).value, + ์šฉ๋Ÿ‰: (document.getElementById('storage-์šฉ๋Ÿ‰') as HTMLInputElement).value, + ๋‹ด๋‹น์ž_์ •: (document.getElementById('storage-๋‹ด๋‹น์ž_์ •') as HTMLInputElement).value, + ๋‹ด๋‹น์ž_๋ถ€: (document.getElementById('storage-๋‹ด๋‹น์ž_๋ถ€') as HTMLInputElement).value, + ๊ตฌ๋งค์ผ: (document.getElementById('storage-๊ตฌ๋งค์ผ') as HTMLInputElement).value, + ๊ธˆ์•ก: (document.getElementById('storage-๊ธˆ์•ก') as HTMLInputElement).value, + ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('storage-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, + ํ’ˆ์˜์„œ๋ช… + }; + + if (id) { + const idx = state.masterData.hw.findIndex(a => a.id === id); + if(idx !== -1) state.masterData.hw[idx] = newAsset; + } else { + state.masterData.hw.push(newAsset); + } + + closeModals(); + renderContent(); + }); + + // ์‚ญ์ œ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ + btnDeleteStorage?.addEventListener('click', (e) => { + e.preventDefault(); + const id = (document.getElementById('storage-asset-id') as HTMLInputElement).value; + if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { + state.masterData.hw = state.masterData.hw.filter(a => a.id !== id); + closeModals(); + renderContent(); + } + }); +} + +/** + * ์Šคํ† ๋ฆฌ์ง€ ์ƒ์„ธ ๋ชจ๋‹ฌ ์—ด๊ธฐ + * @param asset ์ˆ˜์ • ์‹œ ์ž์‚ฐ ๋ฐ์ดํ„ฐ, ์‹ ๊ทœ ์‹œ undefined + */ +export function openStorageModal(asset?: HardwareAsset) { + const storageModal = document.getElementById('storage-asset-modal') as HTMLDivElement; + const storageForm = document.getElementById('storage-asset-form') as HTMLFormElement; + const deleteBtn = document.getElementById('btn-delete-storage-asset')!; + + openModal('storage-asset-modal'); + storageForm.reset(); + + if (asset) { + document.getElementById('storage-modal-title')!.textContent = '์Šคํ† ๋ฆฌ์ง€ ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •'; + deleteBtn.style.display = 'block'; + + (document.getElementById('storage-asset-id') as HTMLInputElement).value = asset.id; + (document.getElementById('storage-๋ฒ•์ธ') as HTMLSelectElement).value = asset.๋ฒ•์ธ; + (document.getElementById('storage-์œ ํ˜•') as HTMLSelectElement).value = asset.storage์œ ํ˜• || 'NAS'; + (document.getElementById('storage-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value = asset.์ž์‚ฐ์ฝ”๋“œ; + (document.getElementById('storage-๋ช…์นญ') as HTMLInputElement).value = asset.๋ช…์นญ; + (document.getElementById('storage-์œ„์น˜') as HTMLInputElement).value = asset.์œ„์น˜ || ''; + (document.getElementById('storage-๋ชจ๋ธ๋ช…') as HTMLInputElement).value = asset.๋ชจ๋ธ๋ช… || ''; + (document.getElementById('storage-์šฉ๋Ÿ‰') as HTMLInputElement).value = asset.์šฉ๋Ÿ‰ || ''; + (document.getElementById('storage-๋‹ด๋‹น์ž_์ •') as HTMLInputElement).value = asset.๋‹ด๋‹น์ž_์ • || ''; + (document.getElementById('storage-๋‹ด๋‹น์ž_๋ถ€') as HTMLInputElement).value = asset.๋‹ด๋‹น์ž_๋ถ€ || ''; + (document.getElementById('storage-IP์ฃผ์†Œ') as HTMLInputElement).value = asset.IP์ฃผ์†Œ || ''; + (document.getElementById('storage-MAC์ฃผ์†Œ') as HTMLInputElement).value = asset.MACaddress || ''; + (document.getElementById('storage-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; + (document.getElementById('storage-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; + (document.getElementById('storage-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; + (document.getElementById('storage-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = asset.ํ’ˆ์˜์„œ๋ช… ? `๐Ÿ“Ž${asset.ํ’ˆ์˜์„œ๋ช…}` : ''; + } else { + document.getElementById('storage-modal-title')!.textContent = '์ƒˆ ์Šคํ† ๋ฆฌ์ง€ ์ž์‚ฐ ์ถ”๊ฐ€'; + deleteBtn.style.display = 'none'; + (document.getElementById('storage-asset-id') as HTMLInputElement).value = ''; + (document.getElementById('storage-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; + (document.getElementById('storage-์œ ํ˜•') as HTMLSelectElement).value = 'NAS'; + (document.getElementById('storage-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = ''; + } +} diff --git a/src/components/Sidebar.ts b/src/components/Sidebar.ts new file mode 100644 index 0000000..ad9578f --- /dev/null +++ b/src/components/Sidebar.ts @@ -0,0 +1,37 @@ +import { state } from '../state'; + +export function initSidebar(renderContent: () => void) { + const navItems = document.querySelectorAll('.nav-list li'); + const titleElement = document.getElementById('current-tab-title') as HTMLHeadingElement; + const btnAddAsset = document.getElementById('btn-add-asset') as HTMLButtonElement; + + navItems.forEach(item => { + item.addEventListener('click', () => { + // ํƒญ UI ์—…๋ฐ์ดํŠธ + navItems.forEach(nav => nav.classList.remove('active')); + item.classList.add('active'); + + // ์ƒํƒœ ์—…๋ฐ์ดํŠธ + state.activeCategory = item.getAttribute('data-category') as 'hw' | 'sw'; + state.activeSubTab = item.getAttribute('data-tab') || '๋Œ€์‹œ๋ณด๋“œ'; + + // ํƒ€์ดํ‹€ ์—…๋ฐ์ดํŠธ (Deep Green ํฌ์ธํŠธ ์ปฌ๋Ÿฌ ์œ ์ง€) + const catName = state.activeCategory === 'hw' ? 'ํ•˜๋“œ์›จ์–ด' : '์†Œํ”„ํŠธ์›จ์–ด'; + if (titleElement) { + titleElement.textContent = `${catName} / ${state.activeSubTab}`; + } + + // ์ถ”๊ฐ€ ๋ฒ„ํŠผ ๋…ธ์ถœ ์—ฌ๋ถ€ (๋Œ€์‹œ๋ณด๋“œ์—์„œ๋Š” ์ˆจ๊น€) + if (btnAddAsset) { + if (state.activeSubTab === '๋Œ€์‹œ๋ณด๋“œ') { + btnAddAsset.classList.add('hidden'); + } else { + btnAddAsset.classList.remove('hidden'); + } + } + + // ํ™”๋ฉด ๋ฆฌ๋ Œ๋”๋ง + renderContent(); + }); + }); +} diff --git a/src/main.ts b/src/main.ts index bd7d726..9dceb60 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,1071 +1,66 @@ import { createIcons, Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2 } from 'lucide'; -import { MasterAssetData, HardwareAsset, SoftwareAsset, downloadTemplate, exportToExcel, parseExcel } from './excelHandler'; -import { generateDummyData } from './dummyDataGenerator'; +import { downloadTemplate, exportToExcel, parseExcel } from './excelHandler'; +import { state } from './state'; +import { initSidebar } from './components/Sidebar'; +import { initBaseModal } from './components/Modal/BaseModal'; +import { initPCModal, openPcModal } from './components/Modal/PCModal'; +import { initHWModal, openHwModal } from './components/Modal/HWModal'; +import { initStorageModal, openStorageModal } from './components/Modal/StorageModal'; +import { initSWModal, openSwModal } from './components/Modal/SWModal'; +import { initSWUserModal, openSwUserModal } from './components/Modal/SWUserModal'; +import { renderDashboard } from './views/DashboardView'; +import { renderTable } from './views/AssetTableView'; declare var Chart: any; -let activeCharts: any[] = []; - -// --- State Management --- -let masterData: MasterAssetData = generateDummyData(); -let activeCategory: 'hw' | 'sw' = 'hw'; -let activeSubTab: string = '๋Œ€์‹œ๋ณด๋“œ'; - // --- DOM Elements --- const mainContent = document.getElementById('main-content') as HTMLElement; -const titleElement = document.getElementById('current-tab-title') as HTMLHeadingElement; const uploadInput = document.getElementById('excel-upload') as HTMLInputElement; - const btnAddAsset = document.getElementById('btn-add-asset') as HTMLButtonElement; const btnDownloadTemp = document.getElementById('btn-download-template') as HTMLButtonElement; const btnExport = document.getElementById('btn-export-excel') as HTMLButtonElement; -// Nav items -const navItems = document.querySelectorAll('.nav-list li'); - -// Modal Elements -const hwModal = document.getElementById('hw-asset-modal') as HTMLDivElement; -const swModal = document.getElementById('sw-asset-modal') as HTMLDivElement; -const pcModal = document.getElementById('pc-asset-modal') as HTMLDivElement; -const storageModal = document.getElementById('storage-asset-modal') as HTMLDivElement; -const hwForm = document.getElementById('hw-asset-form') as HTMLFormElement; -const swForm = document.getElementById('sw-asset-form') as HTMLFormElement; -const pcForm = document.getElementById('pc-asset-form') as HTMLFormElement; -const storageForm = document.getElementById('storage-asset-form') as HTMLFormElement; - -const dashboardDetailModal = document.getElementById('dashboard-detail-modal') as HTMLDivElement; -const btnCloseDashboardDetail = document.getElementById('btn-close-dashboard-detail') as HTMLButtonElement; -btnCloseDashboardDetail?.addEventListener('click', () => { - dashboardDetailModal.classList.add('hidden'); -}); - // Initialize Icons createIcons({ icons: { Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2 } }); -// --- Navigation Logic --- -navItems.forEach(item => { - item.addEventListener('click', (e) => { - // ํƒญ UI ์—…๋ฐ์ดํŠธ - navItems.forEach(nav => nav.classList.remove('active')); - item.classList.add('active'); +// Initialize Components +const { closeAllModals } = initBaseModal(); +initSidebar(renderContent); +initPCModal(renderContent, closeAllModals); +initHWModal(renderContent, closeAllModals); +initStorageModal(renderContent, closeAllModals); +initSWModal(renderContent, closeAllModals); +initSWUserModal(renderContent, closeAllModals); - // ์ƒํƒœ ์—…๋ฐ์ดํŠธ - activeCategory = item.getAttribute('data-category') as 'hw' | 'sw'; - activeSubTab = item.getAttribute('data-tab') || '๋Œ€์‹œ๋ณด๋“œ'; - - // ํƒ€์ดํ‹€ ์—…๋ฐ์ดํŠธ - const catName = activeCategory === 'hw' ? 'ํ•˜๋“œ์›จ์–ด' : '์†Œํ”„ํŠธ์›จ์–ด'; - titleElement.textContent = `${catName} / ${activeSubTab}`; - - // ์ถ”๊ฐ€ ๋ฒ„ํŠผ ๋…ธ์ถœ ์—ฌ๋ถ€ - if (activeSubTab === '๋Œ€์‹œ๋ณด๋“œ') { - btnAddAsset.classList.add('hidden'); - } else { - btnAddAsset.classList.remove('hidden'); - } - - renderContent(); - }); -}); - -// --- Render Logic --- -function renderContent() { - mainContent.innerHTML = ''; // Clear - - if (activeSubTab === '๋Œ€์‹œ๋ณด๋“œ') { - renderDashboard(); - } else { - renderTable(); - } -} - -function isHwIdle(a: HardwareAsset) { - if (a.type === '๊ฐœ์ธPC') return !a.์‚ฌ์šฉ์ž || a.์‚ฌ์šฉ์ž.trim() === '' || a.์‚ฌ์šฉ์ž.trim() === '-'; - if (a.type === '์Šคํ† ๋ฆฌ์ง€') return !a.๋‹ด๋‹น์ž_์ • || a.๋‹ด๋‹น์ž_์ •.trim() === '' || a.๋‹ด๋‹น์ž_์ •.trim() === '-'; - return !a.๊ด€๋ฆฌ์ž || a.๊ด€๋ฆฌ์ž.trim() === '' || a.๊ด€๋ฆฌ์ž.trim() === '-'; -} - -function getHwAgeYears(a: HardwareAsset) { - if (!a.๊ตฌ๋งค์ผ) return 0; - return (Date.now() - new Date(a.๊ตฌ๋งค์ผ).getTime()) / (1000 * 60 * 60 * 24 * 365.25); -} - -function isSWExpiring(sw: SoftwareAsset) { - if (sw.type === '๊ตฌ๋…SW' && sw.๊ตฌ๋…์ผ) { - const parts = sw.๊ตฌ๋…์ผ.split('~'); - if (parts.length > 1) { - const endStr = parts[1].trim(); - const endMs = new Date(endStr.replace(/\\./g, '-')).getTime(); - const diffDays = (endMs - Date.now()) / (1000 * 60 * 60 * 24); - return diffDays >= 0 && diffDays <= 30; - } - } else if (sw.type === '์˜๊ตฌSW' && sw.๋น„๊ณ  && sw.๋น„๊ณ .includes('์œ ์ง€๋ณด์ˆ˜: ~')) { - const endStr = sw.๋น„๊ณ .split('~')[1].trim(); - const endMs = new Date(endStr.replace(/\\./g, '-')).getTime(); - const diffDays = (endMs - Date.now()) / (1000 * 60 * 60 * 24); - return diffDays >= 0 && diffDays <= 30; - } - return false; -} - -function openDashboardDetail(title: string, list: HardwareAsset[]) { - const modal = document.getElementById('dashboard-detail-modal') as HTMLDivElement; - const titleEl = document.getElementById('dashboard-detail-modal-title') as HTMLHeadingElement; - const tbody = document.getElementById('dashboard-detail-tbody') as HTMLTableSectionElement; - const thead = tbody.closest('table')!.querySelector('thead')!; - - titleEl.textContent = title; - thead.innerHTML = `No์œ ํ˜•์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ/๋ชจ๋ธ์œ„์น˜๋‹ด๋‹น/์‚ฌ์šฉ์ž๊ตฌ๋งค์ผ๊ธˆ์•ก`; - tbody.innerHTML = ''; - if (list.length === 0) { - tbody.innerHTML = `ํ•ด๋‹น ์กฐ๊ฑด์˜ ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; - } else { - list.forEach((asset, idx) => { - let manager = asset.๊ด€๋ฆฌ์ž || asset.์‚ฌ์šฉ์ž || asset.๋‹ด๋‹น์ž_์ • || '-'; - let name = asset.๋ช…์นญ || asset.๋ชจ๋ธ๋ช… || '-'; - let typeDisplay = asset.type === '์ „์‚ฐ๋น„ํ’ˆ' ? `์ „์‚ฐ๋น„ํ’ˆ(${asset.๋น„ํ’ˆ์œ ํ˜•||'-'})` : asset.type; - - const tr = document.createElement('tr'); - tr.innerHTML = ` - ${idx+1} - ${typeDisplay} - ${asset.์ž์‚ฐ์ฝ”๋“œ} - ${name} - ${asset.์œ„์น˜||'-'} - ${manager} - ${asset.๊ตฌ๋งค์ผ||'-'} - ${asset.๊ธˆ์•ก||'-'} - `; - tbody.appendChild(tr); - }); - } - modal.classList.remove('hidden'); -} - -function openSwDashboardDetail(title: string, list: SoftwareAsset[]) { - const modal = document.getElementById('dashboard-detail-modal') as HTMLDivElement; - const titleEl = document.getElementById('dashboard-detail-modal-title') as HTMLHeadingElement; - const tbody = document.getElementById('dashboard-detail-tbody') as HTMLTableSectionElement; - const thead = tbody.closest('table')!.querySelector('thead')!; - - titleEl.textContent = title; - thead.innerHTML = `No์œ ํ˜•๋ฒ•์ธ์ œํ’ˆ๋ช…๊ตฌ๋…์ผ/๋น„๊ณ ์ˆ˜๋Ÿ‰๊ธˆ์•ก`; - tbody.innerHTML = ''; - if (list.length === 0) { - tbody.innerHTML = `ํ•ด๋‹น ์กฐ๊ฑด์˜ ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.`; - } else { - list.forEach((sw, idx) => { - const tr = document.createElement('tr'); - tr.innerHTML = ` - ${idx+1} - ${sw.type === '๊ตฌ๋…SW' ? '๊ตฌ๋…' : '์˜๊ตฌ'} - ${sw.๋ฒ•์ธ||'-'} - ${sw.์ œํ’ˆ๋ช…||'-'} - ${sw.๊ตฌ๋…์ผ || sw.๋น„๊ณ  || '-'} - ${sw.์ˆ˜๋Ÿ‰||'-'} - ${sw.๊ธˆ์•ก||'-'} - `; - tbody.appendChild(tr); - }); - } - modal.classList.remove('hidden'); -} - -function openSwUsageDetail(title: string, list: SoftwareAsset[]) { - const modal = document.getElementById('dashboard-detail-modal') as HTMLDivElement; - const titleEl = document.getElementById('dashboard-detail-modal-title') as HTMLHeadingElement; - const tbody = document.getElementById('dashboard-detail-tbody') as HTMLTableSectionElement; - const thead = tbody.closest('table')!.querySelector('thead')!; - - titleEl.textContent = title; - thead.innerHTML = `No๋ฒ•์ธ์ œํ’ˆ๋ช…์ˆ˜๋Ÿ‰์‚ฌ์šฉ์ค‘์‚ฌ์šฉ๊ฐ€๋Šฅ๊ตฌ๋งค์ผ๊ธˆ์•ก`; - tbody.innerHTML = ''; - if (list.length === 0) { - tbody.innerHTML = `ํ•ด๋‹น ์œ ํ˜•์˜ ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.`; - } else { - list.forEach((sw, idx) => { - const assigned = masterData.swUsers.filter(u => u.swId === sw.id).length; - const qty = typeof sw.์ˆ˜๋Ÿ‰ === 'number' ? sw.์ˆ˜๋Ÿ‰ : parseInt(sw.์ˆ˜๋Ÿ‰ || '0', 10); - const available = qty - assigned; - const availColor = available > 0 ? 'var(--dash-primary)' : 'var(--dash-danger)'; - - const tr = document.createElement('tr'); - tr.innerHTML = ` - ${idx+1} - ${sw.๋ฒ•์ธ||'-'} - ${sw.์ œํ’ˆ๋ช…||'-'} - ${qty} - ${assigned} - ${available} - ${sw.๊ตฌ๋งค์ผ||'-'} - ${sw.๊ธˆ์•ก||'-'} - `; - tbody.appendChild(tr); - }); - } - modal.classList.remove('hidden'); -} - -function renderDashboard() { - mainContent.innerHTML = ''; - - activeCharts.forEach(c => c.destroy()); - activeCharts = []; - - if (activeCategory === 'hw') { - // 1. Data Aggregation - const types = ['๊ฐœ์ธPC', '์„œ๋ฒ„', '์Šคํ† ๋ฆฌ์ง€', '์ „์‚ฐ๋น„ํ’ˆ']; - const units = ['๋Œ€', '๋Œ€', '๋Œ€', '๊ฐœ']; - const groups: any = {}; - types.forEach(t => { - groups[t] = { - idle: [], active: [], - aged: [], normal: [] - }; - }); - - masterData.hw.forEach(a => { - if (!groups[a.type]) return; - if (isHwIdle(a)) groups[a.type].idle.push(a); - else groups[a.type].active.push(a); - - const ageY = getHwAgeYears(a); - const isAged = a.type === '์ „์‚ฐ๋น„ํ’ˆ' ? ageY >= 3 : ageY >= 5; - if (isAged) groups[a.type].aged.push(a); - else groups[a.type].normal.push(a); - }); - - const counts = types.map(t => groups[t].idle.length + groups[t].active.length); - - // ์‚ฌ์šฉํ˜„ํ™ฉ ์นด๋“œ ์ƒ์„ฑ - let usageCards = ''; - types.forEach((t, i) => { - const total = groups[t].idle.length + groups[t].active.length; - const used = groups[t].active.length; - const per = total > 0 ? Math.round((used / total) * 100) : 0; - const barColor = per >= 50 ? 'var(--dash-primary)' : 'var(--dash-danger)'; - const perColor = per >= 50 ? 'var(--dash-primary)' : 'var(--dash-danger)'; - const badge = per >= 50 - ? `
์ž˜ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”
` - : `
์ ๊ฒ€์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
`; - - usageCards += ` -
-
- ${t} ์‚ฌ์šฉํ˜„ํ™ฉ -
-
- ${total}${units[i]} ์ค‘ ${used}${units[i]} ์‚ฌ์šฉ ์ค‘ ยท ์œ ํœด ${groups[t].idle.length}${units[i]} -
-
-
${per}%
- ${badge} -
-
-
-
-
`; - }); - - // ๋…ธํ›„ํ™” ์นด๋“œ ์ƒ์„ฑ - let agedCards = ''; - types.forEach((t, i) => { - const total = groups[t].aged.length + groups[t].normal.length; - const agedCount = groups[t].aged.length; - const agedPer = total > 0 ? Math.round((agedCount / total) * 100) : 0; - const threshold = t === '์ „์‚ฐ๋น„ํ’ˆ' ? '3๋…„' : '5๋…„'; - - agedCards += ` -
-
-
- ${t} ๋…ธํ›„ํ™” ํ˜„ํ™ฉ - ${threshold} ์ดˆ๊ณผ -
-
- ์ „์ฒด ${total}${units[i]} ์ค‘ ${agedCount}${units[i]} ๋…ธํ›„ ์žฅ๋น„ -
-
${agedCount}${units[i]}
-
-
-
- ${agedPer}% -
-
-
`; - }); - - mainContent.innerHTML = ` -

์‚ฌ์šฉํ˜„ํ™ฉ

-
- ${usageCards} -
- -

๋…ธํ›„ํ™” ์ž์‚ฐ ๋น„์œจ

-
- ${agedCards} -
- `; - - // HW ์นด๋“œ ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ - mainContent.querySelectorAll('[data-action="idle"]').forEach(card => { - card.addEventListener('click', () => { - const t = card.getAttribute('data-type')!; - openDashboardDetail(`[${t}] ์œ ํœด ์ž์‚ฐ ๋ชฉ๋ก`, groups[t].idle); - }); - }); - mainContent.querySelectorAll('[data-action="aged"]').forEach(card => { - card.addEventListener('click', () => { - const t = card.getAttribute('data-type')!; - openDashboardDetail(`[${t}] ๋…ธํ›„ ์žฅ๋น„ ๋ชฉ๋ก`, groups[t].aged); - }); - }); - - } else { - // S/W Dashboard - let subQty = 0, subUsed = 0, subExp = 0, subTotal = 0; - let permQty = 0, permUsed = 0, permExp = 0, permTotal = 0; - - masterData.sw.forEach(sw => { - const assigned = masterData.swUsers.filter(u => u.swId === sw.id).length; - const qty = typeof sw.์ˆ˜๋Ÿ‰ === 'number' ? sw.์ˆ˜๋Ÿ‰ : parseInt(sw.์ˆ˜๋Ÿ‰||'0', 10); - - if (sw.type === '๊ตฌ๋…SW') { - subQty += qty; subUsed += assigned; subTotal++; - if (isSWExpiring(sw)) subExp++; - } else { - permQty += qty; permUsed += assigned; permTotal++; - if (isSWExpiring(sw)) permExp++; - } - }); - - const subPer = subQty > 0 ? Math.round((subUsed/subQty)*100) : 0; - const permPer = permQty > 0 ? Math.round((permUsed/permQty)*100) : 0; - const subExpPer = subTotal > 0 ? Math.round((subExp/subTotal)*100) : 0; - const permExpPer = permTotal > 0 ? Math.round((permExp/permTotal)*100) : 0; - - // ์ƒํƒœ ๋ฑƒ์ง€ (50% ๋ฏธ๋งŒ์ด๋ฉด ๋นจ๊ฐ„์ƒ‰ ๊ฒฝ๊ณ ) - const subBadge = subPer >= 50 - ? `
์ž˜ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”
` - : `
์ ๊ฒ€์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
`; - const permBadge = permPer >= 50 - ? `
์ž˜ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”
` - : `
์ ๊ฒ€์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
`; - - const subBarColor = subPer >= 50 ? 'var(--dash-primary)' : 'var(--dash-danger)'; - const permBarColor = permPer >= 50 ? 'var(--dash-primary)' : 'var(--dash-danger)'; - const subPerColor = subPer >= 50 ? 'var(--dash-primary)' : 'var(--dash-danger)'; - const permPerColor = permPer >= 50 ? 'var(--dash-primary)' : 'var(--dash-danger)'; - - mainContent.innerHTML = ` -
-
-
- ๊ตฌ๋… ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ์ •๋ณด -
-
- ${subQty}๊ฐœ์˜ ์ œํ’ˆ ์ค‘ ${subUsed}๊ฐœ ์‚ฌ์šฉ ์ค‘ -
-
-
- ${subPer}% -
- ${subBadge} -
-
-
-
-
- -
-
- ์˜๊ตฌ ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ์ •๋ณด -
-
- ${permQty}๊ฐœ์˜ ์ œํ’ˆ ์ค‘ ${permUsed}๊ฐœ ์‚ฌ์šฉ ์ค‘ -
-
-
- ${permPer}% -
- ${permBadge} -
-
-
-
-
-
- -
-
-
-
- ๊ตฌ๋… SW ๋งŒ๋ฃŒ ์˜ˆ์ • -
-
- 30์ผ ์ด๋‚ด์— ${subTotal}๊ฐœ์˜ ์ œํ’ˆ ์ค‘ ${subExp}๊ฐœ ๋งŒ๋ฃŒ ์˜ˆ์ • -
-
${subExp}๊ฐœ
-
-
-
- ${subExpPer}% -
-
-
- -
-
-
- ์œ ์ง€๋ณด์ˆ˜ ๋งŒ๋ฃŒ ์˜ˆ์ • -
-
- 30์ผ ์ด๋‚ด์— ${permTotal}๊ฐœ์˜ ์ œํ’ˆ ์ค‘ ${permExp}๊ฐœ ๋งŒ๋ฃŒ ์˜ˆ์ • -
-
${permExp}๊ฐœ
-
-
-
- ${permExpPer}% -
-
-
-
- `; - - // SW ์‚ฌ์šฉ์ •๋ณด ์นด๋“œ ํด๋ฆญ ์ด๋ฒคํŠธ - ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์†Œํ”„ํŠธ์›จ์–ด ๋ชฉ๋ก ํ‘œ์‹œ - const subSwList = masterData.sw.filter(sw => sw.type === '๊ตฌ๋…SW'); - const permSwList = masterData.sw.filter(sw => sw.type === '์˜๊ตฌSW'); - mainContent.querySelector('[data-action="sub-usage"]')?.addEventListener('click', () => { - openSwUsageDetail('๊ตฌ๋… ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ ๋ชฉ๋ก', subSwList); - }); - mainContent.querySelector('[data-action="perm-usage"]')?.addEventListener('click', () => { - openSwUsageDetail('์˜๊ตฌ ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ ๋ชฉ๋ก', permSwList); - }); - - // SW ๋งŒ๋ฃŒ ์นด๋“œ ํด๋ฆญ ์ด๋ฒคํŠธ - const expSubList = masterData.sw.filter(sw => sw.type === '๊ตฌ๋…SW' && isSWExpiring(sw)); - const expPermList = masterData.sw.filter(sw => sw.type === '์˜๊ตฌSW' && isSWExpiring(sw)); - mainContent.querySelector('[data-action="sub-exp"]')?.addEventListener('click', () => { - openSwDashboardDetail('๊ตฌ๋… SW ๋งŒ๋ฃŒ ์˜ˆ์ • ๋ชฉ๋ก', expSubList); - }); - mainContent.querySelector('[data-action="perm-exp"]')?.addEventListener('click', () => { - openSwDashboardDetail('์œ ์ง€๋ณด์ˆ˜ ๋งŒ๋ฃŒ ์˜ˆ์ • ๋ชฉ๋ก', expPermList); - }); - } -} - -function renderTable() { - const container = document.createElement('div'); - container.className = 'table-container'; - const table = document.createElement('table'); - - if (activeCategory === 'hw') { - const list = masterData.hw.filter(a => a.type === activeSubTab); - - // Header - if (activeSubTab === '๊ฐœ์ธPC') { - table.innerHTML = ` - - - No๋ฒ•์ธ์ž์‚ฐ์ฝ”๋“œ์‚ฌ์šฉ์ž - ์œ„์น˜CPUGPURAM - SSD1SSD2HDD1HDD2 - ๊ตฌ๋งค์ผ๊ธˆ์•ก๋‚ฉํ’ˆ์—…์ฒดํ’ˆ์˜์„œ๊ด€๋ฆฌ - - - - `; - container.appendChild(table); - mainContent.appendChild(container); - - const tbody = document.getElementById('dynamic-tbody')!; - if (list.length === 0) { - tbody.innerHTML = `๋“ฑ๋ก๋œ [${activeSubTab}] ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; - return; - } - - list.forEach((asset, idx) => { - const tr = document.createElement('tr'); - tr.style.cursor = 'pointer'; - tr.innerHTML = ` - ${idx + 1}${asset.๋ฒ•์ธ}${asset.์ž์‚ฐ์ฝ”๋“œ}${asset.์‚ฌ์šฉ์ž||''} - ${asset.์œ„์น˜||''}${asset.CPU||''}${asset.GPU||''}${asset.RAM||''} - ${asset.SSD1||'-'}${asset.SSD2||'-'}${asset.HDD1||'-'}${asset.HDD2||'-'} - ${asset.๊ตฌ๋งค์ผ||''} - ${asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''} - ${asset.๋‚ฉํ’ˆ์—…์ฒด||''} - ${asset.ํ’ˆ์˜์„œ๋ช… ? `` : '-'} - - `; - tr.addEventListener('click', (e) => { - if ((e.target as HTMLElement).tagName.toLowerCase() === 'button') return; - openPcModal(asset); - }); - tr.querySelector('.btn-edit')?.addEventListener('click', () => openPcModal(asset)); - tbody.appendChild(tr); - }); - } else if (activeSubTab === '์Šคํ† ๋ฆฌ์ง€') { - table.innerHTML = ` - - - No๋ฒ•์ธ์œ ํ˜•์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ - ์œ„์น˜๋ชจ๋ธ๋ช…์šฉ๋Ÿ‰๋‹ด๋‹น์ž(์ •)๋‹ด๋‹น์ž(๋ถ€) - IP์ฃผ์†ŒMAC ์ฃผ์†Œ - ๊ตฌ๋งค์ผ๊ธˆ์•ก๋‚ฉํ’ˆ์—…์ฒดํ’ˆ์˜์„œ๊ด€๋ฆฌ - - - - `; - container.appendChild(table); - mainContent.appendChild(container); - - const tbody = document.getElementById('dynamic-tbody')!; - if (list.length === 0) { - tbody.innerHTML = `๋“ฑ๋ก๋œ [${activeSubTab}] ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; - return; - } - - list.forEach((asset, idx) => { - const tr = document.createElement('tr'); - tr.style.cursor = 'pointer'; - tr.innerHTML = ` - ${idx + 1}${asset.๋ฒ•์ธ}${asset.storage์œ ํ˜•||''}${asset.์ž์‚ฐ์ฝ”๋“œ}${asset.๋ช…์นญ} - ${asset.์œ„์น˜||''}${asset.๋ชจ๋ธ๋ช…||''}${asset.์šฉ๋Ÿ‰||''}${asset.๋‹ด๋‹น์ž_์ •||''}${asset.๋‹ด๋‹น์ž_๋ถ€||''} - ${asset.IP์ฃผ์†Œ||''}${asset.MACaddress||''} - ${asset.๊ตฌ๋งค์ผ||''} - ${asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''} - ${asset.๋‚ฉํ’ˆ์—…์ฒด||''} - ${asset.ํ’ˆ์˜์„œ๋ช… ? `` : '-'} - - `; - tr.addEventListener('click', (e) => { - if ((e.target as HTMLElement).tagName.toLowerCase() === 'button') return; - openStorageModal(asset); - }); - tr.querySelector('.btn-edit')?.addEventListener('click', () => openStorageModal(asset)); - tbody.appendChild(tr); - }); - } else { - table.innerHTML = ` - - - No๋ฒ•์ธ - ${activeSubTab === '์ „์‚ฐ๋น„ํ’ˆ' ? '์œ ํ˜•' : ''} - ์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ - ์œ„์น˜๊ด€๋ฆฌ์žIP์ฃผ์†ŒMAC ์ฃผ์†Œ - H/W ์‚ฌ์–‘OS - ๊ตฌ๋งค์ผ๊ธˆ์•ก๋‚ฉํ’ˆ์—…์ฒดํ’ˆ์˜์„œ๊ด€๋ฆฌ - - - - `; - container.appendChild(table); - mainContent.appendChild(container); - - const tbody = document.getElementById('dynamic-tbody')!; - if (list.length === 0) { - tbody.innerHTML = `๋“ฑ๋ก๋œ [${activeSubTab}] ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; - return; - } - - list.forEach((asset, idx) => { - const tr = document.createElement('tr'); - tr.style.cursor = 'pointer'; - tr.innerHTML = ` - ${idx + 1}${asset.๋ฒ•์ธ} - ${activeSubTab === '์ „์‚ฐ๋น„ํ’ˆ' ? `${asset.๋น„ํ’ˆ์œ ํ˜•||'-'}` : ''} - ${asset.์ž์‚ฐ์ฝ”๋“œ}${asset.๋ช…์นญ} - ${asset.์œ„์น˜}${asset.๊ด€๋ฆฌ์ž}${asset.IP์ฃผ์†Œ}${asset.MACaddress} - ${asset.HW์‚ฌ์–‘} - ${asset.OS} - ${asset.๊ตฌ๋งค์ผ||''} - ${asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''} - ${asset.๋‚ฉํ’ˆ์—…์ฒด||''} - ${asset.ํ’ˆ์˜์„œ๋ช… ? `` : '-'} - - `; - tr.addEventListener('click', (e) => { - if ((e.target as HTMLElement).tagName.toLowerCase() === 'button') return; - openHwModal(asset); - }); - tr.querySelector('.btn-edit')?.addEventListener('click', () => openHwModal(asset)); - tbody.appendChild(tr); - }); - } - - } else { - // SW - const list = masterData.sw.filter(a => a.type === activeSubTab); - - // Header - let theadHTML = ''; - if (activeSubTab === '๊ตฌ๋…SW') { - theadHTML = ` - No๋ฒ•์ธ์ œํ’ˆ๋ช…๊ตฌ๋งค์ผ๊ตฌ๋…์ผ - ๊ธˆ์•ก์ˆ˜๋Ÿ‰์‚ฌ์šฉ๊ฐ€๋Šฅ๊ณ„์ •๋ช…๋‚ฉํ’ˆ์—…์ฒด๋น„๊ณ ๊ด€๋ฆฌ - `; - } else { - theadHTML = ` - No๋ฒ•์ธ์ œํ’ˆ๋ช…๊ตฌ๋งค์ผ์œ ์ง€๋ณด์ˆ˜ - ๊ธˆ์•ก์ˆ˜๋Ÿ‰์‚ฌ์šฉ๊ฐ€๋Šฅ๊ณ„์ •๋ช…๋‚ฉํ’ˆ์—…์ฒด๋น„๊ณ ๊ด€๋ฆฌ - `; - } - - table.innerHTML = ` - ${theadHTML} - - `; - container.appendChild(table); - mainContent.appendChild(container); - - const tbody = document.getElementById('dynamic-tbody')!; - if (list.length === 0) { - tbody.innerHTML = `๋“ฑ๋ก๋œ [${activeSubTab}] ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.`; - createIcons({ icons: { Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Mouse, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2 } }); - return; - } - - list.forEach((asset, idx) => { - const assignedUsers = masterData.swUsers.filter(u => u.swId === asset.id); - const available = asset.์ˆ˜๋Ÿ‰ - assignedUsers.length; - - const tr = document.createElement('tr'); - tr.style.cursor = 'pointer'; - - let middleRowHTML = ''; - if (activeSubTab === '๊ตฌ๋…SW') { - middleRowHTML = `${asset.๊ตฌ๋…์ผ||''}`; - } else { - middleRowHTML = `${asset.์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€ ? 'Y' : 'N'}`; - } - - tr.innerHTML = ` - ${idx + 1} - ${asset.๋ฒ•์ธ} - ${asset.์ œํ’ˆ๋ช…} - ${asset.๊ตฌ๋งค์ผ||''} - ${middleRowHTML} - ${asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''} - ${asset.์ˆ˜๋Ÿ‰} - ${available} - ${asset.๊ณ„์ •๋ช…||''} - ${asset.๋‚ฉํ’ˆ์—…์ฒด||''} - ${asset.๋น„๊ณ ||''} - - - - - `; - tr.addEventListener('click', (e) => { - const target = e.target as HTMLElement; - if (target.tagName.toLowerCase() === 'button' || target.closest('button')) return; - openSwModal(asset); - }); - tr.querySelector('.btn-edit')?.addEventListener('click', () => openSwModal(asset)); - tr.querySelector('.btn-users')?.addEventListener('click', () => openSwUserModal(asset)); - tbody.appendChild(tr); - }); - } - - // BUG FIX: initialize icons for newly inserted DOM blocks - createIcons({ icons: { Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Mouse, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2 } }); -} - -// --- Modals --- -function closeModals() { - hwModal.classList.add('hidden'); - swModal.classList.add('hidden'); - pcModal.classList.add('hidden'); - storageModal.classList.add('hidden'); - document.getElementById('sw-user-modal')?.classList.add('hidden'); - document.getElementById('sw-user-edit-modal')?.classList.add('hidden'); -} - -document.querySelectorAll('.btn-icon, #btn-cancel-hw-modal, #btn-cancel-sw-modal, #btn-cancel-pc-modal, #btn-cancel-storage-modal').forEach(btn => { - btn.addEventListener('click', closeModals); -}); - -// ESCํ‚ค, ์™ธ๋ถ€ํด๋ฆญ ๋‹ซ๊ธฐ -window.addEventListener('keydown', (e) => { - if (e.key === 'Escape') closeModals(); -}); -document.querySelectorAll('.modal-overlay').forEach(overlay => { - overlay.addEventListener('click', (e) => { - if (e.target === overlay) closeModals(); - }); +// Dashboard Detail ๋‹ซ๊ธฐ ๋ฒ„ํŠผ (๊ณตํ†ต ์ฒ˜๋ฆฌ์šฉ) +const btnCloseDashboardDetail = document.getElementById('btn-close-dashboard-detail') as HTMLButtonElement; +btnCloseDashboardDetail?.addEventListener('click', () => { + document.getElementById('dashboard-detail-modal')?.classList.add('hidden'); }); // Add Element Button -btnAddAsset.addEventListener('click', () => { - if (activeSubTab === '๋Œ€์‹œ๋ณด๋“œ') return; - if (activeCategory === 'hw') { - if (activeSubTab === '๊ฐœ์ธPC') { - openPcModal(); - } else if (activeSubTab === '์Šคํ† ๋ฆฌ์ง€') { - openStorageModal(); - } else { - openHwModal(); - } +btnAddAsset?.addEventListener('click', () => { + if (state.activeSubTab === '๋Œ€์‹œ๋ณด๋“œ') return; + if (state.activeCategory === 'hw') { + if (state.activeSubTab === '๊ฐœ์ธPC') openPcModal(); + else if (state.activeSubTab === '์Šคํ† ๋ฆฌ์ง€') openStorageModal(); + else openHwModal(); } else { openSwModal(); } }); -// HW Modal open logic -function openHwModal(asset?: HardwareAsset) { - hwModal.classList.remove('hidden'); - hwForm.reset(); - const deleteBtn = document.getElementById('btn-delete-hw-asset')!; - - if (asset) { - document.getElementById('hw-modal-title')!.textContent = '์ž์‚ฐ ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •'; - deleteBtn.style.display = 'block'; - - (document.getElementById('hw-asset-id') as HTMLInputElement).value = asset.id; - (document.getElementById('hw-asset-type') as HTMLInputElement).value = asset.type; - (document.getElementById('hw-๋ฒ•์ธ') as HTMLInputElement).value = asset.๋ฒ•์ธ; - (document.getElementById('hw-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value = asset.์ž์‚ฐ์ฝ”๋“œ; - (document.getElementById('hw-๋ช…์นญ') as HTMLInputElement).value = asset.๋ช…์นญ; - (document.getElementById('hw-์œ„์น˜') as HTMLInputElement).value = asset.์œ„์น˜; - (document.getElementById('hw-๊ด€๋ฆฌ์ž') as HTMLInputElement).value = asset.๊ด€๋ฆฌ์ž; - (document.getElementById('hw-IP์ฃผ์†Œ') as HTMLInputElement).value = asset.IP์ฃผ์†Œ; - (document.getElementById('hw-MACaddress') as HTMLInputElement).value = asset.MACaddress; - (document.getElementById('hw-OS') as HTMLInputElement).value = asset.OS; - (document.getElementById('hw-HW์‚ฌ์–‘') as HTMLTextAreaElement).value = asset.HW์‚ฌ์–‘; - (document.getElementById('hw-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; - (document.getElementById('hw-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; - (document.getElementById('hw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; - (document.getElementById('hw-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = asset.ํ’ˆ์˜์„œ๋ช… ? `๐Ÿ“Ž${asset.ํ’ˆ์˜์„œ๋ช…}` : ''; - (document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•') as HTMLSelectElement).value = asset.๋น„ํ’ˆ์œ ํ˜• || '๋…ธํŠธ๋ถ'; - } else { - document.getElementById('hw-modal-title')!.textContent = `์ƒˆ ${activeSubTab} ์ž์‚ฐ ์ถ”๊ฐ€`; - deleteBtn.style.display = 'none'; - (document.getElementById('hw-asset-id') as HTMLInputElement).value = ''; - (document.getElementById('hw-asset-type') as HTMLInputElement).value = activeSubTab; - (document.getElementById('hw-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = ''; - (document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•') as HTMLSelectElement).value = '๋…ธํŠธ๋ถ'; - } - - if (activeSubTab === '์ „์‚ฐ๋น„ํ’ˆ') { - document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•-group')!.style.display = 'block'; - } else { - document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•-group')!.style.display = 'none'; - } -} - -// PC Modal open logic -function openPcModal(asset?: HardwareAsset) { - pcModal.classList.remove('hidden'); - pcForm.reset(); - const deleteBtn = document.getElementById('btn-delete-pc-asset')!; - - if (asset) { - document.getElementById('pc-modal-title')!.textContent = '๊ฐœ์ธPC ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •'; - deleteBtn.style.display = 'block'; - - (document.getElementById('pc-asset-id') as HTMLInputElement).value = asset.id; - (document.getElementById('pc-๋ฒ•์ธ') as HTMLSelectElement).value = asset.๋ฒ•์ธ; - (document.getElementById('pc-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value = asset.์ž์‚ฐ์ฝ”๋“œ; - (document.getElementById('pc-์‚ฌ์šฉ์ž') as HTMLInputElement).value = asset.์‚ฌ์šฉ์ž || ''; - (document.getElementById('pc-์œ„์น˜') as HTMLInputElement).value = asset.์œ„์น˜ || ''; - (document.getElementById('pc-CPU') as HTMLInputElement).value = asset.CPU || ''; - (document.getElementById('pc-GPU') as HTMLInputElement).value = asset.GPU || ''; - (document.getElementById('pc-RAM') as HTMLInputElement).value = asset.RAM || ''; - (document.getElementById('pc-SSD1') as HTMLInputElement).value = asset.SSD1 || ''; - (document.getElementById('pc-SSD2') as HTMLInputElement).value = asset.SSD2 || ''; - (document.getElementById('pc-HDD1') as HTMLInputElement).value = asset.HDD1 || ''; - (document.getElementById('pc-HDD2') as HTMLInputElement).value = asset.HDD2 || ''; - (document.getElementById('pc-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; - (document.getElementById('pc-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; - (document.getElementById('pc-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; - (document.getElementById('pc-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = asset.ํ’ˆ์˜์„œ๋ช… ? `๐Ÿ“Ž${asset.ํ’ˆ์˜์„œ๋ช…}` : ''; - } else { - document.getElementById('pc-modal-title')!.textContent = '์ƒˆ ๊ฐœ์ธPC ์ž์‚ฐ ์ถ”๊ฐ€'; - deleteBtn.style.display = 'none'; - (document.getElementById('pc-asset-id') as HTMLInputElement).value = ''; - (document.getElementById('pc-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; - (document.getElementById('pc-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = ''; - } -} - -// Storage Modal open logic -function openStorageModal(asset?: HardwareAsset) { - storageModal.classList.remove('hidden'); - storageForm.reset(); - const deleteBtn = document.getElementById('btn-delete-storage-asset')!; - - if (asset) { - document.getElementById('storage-modal-title')!.textContent = '์Šคํ† ๋ฆฌ์ง€ ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •'; - deleteBtn.style.display = 'block'; - - (document.getElementById('storage-asset-id') as HTMLInputElement).value = asset.id; - (document.getElementById('storage-๋ฒ•์ธ') as HTMLSelectElement).value = asset.๋ฒ•์ธ; - (document.getElementById('storage-์œ ํ˜•') as HTMLSelectElement).value = asset.storage์œ ํ˜• || 'NAS'; - (document.getElementById('storage-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value = asset.์ž์‚ฐ์ฝ”๋“œ; - (document.getElementById('storage-๋ช…์นญ') as HTMLInputElement).value = asset.๋ช…์นญ; - (document.getElementById('storage-์œ„์น˜') as HTMLInputElement).value = asset.์œ„์น˜ || ''; - (document.getElementById('storage-๋ชจ๋ธ๋ช…') as HTMLInputElement).value = asset.๋ชจ๋ธ๋ช… || ''; - (document.getElementById('storage-์šฉ๋Ÿ‰') as HTMLInputElement).value = asset.์šฉ๋Ÿ‰ || ''; - (document.getElementById('storage-๋‹ด๋‹น์ž_์ •') as HTMLInputElement).value = asset.๋‹ด๋‹น์ž_์ • || ''; - (document.getElementById('storage-๋‹ด๋‹น์ž_๋ถ€') as HTMLInputElement).value = asset.๋‹ด๋‹น์ž_๋ถ€ || ''; - (document.getElementById('storage-IP์ฃผ์†Œ') as HTMLInputElement).value = asset.IP์ฃผ์†Œ || ''; - (document.getElementById('storage-MAC์ฃผ์†Œ') as HTMLInputElement).value = asset.MACaddress || ''; - (document.getElementById('storage-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; - (document.getElementById('storage-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; - (document.getElementById('storage-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; - (document.getElementById('storage-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = asset.ํ’ˆ์˜์„œ๋ช… ? `๐Ÿ“Ž${asset.ํ’ˆ์˜์„œ๋ช…}` : ''; - } else { - document.getElementById('storage-modal-title')!.textContent = '์ƒˆ ์Šคํ† ๋ฆฌ์ง€ ์ž์‚ฐ ์ถ”๊ฐ€'; - deleteBtn.style.display = 'none'; - (document.getElementById('storage-asset-id') as HTMLInputElement).value = ''; - (document.getElementById('storage-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; - (document.getElementById('storage-์œ ํ˜•') as HTMLSelectElement).value = 'NAS'; - (document.getElementById('storage-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText = ''; - } -} - -// SW Modal open logic -function openSwModal(asset?: SoftwareAsset) { - swModal.classList.remove('hidden'); - swForm.reset(); - const deleteBtn = document.getElementById('btn-delete-sw-asset')!; - - const subGroup = document.getElementById('sw-๊ตฌ๋…์ผ-group')!; - const permGroup = document.getElementById('sw-์œ ์ง€๋ณด์ˆ˜-group')!; - if (activeSubTab === '๊ตฌ๋…SW') { - subGroup.style.display = 'block'; - permGroup.style.display = 'none'; - } else { - subGroup.style.display = 'none'; - permGroup.style.display = 'block'; - } - - if (asset) { - document.getElementById('sw-modal-title')!.textContent = `${activeSubTab} ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ •`; - deleteBtn.style.display = 'block'; - - (document.getElementById('sw-asset-id') as HTMLInputElement).value = asset.id; - (document.getElementById('sw-asset-type') as HTMLInputElement).value = asset.type; - (document.getElementById('sw-๋ฒ•์ธ') as HTMLSelectElement).value = asset.๋ฒ•์ธ; - (document.getElementById('sw-์ œํ’ˆ๋ช…') as HTMLInputElement).value = asset.์ œํ’ˆ๋ช…; - (document.getElementById('sw-๊ตฌ๋งค์ผ') as HTMLInputElement).value = asset.๊ตฌ๋งค์ผ || ''; - (document.getElementById('sw-๊ตฌ๋…์ผ') as HTMLInputElement).value = asset.๊ตฌ๋…์ผ || ''; - (document.getElementById('sw-์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€') as HTMLInputElement).checked = !!asset.์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€; - (document.getElementById('sw-๊ธˆ์•ก') as HTMLInputElement).value = asset.๊ธˆ์•ก ? Number(asset.๊ธˆ์•ก.replace(/,/g, '')).toLocaleString() : ''; - (document.getElementById('sw-์ˆ˜๋Ÿ‰') as HTMLInputElement).value = String(asset.์ˆ˜๋Ÿ‰); - (document.getElementById('sw-๊ณ„์ •๋ช…') as HTMLInputElement).value = asset.๊ณ„์ •๋ช… || ''; - (document.getElementById('sw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value = asset.๋‚ฉํ’ˆ์—…์ฒด || ''; - (document.getElementById('sw-๋น„๊ณ ') as HTMLInputElement).value = asset.๋น„๊ณ  || ''; - } else { - document.getElementById('sw-modal-title')!.textContent = `์ƒˆ ${activeSubTab} ์ž์‚ฐ ์ถ”๊ฐ€`; - deleteBtn.style.display = 'none'; - (document.getElementById('sw-asset-id') as HTMLInputElement).value = ''; - (document.getElementById('sw-asset-type') as HTMLInputElement).value = activeSubTab; - (document.getElementById('sw-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; - } -} - -// HW Save -document.getElementById('btn-save-hw-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - if (!hwForm.checkValidity()) { hwForm.reportValidity(); return; } - - const id = (document.getElementById('hw-asset-id') as HTMLInputElement).value; - const fileInput = document.getElementById('hw-ํ’ˆ์˜์„œ') as HTMLInputElement; - const ํ’ˆ์˜์„œ๋ช… = fileInput.files && fileInput.files.length > 0 ? fileInput.files[0].name : (document.getElementById('hw-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText.replace('๐Ÿ“Ž', ''); - - const newAsset: HardwareAsset = { - id: id || Math.random().toString(36).substring(2, 9), - type: (document.getElementById('hw-asset-type') as HTMLInputElement).value, - ๋ฒ•์ธ: (document.getElementById('hw-๋ฒ•์ธ') as HTMLInputElement).value, - ์ž์‚ฐ์ฝ”๋“œ: (document.getElementById('hw-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value, - ๋ช…์นญ: (document.getElementById('hw-๋ช…์นญ') as HTMLInputElement).value, - ์œ„์น˜: (document.getElementById('hw-์œ„์น˜') as HTMLInputElement).value, - ๊ด€๋ฆฌ์ž: (document.getElementById('hw-๊ด€๋ฆฌ์ž') as HTMLInputElement).value, - IP์ฃผ์†Œ: (document.getElementById('hw-IP์ฃผ์†Œ') as HTMLInputElement).value, - MACaddress: (document.getElementById('hw-MACaddress') as HTMLInputElement).value, - OS: (document.getElementById('hw-OS') as HTMLInputElement).value, - HW์‚ฌ์–‘: (document.getElementById('hw-HW์‚ฌ์–‘') as HTMLTextAreaElement).value, - ๊ตฌ๋งค์ผ: (document.getElementById('hw-๊ตฌ๋งค์ผ') as HTMLInputElement).value, - ๊ธˆ์•ก: (document.getElementById('hw-๊ธˆ์•ก') as HTMLInputElement).value, - ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('hw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, - ํ’ˆ์˜์„œ๋ช…, - ๋น„ํ’ˆ์œ ํ˜•: (document.getElementById('hw-asset-type') as HTMLInputElement).value === '์ „์‚ฐ๋น„ํ’ˆ' - ? (document.getElementById('hw-๋น„ํ’ˆ์œ ํ˜•') as HTMLSelectElement).value : undefined - }; - - if (id) { - const idx = masterData.hw.findIndex(a => a.id === id); - if(idx !== -1) masterData.hw[idx] = newAsset; - } else { - masterData.hw.push(newAsset); - } - closeModals(); renderContent(); -}); - -// PC Save -document.getElementById('btn-save-pc-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - if (!pcForm.checkValidity()) { pcForm.reportValidity(); return; } - - const id = (document.getElementById('pc-asset-id') as HTMLInputElement).value; - const fileInput = document.getElementById('pc-ํ’ˆ์˜์„œ') as HTMLInputElement; - const ํ’ˆ์˜์„œ๋ช… = fileInput.files && fileInput.files.length > 0 ? fileInput.files[0].name : (document.getElementById('pc-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText.replace('๐Ÿ“Ž', ''); - - const newAsset: HardwareAsset = { - id: id || Math.random().toString(36).substring(2, 9), - type: '๊ฐœ์ธPC', - ๋ฒ•์ธ: (document.getElementById('pc-๋ฒ•์ธ') as HTMLSelectElement).value, - ์ž์‚ฐ์ฝ”๋“œ: (document.getElementById('pc-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value, - ๋ช…์นญ: '', - ์œ„์น˜: (document.getElementById('pc-์œ„์น˜') as HTMLInputElement).value, - ๊ด€๋ฆฌ์ž: '', - IP์ฃผ์†Œ: '', - MACaddress: '', - HW์‚ฌ์–‘: '', - OS: '', - ์‚ฌ์šฉ์ž: (document.getElementById('pc-์‚ฌ์šฉ์ž') as HTMLInputElement).value, - CPU: (document.getElementById('pc-CPU') as HTMLInputElement).value, - GPU: (document.getElementById('pc-GPU') as HTMLInputElement).value, - RAM: (document.getElementById('pc-RAM') as HTMLInputElement).value, - SSD1: (document.getElementById('pc-SSD1') as HTMLInputElement).value, - SSD2: (document.getElementById('pc-SSD2') as HTMLInputElement).value, - HDD1: (document.getElementById('pc-HDD1') as HTMLInputElement).value, - HDD2: (document.getElementById('pc-HDD2') as HTMLInputElement).value, - ๊ตฌ๋งค์ผ: (document.getElementById('pc-๊ตฌ๋งค์ผ') as HTMLInputElement).value, - ๊ธˆ์•ก: (document.getElementById('pc-๊ธˆ์•ก') as HTMLInputElement).value, - ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('pc-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, - ํ’ˆ์˜์„œ๋ช… - }; - - if (id) { - const idx = masterData.hw.findIndex(a => a.id === id); - if(idx !== -1) masterData.hw[idx] = newAsset; - } else { - masterData.hw.push(newAsset); - } - closeModals(); renderContent(); -}); - -// Storage Save -document.getElementById('btn-save-storage-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - if (!storageForm.checkValidity()) { storageForm.reportValidity(); return; } - - const id = (document.getElementById('storage-asset-id') as HTMLInputElement).value; - const fileInput = document.getElementById('storage-ํ’ˆ์˜์„œ') as HTMLInputElement; - const ํ’ˆ์˜์„œ๋ช… = fileInput.files && fileInput.files.length > 0 ? fileInput.files[0].name : (document.getElementById('storage-ํ’ˆ์˜์„œ๋ช…') as HTMLElement).innerText.replace('๐Ÿ“Ž', ''); - - const newAsset: HardwareAsset = { - id: id || Math.random().toString(36).substring(2, 9), - type: '์Šคํ† ๋ฆฌ์ง€', - ๋ฒ•์ธ: (document.getElementById('storage-๋ฒ•์ธ') as HTMLSelectElement).value, - storage์œ ํ˜•: (document.getElementById('storage-์œ ํ˜•') as HTMLSelectElement).value, - ์ž์‚ฐ์ฝ”๋“œ: (document.getElementById('storage-์ž์‚ฐ์ฝ”๋“œ') as HTMLInputElement).value, - ๋ช…์นญ: (document.getElementById('storage-๋ช…์นญ') as HTMLInputElement).value, - ์œ„์น˜: (document.getElementById('storage-์œ„์น˜') as HTMLInputElement).value, - ๊ด€๋ฆฌ์ž: '', - IP์ฃผ์†Œ: (document.getElementById('storage-IP์ฃผ์†Œ') as HTMLInputElement).value, - MACaddress: (document.getElementById('storage-MAC์ฃผ์†Œ') as HTMLInputElement).value, - HW์‚ฌ์–‘: '', - OS: '', - ๋ชจ๋ธ๋ช…: (document.getElementById('storage-๋ชจ๋ธ๋ช…') as HTMLInputElement).value, - ์šฉ๋Ÿ‰: (document.getElementById('storage-์šฉ๋Ÿ‰') as HTMLInputElement).value, - ๋‹ด๋‹น์ž_์ •: (document.getElementById('storage-๋‹ด๋‹น์ž_์ •') as HTMLInputElement).value, - ๋‹ด๋‹น์ž_๋ถ€: (document.getElementById('storage-๋‹ด๋‹น์ž_๋ถ€') as HTMLInputElement).value, - ๊ตฌ๋งค์ผ: (document.getElementById('storage-๊ตฌ๋งค์ผ') as HTMLInputElement).value, - ๊ธˆ์•ก: (document.getElementById('storage-๊ธˆ์•ก') as HTMLInputElement).value, - ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('storage-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, - ํ’ˆ์˜์„œ๋ช… - }; - - if (id) { - const idx = masterData.hw.findIndex(a => a.id === id); - if(idx !== -1) masterData.hw[idx] = newAsset; - } else { - masterData.hw.push(newAsset); - } - closeModals(); renderContent(); -}); - -// SW Save -document.getElementById('btn-save-sw-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - if (!swForm.checkValidity()) { swForm.reportValidity(); return; } - - const id = (document.getElementById('sw-asset-id') as HTMLInputElement).value; - const newAsset: SoftwareAsset = { - id: id || Math.random().toString(36).substring(2, 9), - type: (document.getElementById('sw-asset-type') as HTMLInputElement).value, - ๋ฒ•์ธ: (document.getElementById('sw-๋ฒ•์ธ') as HTMLSelectElement).value, - ์ œํ’ˆ๋ช…: (document.getElementById('sw-์ œํ’ˆ๋ช…') as HTMLInputElement).value, - ๊ตฌ๋งค์ผ: (document.getElementById('sw-๊ตฌ๋งค์ผ') as HTMLInputElement).value, - ๊ตฌ๋…์ผ: (document.getElementById('sw-๊ตฌ๋…์ผ') as HTMLInputElement).value, - ์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€: (document.getElementById('sw-์œ ์ง€๋ณด์ˆ˜์—ฌ๋ถ€') as HTMLInputElement).checked, - ๊ธˆ์•ก: (document.getElementById('sw-๊ธˆ์•ก') as HTMLInputElement).value, - ์ˆ˜๋Ÿ‰: parseInt((document.getElementById('sw-์ˆ˜๋Ÿ‰') as HTMLInputElement).value || '1', 10), - ๊ณ„์ •๋ช…: (document.getElementById('sw-๊ณ„์ •๋ช…') as HTMLInputElement).value, - ๋‚ฉํ’ˆ์—…์ฒด: (document.getElementById('sw-๋‚ฉํ’ˆ์—…์ฒด') as HTMLInputElement).value, - ๋น„๊ณ : (document.getElementById('sw-๋น„๊ณ ') as HTMLInputElement).value, - }; - - if (id) { - const idx = masterData.sw.findIndex(a => a.id === id); - if(idx !== -1) masterData.sw[idx] = newAsset; - } else { - masterData.sw.push(newAsset); - } - closeModals(); renderContent(); -}); - -// Deletes -document.getElementById('btn-delete-hw-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - const id = (document.getElementById('hw-asset-id') as HTMLInputElement).value; - if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { - masterData.hw = masterData.hw.filter(a => a.id !== id); - closeModals(); renderContent(); - } -}); -document.getElementById('btn-delete-pc-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - const id = (document.getElementById('pc-asset-id') as HTMLInputElement).value; - if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { - masterData.hw = masterData.hw.filter(a => a.id !== id); - closeModals(); renderContent(); - } -}); -document.getElementById('btn-delete-storage-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - const id = (document.getElementById('storage-asset-id') as HTMLInputElement).value; - if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { - masterData.hw = masterData.hw.filter(a => a.id !== id); - closeModals(); renderContent(); - } -}); -document.getElementById('btn-delete-sw-asset')?.addEventListener('click', (e) => { - e.preventDefault(); - const id = (document.getElementById('sw-asset-id') as HTMLInputElement).value; - if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) { - masterData.sw = masterData.sw.filter(a => a.id !== id); - closeModals(); renderContent(); - } -}); - // --- Excel Controls --- -btnDownloadTemp.addEventListener('click', () => downloadTemplate()); -btnExport.addEventListener('click', () => exportToExcel(masterData)); +btnDownloadTemp?.addEventListener('click', () => downloadTemplate()); +btnExport?.addEventListener('click', () => exportToExcel(state.masterData)); -uploadInput.addEventListener('change', async (e) => { +uploadInput?.addEventListener('change', async (e) => { const file = (e.target as HTMLInputElement).files?.[0]; if (!file) return; try { - masterData = await parseExcel(file); + state.masterData = await parseExcel(file); renderContent(); alert('๋ชจ๋“  ์‹œํŠธ ๋ฐ์ดํ„ฐ ์—ฐ๋™ ์™„๋ฃŒ'); } catch (error) { @@ -1076,161 +71,18 @@ uploadInput.addEventListener('change', async (e) => { } }); -// --- SW User Modal Logic --- -const swUserModal = document.getElementById('sw-user-modal') as HTMLDivElement; -const swUserEditModal = document.getElementById('sw-user-edit-modal') as HTMLDivElement; -let currentSwUserAssetId: string = ''; -let tempSwUsers: import("./excelHandler").SWUser[] = []; - -function renderUserList() { - const tbody = document.getElementById('user-list-body')!; - tbody.innerHTML = ''; - if (tempSwUsers.length === 0) { - tbody.innerHTML = 'ํ• ๋‹น๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; - return; - } +/** + * ์ „์—ญ ๋ Œ๋”๋ง ํ•จ์ˆ˜ - ๊ฐ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ˜ธ์ถœํ•˜์—ฌ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค. + */ +function renderContent() { + mainContent.innerHTML = ''; // ํ™”๋ฉด ์ดˆ๊ธฐํ™” - tempSwUsers.forEach((user, idx) => { - const tr = document.createElement('tr'); - tr.style.cssText = 'border-bottom: 1px solid var(--border); transition: background-color 0.2s;'; - tr.addEventListener('mouseenter', () => tr.style.backgroundColor = 'var(--bg-light)'); - tr.addEventListener('mouseleave', () => tr.style.backgroundColor = 'transparent'); - - // ๋ฒ•์ธ, ๋ถ€์„œ/ํŒ€, ์ง์œ„, ์ด๋ฆ„, ์‚ฌ์šฉ๊ธฐ๊ฐ„, ์ฒจ๋ถ€ํŒŒ์ผ, ๊ด€๋ฆฌ - const deptTeam = [user.๋ถ€์„œ, user.ํŒ€].filter(Boolean).join(' / ') || '-'; - const attachIcon = user.์‹ ์ฒญ์„œ๋ช… ? `` : '-'; - - tr.innerHTML = ` - ${user.๋ฒ•์ธ} - ${deptTeam} - ${user.์ง์œ„ || '-'} - ${user.์ด๋ฆ„} - ${user.์‚ฌ์šฉ๊ธฐ๊ฐ„ || '-'} - ${attachIcon} - - - - - `; - tbody.appendChild(tr); - }); - - createIcons({ icons: { Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Mouse, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2 } }); - - tbody.querySelectorAll('.btn-edit-user').forEach(btn => { - btn.addEventListener('click', (e) => { - const idx = parseInt((e.currentTarget as HTMLElement).getAttribute('data-idx')!); - openUserEditModal(idx); - }); - }); - - tbody.querySelectorAll('.btn-remove-user').forEach(btn => { - btn.addEventListener('click', (e) => { - e.stopPropagation(); - const idx = parseInt((e.currentTarget as HTMLButtonElement).getAttribute('data-idx')!); - tempSwUsers.splice(idx, 1); - renderUserList(); - }); - }); -} - -function openSwUserModal(asset: SoftwareAsset) { - swUserModal.classList.remove('hidden'); - currentSwUserAssetId = asset.id; - tempSwUsers = masterData.swUsers.filter(u => u.swId === asset.id).map(u => ({...u})); - renderUserList(); -} - -function openUserEditModal(idx: number) { - swUserEditModal.classList.remove('hidden'); - (document.getElementById('edit-user-idx') as HTMLInputElement).value = String(idx); - - if (idx === -1) { - document.getElementById('sw-user-edit-modal-title')!.innerText = '์ƒˆ ์‚ฌ์šฉ์ž ์ถ”๊ฐ€'; - (document.getElementById('new-user-๋ฒ•์ธ') as HTMLSelectElement).value = 'ํ•œ๋งฅ'; - (document.getElementById('new-user-๋ถ€์„œ') as HTMLInputElement).value = ''; - (document.getElementById('new-user-ํŒ€') as HTMLInputElement).value = ''; - (document.getElementById('new-user-์ง์œ„') as HTMLInputElement).value = ''; - (document.getElementById('new-user-์ด๋ฆ„') as HTMLInputElement).value = ''; - (document.getElementById('new-user-์‚ฌ์šฉ๊ธฐ๊ฐ„') as HTMLInputElement).value = ''; - (document.getElementById('new-user-์‹ ์ฒญ์„œ') as HTMLInputElement).value = ''; - document.getElementById('new-user-์‹ ์ฒญ์„œ๋ช…')!.innerText = ''; + if (state.activeSubTab === '๋Œ€์‹œ๋ณด๋“œ') { + renderDashboard(mainContent); } else { - document.getElementById('sw-user-edit-modal-title')!.innerText = '์‚ฌ์šฉ์ž ์ˆ˜์ •'; - const u = tempSwUsers[idx]; - (document.getElementById('new-user-๋ฒ•์ธ') as HTMLSelectElement).value = u.๋ฒ•์ธ; - (document.getElementById('new-user-๋ถ€์„œ') as HTMLInputElement).value = u.๋ถ€์„œ; - (document.getElementById('new-user-ํŒ€') as HTMLInputElement).value = u.ํŒ€; - (document.getElementById('new-user-์ง์œ„') as HTMLInputElement).value = u.์ง์œ„; - (document.getElementById('new-user-์ด๋ฆ„') as HTMLInputElement).value = u.์ด๋ฆ„; - (document.getElementById('new-user-์‚ฌ์šฉ๊ธฐ๊ฐ„') as HTMLInputElement).value = u.์‚ฌ์šฉ๊ธฐ๊ฐ„; - (document.getElementById('new-user-์‹ ์ฒญ์„œ') as HTMLInputElement).value = ''; // file input cannot be programmatically set - document.getElementById('new-user-์‹ ์ฒญ์„œ๋ช…')!.innerText = u.์‹ ์ฒญ์„œ๋ช… ? `๐Ÿ“Ž${u.์‹ ์ฒญ์„œ๋ช…}` : ''; + renderTable(mainContent); } } -document.getElementById('btn-open-add-user')?.addEventListener('click', () => { - openUserEditModal(-1); -}); - -document.getElementById('btn-save-edit-user')?.addEventListener('click', () => { - const idx = parseInt((document.getElementById('edit-user-idx') as HTMLInputElement).value); - const ๋ฒ•์ธ = (document.getElementById('new-user-๋ฒ•์ธ') as HTMLSelectElement).value; - const ๋ถ€์„œ = (document.getElementById('new-user-๋ถ€์„œ') as HTMLInputElement).value; - const ํŒ€ = (document.getElementById('new-user-ํŒ€') as HTMLInputElement).value; - const ์ง์œ„ = (document.getElementById('new-user-์ง์œ„') as HTMLInputElement).value; - const ์ด๋ฆ„ = (document.getElementById('new-user-์ด๋ฆ„') as HTMLInputElement).value.trim(); - const ์‚ฌ์šฉ๊ธฐ๊ฐ„ = (document.getElementById('new-user-์‚ฌ์šฉ๊ธฐ๊ฐ„') as HTMLInputElement).value; - - const fileInput = document.getElementById('new-user-์‹ ์ฒญ์„œ') as HTMLInputElement; - let ์‹ ์ฒญ์„œ๋ช… = ''; - if (fileInput.files && fileInput.files.length > 0) { - ์‹ ์ฒญ์„œ๋ช… = fileInput.files[0].name; - } else if (idx !== -1) { - // Keep existing file if not changed - ์‹ ์ฒญ์„œ๋ช… = tempSwUsers[idx].์‹ ์ฒญ์„œ๋ช…; - } - - if (!์ด๋ฆ„) { alert('์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'); return; } - - if (idx === -1) { - tempSwUsers.push({ - id: Math.random().toString(36).substring(2, 9), - swId: currentSwUserAssetId, - ๋ฒ•์ธ, ๋ถ€์„œ, ํŒ€, ์ง์œ„, ์ด๋ฆ„, ์‚ฌ์šฉ๊ธฐ๊ฐ„, ์‹ ์ฒญ์„œ๋ช… - }); - } else { - tempSwUsers[idx] = { ...tempSwUsers[idx], ๋ฒ•์ธ, ๋ถ€์„œ, ํŒ€, ์ง์œ„, ์ด๋ฆ„, ์‚ฌ์šฉ๊ธฐ๊ฐ„, ์‹ ์ฒญ์„œ๋ช… }; - } - - swUserEditModal.classList.add('hidden'); - renderUserList(); -}); - -document.getElementById('btn-cancel-sw-user-edit')?.addEventListener('click', () => { - swUserEditModal.classList.add('hidden'); -}); -document.getElementById('btn-close-sw-user-edit-modal')?.addEventListener('click', () => { - swUserEditModal.classList.add('hidden'); -}); - -document.getElementById('btn-save-sw-user-mapping')?.addEventListener('click', () => { - // Remove existing mappings for this asset - masterData.swUsers = masterData.swUsers.filter(u => u.swId !== currentSwUserAssetId); - // Add updated mappings - masterData.swUsers.push(...tempSwUsers); - - swUserModal.classList.add('hidden'); - renderContent(); -}); - -document.getElementById('btn-cancel-sw-user-modal')?.addEventListener('click', () => { - swUserModal.classList.add('hidden'); -}); -document.getElementById('btn-close-sw-user-modal')?.addEventListener('click', () => { - swUserModal.classList.add('hidden'); -}); - - // Initial Render renderContent(); diff --git a/src/state.ts b/src/state.ts new file mode 100644 index 0000000..9f72589 --- /dev/null +++ b/src/state.ts @@ -0,0 +1,23 @@ +import { MasterAssetData } from './excelHandler'; +import { generateDummyData } from './dummyDataGenerator'; + +// --- State Definitions --- +export interface AppState { + masterData: MasterAssetData; + activeCategory: 'hw' | 'sw'; + activeSubTab: string; + activeCharts: any[]; +} + +// --- Initial State --- +export const state: AppState = { + masterData: generateDummyData(), + activeCategory: 'hw', + activeSubTab: '๋Œ€์‹œ๋ณด๋“œ', + activeCharts: [] +}; + +// --- State Helpers --- +export function updateState(newState: Partial) { + Object.assign(state, newState); +} diff --git a/src/views/AssetTableView.ts b/src/views/AssetTableView.ts new file mode 100644 index 0000000..91254bf --- /dev/null +++ b/src/views/AssetTableView.ts @@ -0,0 +1,95 @@ +import { state } from '../state'; +import { createIcons, Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2 } from 'lucide'; +import { openPcModal } from '../components/Modal/PCModal'; +import { openHwModal } from '../components/Modal/HWModal'; +import { openStorageModal } from '../components/Modal/StorageModal'; +import { openSwModal } from '../components/Modal/SWModal'; +import { openSwUserModal } from '../components/Modal/SWUserModal'; + +/** + * ์ž์‚ฐ ๋ชฉ๋ก ํ…Œ์ด๋ธ” ๋ Œ๋”๋ง ๋ฉ”์ธ ํ•จ์ˆ˜ + */ +export function renderTable(mainContent: HTMLElement) { + const container = document.createElement('div'); + container.className = 'table-container'; + const table = document.createElement('table'); + + if (state.activeCategory === 'hw') { + renderHwTable(table, container, mainContent); + } else { + renderSwTable(table, container, mainContent); + } + + // ํ…Œ์ด๋ธ” ๋‚ด ์•„์ด์ฝ˜ ์ดˆ๊ธฐํ™” + createIcons({ + icons: { Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2 } + }); +} + +function renderHwTable(table: HTMLTableElement, container: HTMLElement, mainContent: HTMLElement) { + const list = state.masterData.hw.filter(a => a.type === state.activeSubTab); + + if (state.activeSubTab === '๊ฐœ์ธPC') { + table.innerHTML = `No๋ฒ•์ธ์ž์‚ฐ์ฝ”๋“œ์‚ฌ์šฉ์ž์œ„์น˜CPUGPURAMSSD1SSD2HDD1HDD2๊ตฌ๋งค์ผ๊ธˆ์•ก๋‚ฉํ’ˆ์—…์ฒดํ’ˆ์˜์„œ๊ด€๋ฆฌ`; + container.appendChild(table); + mainContent.appendChild(container); + const tbody = document.getElementById('dynamic-tbody')!; + if (list.length === 0) { tbody.innerHTML = `๋“ฑ๋ก๋œ ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; return; } + list.forEach((asset, idx) => { + const tr = document.createElement('tr'); + tr.style.cursor = 'pointer'; + tr.innerHTML = `${idx+1}${asset.๋ฒ•์ธ}${asset.์ž์‚ฐ์ฝ”๋“œ}${asset.์‚ฌ์šฉ์ž||''}${asset.์œ„์น˜||''}${asset.CPU||''}${asset.GPU||''}${asset.RAM||''}${asset.SSD1||'-'}${asset.SSD2||'-'}${asset.HDD1||'-'}${asset.HDD2||'-'}${asset.๊ตฌ๋งค์ผ||''}${asset.๊ธˆ์•ก||''}${asset.๋‚ฉํ’ˆ์—…์ฒด||''}${asset.ํ’ˆ์˜์„œ๋ช… ? '' : '-'}`; + tr.addEventListener('click', (e) => { if (!(e.target as HTMLElement).closest('button')) openPcModal(asset); }); + tr.querySelector('.btn-edit')?.addEventListener('click', () => openPcModal(asset)); + tbody.appendChild(tr); + }); + } else if (state.activeSubTab === '์Šคํ† ๋ฆฌ์ง€') { + table.innerHTML = `No๋ฒ•์ธ์œ ํ˜•์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ์œ„์น˜๋ชจ๋ธ๋ช…์šฉ๋Ÿ‰๋‹ด๋‹น์ž(์ •)IP์ฃผ์†Œ๊ตฌ๋งค์ผ๊ธˆ์•ก๊ด€๋ฆฌ`; + container.appendChild(table); + mainContent.appendChild(container); + const tbody = document.getElementById('dynamic-tbody')!; + if (list.length === 0) { tbody.innerHTML = `๋“ฑ๋ก๋œ ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; return; } + list.forEach((asset, idx) => { + const tr = document.createElement('tr'); + tr.style.cursor = 'pointer'; + tr.innerHTML = `${idx+1}${asset.๋ฒ•์ธ}${asset.storage์œ ํ˜•||''}${asset.์ž์‚ฐ์ฝ”๋“œ}${asset.๋ช…์นญ}${asset.์œ„์น˜||''}${asset.๋ชจ๋ธ๋ช…||''}${asset.์šฉ๋Ÿ‰||''}${asset.๋‹ด๋‹น์ž_์ •||''}${asset.IP์ฃผ์†Œ||''}${asset.๊ตฌ๋งค์ผ||''}${asset.๊ธˆ์•ก||''}`; + tr.addEventListener('click', (e) => { if (!(e.target as HTMLElement).closest('button')) openStorageModal(asset); }); + tr.querySelector('.btn-edit')?.addEventListener('click', () => openStorageModal(asset)); + tbody.appendChild(tr); + }); + } else { + table.innerHTML = `No๋ฒ•์ธ${state.activeSubTab === '์ „์‚ฐ๋น„ํ’ˆ' ? '์œ ํ˜•' : ''}์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ์œ„์น˜๊ด€๋ฆฌ์ž๊ตฌ๋งค์ผ๊ธˆ์•ก๊ด€๋ฆฌ`; + container.appendChild(table); + mainContent.appendChild(container); + const tbody = document.getElementById('dynamic-tbody')!; + if (list.length === 0) { tbody.innerHTML = `๋“ฑ๋ก๋œ ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; return; } + list.forEach((asset, idx) => { + const tr = document.createElement('tr'); + tr.style.cursor = 'pointer'; + tr.innerHTML = `${idx+1}${asset.๋ฒ•์ธ}${state.activeSubTab === '์ „์‚ฐ๋น„ํ’ˆ' ? `${asset.๋น„ํ’ˆ์œ ํ˜•||'-'}` : ''}${asset.์ž์‚ฐ์ฝ”๋“œ}${asset.๋ช…์นญ}${asset.์œ„์น˜}${asset.๊ด€๋ฆฌ์ž}${asset.๊ตฌ๋งค์ผ||''}${asset.๊ธˆ์•ก||''}`; + tr.addEventListener('click', (e) => { if (!(e.target as HTMLElement).closest('button')) openHwModal(asset); }); + tr.querySelector('.btn-edit')?.addEventListener('click', () => openHwModal(asset)); + tbody.appendChild(tr); + }); + } +} + +function renderSwTable(table: HTMLTableElement, container: HTMLElement, mainContent: HTMLElement) { + const list = state.masterData.sw.filter(a => a.type === state.activeSubTab); + table.innerHTML = `No๋ฒ•์ธ์ œํ’ˆ๋ช…๊ตฌ๋งค์ผ์ˆ˜๋Ÿ‰์‚ฌ์šฉ๊ฐ€๋Šฅ๊ด€๋ฆฌ`; + container.appendChild(table); + mainContent.appendChild(container); + const tbody = document.getElementById('dynamic-tbody')!; + if (list.length === 0) { tbody.innerHTML = `์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.`; return; } + list.forEach((asset, idx) => { + const assigned = state.masterData.swUsers.filter(u => u.swId === asset.id).length; + const avail = asset.์ˆ˜๋Ÿ‰ - assigned; + const tr = document.createElement('tr'); + tr.style.cursor = 'pointer'; + tr.innerHTML = `${idx+1}${asset.๋ฒ•์ธ}${asset.์ œํ’ˆ๋ช…}${asset.๊ตฌ๋งค์ผ||''}${asset.์ˆ˜๋Ÿ‰}${avail}`; + tr.addEventListener('click', (e) => { if (!(e.target as HTMLElement).closest('button')) openSwModal(asset); }); + tr.querySelector('.btn-edit')?.addEventListener('click', () => openSwModal(asset)); + tr.querySelector('.btn-users')?.addEventListener('click', () => openSwUserModal(asset)); + tbody.appendChild(tr); + }); +} diff --git a/src/views/DashboardView.ts b/src/views/DashboardView.ts new file mode 100644 index 0000000..4101b34 --- /dev/null +++ b/src/views/DashboardView.ts @@ -0,0 +1,287 @@ +import { state } from '../state'; +import { HardwareAsset, SoftwareAsset } from '../excelHandler'; + +/** + * ๋Œ€์‹œ๋ณด๋“œ ๋ Œ๋”๋ง ๋ฉ”์ธ ํ•จ์ˆ˜ + */ +export function renderDashboard(mainContent: HTMLElement) { + mainContent.innerHTML = ''; + + // ๊ธฐ์กด ์ฐจํŠธ ๋ฆฌ์†Œ์Šค ํ•ด์ œ + state.activeCharts.forEach(c => c.destroy()); + state.activeCharts = []; + + if (state.activeCategory === 'hw') { + renderHwDashboard(mainContent); + } else { + renderSwDashboard(mainContent); + } +} + +// --- ํ•˜๋“œ์›จ์–ด ๋Œ€์‹œ๋ณด๋“œ --- +function renderHwDashboard(container: HTMLElement) { + const types = ['๊ฐœ์ธPC', '์„œ๋ฒ„', '์Šคํ† ๋ฆฌ์ง€', '์ „์‚ฐ๋น„ํ’ˆ']; + const units = ['๋Œ€', '๋Œ€', '๋Œ€', '๊ฐœ']; + const groups: any = {}; + + types.forEach(t => { groups[t] = { idle: [], active: [], aged: [], normal: [] }; }); + + state.masterData.hw.forEach(a => { + if (!groups[a.type]) return; + if (isHwIdle(a)) groups[a.type].idle.push(a); + else groups[a.type].active.push(a); + + const ageY = getHwAgeYears(a); + const isAged = a.type === '์ „์‚ฐ๋น„ํ’ˆ' ? ageY >= 3 : ageY >= 5; + if (isAged) groups[a.type].aged.push(a); + else groups[a.type].normal.push(a); + }); + + // ์‚ฌ์šฉํ˜„ํ™ฉ ์นด๋“œ ์ƒ์„ฑ + let usageCards = ''; + types.forEach((t, i) => { + const total = groups[t].idle.length + groups[t].active.length; + const used = groups[t].active.length; + const per = total > 0 ? Math.round((used / total) * 100) : 0; + const barColor = per >= 50 ? 'var(--dash-primary)' : 'var(--dash-danger)'; + + usageCards += ` +
+
+ ${t} ์‚ฌ์šฉํ˜„ํ™ฉ +
+
+ ${total}${units[i]} ์ค‘ ${used}${units[i]} ์‚ฌ์šฉ ์ค‘ ยท ์œ ํœด ${groups[t].idle.length}${units[i]} +
+
+
${per}%
+
+ ${per >= 50 ? '์ž˜ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”' : '์ ๊ฒ€์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค'} +
+
+
+
+
+
`; + }); + + // ๋…ธํ›„ํ™” ์นด๋“œ ์ƒ์„ฑ + let agedCards = ''; + types.forEach((t, i) => { + const total = groups[t].aged.length + groups[t].normal.length; + const agedCount = groups[t].aged.length; + const agedPer = total > 0 ? Math.round((agedCount / total) * 100) : 0; + const threshold = t === '์ „์‚ฐ๋น„ํ’ˆ' ? '3๋…„' : '5๋…„'; + + agedCards += ` +
+
+
+ ${t} ๋…ธํ›„ํ™” ํ˜„ํ™ฉ + ${threshold} ์ดˆ๊ณผ +
+
+ ์ „์ฒด ${total}${units[i]} ์ค‘ ${agedCount}${units[i]} ๋…ธํ›„ ์žฅ๋น„ +
+
${agedCount}${units[i]}
+
+
+
+ ${agedPer}% +
+
+
`; + }); + + container.innerHTML = ` +

์‚ฌ์šฉํ˜„ํ™ฉ

+
${usageCards}
+

๋…ธํ›„ํ™” ์ž์‚ฐ ๋น„์œจ

+
${agedCards}
+ `; + + // ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ + container.querySelectorAll('[data-action="idle"]').forEach(card => { + card.addEventListener('click', () => { + const t = card.getAttribute('data-type')!; + openDashboardDetail(`[${t}] ์œ ํœด ์ž์‚ฐ ๋ชฉ๋ก`, groups[t].idle); + }); + }); + container.querySelectorAll('[data-action="aged"]').forEach(card => { + card.addEventListener('click', () => { + const t = card.getAttribute('data-type')!; + openDashboardDetail(`[${t}] ๋…ธํ›„ ์žฅ๋น„ ๋ชฉ๋ก`, groups[t].aged); + }); + }); +} + +// --- ์†Œํ”„ํŠธ์›จ์–ด ๋Œ€์‹œ๋ณด๋“œ --- +function renderSwDashboard(container: HTMLElement) { + let subQty = 0, subUsed = 0, subExp = 0, subTotal = 0; + let permQty = 0, permUsed = 0, permExp = 0, permTotal = 0; + + state.masterData.sw.forEach(sw => { + const assigned = state.masterData.swUsers.filter(u => u.swId === sw.id).length; + const qty = typeof sw.์ˆ˜๋Ÿ‰ === 'number' ? sw.์ˆ˜๋Ÿ‰ : parseInt(sw.์ˆ˜๋Ÿ‰||'0', 10); + if (sw.type === '๊ตฌ๋…SW') { + subQty += qty; subUsed += assigned; subTotal++; + if (isSWExpiring(sw)) subExp++; + } else { + permQty += qty; permUsed += assigned; permTotal++; + if (isSWExpiring(sw)) permExp++; + } + }); + + const subPer = subQty > 0 ? Math.round((subUsed/subQty)*100) : 0; + const permPer = permQty > 0 ? Math.round((permUsed/permQty)*100) : 0; + const subExpPer = subTotal > 0 ? Math.round((subExp/subTotal)*100) : 0; + const permExpPer = permTotal > 0 ? Math.round((permExp/permTotal)*100) : 0; + + container.innerHTML = ` +
+
+ ๊ตฌ๋… ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ์ •๋ณด +
${subQty}๊ฐœ์˜ ์ œํ’ˆ ์ค‘ ${subUsed}๊ฐœ ์‚ฌ์šฉ ์ค‘
+
+
${subPer}%
+
+
+
+
+
+
+ ์˜๊ตฌ ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ์ •๋ณด +
${permQty}๊ฐœ์˜ ์ œํ’ˆ ์ค‘ ${permUsed}๊ฐœ ์‚ฌ์šฉ ์ค‘
+
+
${permPer}%
+
+
+
+
+
+
+
+
+
+ ๊ตฌ๋… SW ๋งŒ๋ฃŒ ์˜ˆ์ • +
${subExp}๊ฐœ ๋งŒ๋ฃŒ ์˜ˆ์ •
+
+
+
+
+
+ ์œ ์ง€๋ณด์ˆ˜ ๋งŒ๋ฃŒ ์˜ˆ์ • +
${permExp}๊ฐœ ๋งŒ๋ฃŒ ์˜ˆ์ •
+
+
+
+
+ `; + + // ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ + container.querySelector('[data-action="sub-usage"]')?.addEventListener('click', () => { + openSwUsageDetail('๊ตฌ๋… ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ ๋ชฉ๋ก', state.masterData.sw.filter(sw => sw.type === '๊ตฌ๋…SW')); + }); + container.querySelector('[data-action="perm-usage"]')?.addEventListener('click', () => { + openSwUsageDetail('์˜๊ตฌ ์†Œํ”„ํŠธ์›จ์–ด ์‚ฌ์šฉ ๋ชฉ๋ก', state.masterData.sw.filter(sw => sw.type === '์˜๊ตฌSW')); + }); + container.querySelector('[data-action="sub-exp"]')?.addEventListener('click', () => { + openSwDashboardDetail('๊ตฌ๋… SW ๋งŒ๋ฃŒ ์˜ˆ์ • ๋ชฉ๋ก', state.masterData.sw.filter(sw => sw.type === '๊ตฌ๋…SW' && isSWExpiring(sw))); + }); + container.querySelector('[data-action="perm-exp"]')?.addEventListener('click', () => { + openSwDashboardDetail('์œ ์ง€๋ณด์ˆ˜ ๋งŒ๋ฃŒ ์˜ˆ์ • ๋ชฉ๋ก', state.masterData.sw.filter(sw => sw.type === '์˜๊ตฌSW' && isSWExpiring(sw))); + }); +} + +// --- ๊ณตํ†ต ํ—ฌํผ ํ•จ์ˆ˜๋“ค --- +function isHwIdle(a: HardwareAsset) { + if (a.type === '๊ฐœ์ธPC') return !a.์‚ฌ์šฉ์ž || a.์‚ฌ์šฉ์ž.trim() === '' || a.์‚ฌ์šฉ์ž.trim() === '-'; + if (a.type === '์Šคํ† ๋ฆฌ์ง€') return !a.๋‹ด๋‹น์ž_์ • || a.๋‹ด๋‹น์ž_์ •.trim() === '' || a.๋‹ด๋‹น์ž_์ •.trim() === '-'; + return !a.๊ด€๋ฆฌ์ž || a.๊ด€๋ฆฌ์ž.trim() === '' || a.๊ด€๋ฆฌ์ž.trim() === '-'; +} + +function getHwAgeYears(a: HardwareAsset) { + if (!a.๊ตฌ๋งค์ผ) return 0; + return (Date.now() - new Date(a.๊ตฌ๋งค์ผ).getTime()) / (1000 * 60 * 60 * 24 * 365.25); +} + +function isSWExpiring(sw: SoftwareAsset) { + if (sw.type === '๊ตฌ๋…SW' && sw.๊ตฌ๋…์ผ) { + const parts = sw.๊ตฌ๋…์ผ.split('~'); + if (parts.length > 1) { + const endStr = parts[1].trim(); + const endMs = new Date(endStr.replace(/\./g, '-')).getTime(); + const diffDays = (endMs - Date.now()) / (1000 * 60 * 60 * 24); + return diffDays >= 0 && diffDays <= 30; + } + } else if (sw.type === '์˜๊ตฌSW' && sw.๋น„๊ณ  && sw.๋น„๊ณ .includes('์œ ์ง€๋ณด์ˆ˜: ~')) { + const endStr = sw.๋น„๊ณ .split('~')[1].trim(); + const endMs = new Date(endStr.replace(/\./g, '-')).getTime(); + const diffDays = (endMs - Date.now()) / (1000 * 60 * 60 * 24); + return diffDays >= 0 && diffDays <= 30; + } + return false; +} + +// --- ๋Œ€์‹œ๋ณด๋“œ ์ƒ์„ธ ๋ชจ๋‹ฌ ์ œ์–ด (main.ts์˜ ํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉ ๋˜๋Š” ์ด๋™ ํ•„์š”) --- +// ์ผ๋‹จ main.ts์— ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ „์—ญ์—์„œ ๊ฐ€์ ธ์™€ ์“ธ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ์—ฌ๊ธฐ์„œ ์ง์ ‘ ์ •์˜ํ•˜๊ฑฐ๋‚˜ main.ts์—์„œ export ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +// ๊ตฌ์กฐ ๊ฐœ์„ ์„ ์œ„ํ•ด main.ts์—์„œ ์ด ํ•จ์ˆ˜๋“ค๋„ DashboardView๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. + +function openDashboardDetail(title: string, list: HardwareAsset[]) { + const modal = document.getElementById('dashboard-detail-modal') as HTMLDivElement; + const titleEl = document.getElementById('dashboard-detail-modal-title') as HTMLHeadingElement; + const tbody = document.getElementById('dashboard-detail-tbody') as HTMLTableSectionElement; + const thead = tbody.closest('table')!.querySelector('thead')!; + + titleEl.textContent = title; + thead.innerHTML = `No์œ ํ˜•์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ/๋ชจ๋ธ์œ„์น˜๋‹ด๋‹น/์‚ฌ์šฉ์ž๊ตฌ๋งค์ผ๊ธˆ์•ก`; + tbody.innerHTML = ''; + if (list.length === 0) { + tbody.innerHTML = `ํ•ด๋‹น ์กฐ๊ฑด์˜ ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; + } else { + list.forEach((asset, idx) => { + let manager = asset.๊ด€๋ฆฌ์ž || asset.์‚ฌ์šฉ์ž || asset.๋‹ด๋‹น์ž_์ • || '-'; + let name = asset.๋ช…์นญ || asset.๋ชจ๋ธ๋ช… || '-'; + const tr = document.createElement('tr'); + tr.innerHTML = `${idx+1}${asset.type}${asset.์ž์‚ฐ์ฝ”๋“œ}${name}${asset.์œ„์น˜||'-'}${manager}${asset.๊ตฌ๋งค์ผ||'-'}${asset.๊ธˆ์•ก||'-'}`; + tbody.appendChild(tr); + }); + } + modal.classList.remove('hidden'); +} + +function openSwDashboardDetail(title: string, list: SoftwareAsset[]) { + const modal = document.getElementById('dashboard-detail-modal') as HTMLDivElement; + const titleEl = document.getElementById('dashboard-detail-modal-title') as HTMLHeadingElement; + const tbody = document.getElementById('dashboard-detail-tbody') as HTMLTableSectionElement; + const thead = tbody.closest('table')!.querySelector('thead')!; + + titleEl.textContent = title; + thead.innerHTML = `No์œ ํ˜•๋ฒ•์ธ์ œํ’ˆ๋ช…์ˆ˜๋Ÿ‰๊ธˆ์•ก`; + tbody.innerHTML = ''; + list.forEach((sw, idx) => { + const tr = document.createElement('tr'); + tr.innerHTML = `${idx+1}${sw.type}${sw.๋ฒ•์ธ}${sw.์ œํ’ˆ๋ช…}${sw.์ˆ˜๋Ÿ‰}${sw.๊ธˆ์•ก}`; + tbody.appendChild(tr); + }); + modal.classList.remove('hidden'); +} + +function openSwUsageDetail(title: string, list: SoftwareAsset[]) { + const modal = document.getElementById('dashboard-detail-modal') as HTMLDivElement; + const titleEl = document.getElementById('dashboard-detail-modal-title') as HTMLHeadingElement; + const tbody = document.getElementById('dashboard-detail-tbody') as HTMLTableSectionElement; + const thead = tbody.closest('table')!.querySelector('thead')!; + + titleEl.textContent = title; + thead.innerHTML = `No๋ฒ•์ธ์ œํ’ˆ๋ช…์ˆ˜๋Ÿ‰์‚ฌ์šฉ์ค‘์‚ฌ์šฉ๊ฐ€๋Šฅ`; + tbody.innerHTML = ''; + list.forEach((sw, idx) => { + const assigned = state.masterData.swUsers.filter(u => u.swId === sw.id).length; + const avail = (typeof sw.์ˆ˜๋Ÿ‰ === 'number' ? sw.์ˆ˜๋Ÿ‰ : parseInt(sw.์ˆ˜๋Ÿ‰||'0', 10)) - assigned; + const tr = document.createElement('tr'); + tr.innerHTML = `${idx+1}${sw.๋ฒ•์ธ}${sw.์ œํ’ˆ๋ช…}${sw.์ˆ˜๋Ÿ‰}${assigned}${avail}`; + tbody.appendChild(tr); + }); + modal.classList.remove('hidden'); +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..7065ca9 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +}