diff --git a/src/frontend/src/components/QuantDataGrid.vue b/src/frontend/src/components/QuantDataGrid.vue index 1c04b91a..495f8fb6 100644 --- a/src/frontend/src/components/QuantDataGrid.vue +++ b/src/frontend/src/components/QuantDataGrid.vue @@ -10,8 +10,12 @@ const props = defineProps<{ filename?: string; }>(); -const emit = defineEmits(['row-selected', 'cell-value-changed']); +const emit = defineEmits(['row-selected', 'cell-value-changed', 'cell-double-clicked']); const gridApi = ref(null); + +const onCellDoubleClicked = (event: any) => { + emit('cell-double-clicked', event); +}; const selectedCount = ref(0); const quickFilterText = ref(''); const isExportMenuOpen = ref(false); @@ -141,6 +145,7 @@ defineExpose({ exportToExcel: exportToCsv, resetGridState, autoSizeColumns, grid @grid-ready="onGridReady" @selection-changed="onSelectionChanged" @cell-value-changed="onCellValueChanged" + @cell-double-clicked="onCellDoubleClicked" /> diff --git a/src/frontend/src/composables/useSystemSettings.ts b/src/frontend/src/composables/useSystemSettings.ts index d21dce46..22db2e2b 100644 --- a/src/frontend/src/composables/useSystemSettings.ts +++ b/src/frontend/src/composables/useSystemSettings.ts @@ -42,7 +42,7 @@ export function useSystemSettings() { const isBatchRunning = ref(false); const batchProgress = ref(0); const dbConnections = ref(4); - const aiRecommendation = ref('๐Ÿค– AI AX Recommendation: RSI ์ƒํ•œ๊ฐ’์„ 70.0์—์„œ 68.5๋กœ ๋ณด์ • ์‹œ ์Šฌ๋ฆฌํ”ผ์ง€ 0.14% ๊ฐ์†Œ๊ฐ€ ์˜ˆ์ธก๋ฉ๋‹ˆ๋‹ค.'); + const aiRecommendation = ref('๐Ÿค– AI AX Insights: ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์„ ํƒํ•˜๋ฉด ๋„๋ฉ”์ธ ๋งž์ถค ์‹ค์‹œ๊ฐ„ ๋ฆฌ์Šคํฌ/ํŒฉํ„ฐ ์ง€๋Šฅ ๋ถ„์„์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.'); const liveLogs = ref([ '[14:00:01] [INFO] SignalR WebSocket Hub connected to wss://localhost:5173/hub', @@ -73,6 +73,29 @@ export function useSystemSettings() { }); }); + const selectItemWithInsight = (item: SettingItem, editMode: boolean = false) => { + selectedItem.value = JSON.parse(JSON.stringify(item)); + isEditMode.value = editMode; + updateAiInsightForSelectedItem(item); + }; + + const updateAiInsightForSelectedItem = (item: SettingItem) => { + if (item.domain === 'WMS') { + aiRecommendation.value = `๐Ÿค– AI AX Insights [WMS ์ž์‚ฐ]: ${item.setting_key} (๊ฐ’: ${item.setting_value}) - D+2 ์ฆ‰์‹œ๋ฐฉ์–ด ํ˜„๊ธˆ๋ชฉํ‘œ ์•ˆ์ „์œจ 100% ์ถฉ์กฑ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.`; + } else if (item.domain === 'OMS') { + aiRecommendation.value = `๐Ÿ“‰ AI AX Insights [OMS ์ฃผ๋ฌธ]: ${item.setting_key} (๊ฐ’: ${item.setting_value}) - ํ˜ธ๊ฐ€ ์Šคํ”„๋ ˆ๋“œ ๋ฐฑํ…Œ์ŠคํŠธ ๊ธฐ๋ฐ˜ ์Šฌ๋ฆฌํ”ผ์ง€ 0.14% ์ตœ์ ํ™” ์ƒํƒœ์ž…๋‹ˆ๋‹ค.`; + } else if (item.domain === 'ERP') { + aiRecommendation.value = `๐Ÿ“‘ AI AX Insights [ERP ์žฌ๋ฌด]: ${item.setting_key} (๊ฐ’: ${item.setting_value}) - Maker-Checker ๊ฒฐ์žฌ ๋ฆด๋ ˆ์ด ์Šน์ธ ์™„๋ฃŒ ๋ฐ ์„ธ๋ฌด ๊ณ„์ • ์ •ํ•ฉ์„ฑ์ด ๊ฒ€์ฆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`; + } + }; + + const quickChangeStatus = (newStatus: 'ACTIVE' | 'WARNING' | 'BLOCKED') => { + if (!selectedItem.value) return; + selectedItem.value.status = newStatus; + saveDetailForm(); + showToast(`โšก ์ƒํƒœ๊ฐ€ [${newStatus}]๋กœ ์ฆ‰์‹œ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, newStatus === 'ACTIVE' ? 'success' : newStatus === 'WARNING' ? 'warning' : 'error'); + }; + const loadData = async () => { items.value = [ { @@ -100,7 +123,7 @@ export function useSystemSettings() { } ]; if (items.value.length > 0) { - selectedItem.value = JSON.parse(JSON.stringify(items.value[0])); + selectItemWithInsight(items.value[0]); } }; @@ -115,7 +138,7 @@ export function useSystemSettings() { audit_history: [{ timestamp: new Date().toISOString().slice(0, 16).replace('T', ' '), user: 'admin_kjh', change: '๊ธฐ์กด ํ•ญ๋ชฉ ๊ธฐ๋ฐ˜ ๋ณต์ œ ์ƒ์„ฑ' }] }; items.value.unshift(cloned); - selectedItem.value = cloned; + selectItemWithInsight(cloned, true); showToast(`๐Ÿ“‹ [${cloned.setting_key}] ํ•ญ๋ชฉ์ด ๋ณต์ œ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, 'success'); }; @@ -160,7 +183,11 @@ export function useSystemSettings() { if (confirm(`[${selectedItem.value.setting_key}] ํ•ญ๋ชฉ์„ ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?`)) { liveLogs.value.unshift(`[${new Date().toLocaleTimeString()}] [DELETE] Deleted key: ${selectedItem.value.setting_key}`); items.value = items.value.filter(i => i.id !== selectedItem.value?.id); - selectedItem.value = items.value.length > 0 ? items.value[0] : null; + if (items.value.length > 0) { + selectItemWithInsight(items.value[0]); + } else { + selectedItem.value = null; + } showToast('ํ•ญ๋ชฉ์ด ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.', 'warning'); } }; @@ -177,6 +204,6 @@ export function useSystemSettings() { isOmsModalOpen, isWmsModalOpen, isErpModalOpen, isModalOpen, isGuideModalOpen, isEditMode, masterPanelWidth, isDraggingSplitter, pingMs, isBatchRunning, batchProgress, dbConnections, aiRecommendation, liveLogs, items, selectedItem, toastMessage, filteredItems, - showToast, loadData, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio + showToast, loadData, selectItemWithInsight, quickChangeStatus, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio }; } diff --git a/src/frontend/src/views/SystemSettingsView.vue b/src/frontend/src/views/SystemSettingsView.vue index 95b717e0..d6f0de51 100644 --- a/src/frontend/src/views/SystemSettingsView.vue +++ b/src/frontend/src/views/SystemSettingsView.vue @@ -18,7 +18,7 @@ const { isOmsModalOpen, isWmsModalOpen, isErpModalOpen, isModalOpen, isGuideModalOpen, isEditMode, masterPanelWidth, isDraggingSplitter, pingMs, isBatchRunning, batchProgress, dbConnections, aiRecommendation, liveLogs, items, selectedItem, toastMessage, filteredItems, - showToast, loadData, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio + showToast, loadData, selectItemWithInsight, quickChangeStatus, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio } = useSystemSettings(); const omsOrderForm = ref({ symbol: '005930 (์‚ผ์„ฑ์ „์ž)', orderType: 'LIMIT', price: '72,500', qty: '100' }); @@ -51,8 +51,14 @@ const columnDefs = ref([ const handleRowSelect = (rows: any[]) => { if (rows.length > 0) { - selectedItem.value = JSON.parse(JSON.stringify(rows[0])); - isEditMode.value = false; + selectItemWithInsight(rows[0], false); + } +}; + +const handleCellDoubleClicked = (params: any) => { + if (params && params.data) { + selectItemWithInsight(params.data, true); + showToast(`โœ๏ธ [${params.data.setting_key}] ํ•ญ๋ชฉ์ด ๋”๋ธ”ํด๋ฆญ๋˜์–ด ํŽธ์ง‘ ๋ชจ๋“œ๋กœ ์ž๋™ ์ „ํ™˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, 'success'); } }; @@ -162,6 +168,7 @@ const triggerExport = (fmt: string) => { :rowData="filteredItems" rowSelection="single" @row-selected="handleRowSelect" + @cell-double-clicked="handleCellDoubleClicked" />
- + +
+ + + +
{ user-select: none; } +.quick-status-toggle-bar { + display: flex; + gap: 6px; + margin-bottom: 4px; +} + +.status-toggle-btn { + padding: 3px 8px; + font-size: 0.65rem; + font-weight: 700; + border: none; + border-radius: 4px; + cursor: pointer; + color: white; +} + +.status-toggle-btn.active { background-color: #166534; } +.status-toggle-btn.warning { background-color: #D97706; } +.status-toggle-btn.blocked { background-color: #DC2626; } + .draft-saved-chip { font-size: 0.65rem; font-weight: 700;