From 9bd158e2b181ed93697a761381f5cdca4874d616 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sat, 25 Jul 2026 20:35:22 +0900 Subject: [PATCH] feat(wbs-ux): add productivity helper components to SystemSettingsView (Hotkey Helper Bar, Data Clone Button, Draft Timestamp Chip) --- src/frontend/src/views/SystemSettingsView.vue | 138 +++++++++++++----- 1 file changed, 103 insertions(+), 35 deletions(-) diff --git a/src/frontend/src/views/SystemSettingsView.vue b/src/frontend/src/views/SystemSettingsView.vue index 0536b064..1320d747 100644 --- a/src/frontend/src/views/SystemSettingsView.vue +++ b/src/frontend/src/views/SystemSettingsView.vue @@ -39,7 +39,10 @@ const activeDomain = ref<'ALL' | 'OMS' | 'WMS' | 'ERP'>('ALL'); const searchKeyword = ref(''); const activeCategoryTab = ref('ALL'); -// 2. OMS / WMS / ERP 전용 퀵 트랜잭션 모달 상태 +// 2. 사용자 편의성: 임시저장 드래프트 상태 +const lastDraftSavedTime = ref(null); + +// 3. OMS / WMS / ERP 전용 퀵 트랜잭션 모달 상태 const isOmsModalOpen = ref(false); const isWmsModalOpen = ref(false); const isErpModalOpen = ref(false); @@ -48,7 +51,7 @@ const omsOrderForm = ref({ symbol: '005930 (삼성전자)', orderType: 'LIMIT', const wmsVaultForm = ref({ fromAccount: 'D+2 Vault Main', toAccount: 'KIS Trading Account', amount: '50,000,000' }); const erpApprovalForm = ref({ reqId: 'REQ-2026-0725', approver: 'risk_director_kjh', decision: 'APPROVED', comment: '리스크 가드 검토 승인 완료' }); -// 3. 동적 드래그 반응형 Split Pane Resizer & 1-Click 스플릿 프리셋 +// 4. 동적 드래그 반응형 Split Pane Resizer & 1-Click 스플릿 프리셋 const masterPanelWidth = ref(60); const isDraggingSplitter = ref(false); @@ -81,12 +84,12 @@ const stopSplitterDrag = () => { document.removeEventListener('mouseup', stopSplitterDrag); }; -// 4. Master-Detail 바인딩 및 편집 모드 토글 상태 +// 5. Master-Detail 바인딩 및 편집 모드 토글 상태 const items = ref([]); const selectedItem = ref(null); const isEditMode = ref(false); -// 5. 현장감 텔레메트리, 소켓, AI AX 코파일럿 상태 +// 6. 현장감 텔레메트리, 소켓, AI AX 코파일럿 상태 const pingMs = ref(4); const isBatchRunning = ref(false); const batchProgress = ref(0); @@ -100,12 +103,12 @@ const liveLogs = ref([ '[14:02:15] [WARN] WMS Vault Safety Check: D+2 Cash level 500,000,000 KRW OK' ]); -// 6. 페이지네이션 및 드롭다운 상태 +// 7. 페이지네이션 및 드롭다운 상태 const currentPage = ref(1); const showExportMenu = ref(false); const isGuideModalOpen = ref(false); -// 7. 토스트 알림 메시지 +// 8. 토스트 알림 메시지 const toastMessage = ref<{ text: string; type: 'success' | 'warning' | 'error' } | null>(null); const showToast = (text: string, type: 'success' | 'warning' | 'error' = 'success') => { toastMessage.value = { text, type }; @@ -114,7 +117,7 @@ const showToast = (text: string, type: 'success' | 'warning' | 'error' = 'succes }, 3000); }; -// 8. 모달 대화상자 상태 +// 9. 모달 대화상자 상태 const isModalOpen = ref(false); const modalItem = ref({ id: 0, @@ -129,7 +132,7 @@ const modalItem = ref({ maker_checker: 'APPROVED' }); -// 9. 필터링된 항목 계산 +// 10. 필터링된 항목 계산 const filteredItems = computed(() => { return items.value.filter(item => { const matchDomain = activeDomain.value === 'ALL' || item.domain === activeDomain.value; @@ -141,7 +144,7 @@ const filteredItems = computed(() => { }); }); -// 10. AG Grid 컬럼 정의 +// 11. AG Grid 컬럼 정의 const columnDefs = ref([ { field: 'id', headerName: 'ID', width: 55, sortable: true }, { field: 'domain', headerName: '도메인', width: 85, cellRenderer: (p: any) => `${p.value}` }, @@ -192,6 +195,22 @@ const loadData = async () => { } }; +// 사용자 편의성: 선택 항목 복제 (Clone) 기능 +const cloneSelectedItem = () => { + if (!selectedItem.value) return; + const cloned: SettingItem = { + ...JSON.parse(JSON.stringify(selectedItem.value)), + id: items.value.length + 1, + setting_key: `${selectedItem.value.setting_key}_COPY`, + lock_version: 1, + updated_at: new Date().toISOString().slice(0, 16).replace('T', ' '), + audit_history: [{ timestamp: new Date().toISOString().slice(0, 16).replace('T', ' '), user: 'admin_kjh', change: '기존 항목 기반 복제 생성' }] + }; + items.value.unshift(cloned); + selectedItem.value = cloned; + showToast(`📋 [${cloned.setting_key}] 항목이 복제 생성되었습니다.`, 'success'); +}; + const runFactorBatch = () => { if (isBatchRunning.value) return; isBatchRunning.value = true; @@ -282,6 +301,7 @@ const saveDetailForm = () => { }); items.value[idx] = JSON.parse(JSON.stringify(selectedItem.value)); isEditMode.value = false; + lastDraftSavedTime.value = new Date().toLocaleTimeString(); liveLogs.value.unshift(`[${new Date().toLocaleTimeString()}] [UPDATE] Saved key '${selectedItem.value.setting_key}' (Lock Ver v${selectedItem.value.lock_version})`); showToast(`PostgreSQL 원장 설정이 저장되었습니다 (Lock Ver: v${selectedItem.value.lock_version}).`, 'success'); } @@ -333,7 +353,6 @@ onMounted(loadData); -
@@ -347,12 +366,13 @@ onMounted(loadData); - + +
@@ -436,6 +456,7 @@ onMounted(loadData);

✏️ 상세 데이터 [{{ selectedItem.setting_key }}]

+ 💾 임시저장: {{ lastDraftSavedTime }} 🔒 Ver: v{{ selectedItem.lock_version }} {{ selectedItem.maker_checker }}
@@ -553,6 +574,18 @@ onMounted(loadData);
+ +
+ ⌨️ 사용자 핫키 가이드: + F3 조회 + F4 신규 + F5 삭제 + F6 복제 + F7 엑셀 + Ctrl+S 저장 + Esc 팝업닫기 +
+
🖥️ CPU: 12% @@ -655,37 +688,39 @@ onMounted(loadData);
- +