주요 정리 내용: - 핵심 엔진 분리: state, excelHandler 등을 src/core/ 디렉토리로 격리 - 모달 컴포넌트화: index.html의 거대 HTML 구조를 각 모달 TS 파일로 내장 및 동적 주입 - index.html 최적화: 수백 줄의 중복 코드를 제거하여 슬림한 Shell 구조로 변환 - 전역 복구: 병합 과정에서 발생한 한글 인코딩 깨짐 전수 복구 및 빌드 오류 해결 - 경로 정합성: 파일 구조 변경에 따른 모든 import 경로 일괄 업데이트
110 lines
4.9 KiB
TypeScript
110 lines
4.9 KiB
TypeScript
import { HardwareAsset, SoftwareAsset } from '../../core/excelHandler';
|
|
import { state } from '../../core/state';
|
|
|
|
const DASHBOARD_DETAIL_MODAL_HTML = `
|
|
<div id="dashboard-detail-modal" class="modal-overlay hidden">
|
|
<div class="modal-content wide" style="max-width: 1000px;">
|
|
<div class="modal-header">
|
|
<h2 id="dashboard-detail-modal-title">상세 목록</h2>
|
|
<button id="btn-close-dashboard-detail-modal" class="btn-icon" aria-label="닫기"><i data-lucide="x"></i></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="table-container">
|
|
<table style="width:100%;">
|
|
<thead></thead>
|
|
<tbody id="dashboard-detail-tbody"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<div></div>
|
|
<button id="btn-cancel-dashboard-detail-modal" class="btn btn-outline">닫기</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
export function initDashboardDetailModal() {
|
|
if (!document.getElementById('dashboard-detail-modal')) {
|
|
document.body.insertAdjacentHTML('beforeend', DASHBOARD_DETAIL_MODAL_HTML);
|
|
}
|
|
|
|
const modal = document.getElementById('dashboard-detail-modal')!;
|
|
const closeBtn = document.getElementById('btn-close-dashboard-detail-modal')!;
|
|
const cancelBtn = document.getElementById('btn-cancel-dashboard-detail-modal')!;
|
|
|
|
const closeModal = () => modal.classList.add('hidden');
|
|
closeBtn.addEventListener('click', closeModal);
|
|
cancelBtn.addEventListener('click', closeModal);
|
|
modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); });
|
|
}
|
|
|
|
export function openDashboardDetail(title: string, list: HardwareAsset[]) {
|
|
const modal = document.getElementById('dashboard-detail-modal');
|
|
if (!modal) return;
|
|
const titleEl = document.getElementById('dashboard-detail-modal-title');
|
|
const tbody = document.getElementById('dashboard-detail-tbody');
|
|
if (!titleEl || !tbody) return;
|
|
const thead = tbody.closest('table')?.querySelector('thead');
|
|
if (!thead) return;
|
|
|
|
titleEl.textContent = title;
|
|
thead.innerHTML = `<tr><th>No</th><th>유형</th><th>자산코드</th><th>명칭/모델</th><th>위치</th><th>담당/사용자</th><th>구매일</th><th>금액</th></tr>`;
|
|
tbody.innerHTML = '';
|
|
if (list.length === 0) {
|
|
tbody.innerHTML = `<tr><td colspan="8" style="text-align:center; padding: 2rem;">해당 조건의 자산이 없습니다.</td></tr>`;
|
|
} else {
|
|
list.forEach((asset, idx) => {
|
|
let manager = asset.관리자 || asset.사용자 || asset.담당자_정 || '-';
|
|
let name = asset.명칭 || asset.모델명 || '-';
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `<td>${idx+1}</td><td>${asset.type}</td><td>${asset.자산코드}</td><td>${name}</td><td>${asset.위치||'-'}</td><td>${manager}</td><td>${asset.구매일||'-'}</td><td>${asset.금액||'-'}</td>`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
}
|
|
modal.classList.remove('hidden');
|
|
}
|
|
|
|
export function openSwDashboardDetail(title: string, list: SoftwareAsset[]) {
|
|
const modal = document.getElementById('dashboard-detail-modal');
|
|
if (!modal) return;
|
|
const titleEl = document.getElementById('dashboard-detail-modal-title');
|
|
const tbody = document.getElementById('dashboard-detail-tbody');
|
|
if (!titleEl || !tbody) return;
|
|
const thead = tbody.closest('table')?.querySelector('thead');
|
|
if (!thead) return;
|
|
|
|
titleEl.textContent = title;
|
|
thead.innerHTML = `<tr><th>No</th><th>유형</th><th>법인</th><th>제품명</th><th>수량</th><th>금액</th></tr>`;
|
|
tbody.innerHTML = '';
|
|
list.forEach((sw, idx) => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `<td>${idx+1}</td><td>${sw.type}</td><td>${sw.법인}</td><td>${sw.제품명}</td><td>${sw.수량}</td><td>${sw.금액}</td>`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
modal.classList.remove('hidden');
|
|
}
|
|
|
|
export function openSwUsageDetail(title: string, list: SoftwareAsset[]) {
|
|
const modal = document.getElementById('dashboard-detail-modal');
|
|
if (!modal) return;
|
|
const titleEl = document.getElementById('dashboard-detail-modal-title');
|
|
const tbody = document.getElementById('dashboard-detail-tbody');
|
|
if (!titleEl || !tbody) return;
|
|
const thead = tbody.closest('table')?.querySelector('thead');
|
|
if (!thead) return;
|
|
|
|
titleEl.textContent = title;
|
|
thead.innerHTML = `<tr><th>No</th><th>법인</th><th>제품명</th><th>수량</th><th>사용중</th><th>사용가능</th></tr>`;
|
|
tbody.innerHTML = '';
|
|
list.forEach((sw, idx) => {
|
|
const assigned = state.masterData.swUsers.filter(u => u.swId === sw.id).length;
|
|
const qty = typeof sw.수량 === 'number' ? sw.수량 : parseInt(sw.수량||'0', 10);
|
|
const avail = qty - assigned;
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `<td>${idx+1}</td><td>${sw.법인}</td><td>${sw.제품명}</td><td>${qty}</td><td>${assigned}</td><td>${avail}</td>`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
modal.classList.remove('hidden');
|
|
}
|