refactor: complete modal class-based architecture, design system integration, and map editor modularization

This commit is contained in:
2026-06-01 14:57:07 +09:00
parent 590ddd0e85
commit 9cd5d59bf8
32 changed files with 1838 additions and 1670 deletions

View File

@@ -14,18 +14,26 @@ export interface FilterOptions {
showDept?: boolean;
showLoc?: boolean;
showField?: boolean;
showType?: boolean;
extraHTML?: string;
onFilterChange: (filters: any) => void;
}
export function renderFilterBar(container: HTMLElement, options: FilterOptions) {
const { keywordLabel = '통합 검색', showCorp = false, showDept = false, showLoc = false, showField = false, extraHTML = '', onFilterChange } = options;
const { keywordLabel = '통합 검색', showCorp = false, showDept = false, showLoc = false, showField = false, showType = false, extraHTML = '', onFilterChange } = options;
container.innerHTML = `
<div class="search-item flex-1">
<label>${keywordLabel}</label>
<input type="text" id="filter-keyword" placeholder="검색어를 입력하세요..." autocomplete="off">
</div>
${showType ? `
<div class="search-item">
<label>${ASSET_SCHEMA.ASSET_TYPE.ui}</label>
<select id="filter-type">
<option value="">전체 유형</option>
</select>
</div>` : ''}
${showField ? `
<div class="search-item">
<label>${ASSET_SCHEMA.SW_FIELD.ui}</label>
@@ -66,7 +74,8 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
corp: (container.querySelector('#filter-corp') as HTMLSelectElement)?.value || '',
dept: (container.querySelector('#filter-dept') as HTMLSelectElement)?.value || '',
loc: (container.querySelector('#filter-loc') as HTMLSelectElement)?.value || '',
field: (container.querySelector('#filter-field') as HTMLSelectElement)?.value || ''
field: (container.querySelector('#filter-field') as HTMLSelectElement)?.value || '',
type: (container.querySelector('#filter-type') as HTMLSelectElement)?.value || ''
};
onFilterChange(filters);
};
@@ -76,9 +85,10 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
container.querySelector('#filter-dept')?.addEventListener('change', triggerChange);
container.querySelector('#filter-loc')?.addEventListener('change', triggerChange);
container.querySelector('#filter-field')?.addEventListener('change', triggerChange);
container.querySelector('#filter-type')?.addEventListener('change', triggerChange);
container.querySelector('#btn-reset-filters')?.addEventListener('click', () => {
['filter-keyword', 'filter-corp', 'filter-dept', 'filter-loc', 'filter-field'].forEach(id => {
['filter-keyword', 'filter-corp', 'filter-dept', 'filter-loc', 'filter-field', 'filter-type'].forEach(id => {
const el = container.querySelector(`#${id}`);
if (el) (el as any).value = '';
});
@@ -98,7 +108,8 @@ export function applyCommonFilters(list: any[], filters: any, searchKeys: (keyof
const matchDept = !filters.dept || (item[ASSET_SCHEMA.CURRENT_DEPT.key] || item[ASSET_SCHEMA.CURRENT_DEPT.db]) === filters.dept;
const matchLoc = !filters.loc || (item[ASSET_SCHEMA.LOCATION.key] || item[ASSET_SCHEMA.LOCATION.db]) === filters.loc;
const matchField = !filters.field || (item[ASSET_SCHEMA.SW_FIELD.key] || item[ASSET_SCHEMA.SW_FIELD.db]) === filters.field;
const matchType = !filters.type || (item[ASSET_SCHEMA.ASSET_TYPE.key] || item[ASSET_SCHEMA.ASSET_TYPE.db]) === filters.type;
return matchKeyword && matchCorp && matchDept && matchLoc && matchField;
return matchKeyword && matchCorp && matchDept && matchLoc && matchField && matchType;
});
}

View File

@@ -21,6 +21,9 @@ export const ASSET_SCHEMA = {
MANAGER_SUB: { key: 'manager_secondary', db: 'manager_secondary', ui: '담당자(부)' },
LOCATION: { key: 'location', db: 'location', ui: '자산위치' },
LOC_DETAIL: { key: 'location_detail', db: 'location_detail', ui: '상세위치' },
LOCATION_PHOTO: { key: 'location_photo', db: 'location_photo', ui: '배치도이미지' },
LOC_X: { key: 'loc_x', db: 'loc_x', ui: '위치X' },
LOC_Y: { key: 'loc_y', db: 'loc_y', ui: '위치Y' },
MEMO: { key: 'memo', db: 'memo', ui: '메모' },
// ─── 하드웨어 상세 (Hardware) ───