feat: implement unified schema mapper, enhance UI/UX with responsive design, and optimize asset log logic

This commit is contained in:
2026-04-23 18:00:10 +09:00
parent bb1cc36d01
commit 9365af4522
21 changed files with 1129 additions and 892 deletions

View File

@@ -1,20 +1,24 @@
import { state } from '../../core/state';
import { openSwModal } from '../../components/Modal/SWModal';
import { createIcons, Cloud, CreditCard, DollarSign } from 'lucide';
import { ASSET_SCHEMA, UI_TEXT } from '../../core/schema';
import { createIcons, Cloud, CreditCard, DollarSign, RefreshCcw } from 'lucide';
/**
* 클라우드(운영 서비스) 자산 목록 뷰
* 라인 정렬 보정 및 헤더 통일
*/
export function renderCloudList(container: HTMLElement) {
// DB에서 직접 로드된 전용 배열을 사용하여 데이터 소스를 일원화함
const getFullList = () => state.masterData.cloud || [];
const filterBar = document.createElement('div');
filterBar.className = 'search-bar';
filterBar.innerHTML = `
<div class="search-item flex-1">
<label>통합 검색 (제품명/부서/계정명)</label>
<label>통합 검색 (${ASSET_SCHEMA.PRODUCT.ui}/부서/${ASSET_SCHEMA.ACCOUNT.ui})</label>
<input type="text" id="filter-keyword" placeholder="검색어를 입력하세요..." autocomplete="off">
</div>
<div class="search-item">
<label>결제수단</label>
<label>${ASSET_SCHEMA.PAY_METHOD.ui}</label>
<select id="filter-payment">
<option value="">전체 결제수단</option>
<option value="법인카드">법인카드</option>
@@ -22,7 +26,7 @@ export function renderCloudList(container: HTMLElement) {
</select>
</div>
<button id="btn-reset-filters" class="btn btn-outline btn-reset">
<i data-lucide="refresh-ccw"></i> 필터 초기화
<i data-lucide="refresh-ccw"></i> ${UI_TEXT.ACTION.RESET_FILTER}
</button>
`;
container.appendChild(filterBar);
@@ -33,16 +37,16 @@ export function renderCloudList(container: HTMLElement) {
table.innerHTML = `
<thead>
<tr>
<th style="text-align:center;">No.</th>
<th style="text-align:center;">플랫폼명</th>
<th style="text-align:center;">법인</th>
<th style="text-align:center;">담당부서</th>
<th style="text-align:center;">진행 프로젝트(사용용도)</th>
<th style="text-align:center;">계정명(관리자)</th>
<th style="text-align:center;">결제수단</th>
<th style="text-align:center;">결제일</th>
<th style="text-align:center;">당월 청구액</th>
<th style="text-align:center;">비고</th>
<th class="text-center">No.</th>
<th>${ASSET_SCHEMA.PLATFORM.ui}</th>
<th class="text-center">${ASSET_SCHEMA.CORP.ui}</th>
<th class="text-center">담당부서</th>
<th>용도(프로젝트)</th>
<th>${ASSET_SCHEMA.ACCOUNT.ui}</th>
<th class="text-center">${ASSET_SCHEMA.PAY_METHOD.ui}</th>
<th class="text-center">${ASSET_SCHEMA.PAY_DAY.ui}</th>
<th class="text-center">${ASSET_SCHEMA.BILLING.ui}</th>
<th>${ASSET_SCHEMA.REMARKS.ui}</th>
</tr>
</thead>
<tbody id="cloud-tbody"></tbody>
@@ -61,16 +65,16 @@ export function renderCloudList(container: HTMLElement) {
const filtered = getFullList().filter(asset => {
const kwMatch = !keyword ||
(asset. || '').toLowerCase().includes(keyword) ||
(asset[ASSET_SCHEMA.PRODUCT.key] || '').toLowerCase().includes(keyword) ||
(asset. || '').toLowerCase().includes(keyword) ||
(asset. || '').toLowerCase().includes(keyword);
const payMatch = !payment || asset. === payment;
(asset[ASSET_SCHEMA.ACCOUNT.key] || '').toLowerCase().includes(keyword);
const payMatch = !payment || asset[ASSET_SCHEMA.PAY_METHOD.key] === payment;
return kwMatch && payMatch;
});
tbody.innerHTML = '';
if (filtered.length === 0) {
tbody.innerHTML = '<tr><td colspan="10" style="text-align:center; padding: 3rem; color: var(--text-muted);">등록된 클라우드 서비스가 없습니다.</td></tr>';
tbody.innerHTML = `<tr><td colspan="10" class="text-center" style="padding: 3rem; color: var(--text-muted);">${UI_TEXT.MESSAGES.NO_DATA}</td></tr>`;
return;
}
@@ -78,29 +82,30 @@ export function renderCloudList(container: HTMLElement) {
const tr = document.createElement('tr');
tr.style.cursor = 'pointer';
const paymentBadge = asset. === '법인카드'
? '<span style="color:#6366f1; font-weight:600;"><i data-lucide="credit-card" style="width:14px; height:14px; vertical-align:middle; margin-right:4px;"></i>법인카드 (' + (asset.||'미상') + ')</span>'
: (asset. === '인보이스'
const payMethod = asset[ASSET_SCHEMA.PAY_METHOD.key];
const paymentBadge = payMethod === '법인카드'
? `<span style="color:#6366f1; font-weight:600;"><i data-lucide="credit-card" style="width:14px; height:14px; vertical-align:middle; margin-right:4px;"></i>법인카드</span>`
: (payMethod === '인보이스'
? '<span style="color:#10b981; font-weight:600;"><i data-lucide="dollar-sign" style="width:14px; height:14px; vertical-align:middle; margin-right:4px;"></i>인보이스</span>'
: '<span style="color:var(--text-muted)">미설정</span>');
tr.innerHTML = `
<td style="text-align:center;">${idx+1}</td>
<td style="font-weight:600; color:var(--primary-color)"><i data-lucide="cloud" style="width:14px; height:14px; vertical-align:middle; margin-right:4px;"></i> ${asset.||'미지정'}</td>
<td style="text-align:center;">${asset.||''}</td>
<td style="text-align:center;">${asset.||''}</td>
<td>${asset.||''}</td>
<td>${asset.||''}</td>
<td style="text-align:center;">${paymentBadge}</td>
<td style="text-align:center;">${asset. ? asset. + '일' : ''}</td>
<td style="text-align:right; font-weight:600;">₩ ${asset. ? Number(asset.).toLocaleString() : '0'}</td>
<td>${asset.||''}</td>
<td class="text-center">${idx+1}</td>
<td style="font-weight:600; color:var(--primary-color)"><i data-lucide="cloud" style="width:14px; height:14px; vertical-align:middle; margin-right:4px;"></i> ${asset[ASSET_SCHEMA.PLATFORM.key]||'미지정'}</td>
<td class="text-center">${asset[ASSET_SCHEMA.CORP.key]||''}</td>
<td class="text-center">${asset.||''}</td>
<td>${asset[ASSET_SCHEMA.PRODUCT.key]||''}</td>
<td>${asset[ASSET_SCHEMA.ACCOUNT.key]||''}</td>
<td class="text-center">${paymentBadge}</td>
<td class="text-center">${asset[ASSET_SCHEMA.PAY_DAY.key] ? asset[ASSET_SCHEMA.PAY_DAY.key] + '일' : ''}</td>
<td class="text-right" style="font-weight:600;">₩ ${asset[ASSET_SCHEMA.BILLING.key] ? Number(asset[ASSET_SCHEMA.BILLING.key]).toLocaleString() : '0'}</td>
<td>${asset[ASSET_SCHEMA.REMARKS.key]||''}</td>
`;
tr.addEventListener('click', () => openSwModal(asset, 'view'));
tbody.appendChild(tr);
});
createIcons({ icons: { Cloud, CreditCard, DollarSign } });
createIcons({ icons: { Cloud, CreditCard, DollarSign, RefreshCcw } });
};
document.getElementById('filter-keyword')?.addEventListener('input', updateTable);