From cbfc1bcd1da75e6eb8947127ac81e1a6e6670c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=ED=83=9C=ED=9B=88?= Date: Thu, 25 Jun 2026 13:54:49 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=90=EC=82=B0=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EC=8B=9C=20=EB=A9=94=EB=AA=A8,=20?= =?UTF-8?q?=EC=9A=A9=EB=8F=84,=20=EC=A0=91=EC=86=8D=EC=A0=95=EB=B3=B4,=20?= =?UTF-8?q?=EC=9C=A0=ED=98=95=20=EB=B3=80=EA=B2=BD=20=EC=82=AC=ED=95=AD?= =?UTF-8?q?=EB=8F=84=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=9D=B4=EB=A0=A5?= =?UTF-8?q?=EC=97=90=20=EA=B8=B0=EB=A1=9D=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/server.js b/server.js index 865ffc1..5b8bb95 100644 --- a/server.js +++ b/server.js @@ -288,6 +288,7 @@ app.post('/api/asset/:category/save', async (req, res) => { // 3.0 History Tracking & Auto Field Update const [oldCoreRows] = await connection.query('SELECT * FROM asset_core WHERE id = ?', [asset.id]); const [oldSpecRows] = await connection.query('SELECT * FROM asset_spec WHERE asset_id = ?', [asset.id]); + const [oldRemoteRows] = await connection.query('SELECT * FROM asset_remote WHERE asset_id = ? AND is_active = 1', [asset.id]); const oldCore = oldCoreRows[0] || {}; const oldSpec = oldSpecRows[0] || {}; @@ -350,6 +351,85 @@ app.post('/api/asset/:category/save', async (req, res) => { }); } + // 3.0.4 메모, 용도, 유형 변동 감지 + const oldMemo = String(oldCore.memo || '').trim(); + const newMemo = String(asset.memo || '').trim(); + if (newMemo !== '' && oldMemo !== newMemo) { + historyLogs.push({ + event_type: 'MEMO_CHANGE', + details: `[메모 변경] ${oldMemo || '(없음)'} -> ${newMemo}` + }); + } + + const oldPurpose = String(oldCore.asset_purpose || '').trim(); + const newPurpose = String(asset.asset_purpose || '').trim(); + if (newPurpose !== '' && oldPurpose !== newPurpose) { + historyLogs.push({ + event_type: 'PURPOSE_CHANGE', + details: `[용도 변경] ${oldPurpose || '(없음)'} -> ${newPurpose}` + }); + } + + const oldType = String(oldCore.asset_type || '').trim(); + const newType = String(asset.asset_type || '').trim(); + if (newType !== '' && oldType !== newType) { + historyLogs.push({ + event_type: 'TYPE_CHANGE', + details: `[유형 변경] ${oldType || '(없음)'} -> ${newType}` + }); + } + + // 3.0.5 접속정보 변동 감지 + const formatRemote = (r) => { + const type = r.net_type || r.type || ''; + const name = r.net_name || r.name || ''; + const val1 = r.net_value1 || r.val1 || ''; + const val2 = r.net_value2 || r.val2 || ''; + return `${type}:${name}:${val1}:${val2}`; + }; + + const oldRemotesSummary = oldRemoteRows.map(formatRemote).sort().join(' | '); + + let newNets = []; + if (asset.remotes) { + try { + newNets = typeof asset.remotes === 'string' ? JSON.parse(asset.remotes) : asset.remotes; + } catch(e) { newNets = []; } + } else if (asset.ip_address || asset.mac_address || asset.remote_tool) { + if (asset.ip_address || asset.mac_address) { + newNets.push({ type: 'IP', name: '기본망', val1: asset.ip_address, val2: asset.mac_address }); + } + if (asset.remote_tool || asset.remote_id || asset.remote_pw) { + newNets.push({ type: 'REMOTE', name: asset.remote_tool, val1: asset.remote_id, val2: asset.remote_pw }); + } + } + const newRemotesSummary = newNets.map(formatRemote).sort().join(' | '); + + if (newRemotesSummary !== '' && oldRemotesSummary !== newRemotesSummary) { + const formatDisplay = (summary) => { + if (!summary) return '(없음)'; + return summary.split(' | ').map(item => { + const [type, name, val1, val2] = item.split(':'); + if (type === 'IP') { + return `[IP] ${name}: ${val1} (MAC: ${val2 || '없음'})`; + } else { + let id = '', pw = ''; + try { + const parsed = JSON.parse(val2); + id = parsed.id || ''; + pw = parsed.pw || ''; + } catch(e) { id = val1; pw = val2; } + return `[원격] ${name}: ID=${id || '없음'}, PW=${pw ? '***' : '없음'}`; + } + }).join(', '); + }; + + historyLogs.push({ + event_type: 'REMOTE_CHANGE', + details: `[접속정보 변경] ${formatDisplay(oldRemotesSummary)} -> ${formatDisplay(newRemotesSummary)}` + }); + } + // 로그 일괄 삽입 for (const log of historyLogs) { await connection.query(