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:
110
src/views/List/NetworkListView.ts
Normal file
110
src/views/List/NetworkListView.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { state } from '../../core/state';
|
||||
import { openHwModal } from '../../components/Modal/HWModal';
|
||||
import { formatInline, createBadge, sortAssets, dynamicSort, getActionButtonsHTML } from '../../core/utils';
|
||||
import { ASSET_SCHEMA, UI_TEXT } from '../../core/schema';
|
||||
import { setupTableSorting, SortState } from '../../core/tableHandler';
|
||||
import { createIcons, RefreshCcw, Download, Upload, FileSpreadsheet, Plus } from 'lucide';
|
||||
|
||||
/**
|
||||
* 네트워크 자산 목록 뷰
|
||||
*/
|
||||
export function renderNetworkList(container: HTMLElement) {
|
||||
const fullList = sortAssets(state.masterData.network || []);
|
||||
let sortState: SortState = { key: '', direction: 'asc' };
|
||||
|
||||
const filterBar = document.createElement('div');
|
||||
filterBar.className = 'search-bar';
|
||||
filterBar.innerHTML = `
|
||||
<div class="search-item flex-1">
|
||||
<label>통합 검색 (${ASSET_SCHEMA.MODEL_NAME.ui}/${ASSET_SCHEMA.MANAGER_MAIN.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> ${UI_TEXT.ACTION.RESET_FILTER}
|
||||
</button>
|
||||
${getActionButtonsHTML()}
|
||||
`;
|
||||
container.appendChild(filterBar);
|
||||
|
||||
const tableWrapper = document.createElement('div');
|
||||
tableWrapper.className = 'table-container';
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center" style="width:50px;">No.</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.HW_STATUS.key}">${ASSET_SCHEMA.HW_STATUS.ui}</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.MANAGER_MAIN.key}">현 사용자</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.ASSET_TYPE.key}">${ASSET_SCHEMA.ASSET_TYPE.ui}</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.ASSET_MFR.key}">${ASSET_SCHEMA.ASSET_MFR.ui}</th>
|
||||
<th data-sort="${ASSET_SCHEMA.MODEL_NAME.key}">${ASSET_SCHEMA.MODEL_NAME.ui}</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.ASSET_COUNT.key}">${ASSET_SCHEMA.ASSET_COUNT.ui}</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.LOCATION.key}">${ASSET_SCHEMA.LOCATION.ui}(건물)</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.LOC_DETAIL.key}">${ASSET_SCHEMA.LOC_DETAIL.ui}</th>
|
||||
<th class="text-center" data-sort="${ASSET_SCHEMA.MEMO.key}">${ASSET_SCHEMA.MEMO.ui}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="dynamic-tbody"></tbody>
|
||||
`;
|
||||
|
||||
tableWrapper.appendChild(table);
|
||||
container.appendChild(tableWrapper);
|
||||
const tbody = table.querySelector('tbody')!;
|
||||
|
||||
const updateTable = () => {
|
||||
const keywordInput = document.getElementById('filter-keyword') as HTMLInputElement;
|
||||
const keyword = keywordInput ? keywordInput.value.toLowerCase().trim() : '';
|
||||
|
||||
let filtered = fullList.filter(asset => {
|
||||
const matchKeyword = !keyword ||
|
||||
String(asset[ASSET_SCHEMA.MODEL_NAME.key]||'').toLowerCase().includes(keyword) ||
|
||||
String(asset[ASSET_SCHEMA.MANAGER_MAIN.key]||'').toLowerCase().includes(keyword) ||
|
||||
String(asset[ASSET_SCHEMA.ASSET_MFR.key]||'').toLowerCase().includes(keyword);
|
||||
return matchKeyword;
|
||||
});
|
||||
|
||||
if (sortState.key) {
|
||||
filtered = dynamicSort(filtered, sortState.key, sortState.direction);
|
||||
}
|
||||
|
||||
tbody.innerHTML = '';
|
||||
if (filtered.length === 0) {
|
||||
tbody.innerHTML = `<tr><td colspan="10" class="text-center" style="padding: 3rem; color: var(--text-muted);">${UI_TEXT.MESSAGES.NO_DATA}</td></tr>`;
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.forEach((asset, idx) => {
|
||||
const tr = document.createElement('tr');
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.innerHTML = `
|
||||
<td class="text-center">${idx + 1}</td>
|
||||
<td class="text-center"><span class="badge badge-success">${asset[ASSET_SCHEMA.HW_STATUS.key] || '운영중'}</span></td>
|
||||
<td class="text-center">${asset[ASSET_SCHEMA.MANAGER_MAIN.key] || '-'}</td>
|
||||
<td class="text-center">${asset[ASSET_SCHEMA.ASSET_TYPE.key] || ''}</td>
|
||||
<td class="text-center">${asset[ASSET_SCHEMA.ASSET_MFR.key] || ''}</td>
|
||||
<td>${formatInline(asset[ASSET_SCHEMA.MODEL_NAME.key] || '-')}</td>
|
||||
<td class="text-center">${asset[ASSET_SCHEMA.ASSET_COUNT.key] || '1'}</td>
|
||||
<td class="text-center">${asset[ASSET_SCHEMA.LOCATION.key] || '-'}</td>
|
||||
<td class="text-center">${asset[ASSET_SCHEMA.LOC_DETAIL.key] || '-'}</td>
|
||||
<td class="text-center">${formatInline(asset[ASSET_SCHEMA.MEMO.key]||'-')}</td>
|
||||
`;
|
||||
tr.addEventListener('click', () => openHwModal(asset, 'view'));
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
|
||||
setupTableSorting(table, sortState, (key, dir) => {
|
||||
sortState = { key, direction: dir };
|
||||
updateTable();
|
||||
});
|
||||
|
||||
createIcons({ icons: { RefreshCcw, Download, Upload, FileSpreadsheet, Plus } });
|
||||
};
|
||||
|
||||
document.getElementById('filter-keyword')?.addEventListener('input', updateTable);
|
||||
document.getElementById('btn-reset-filters')?.addEventListener('click', () => {
|
||||
(document.getElementById('filter-keyword') as HTMLInputElement).value = '';
|
||||
updateTable();
|
||||
});
|
||||
|
||||
updateTable();
|
||||
}
|
||||
Reference in New Issue
Block a user