diff --git a/src/components/Modal/BaseModal.ts b/src/components/Modal/BaseModal.ts
index 7e1c518..e8c895d 100644
--- a/src/components/Modal/BaseModal.ts
+++ b/src/components/Modal/BaseModal.ts
@@ -4,7 +4,9 @@
export function initBaseModal() {
const closeAllModals = () => {
const modals = document.querySelectorAll('.modal-overlay');
- modals.forEach(modal => modal.classList.add('hidden'));
+ modals.forEach(modal => {
+ modal.classList.add('hidden');
+ });
};
// ESC 키로 닫기
@@ -12,12 +14,21 @@ export function initBaseModal() {
if (e.key === 'Escape') closeAllModals();
});
- // 배경(Overlay) 클릭 시 닫기 (동적 생성된 모달 대응을 위해 이벤트 위임 고려 가능하나 일단 단순 구현)
+ // 배경(Overlay) 및 닫기 버튼 클릭 시 닫기 (이벤트 위임)
document.addEventListener('click', (e) => {
const target = e.target as HTMLElement;
+
+ // 1. 오버레이 클릭 시 닫기
if (target.classList.contains('modal-overlay')) {
closeAllModals();
}
+
+ // 2. 닫기 아이콘(data-lucide="x") 또는 닫기/취소 버튼 클릭 시 닫기
+ // 버튼 ID가 btn-close- 또는 btn-cancel-로 시작하는 경우 대응
+ const btn = target.closest('button');
+ if (btn && (btn.id.startsWith('btn-close-') || btn.id.startsWith('btn-cancel-'))) {
+ closeAllModals();
+ }
});
return { closeAllModals };
diff --git a/src/components/Modal/HWModal.ts b/src/components/Modal/HWModal.ts
index a330711..9a9fce4 100644
--- a/src/components/Modal/HWModal.ts
+++ b/src/components/Modal/HWModal.ts
@@ -46,7 +46,7 @@ const HW_MODAL_HTML = `
-
네트워크 정보 (Connectivity)
+ 네트워크 정보 (Connectivity) 보안 정보
@@ -56,7 +56,7 @@ const HW_MODAL_HTML = `
-
+
diff --git a/src/main.ts b/src/main.ts
index 98fd064..40dc02a 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,6 +3,7 @@ import { renderSidebar } from './components/Sidebar';
import { renderDashboard } from './views/DashboardView';
import { renderTable } from './views/AssetTableView';
import { downloadTemplate, exportToExcel, parseExcel, HardwareAsset } from './core/excelHandler';
+import { initBaseModal } from './components/Modal/BaseModal';
import { initPcModal } from './components/Modal/PCModal';
import { initHwModal, openHwModal } from './components/Modal/HWModal';
import { initStorageModal } from './components/Modal/StorageModal';
@@ -36,12 +37,14 @@ function initApp() {
}
});
- // 3. 모달 초기화 (HTML 주입 및 이벤트 바인딩)
- initPcModal(() => renderTable(mainContent), () => {});
- initHwModal();
- initStorageModal(() => renderTable(mainContent), () => {});
- initSwModal(() => renderTable(mainContent), () => {});
- initSwUserModal(() => renderTable(mainContent), () => {});
+ // 3. 모달 초기화 (HTML 주입 및 개별 로직 바인딩)
+ const { closeAllModals } = initBaseModal();
+
+ initPcModal(() => renderTable(mainContent), closeAllModals);
+ initHwModal(); // HW 모달은 내부에서 자체 닫기 로직 포함 중이나 추후 통일 가능
+ initStorageModal(() => renderTable(mainContent), closeAllModals);
+ initSwModal(() => renderTable(mainContent), closeAllModals);
+ initSwUserModal(() => renderTable(mainContent), closeAllModals);
initDashboardDetailModal();
// 4. 전역 버튼 이벤트 바인딩
diff --git a/src/styles/modal.css b/src/styles/modal.css
index 25ed49b..cd3fb31 100644
--- a/src/styles/modal.css
+++ b/src/styles/modal.css
@@ -126,6 +126,19 @@
font-size: 0.8125rem;
font-weight: 600;
color: var(--text-muted);
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.badge-security {
+ font-size: 10px;
+ background-color: #fef2f2;
+ color: #ef4444;
+ padding: 1px 4px;
+ border-radius: 3px;
+ border: 1px solid #fee2e2;
+ font-weight: 700;
}
.form-group input,
diff --git a/src/views/AssetTableView.ts b/src/views/AssetTableView.ts
index 961d38f..5a91d63 100644
--- a/src/views/AssetTableView.ts
+++ b/src/views/AssetTableView.ts
@@ -62,7 +62,7 @@ function renderHwTable(table: HTMLTableElement, container: HTMLElement, mainCont
} else {
// 서버 또는 전산비품
if (state.activeSubTab === '서버') {
- table.innerHTML = `| No | 법인 | 자산번호 | 유형 | 용도 | 상세 | 설치위치 | 담당자 | IP 주소 | 원격접속 | 모델명 | OS | CPU | RAM | Storage |
|---|
`;
+ table.innerHTML = `| No | 법인 | 자산번호 | 유형 | 용도 | 상세 | 설치위치 | 담당자 | 모델명 | OS | CPU | RAM | Storage |
`;
} else {
table.innerHTML = `| No | 법인 | ${state.activeSubTab === '전산비품' ? '유형 | ' : ''}자산코드 | 명칭 | 위치 | 관리자 | 구매일 | 금액 | 관리 |
`;
}
@@ -71,7 +71,7 @@ function renderHwTable(table: HTMLTableElement, container: HTMLElement, mainCont
container.appendChild(tableWrapper);
mainContent.appendChild(container);
const tbody = document.getElementById('dynamic-tbody')!;
- const colCount = state.activeSubTab === '서버' ? 15 : (state.activeSubTab === '전산비품' ? 11 : 10);
+ const colCount = state.activeSubTab === '서버' ? 13 : (state.activeSubTab === '전산비품' ? 11 : 10);
if (list.length === 0) { tbody.innerHTML = `| 등록된 자산이 없습니다. |
`; return; }
list.forEach((asset, idx) => {
@@ -84,25 +84,29 @@ function renderHwTable(table: HTMLTableElement, container: HTMLElement, mainCont
const mainManager = asset.담당자_정 || '';
const subManager = asset.담당자_부 || '';
const managerHtml = [mainManager ? `${getBadge('정', '#1E5149')} ${mainManager}` : '', subManager ? `${getBadge('부', '#9CA3AF')} ${subManager}` : ''].filter(v => v !== '').join(' / ');
- const tools = (asset.원격접속 || '').split('\n');
- const ids = (asset.서버ID || '').split('\n');
- const pws = (asset.서버PW || '').split('\n');
- const maxLen = Math.max(tools.length, ids.length, pws.length);
- let remoteItems = [];
- for(let i=0; i v && v !== '').join(' / ');
const storageInfo = [asset.SSD1, asset.SSD2].filter(v => v && v !== '').join(' / ');
- tr.innerHTML = `${idx+1} | ${formatInline(asset.법인)} | ${formatInline(asset.자산코드)} | ${formatInline(asset.storage유형)} | ${formatInline(asset.용도)} | ${formatInline(asset.상세)} | ${formatInline(asset.위치)} | ${managerHtml} | ${formatInline(ipInfo)} | ${remoteHtml} | ${formatInline(asset.모델명)} | ${formatInline(asset.OS)} | ${formatInline(asset.CPU)} | ${formatInline(asset.RAM)} | ${formatInline(storageInfo)} | `;
+ // 위치 정보 가공 (서관/동관 -> IDC)
+ let locationHtml = formatInline(asset.위치);
+ if (locationHtml.startsWith('서관') || locationHtml.startsWith('동관')) {
+ locationHtml = `IDC(${locationHtml})`;
+ }
+
+ tr.innerHTML = `
+ ${idx+1} |
+ ${formatInline(asset.법인)} |
+ ${formatInline(asset.자산코드)} |
+ ${formatInline(asset.storage유형)} |
+ ${formatInline(asset.용도)} |
+ ${formatInline(asset.상세)} |
+ ${locationHtml} |
+ ${managerHtml} |
+ ${formatInline(asset.모델명)} |
+ ${formatInline(asset.OS)} |
+ ${formatInline(asset.CPU)} |
+ ${formatInline(asset.RAM)} |
+ ${formatInline(storageInfo)} |
+ `;
tr.addEventListener('click', (e) => { if (!(e.target as HTMLElement).closest('button')) openHwModal(asset); });
} else {
tr.innerHTML = `${idx+1} | ${asset.법인} | ${state.activeSubTab === '전산비품' ? `${asset.비품유형||'-'} | ` : ''}${asset.자산코드} | ${asset.명칭} | ${asset.위치} | ${asset.관리자} | ${asset.구매일||''} | ${asset.금액||''} | | `;