diff --git a/server.js b/server.js index 103bafb..4772a4c 100644 --- a/server.js +++ b/server.js @@ -84,7 +84,8 @@ const hardwareInsertSQL = (table) => ` id, corp, asset_code, purchase_date, type, detail_purpose, purpose, details, current_org, prev_org, location, manager_main, manager_sub, ip_address, remote_tool, server_id, server_pw, model_name, os, cpu, ram, gpu, - storage1, storage2, storage3, monitoring, price, remarks + storage1, storage2, storage3, monitoring, price, remarks, + storage_location, status ) VALUES ? `; @@ -92,7 +93,8 @@ const getHardwareValues = (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.SSD1||'', a.SSD2||'', a.HDD1||'', a.모니터링||'', a.금액||'', a.비고||'', + a.보관위치||'', a.현재상태||'' ]; const mapHardware = (r, defaultType) => ({ @@ -101,7 +103,8 @@ const mapHardware = (r, defaultType) => ({ 이전사용조직: 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 + SSD2: r.storage2, HDD1: r.storage3, 모니터링: r.monitoring, 금액: r.price, 비고: r.remarks, + 보관위치: r.storage_location, 현재상태: r.status }); // --- API 라우트 정의 --- @@ -320,6 +323,34 @@ app.post('/api/sw-users/batch', async (req, res) => { } catch (err) { res.status(500).json({ error: err.message }); } }); +// 자산번호 자동 생성 API +app.get('/api/generate-asset-code', async (req, res) => { + const { prefix } = req.query; + if (!prefix) return res.status(400).json({ error: 'Prefix is required' }); + + try { + const tables = ['pc_assets', 'server_assets', 'storage_assets', 'equip_assets', 'mobile_assets']; + let maxNum = 0; + + for (const table of tables) { + const [rows] = await pool.query( + `SELECT asset_code FROM ${table} WHERE asset_code LIKE ?`, + [`${prefix}%`] + ); + rows.forEach(r => { + const numPart = r.asset_code.replace(prefix, ''); + const num = parseInt(numPart); + if (!isNaN(num) && num > maxNum) maxNum = num; + }); + } + + const nextNum = (maxNum + 1).toString().padStart(3, '0'); + res.json({ nextCode: `${prefix}${nextNum}` }); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + // 초기화 및 서버 기동 ensureTables().then(() => { app.listen(PORT, () => { diff --git a/src/components/Modal/HWModal.ts b/src/components/Modal/HWModal.ts index 29049d2..dcc94f2 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 } from '../../core/excelHandler'; +import { HardwareAsset, MasterAssetData, HardwareLog } from '../../core/excelHandler'; import { openModal, closeModals } from './BaseModal'; -import { createIcons, Paperclip } from 'lucide'; +import { createIcons, Paperclip, History, Plus, X, Save, Edit2, RotateCcw } from 'lucide'; import { CORP_LIST, ORG_LIST, HW_TYPE_LIST, LOCATION_DATA, TYPE_PREFIX_MAP } from './SharedData'; import { generateOptionsHTML, @@ -16,6 +16,8 @@ import { let currentAsset: HardwareAsset | null = null; let isEditMode = false; +const STATUS_LIST = ['대여중', '보관중', '수리중', '기타']; + const HW_MODAL_HTML = `