feat: restructure navigation, customize list columns, and move action buttons to search bar
1. Restructured navigation hierarchy (Hardware, Software, Ops Support, etc.). 2. Customized table columns for all asset categories according to new specs. 3. Moved Template/Upload/Export/Add buttons to search bar with layout optimization. 4. Hidden Asset Code and Previous User from list views (Modal only). 5. Added Current/Previous User and detailed PC spec fields (GPU, HDD3/4).
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { state } from '../../core/state';
|
||||
import { formatPrice, dynamicSort, createBadge } from '../../core/utils';
|
||||
import { createIcons, Plus, Edit2, Trash2 } from 'lucide';
|
||||
import { formatPrice, dynamicSort, createBadge, getActionButtonsHTML } from '../../core/utils';
|
||||
import { createIcons, Plus, Edit2, Trash2, RefreshCcw, Download, Upload, FileSpreadsheet } from 'lucide';
|
||||
import { openDomainModal } from '../../components/Modal/DomainModal';
|
||||
import { setupTableSorting, SortState } from '../../core/tableHandler';
|
||||
import { formatExcelDate } from '../../core/excelHandler';
|
||||
import { ASSET_SCHEMA } from '../../core/schema';
|
||||
|
||||
// 정렬 상태를 모듈 수준에서 관리하여 화면 갱신 시에도 유지되도록 함
|
||||
let persistentSortState: SortState = { key: '', direction: 'asc' };
|
||||
@@ -13,14 +13,20 @@ export function renderDomainList(container: HTMLElement) {
|
||||
|
||||
const fullList = state.masterData.domain;
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.className = 'list-header';
|
||||
header.innerHTML = `
|
||||
<div class="list-title-area">
|
||||
<h2 class="list-title">도메인 관리</h2>
|
||||
// 검색바 및 액션 버튼 추가
|
||||
const filterBar = document.createElement('div');
|
||||
filterBar.className = 'search-bar';
|
||||
filterBar.innerHTML = `
|
||||
<div class="search-item flex-1">
|
||||
<label>통합 검색 (${ASSET_SCHEMA.DOMAIN_ADDR.ui}/${ASSET_SCHEMA.PRODUCT_NAME.ui})</label>
|
||||
<input type="text" id="filter-keyword" placeholder="검색어를 입력하세요..." autocomplete="off">
|
||||
</div>
|
||||
<button id="btn-reset-filters" class="btn btn-outline btn-reset">
|
||||
<i data-lucide="refresh-ccw"></i> 필터 초기화
|
||||
</button>
|
||||
${getActionButtonsHTML()}
|
||||
`;
|
||||
container.appendChild(header);
|
||||
container.appendChild(filterBar);
|
||||
|
||||
const tableWrapper = document.createElement('div');
|
||||
tableWrapper.className = 'table-container';
|
||||
@@ -29,15 +35,12 @@ export function renderDomainList(container: HTMLElement) {
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center; width:50px;">No.</th>
|
||||
<th style="text-align:center;" data-sort="type">유형</th>
|
||||
<th style="text-align:center;" data-sort="corp">법인</th>
|
||||
<th style="text-align:left;" data-sort="service_name">서비스명</th>
|
||||
<th style="text-align:left;" data-sort="domain_name">관리도메인</th>
|
||||
<th style="text-align:left;" data-sort="remarks">구매업체</th>
|
||||
<th style="text-align:center;" data-sort="start_date">시작일</th>
|
||||
<th style="text-align:center;" data-sort="expiry_date">만료일</th>
|
||||
<th style="text-align:right;" data-sort="price">금액</th>
|
||||
<th style="text-align:center;" data-sort="manager_main">담당자(정/부)</th>
|
||||
<th style="text-align:left;" data-sort="${ASSET_SCHEMA.DOMAIN_ADDR.key}">${ASSET_SCHEMA.DOMAIN_ADDR.ui}</th>
|
||||
<th style="text-align:left;" data-sort="${ASSET_SCHEMA.ASSET_PURPOSE.key}">${ASSET_SCHEMA.ASSET_PURPOSE.ui}</th>
|
||||
<th style="text-align:center;" data-sort="${ASSET_SCHEMA.ASSET_TYPE.key}">${ASSET_SCHEMA.ASSET_TYPE.ui}</th>
|
||||
<th style="text-align:center;" data-sort="${ASSET_SCHEMA.PURCHASE_CORP.key}">${ASSET_SCHEMA.PURCHASE_CORP.ui}</th>
|
||||
<th style="text-align:center;" data-sort="${ASSET_SCHEMA.EXPIRY_DATE.key}">${ASSET_SCHEMA.EXPIRY_DATE.ui}</th>
|
||||
<th style="text-align:center;" data-sort="${ASSET_SCHEMA.MEMO.key}">${ASSET_SCHEMA.MEMO.ui}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="dynamic-tbody"></tbody>
|
||||
@@ -48,7 +51,16 @@ export function renderDomainList(container: HTMLElement) {
|
||||
const tbody = table.querySelector('tbody')!;
|
||||
|
||||
const updateTable = () => {
|
||||
let filtered = [...fullList];
|
||||
const keywordInput = document.getElementById('filter-keyword') as HTMLInputElement;
|
||||
const keyword = keywordInput ? keywordInput.value.toLowerCase().trim() : '';
|
||||
|
||||
let filtered = fullList.filter(item => {
|
||||
const matchKeyword = !keyword ||
|
||||
(item[ASSET_SCHEMA.DOMAIN_ADDR.key] || '').toLowerCase().includes(keyword) ||
|
||||
(item[ASSET_SCHEMA.ASSET_PURPOSE.key] || '').toLowerCase().includes(keyword) ||
|
||||
(item[ASSET_SCHEMA.PRODUCT_NAME.key] || '').toLowerCase().includes(keyword);
|
||||
return matchKeyword;
|
||||
});
|
||||
|
||||
if (persistentSortState.key) {
|
||||
filtered = dynamicSort(filtered, persistentSortState.key, persistentSortState.direction);
|
||||
@@ -56,7 +68,7 @@ export function renderDomainList(container: HTMLElement) {
|
||||
|
||||
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="7" style="text-align:center; padding: 3rem; color: var(--text-muted);">등록된 도메인 정보가 없습니다.</td></tr>`;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,25 +76,17 @@ export function renderDomainList(container: HTMLElement) {
|
||||
const tr = document.createElement('tr');
|
||||
tr.className = 'domain-row';
|
||||
tr.style.cursor = 'pointer';
|
||||
const managerHtml = [
|
||||
item.manager_main ? `${createBadge('정', 'primary')} ${item.manager_main}` : '',
|
||||
item.manager_sub ? `${createBadge('부', 'muted')} ${item.manager_sub}` : ''
|
||||
].filter(v => v !== '').join(' / ');
|
||||
|
||||
tr.innerHTML = `
|
||||
<td style="text-align:center;">${idx + 1}</td>
|
||||
<td style="text-align:center;"><span class="badge badge-${item.type}">${item.type}</span></td>
|
||||
<td style="text-align:center;">${item.corp || ''}</td>
|
||||
<td>${item.service_name || ''}</td>
|
||||
<td>${item.domain_name || ''}</td>
|
||||
<td>${item.remarks || ''}</td>
|
||||
<td style="text-align:center;">${formatExcelDate(item.start_date)}</td>
|
||||
<td style="text-align:center;">${formatExcelDate(item.expiry_date)}</td>
|
||||
<td style="text-align:right;">${formatPrice(item.price)}</td>
|
||||
<td style="text-align:center;">${managerHtml || '-'}</td>
|
||||
<td>${item[ASSET_SCHEMA.DOMAIN_ADDR.key] || ''}</td>
|
||||
<td>${item[ASSET_SCHEMA.ASSET_PURPOSE.key] || ''}</td>
|
||||
<td style="text-align:center;"><span class="badge badge-${item[ASSET_SCHEMA.ASSET_TYPE.key] === '관리중' ? 'primary' : 'muted'}">${item[ASSET_SCHEMA.ASSET_TYPE.key] || '-'}</span></td>
|
||||
<td style="text-align:center;">${item[ASSET_SCHEMA.PURCHASE_CORP.key] || ''}</td>
|
||||
<td style="text-align:center;">${item[ASSET_SCHEMA.EXPIRY_DATE.key] || ''}</td>
|
||||
<td>${formatInline(item[ASSET_SCHEMA.MEMO.key]||'-')}</td>
|
||||
`;
|
||||
tr.addEventListener('click', (e) => {
|
||||
console.log('Row clicked:', item.domain_name);
|
||||
openDomainModal(item);
|
||||
});
|
||||
tbody.appendChild(tr);
|
||||
@@ -92,8 +96,15 @@ export function renderDomainList(container: HTMLElement) {
|
||||
persistentSortState = { key, direction: dir };
|
||||
updateTable();
|
||||
});
|
||||
|
||||
createIcons({ icons: { Plus, Edit2, Trash2, RefreshCcw, Download, Upload, FileSpreadsheet } });
|
||||
};
|
||||
|
||||
document.getElementById('filter-keyword')?.addEventListener('input', updateTable);
|
||||
document.getElementById('btn-reset-filters')?.addEventListener('click', () => {
|
||||
if (document.getElementById('filter-keyword')) (document.getElementById('filter-keyword') as HTMLInputElement).value = '';
|
||||
updateTable();
|
||||
});
|
||||
|
||||
updateTable();
|
||||
createIcons({ icons: { Plus, Edit2, Trash2 } });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user