= ({ 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]}
-
-
-
-
`;
- });
-
- // ๋
ธํํ ์นด๋ ์์ฑ
- 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]}
-
-
-
`;
- });
-
- 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}๊ฐ
-
-
-
-
-
-
-
- ์ ์ง๋ณด์ ๋ง๋ฃ ์์
-
-
- 30์ผ ์ด๋ด์ ${permTotal}๊ฐ์ ์ ํ ์ค ${permExp}๊ฐ ๋ง๋ฃ ์์
-
-
${permExp}๊ฐ
-
-
-
-
- `;
-
- // 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 | ๋ฒ์ธ | ์์ฐ์ฝ๋ | ์ฌ์ฉ์ |
- ์์น | CPU | GPU | RAM |
- SSD1 | SSD2 | HDD1 | HDD2 |
- ๊ตฌ๋งค์ผ | ๊ธ์ก | ๋ฉํ์
์ฒด | ํ์์ | ๊ด๋ฆฌ |
-
-
-
- `;
- 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 | ๋ฒ์ธ | ์์ฐ์ฝ๋ | ์ฌ์ฉ์ | ์์น | CPU | GPU | RAM | SSD1 | SSD2 | HDD1 | HDD2 | ๊ตฌ๋งค์ผ | ๊ธ์ก | ๋ฉํ์
์ฒด | ํ์์ | ๊ด๋ฆฌ |
`;
+ 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]}
+
+
+
`;
+ });
+
+ 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}๊ฐ ์ฌ์ฉ ์ค
+
+
+
+
+
์๊ตฌ ์ํํธ์จ์ด ์ฌ์ฉ์ ๋ณด
+
${permQty}๊ฐ์ ์ ํ ์ค ${permUsed}๊ฐ ์ฌ์ฉ ์ค
+
+
+
+
+
+
+
+
๊ตฌ๋
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"]
+}