feat(ux-ax): integrate real-time AX Insights on row click, double-click smart inline editing, and 1-Click quick status toggle buttons
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 12s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 12s
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been skipped
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 20s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been skipped
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 9s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 9s
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 12s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 12s
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been skipped
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 20s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been skipped
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 9s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 9s
This commit is contained in:
@@ -10,8 +10,12 @@ const props = defineProps<{
|
|||||||
filename?: string;
|
filename?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['row-selected', 'cell-value-changed']);
|
const emit = defineEmits(['row-selected', 'cell-value-changed', 'cell-double-clicked']);
|
||||||
const gridApi = ref<GridApi | null>(null);
|
const gridApi = ref<GridApi | null>(null);
|
||||||
|
|
||||||
|
const onCellDoubleClicked = (event: any) => {
|
||||||
|
emit('cell-double-clicked', event);
|
||||||
|
};
|
||||||
const selectedCount = ref(0);
|
const selectedCount = ref(0);
|
||||||
const quickFilterText = ref('');
|
const quickFilterText = ref('');
|
||||||
const isExportMenuOpen = ref(false);
|
const isExportMenuOpen = ref(false);
|
||||||
@@ -141,6 +145,7 @@ defineExpose({ exportToExcel: exportToCsv, resetGridState, autoSizeColumns, grid
|
|||||||
@grid-ready="onGridReady"
|
@grid-ready="onGridReady"
|
||||||
@selection-changed="onSelectionChanged"
|
@selection-changed="onSelectionChanged"
|
||||||
@cell-value-changed="onCellValueChanged"
|
@cell-value-changed="onCellValueChanged"
|
||||||
|
@cell-double-clicked="onCellDoubleClicked"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function useSystemSettings() {
|
|||||||
const isBatchRunning = ref(false);
|
const isBatchRunning = ref(false);
|
||||||
const batchProgress = ref(0);
|
const batchProgress = ref(0);
|
||||||
const dbConnections = ref(4);
|
const dbConnections = ref(4);
|
||||||
const aiRecommendation = ref<string | null>('🤖 AI AX Recommendation: RSI 상한값을 70.0에서 68.5로 보정 시 슬리피지 0.14% 감소가 예측됩니다.');
|
const aiRecommendation = ref<string | null>('🤖 AI AX Insights: 그리드 레코드를 선택하면 도메인 맞춤 실시간 리스크/팩터 지능 분석이 표시됩니다.');
|
||||||
|
|
||||||
const liveLogs = ref<string[]>([
|
const liveLogs = ref<string[]>([
|
||||||
'[14:00:01] [INFO] SignalR WebSocket Hub connected to wss://localhost:5173/hub',
|
'[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 () => {
|
const loadData = async () => {
|
||||||
items.value = [
|
items.value = [
|
||||||
{
|
{
|
||||||
@@ -100,7 +123,7 @@ export function useSystemSettings() {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
if (items.value.length > 0) {
|
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: '기존 항목 기반 복제 생성' }]
|
audit_history: [{ timestamp: new Date().toISOString().slice(0, 16).replace('T', ' '), user: 'admin_kjh', change: '기존 항목 기반 복제 생성' }]
|
||||||
};
|
};
|
||||||
items.value.unshift(cloned);
|
items.value.unshift(cloned);
|
||||||
selectedItem.value = cloned;
|
selectItemWithInsight(cloned, true);
|
||||||
showToast(`📋 [${cloned.setting_key}] 항목이 복제 생성되었습니다.`, 'success');
|
showToast(`📋 [${cloned.setting_key}] 항목이 복제 생성되었습니다.`, 'success');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,7 +183,11 @@ export function useSystemSettings() {
|
|||||||
if (confirm(`[${selectedItem.value.setting_key}] 항목을 삭제하시겠습니까?`)) {
|
if (confirm(`[${selectedItem.value.setting_key}] 항목을 삭제하시겠습니까?`)) {
|
||||||
liveLogs.value.unshift(`[${new Date().toLocaleTimeString()}] [DELETE] Deleted key: ${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);
|
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');
|
showToast('항목이 삭제되었습니다.', 'warning');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -177,6 +204,6 @@ export function useSystemSettings() {
|
|||||||
isOmsModalOpen, isWmsModalOpen, isErpModalOpen, isModalOpen, isGuideModalOpen, isEditMode,
|
isOmsModalOpen, isWmsModalOpen, isErpModalOpen, isModalOpen, isGuideModalOpen, isEditMode,
|
||||||
masterPanelWidth, isDraggingSplitter, pingMs, isBatchRunning, batchProgress, dbConnections, aiRecommendation,
|
masterPanelWidth, isDraggingSplitter, pingMs, isBatchRunning, batchProgress, dbConnections, aiRecommendation,
|
||||||
liveLogs, items, selectedItem, toastMessage, filteredItems,
|
liveLogs, items, selectedItem, toastMessage, filteredItems,
|
||||||
showToast, loadData, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio
|
showToast, loadData, selectItemWithInsight, quickChangeStatus, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const {
|
|||||||
isOmsModalOpen, isWmsModalOpen, isErpModalOpen, isModalOpen, isGuideModalOpen, isEditMode,
|
isOmsModalOpen, isWmsModalOpen, isErpModalOpen, isModalOpen, isGuideModalOpen, isEditMode,
|
||||||
masterPanelWidth, isDraggingSplitter, pingMs, isBatchRunning, batchProgress, dbConnections, aiRecommendation,
|
masterPanelWidth, isDraggingSplitter, pingMs, isBatchRunning, batchProgress, dbConnections, aiRecommendation,
|
||||||
liveLogs, items, selectedItem, toastMessage, filteredItems,
|
liveLogs, items, selectedItem, toastMessage, filteredItems,
|
||||||
showToast, loadData, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio
|
showToast, loadData, selectItemWithInsight, quickChangeStatus, cloneSelectedItem, runFactorBatch, saveDetailForm, deleteSelectedItem, setSplitRatio
|
||||||
} = useSystemSettings();
|
} = useSystemSettings();
|
||||||
|
|
||||||
const omsOrderForm = ref({ symbol: '005930 (삼성전자)', orderType: 'LIMIT', price: '72,500', qty: '100' });
|
const omsOrderForm = ref({ symbol: '005930 (삼성전자)', orderType: 'LIMIT', price: '72,500', qty: '100' });
|
||||||
@@ -51,8 +51,14 @@ const columnDefs = ref<ColDef[]>([
|
|||||||
|
|
||||||
const handleRowSelect = (rows: any[]) => {
|
const handleRowSelect = (rows: any[]) => {
|
||||||
if (rows.length > 0) {
|
if (rows.length > 0) {
|
||||||
selectedItem.value = JSON.parse(JSON.stringify(rows[0]));
|
selectItemWithInsight(rows[0], false);
|
||||||
isEditMode.value = 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"
|
:rowData="filteredItems"
|
||||||
rowSelection="single"
|
rowSelection="single"
|
||||||
@row-selected="handleRowSelect"
|
@row-selected="handleRowSelect"
|
||||||
|
@cell-double-clicked="handleCellDoubleClicked"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
@@ -246,7 +253,12 @@ const triggerExport = (fmt: string) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<QuantLabel text="상태 제어" />
|
<QuantLabel text="상태 제어 (Quick Toggle)" />
|
||||||
|
<div class="quick-status-toggle-bar">
|
||||||
|
<button class="status-toggle-btn active" @click="quickChangeStatus('ACTIVE')">⚡ ACTIVE로 변경</button>
|
||||||
|
<button class="status-toggle-btn warning" @click="quickChangeStatus('WARNING')">⚠️ WARNING으로 변경</button>
|
||||||
|
<button class="status-toggle-btn blocked" @click="quickChangeStatus('BLOCKED')">🚨 BLOCKED로 변경</button>
|
||||||
|
</div>
|
||||||
<QuantRadio
|
<QuantRadio
|
||||||
v-model="selectedItem.status"
|
v-model="selectedItem.status"
|
||||||
name="statusRadio"
|
name="statusRadio"
|
||||||
@@ -427,6 +439,26 @@ const triggerExport = (fmt: string) => {
|
|||||||
user-select: none;
|
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 {
|
.draft-saved-chip {
|
||||||
font-size: 0.65rem;
|
font-size: 0.65rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|||||||
Reference in New Issue
Block a user