diff --git a/.gitignore b/.gitignore index ad4db5d..df4b3f8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ dist/ Thumbs.db backups/ mysql_data/ +/docs/grafana_integration_proposal.md diff --git a/mobile.html b/mobile.html index 8050aa3..f144251 100644 --- a/mobile.html +++ b/mobile.html @@ -294,6 +294,28 @@ + + + + + diff --git a/src/components/Modal/DomainModal.ts b/src/components/Modal/DomainModal.ts index 7e8fdf8..9f79459 100644 --- a/src/components/Modal/DomainModal.ts +++ b/src/components/Modal/DomainModal.ts @@ -133,6 +133,7 @@ class DomainAssetModal extends BaseModal { revertBtn.addEventListener('click', () => { this.setEditLockMode('view'); + this.isEditMode = false; if (this.currentAsset) this.fillFormData(this.currentAsset); }); diff --git a/src/components/Modal/HWModal.ts b/src/components/Modal/HWModal.ts index 5b78f7f..e14320f 100644 --- a/src/components/Modal/HWModal.ts +++ b/src/components/Modal/HWModal.ts @@ -272,6 +272,7 @@ class HwAssetModal extends BaseModal { protected initChildLogic(onSave: () => void, closeModals: () => void): void { const saveBtn = document.getElementById('btn-save-hw-asset')!; + const revertBtn = document.getElementById('btn-revert-hw-edit')!; const deleteBtn = document.getElementById('btn-delete-hw-asset')!; const categorySelect = document.getElementById('hw-category') as HTMLSelectElement; const typeSelect = document.getElementById('hw-asset_type') as HTMLSelectElement; @@ -412,6 +413,12 @@ class HwAssetModal extends BaseModal { } }); + revertBtn.addEventListener('click', () => { + if (this.currentAsset) { + this.open(this.currentAsset, 'view'); + } + }); + saveBtn.addEventListener('click', async () => { if (!this.currentAsset) return; diff --git a/src/components/Modal/JobSpecModal.ts b/src/components/Modal/JobSpecModal.ts index b290cd7..b38b958 100644 --- a/src/components/Modal/JobSpecModal.ts +++ b/src/components/Modal/JobSpecModal.ts @@ -144,6 +144,7 @@ class JobSpecModal extends BaseModal { revertBtn.addEventListener('click', () => { this.setEditLockMode('view'); + this.isEditMode = false; if (this.currentAsset) this.fillFormData(this.currentAsset); }); diff --git a/src/components/Modal/PartsMasterModal.ts b/src/components/Modal/PartsMasterModal.ts index b3c7061..58babac 100644 --- a/src/components/Modal/PartsMasterModal.ts +++ b/src/components/Modal/PartsMasterModal.ts @@ -101,6 +101,7 @@ class PartsMasterModal extends BaseModal { revertBtn.addEventListener('click', () => { this.setEditLockMode('view'); + this.isEditMode = false; if (this.currentAsset) this.fillFormData(this.currentAsset); }); diff --git a/src/components/Modal/SWModal.ts b/src/components/Modal/SWModal.ts index 1f13e1d..9da0725 100644 --- a/src/components/Modal/SWModal.ts +++ b/src/components/Modal/SWModal.ts @@ -278,6 +278,7 @@ class SwAssetModal extends BaseModal { revertBtn.addEventListener('click', () => { this.setEditLockMode('view'); + this.isEditMode = false; if (this.currentAsset) this.fillFormData(this.currentAsset); }); diff --git a/src/components/Modal/UserModal.ts b/src/components/Modal/UserModal.ts index 5a60419..420223d 100644 --- a/src/components/Modal/UserModal.ts +++ b/src/components/Modal/UserModal.ts @@ -107,6 +107,7 @@ class UserModal extends BaseModal { revertBtn.addEventListener('click', () => { this.setEditLockMode('view'); + this.isEditMode = false; if (this.currentAsset) this.fillFormData(this.currentAsset); }); diff --git a/src/components/Navigation.ts b/src/components/Navigation.ts index a89bb0e..aa53723 100644 --- a/src/components/Navigation.ts +++ b/src/components/Navigation.ts @@ -3,7 +3,7 @@ import { state } from '../core/state'; const MENU_CONFIG: any = { hw: { label: '하드웨어', - tabs: ['대시보드', '서버', 'PC', '스토리지', '공간정보장비', 'PC부품', '부품 마스터', '네트워크', '업무지원장비'] + tabs: ['대시보드', '서버', 'PC', '스토리지', '공간정보장비', 'PC부품', '네트워크', '업무지원장비'] }, sw: { label: '소프트웨어', @@ -65,18 +65,17 @@ export function renderNavigation(onTabChange: (tab: string) => void) { }); if (state.currentUserRole === 'admin' && catKey === 'hw') { - visibleTabs = ['대시보드', '관리도구', '실사 승인', '위치지정']; + visibleTabs = ['대시보드', '관리도구', '실사 승인', '위치지정', '부품 마스터']; } if (visibleTabs.length === 0) return; visibleTabs.forEach((tab: string) => { - if (tab === '부품 마스터') return; const item = document.createElement('div'); const isActive = state.activeSubTab === tab; item.className = `gnb-trigger ${isActive ? 'active' : ''}`; - const isSubMenu = tab === '실사 승인' || tab === '위치지정'; + const isSubMenu = tab === '실사 승인' || tab === '위치지정' || tab === '부품 마스터'; if (isSubMenu) { item.innerHTML = `${tab}`; item.style.fontSize = '11px'; diff --git a/src/core/filterHandler.ts b/src/core/filterHandler.ts index 8d18954..1153640 100644 --- a/src/core/filterHandler.ts +++ b/src/core/filterHandler.ts @@ -15,6 +15,8 @@ export interface FilterOptions { showField?: boolean; showType?: boolean; showStatus?: boolean; + showPartCategory?: boolean; + showPartTier?: boolean; extraHTML?: string; onFilterChange: (filters: any) => void; initialFilters?: any; @@ -37,9 +39,11 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions) showField = false, showType = false, showStatus = false, + showPartCategory = false, + showPartTier = false, extraHTML = '', onFilterChange, - initialFilters = { keyword: '', corp: '', dept: '', loc: '', field: '', type: '', status: '' }, + initialFilters = { keyword: '', corp: '', dept: '', loc: '', field: '', type: '', status: '', partCategory: '', partTier: '' }, fullList = [] } = options; @@ -104,6 +108,22 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions) ${getUnique('CURRENT_DEPT').map(v => ``).join('')} ` : ''} + ${showPartCategory ? ` +
+ + +
` : ''} + ${showPartTier ? ` +
+ + +
` : ''} ${extraHTML}