diff --git a/src/components/Modal/HWModal.ts b/src/components/Modal/HWModal.ts index 6dbe5e5..42fb2f2 100644 --- a/src/components/Modal/HWModal.ts +++ b/src/components/Modal/HWModal.ts @@ -151,27 +151,20 @@ class HwAssetModal extends BaseModal { -
- - -
-
- - -
+
디스크(용량) 정보
- - + +
- -
원격 접속 정보
+ +
네트워크 및 원격 접속 정보
@@ -180,7 +173,7 @@ class HwAssetModal extends BaseModal {
- +
설치 위치
@@ -196,7 +189,7 @@ class HwAssetModal extends BaseModal {
- +
구매 및 증빙 정보
@@ -384,7 +377,7 @@ class HwAssetModal extends BaseModal { document.querySelectorAll('#hw-remote-info-container .remote-info-row').forEach(row => { const type = (row.querySelector('.ri-type') as HTMLSelectElement).value; const val1 = (row.querySelector('.ri-val1') as HTMLInputElement).value; - + if (type === 'IP' && val1) { const tool = (row.querySelector('.ri-tool') as HTMLSelectElement)?.value || ''; const id = (row.querySelector('.ri-id') as HTMLInputElement)?.value || ''; @@ -436,7 +429,7 @@ class HwAssetModal extends BaseModal { private addRemoteInfoRow(info: any = { type: 'IP', name: '원격접속', val1: '', val2: '' }) { const container = document.getElementById('hw-remote-info-container'); if (!container) return; - + // Parse val2 (which contains JSON with id and pw if type is IP) let parsedId = ''; let parsedPw = ''; @@ -469,7 +462,7 @@ class HwAssetModal extends BaseModal { // Second Line: Tool & Credentials (Only for IP) const line2 = document.createElement('div'); line2.className = 'ri-line ri-cred-line'; - line2.style.display = info.type === 'IP' ? 'flex' : 'none'; + line2.style.display = info.type === 'IP' ? 'flex' : 'none'; line2.innerHTML = `
+ ${Object.keys(LOCATION_DATA).map(loc => ``).join('')} + +
+
+ +
+ + + + ${locImages.length > 1 ? ` +
+
+ + +
+ (${currentPage + 1} / ${locImages.length}) +
+ ` : ''} +
+
+
+ +
+ +
+
+ ${mapPath ? ` + +
+ ${boxes.map((box: any, idx: number) => { + const name = box.name || `#${idx+1}`; + return ` +
+
+ `}).join('')} +
+ ` : '
해당 위치의 도면이 등록되지 않았습니다.
'} +
+
+ + +
+
+

📍 구역을 선택하세요

+
+
+
지도에서 자산 위치를 클릭하세요.
+
+
+
+
+

* 지도 위의 구역을 클릭하면 자산 상세 정보가 표시됩니다.

+
+ + `; + + // 이미지 로드 및 윈도우 리사이즈 시 오버레이 크기와 위치를 이미지에 정확히 맞춤 + const syncOverlaySize = () => { + const img = container.querySelector('#main-map-img') as HTMLImageElement; + const overlay = container.querySelector('#box-overlay') as HTMLElement; + if (img && overlay && img.complete) { + overlay.style.width = img.clientWidth + 'px'; + overlay.style.height = img.clientHeight + 'px'; + overlay.style.left = img.offsetLeft + 'px'; + overlay.style.top = img.offsetTop + 'px'; + } + }; + + const img = container.querySelector('#main-map-img') as HTMLImageElement; + if (img) { + if (img.complete) { + syncOverlaySize(); + setTimeout(syncOverlaySize, 50); // 레이아웃 안정화 대기 + } else { + img.onload = syncOverlaySize; + } + } + + window.removeEventListener('resize', syncOverlaySize); + window.addEventListener('resize', syncOverlaySize); + + // 이벤트 바인딩 + const selMain = container.querySelector('#sel-loc-main') as HTMLSelectElement; + selMain?.addEventListener('change', () => { + currentLoc = selMain.value; + currentDetail = LOCATION_DATA[currentLoc][0]; + currentPage = 0; + render(); + }); + + const selDetail = container.querySelector('#sel-loc-detail') as HTMLSelectElement; + selDetail?.addEventListener('change', () => { + currentDetail = selDetail.value; + currentPage = 0; + render(); + }); + + container.querySelector('#btn-prev-page')?.addEventListener('click', () => { currentPage--; render(); }); + container.querySelector('#btn-next-page')?.addEventListener('click', () => { currentPage++; render(); }); + + container.querySelectorAll('.location-box-point').forEach(box => { + box.addEventListener('click', () => { + const x = box.getAttribute('data-x'); + const y = box.getAttribute('data-y'); + + const targetAsset = state.masterData.hw.find(a => + a.location === currentLoc && + a.location_detail === currentDetail && + String(a.loc_x) === String(x) && + String(a.loc_y) === String(y) + ); + + if (targetAsset) { + renderAssetDetail(targetAsset); + } + + container.querySelectorAll('.location-box-point').forEach(b => (b as HTMLElement).style.background = 'rgba(30, 81, 73, 0.1)'); + (box as HTMLElement).style.background = 'rgba(30, 81, 73, 0.4)'; + }); + }); + }; + + const renderAssetDetail = (asset: any) => { + const title = container.querySelector('#loc-list-title')!; + const tableContainer = container.querySelector('#loc-asset-table-container')!; + + title.innerHTML = ` +
+ + 자산 상세 정보 + +
+ `; + + const renderSection = (title: string, fields: { label: string; value: any }[]) => ` +
+
${title}
+
+ ${fields.map(f => ` +
${f.label}
+
${f.value || '-'}
+ `).join('')} +
+
+ `; + + const sectionsHTML = [ + renderSection('기본 관리 정보', [ + { label: ASSET_SCHEMA.ASSET_CODE.ui, value: asset.asset_code }, + { label: ASSET_SCHEMA.PURCHASE_CORP.ui, value: asset.purchase_corp }, + { label: ASSET_SCHEMA.CATEGORY.ui, value: asset.category }, + { label: ASSET_SCHEMA.ASSET_TYPE.ui, value: asset.asset_type }, + { label: ASSET_SCHEMA.HW_STATUS.ui, value: asset.hw_status } + ]), + renderSection('시스템 사양', [ + { label: ASSET_SCHEMA.MODEL_NAME.ui, value: asset.model_name }, + { label: ASSET_SCHEMA.OS.ui, value: asset.os }, + { label: ASSET_SCHEMA.CPU.ui, value: asset.cpu }, + { label: ASSET_SCHEMA.RAM.ui, value: asset.ram }, + { label: ASSET_SCHEMA.GPU.ui, value: asset.gpu } + ]), + renderSection('네트워크 정보', [ + { label: ASSET_SCHEMA.IP_ADDR.ui, value: asset.ip_address }, + { label: ASSET_SCHEMA.MAC_ADDR.ui, value: asset.mac_address }, + { label: ASSET_SCHEMA.REMOTE_TOOL.ui, value: asset.remote_tool } + ]), + renderSection('구매 및 기타', [ + { label: ASSET_SCHEMA.PURCHASE_DATE.ui, value: asset.purchase_date }, + { label: ASSET_SCHEMA.PURCHASE_AMOUNT.ui, value: asset.purchase_amount ? `${Number(asset.purchase_amount).toLocaleString()}원` : '-' }, + { label: ASSET_SCHEMA.MEMO.ui, value: asset.memo } + ]) + ].join(''); + + tableContainer.innerHTML = ` +
+ ${sectionsHTML} +
+ `; + + container.querySelector('#btn-back-to-list')?.addEventListener('click', () => { + title.textContent = `📍 구역을 선택하세요`; + tableContainer.innerHTML = `
지도에서 자산 위치를 클릭하세요.
`; + }); + + container.querySelector('#btn-edit-from-loc')?.addEventListener('click', () => { + openHwModal(asset, 'edit'); + }); + }; + + render(); +} diff --git a/vite.config.ts b/vite.config.ts index 3d35e2a..56b1c1c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,5 +4,15 @@ export default defineConfig({ server: { port: 8080, host: true, // Listen on all local IPs + proxy: { + '/api': { + target: 'http://localhost:3000', + changeOrigin: true, + }, + '/uploads': { + target: 'http://localhost:3000', + changeOrigin: true, + } + } }, });