From e1cdcfd93a201b8ffeebcb538473ed2dc88e04fa Mon Sep 17 00:00:00 2001 From: Taehoon Date: Wed, 22 Apr 2026 17:15:58 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=95=98=EB=93=9C=EC=9B=A8=EC=96=B4=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=20=EB=B3=80=EA=B2=BD=20=EC=9D=B4=EB=A0=A5=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=9E=90=EC=82=B0=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=94=84=EB=A1=9C=EC=84=B8=EC=8A=A4=20=EA=B3=A0?= =?UTF-8?q?=EB=8F=84=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db_fix_data.js | 49 ++ db_init.js | 8 +- server.js | 46 +- src/components/Modal/DashboardDetailModal.ts | 2 +- src/components/Modal/HWModal.ts | 765 +++++++------------ src/components/Modal/ModalUtils.ts | 90 ++- src/components/Modal/PCModal.ts | 362 --------- src/components/Modal/SWModal.ts | 475 ++++-------- src/components/Modal/SharedData.ts | 3 +- src/core/excelHandler.ts | 46 +- src/main.ts | 12 +- src/styles/modal.css | 36 + src/views/Dashboard/HwDashboard.ts | 2 +- src/views/List/EquipmentListView.ts | 5 +- src/views/List/MobileListView.ts | 12 +- src/views/List/PcListView.ts | 8 +- src/views/List/ServerListView.ts | 7 +- src/views/List/SwListView.ts | 2 +- 18 files changed, 730 insertions(+), 1200 deletions(-) create mode 100644 db_fix_data.js delete mode 100644 src/components/Modal/PCModal.ts diff --git a/db_fix_data.js b/db_fix_data.js new file mode 100644 index 0000000..92fb2b4 --- /dev/null +++ b/db_fix_data.js @@ -0,0 +1,49 @@ +import mysql from 'mysql2/promise'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const { DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT } = process.env; + +async function migrateData() { + const connection = await mysql.createConnection({ + host: DB_HOST, + user: DB_USER, + password: DB_PASS, + database: DB_NAME, + port: parseInt(DB_PORT || '3306') + }); + + console.log('๐Ÿ”„ ๊ธฐ์กด ๋ฐ์ดํ„ฐ ๋ณด์ • ์‹œ์ž‘ (์ƒ์„ธ์œ ํ˜• = ์œ ํ˜•)...'); + + const tables = ['pc_assets', 'server_assets', 'storage_assets', 'equip_assets', 'mobile_assets']; + + for (const table of tables) { + // 1. ์œ ํ˜•(type)์ด ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’ ์ฑ„์šฐ๊ธฐ (๋ณด์ • ์ „ ๋‹จ๊ณ„) + let defaultType = '๊ธฐํƒ€'; + if (table === 'server_assets') defaultType = '์„œ๋ฒ„'; + else if (table === 'pc_assets') defaultType = '๊ฐœ์ธPC'; + else if (table === 'storage_assets') defaultType = '์Šคํ† ๋ฆฌ์ง€'; + else if (table === 'equip_assets') defaultType = '์ „์‚ฐ๋น„ํ’ˆ'; + else if (table === 'mobile_assets') defaultType = '๋ชจ๋ฐ”์ผ๊ธฐ๊ธฐ'; + + await connection.query(`UPDATE ${table} SET type = ? WHERE type IS NULL OR type = ''`, [defaultType]); + + // 2. ๊ฐœ์ธPC๊ฐ€ ์•„๋‹Œ ๋ฐ์ดํ„ฐ๋“ค์— ๋Œ€ํ•ด ์ƒ์„ธ์œ ํ˜• = ์œ ํ˜• ์—…๋ฐ์ดํŠธ + const [result] = await connection.query(` + UPDATE ${table} + SET detail_purpose = type + WHERE type NOT IN ('๊ฐœ์ธPC', 'PC') + `); + + console.log(`โœ… ${table}: ${result.affectedRows}๊ฐœ ๋ฐ์ดํ„ฐ ๋ณด์ • ์™„๋ฃŒ`); + } + + console.log('โœจ ๋ชจ๋“  ๊ธฐ์กด ๋ฐ์ดํ„ฐ ๋ณด์ •์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'); + await connection.end(); +} + +migrateData().catch(err => { + console.error('โŒ ๋ฐ์ดํ„ฐ ๋ณด์ • ์‹คํŒจ:', err); + process.exit(1); +}); diff --git a/db_init.js b/db_init.js index 0aa41e8..bc9daa1 100644 --- a/db_init.js +++ b/db_init.js @@ -32,7 +32,7 @@ async function initDB() { id VARCHAR(50) PRIMARY KEY, corp VARCHAR(100) COMMENT '๊ตฌ๋งค๋ฒ•์ธ', asset_code VARCHAR(100) COMMENT '์ž์‚ฐ๋ฒˆํ˜ธ', - purchase_date VARCHAR(50) COMMENT '๊ตฌ๋งค์ผ์ž', + purchase_date VARCHAR(50) COMMENT '๊ตฌ๋งค์—ฐ์›”', type VARCHAR(50) COMMENT '์œ ํ˜•', detail_purpose VARCHAR(50) COMMENT '์ƒ์„ธ์šฉ๋„', purpose VARCHAR(255) COMMENT '์šฉ๋„', @@ -57,6 +57,8 @@ async function initDB() { monitoring VARCHAR(100), price VARCHAR(100) COMMENT '๊ธˆ์•ก', remarks TEXT, + storage_location VARCHAR(255) COMMENT '๋ณด๊ด€์œ„์น˜', + status VARCHAR(50) COMMENT 'ํ˜„์žฌ์ƒํƒœ', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='${comment}'; `; @@ -77,7 +79,7 @@ async function initDB() { license_type VARCHAR(100) COMMENT '๋ผ์ด์„ ์Šค ์œ ํ˜•', quantity INT COMMENT '์ˆ˜๋Ÿ‰', price VARCHAR(100) COMMENT '๊ธˆ์•ก', - purchase_date VARCHAR(50) COMMENT '๊ตฌ๋งค์ผ', + purchase_date VARCHAR(50) COMMENT '๊ตฌ๋งค์—ฐ์›”', expiry_date VARCHAR(50) COMMENT '๋งŒ๋ฃŒ์ผ', vendor VARCHAR(255) COMMENT '๋‚ฉํ’ˆ์—…์ฒด', remarks TEXT COMMENT '๋น„๊ณ ', @@ -95,7 +97,7 @@ async function initDB() { license_key VARCHAR(255) COMMENT '๋ผ์ด์„ ์Šค ํ‚ค', quantity INT COMMENT '์ˆ˜๋Ÿ‰', price VARCHAR(100) COMMENT '๊ธˆ์•ก', - purchase_date VARCHAR(50) COMMENT '๊ตฌ๋งค์ผ', + purchase_date VARCHAR(50) COMMENT '๊ตฌ๋งค์—ฐ์›”', vendor VARCHAR(255) COMMENT '๋‚ฉํ’ˆ์—…์ฒด', remarks TEXT COMMENT '๋น„๊ณ ', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP diff --git a/server.js b/server.js index 4772a4c..c5d0b95 100644 --- a/server.js +++ b/server.js @@ -90,22 +90,48 @@ const hardwareInsertSQL = (table) => ` `; const getHardwareValues = (a) => [ - a.id, a.๋ฒ•์ธ||'', a.์ž์‚ฐ์ฝ”๋“œ||'', a.๊ตฌ๋งค์ผ||'', a.type||'', a.์ƒ์„ธ์šฉ๋„||'', a.์šฉ๋„||'', a.์ƒ์„ธ||'', + a.id, a.๋ฒ•์ธ||'', a.์ž์‚ฐ์ฝ”๋“œ||'', a.๊ตฌ๋งค์—ฐ์›”||'', a.type||'', a.์ƒ์„ธ์šฉ๋„||'', a.์šฉ๋„||'', a.์ƒ์„ธ||'', a.ํ˜„์‚ฌ์šฉ์กฐ์ง||'', a.์ด์ „์‚ฌ์šฉ์กฐ์ง||'', a.์œ„์น˜||'', a.๋‹ด๋‹น์ž_์ •||'', a.๋‹ด๋‹น์ž_๋ถ€||'', a.IP์ฃผ์†Œ||'', a.์›๊ฒฉ์ ‘์†||'', a.์„œ๋ฒ„ID||'', a.์„œ๋ฒ„PW||'', a.๋ชจ๋ธ๋ช…||'', a.OS||'', a.CPU||'', a.RAM||'', a.GPU||'', a.SSD1||'', a.SSD2||'', a.HDD1||'', a.๋ชจ๋‹ˆํ„ฐ๋ง||'', a.๊ธˆ์•ก||'', a.๋น„๊ณ ||'', a.๋ณด๊ด€์œ„์น˜||'', a.ํ˜„์žฌ์ƒํƒœ||'' ]; -const mapHardware = (r, defaultType) => ({ - id: r.id, ๋ฒ•์ธ: r.corp, ์ž์‚ฐ์ฝ”๋“œ: r.asset_code, ๊ตฌ๋งค์ผ: r.purchase_date, type: r.type || defaultType, - ์ƒ์„ธ์šฉ๋„: r.detail_purpose, ์šฉ๋„: r.purpose, ์ƒ์„ธ: r.details, ํ˜„์‚ฌ์šฉ์กฐ์ง: r.current_org, - ์ด์ „์‚ฌ์šฉ์กฐ์ง: r.prev_org, ์œ„์น˜: r.location, ๋‹ด๋‹น์ž_์ •: r.manager_main, ๋‹ด๋‹น์ž_๋ถ€: r.manager_sub, - IP์ฃผ์†Œ: r.ip_address, ์›๊ฒฉ์ ‘์†: r.remote_tool, ์„œ๋ฒ„ID: r.server_id, ์„œ๋ฒ„PW: r.server_pw, - ๋ชจ๋ธ๋ช…: r.model_name, OS: r.os, CPU: r.cpu, RAM: r.ram, GPU: r.gpu, SSD1: r.storage1, - SSD2: r.storage2, HDD1: r.storage3, ๋ชจ๋‹ˆํ„ฐ๋ง: r.monitoring, ๊ธˆ์•ก: r.price, ๋น„๊ณ : r.remarks, - ๋ณด๊ด€์œ„์น˜: r.storage_location, ํ˜„์žฌ์ƒํƒœ: r.status -}); +const mapHardware = (r, defaultType) => { + const type = r.type || defaultType; + return { + id: r.id, + ๋ฒ•์ธ: r.corp, + ์ž์‚ฐ์ฝ”๋“œ: r.asset_code, + ๊ตฌ๋งค์—ฐ์›”: r.purchase_date, + type: type, + ์ƒ์„ธ์šฉ๋„: (type !== '๊ฐœ์ธPC' && !r.detail_purpose) ? type : r.detail_purpose, + ์šฉ๋„: r.purpose, + ์ƒ์„ธ: r.details, + ํ˜„์‚ฌ์šฉ์กฐ์ง: r.current_org, + ์ด์ „์‚ฌ์šฉ์กฐ์ง: r.prev_org, + ์œ„์น˜: r.location, + ๋‹ด๋‹น์ž_์ •: r.manager_main, + ๋‹ด๋‹น์ž_๋ถ€: r.manager_sub, + IP์ฃผ์†Œ: r.ip_address, + ์›๊ฒฉ์ ‘์†: r.remote_tool, + ์„œ๋ฒ„ID: r.server_id, + ์„œ๋ฒ„PW: r.server_pw, + ๋ชจ๋ธ๋ช…: r.model_name, + OS: r.os, + CPU: r.cpu, + RAM: r.ram, + GPU: r.gpu, + SSD1: r.storage1, + SSD2: r.storage2, + HDD1: r.storage3, + ๋ชจ๋‹ˆํ„ฐ๋ง: r.monitoring, + ๊ธˆ์•ก: r.price, + ๋น„๊ณ : r.remarks, + ๋ณด๊ด€์œ„์น˜: r.storage_location, + ํ˜„์žฌ์ƒํƒœ: r.status + }; +}; // --- API ๋ผ์šฐํŠธ ์ •์˜ --- diff --git a/src/components/Modal/DashboardDetailModal.ts b/src/components/Modal/DashboardDetailModal.ts index 4ea6f96..7c5fe94 100644 --- a/src/components/Modal/DashboardDetailModal.ts +++ b/src/components/Modal/DashboardDetailModal.ts @@ -49,7 +49,7 @@ export function openDashboardDetail(title: string, list: HardwareAsset[]) { if (!thead) return; titleEl.textContent = title; - thead.innerHTML = `No์œ ํ˜•์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ/๋ชจ๋ธ์œ„์น˜๋‹ด๋‹น/์‚ฌ์šฉ์ž๊ตฌ๋งค์ผ๊ธˆ์•ก`; + thead.innerHTML = `No์œ ํ˜•์ž์‚ฐ์ฝ”๋“œ๋ช…์นญ/๋ชจ๋ธ์œ„์น˜๋‹ด๋‹น/์‚ฌ์šฉ์ž๊ตฌ๋งค์—ฐ์›”๊ธˆ์•ก`; tbody.innerHTML = ''; if (list.length === 0) { tbody.innerHTML = `ํ•ด๋‹น ์กฐ๊ฑด์˜ ์ž์‚ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.`; diff --git a/src/components/Modal/HWModal.ts b/src/components/Modal/HWModal.ts index dcc94f2..4247dd0 100644 --- a/src/components/Modal/HWModal.ts +++ b/src/components/Modal/HWModal.ts @@ -1,7 +1,7 @@ import { state, saveHardwareAsset, deleteHardwareAsset } from '../../core/state'; -import { HardwareAsset, MasterAssetData, HardwareLog } from '../../core/excelHandler'; -import { openModal, closeModals } from './BaseModal'; -import { createIcons, Paperclip, History, Plus, X, Save, Edit2, RotateCcw } from 'lucide'; +import { HardwareAsset, HardwareLog } from '../../core/excelHandler'; +import { closeModals } from './BaseModal'; +import { createIcons, History, Plus, X, Save, Edit2, RotateCcw, Paperclip } from 'lucide'; import { CORP_LIST, ORG_LIST, HW_TYPE_LIST, LOCATION_DATA, TYPE_PREFIX_MAP } from './SharedData'; import { generateOptionsHTML, @@ -10,7 +10,10 @@ import { parseAndSetLocation, bindLocationEvents, getCombinedLocation, - setEditLock + setEditLock, + createModalFrameHTML, + autoFillForm, + autoExtractForm } from './ModalUtils'; let currentAsset: HardwareAsset | null = null; @@ -18,350 +21,119 @@ let isEditMode = false; const STATUS_LIST = ['๋Œ€์—ฌ์ค‘', '๋ณด๊ด€์ค‘', '์ˆ˜๋ฆฌ์ค‘', '๊ธฐํƒ€']; -const HW_MODAL_HTML = ` -