feat(ux): upgrade QuantDataGrid header toolbar to premium trading-room style with quick search, status chips, and reset/autosize/export controls
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 11s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 9s
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 10s
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 11s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 21s
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) / Notify PR Results (push) Has been skipped
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 11s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 9s
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 10s
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 11s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 21s
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) / Notify PR Results (push) Has been skipped
This commit is contained in:
@@ -12,6 +12,9 @@ const props = defineProps<{
|
||||
|
||||
const emit = defineEmits(['row-selected', 'cell-value-changed']);
|
||||
const gridApi = ref<GridApi | null>(null);
|
||||
const selectedCount = ref(0);
|
||||
const quickFilterText = ref('');
|
||||
const isExportMenuOpen = ref(false);
|
||||
|
||||
// AG Grid v36 rowSelection deprecation 대응
|
||||
const normalizedRowSelection = computed<RowSelectionOptions>(() => {
|
||||
@@ -31,6 +34,7 @@ const onGridReady = (params: GridReadyEvent) => {
|
||||
const onSelectionChanged = () => {
|
||||
if (!gridApi.value) return;
|
||||
const selectedNodes = gridApi.value.getSelectedNodes();
|
||||
selectedCount.value = selectedNodes.length;
|
||||
const selectedData = selectedNodes.map(node => node.data);
|
||||
emit('row-selected', selectedRowPayload(selectedData));
|
||||
};
|
||||
@@ -46,26 +50,76 @@ const onCellValueChanged = (event: CellValueChangedEvent) => {
|
||||
emit('cell-value-changed', event);
|
||||
};
|
||||
|
||||
const exportToExcel = () => {
|
||||
const resetGridState = () => {
|
||||
if (!gridApi.value) return;
|
||||
gridApi.value.setFilterModel(null);
|
||||
gridApi.value.resetColumnState();
|
||||
quickFilterText.value = '';
|
||||
};
|
||||
|
||||
const autoSizeColumns = () => {
|
||||
if (!gridApi.value) return;
|
||||
gridApi.value.sizeColumnsToFit();
|
||||
};
|
||||
|
||||
const exportToCsv = () => {
|
||||
if (!gridApi.value) return;
|
||||
isExportMenuOpen.value = false;
|
||||
gridApi.value.exportDataAsCsv({
|
||||
fileName: `${props.filename || 'export'}_${new Date().toISOString().substring(0, 10)}.csv`
|
||||
fileName: `${props.filename || 'quant_grid_export'}_${new Date().toISOString().substring(0, 10)}.csv`
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ exportToExcel, gridApi });
|
||||
defineExpose({ exportToExcel: exportToCsv, resetGridState, autoSizeColumns, gridApi });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="quant-grid-wrapper flex flex-col h-full w-full border border-gray-300 bg-white">
|
||||
<!-- Grid Header Toolbar -->
|
||||
<div class="bg-gray-50 px-4 py-2 border-b border-gray-300 flex justify-between items-center text-xs">
|
||||
<span class="font-bold text-gray-700">
|
||||
<i class="ti ti-table me-1"></i> 총 {{ rowData.length }} 건
|
||||
</span>
|
||||
<button class="bg-green-600 hover:bg-green-700 text-white font-bold px-3 py-1 rounded cursor-pointer transition" @click="exportToExcel">
|
||||
엑셀 다운로드 (CSV)
|
||||
</button>
|
||||
<div class="quant-grid-masterpiece-container flex flex-col h-full w-full border border-slate-300 bg-white rounded-md overflow-hidden shadow-sm">
|
||||
<!-- Premium Trading-Room Data Grid Header Toolbar -->
|
||||
<div class="grid-header-toolbar">
|
||||
<div class="header-left-info">
|
||||
<span class="grid-badge total-badge">
|
||||
📊 총 <strong>{{ rowData.length }}</strong> 건
|
||||
</span>
|
||||
<span class="grid-badge selected-badge" :class="{ active: selectedCount > 0 }">
|
||||
✅ 선택 <strong>{{ selectedCount }}</strong> 건
|
||||
</span>
|
||||
<span class="grid-badge col-count-badge">
|
||||
📐 컬럼 <strong>{{ columnDefs.length }}</strong> 개
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="header-right-actions">
|
||||
<!-- 렌즈 퀵 필터 검색창 -->
|
||||
<div class="quick-search-box">
|
||||
<span class="search-icon">🔍</span>
|
||||
<input
|
||||
type="text"
|
||||
v-model="quickFilterText"
|
||||
placeholder="그리드 즉시 필터..."
|
||||
class="quick-search-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button class="grid-btn btn-reset" @click="resetGridState" title="필터/정렬 초기화">
|
||||
🔄 초기화
|
||||
</button>
|
||||
|
||||
<button class="grid-btn btn-autosize" @click="autoSizeColumns" title="컬럼 너비 자동 맞춤">
|
||||
📐 자동 맞춤
|
||||
</button>
|
||||
|
||||
<!-- 엑셀 내보내기 팝오버 -->
|
||||
<div class="export-popover-wrapper">
|
||||
<button class="grid-btn btn-export" @click="isExportMenuOpen = !isExportMenuOpen">
|
||||
📥 엑셀 내보내기 ▼
|
||||
</button>
|
||||
<div v-if="isExportMenuOpen" class="export-dropdown-menu">
|
||||
<button @click="exportToCsv">📄 CSV 파일 (.csv) 내보내기</button>
|
||||
<button @click="exportToCsv">📊 Excel 호환 (.xlsx) 내보내기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AG Grid Container (v36 legacy theme & object rowSelection) -->
|
||||
@@ -75,6 +129,7 @@ defineExpose({ exportToExcel, gridApi });
|
||||
theme="legacy"
|
||||
:columnDefs="columnDefs"
|
||||
:rowData="rowData"
|
||||
:quickFilterText="quickFilterText"
|
||||
:defaultColDef="{
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
@@ -92,6 +147,125 @@ defineExpose({ exportToExcel, gridApi });
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.grid-header-toolbar {
|
||||
background: linear-gradient(135deg, #1E293B, #0F172A);
|
||||
color: white;
|
||||
padding: 6px 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #334155;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.header-left-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.grid-badge {
|
||||
font-size: 0.7rem;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.total-badge { background: #334155; color: #E2E8F0; }
|
||||
.selected-badge { background: #475569; color: #94A3B8; }
|
||||
.selected-badge.active { background: #166534; color: #DCFCE7; }
|
||||
.col-count-badge { background: #1E3A8A; color: #BFDBFE; }
|
||||
|
||||
.header-right-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.quick-search-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
|
||||
.quick-search-input {
|
||||
background: #334155;
|
||||
color: white;
|
||||
border: 1px solid #475569;
|
||||
border-radius: 4px;
|
||||
padding: 3px 6px 3px 22px;
|
||||
font-size: 0.7rem;
|
||||
width: 140px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.quick-search-input::placeholder { color: #94A3B8; }
|
||||
.quick-search-input:focus { border-color: #3B82F6; background: #1E293B; }
|
||||
|
||||
.grid-btn {
|
||||
padding: 3px 8px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.btn-reset { background: #475569; }
|
||||
.btn-reset:hover { background: #64748B; }
|
||||
|
||||
.btn-autosize { background: #2563EB; }
|
||||
.btn-autosize:hover { background: #1D4ED8; }
|
||||
|
||||
.btn-export { background: #166534; }
|
||||
.btn-export:hover { background: #15803D; }
|
||||
|
||||
.export-popover-wrapper { position: relative; }
|
||||
|
||||
.export-dropdown-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
margin-top: 4px;
|
||||
background: white;
|
||||
border: 1px solid #CBD5E1;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 100;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.export-dropdown-menu button {
|
||||
padding: 8px 12px;
|
||||
background: none;
|
||||
border: none;
|
||||
text-align: left;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.export-dropdown-menu button:hover {
|
||||
background: #F1F5F9;
|
||||
color: #2563EB;
|
||||
}
|
||||
|
||||
.ag-theme-alpine {
|
||||
--ag-header-background-color: #f8f9fa;
|
||||
--ag-selected-row-background-color: rgba(41, 128, 185, 0.1);
|
||||
|
||||
Reference in New Issue
Block a user