Files
panel/resources/js/views/demos/forms/tables/data-table/AgGridTable.vue
2025-08-25 12:19:58 +03:30

211 lines
5.4 KiB
Vue

<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { AgGridVue } from 'ag-grid-vue3'
import data from '@/views/demos/forms/tables/data-table/datatable'
import { ModuleRegistry, AllCommunityModule } from 'ag-grid-community'
import { ExcelExportModule } from 'ag-grid-enterprise'
import DataTableHeader from './components/DataTableHeader.vue'
import UserDetailsDialog from './components/UserDetailsDialog.vue'
import ConfirmDeleteDialog from './components/ConfirmDeleteDialog.vue'
import { useDataTableGrid } from './composables/useDataTableGrid'
import { useDataTableActions } from './composables/useDataTableActions'
import { useResponsive } from './composables/useResponsive'
import jsPDF from 'jspdf'
import autoTable from 'jspdf-autotable'
ModuleRegistry.registerModules([AllCommunityModule, ExcelExportModule])
const { isMobile, isTablet, windowWidth } = useResponsive()
const {
gridApi,
columnDefs,
rowData,
defaultColDef,
gridOptions,
onGridReady: gridReady,
onCellValueChanged,
updateColumnVisibility,
updatePagination
} = useDataTableGrid(data, isMobile, isTablet)
const {
setupGlobalHandlers,
cleanupGlobalHandlers,
exportToCSV,
exportToExcel,
saveUser,
confirmDelete,
cancelDelete,
showDetailsDialog,
selectedRowData,
deleteRowData,
showDeleteDialog,
deleteRow
} = useDataTableActions(gridApi, rowData)
const quickFilter = ref('')
watch(quickFilter, (newValue) => {
if (gridApi.value) {
gridApi.value.setGridOption('quickFilterText', newValue || '')
}
}, { immediate: false })
const onGridReady = params => {
gridReady(params)
setupGlobalHandlers()
}
const handleSaveUser = updatedData => saveUser(updatedData)
const handleQuickFilterUpdate = (value) => {
quickFilter.value = value || ''
if (gridApi.value) {
gridApi.value.setGridOption('quickFilterText', value || '')
}
}
onMounted(() => {
setupGlobalHandlers()
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
cleanupGlobalHandlers()
window.removeEventListener('resize', handleResize)
})
const handleResize = () => {
windowWidth.value = window.innerWidth
if (gridApi.value) {
updateColumnVisibility()
updatePagination()
setTimeout(() => {
if (gridApi.value && gridApi.value.sizeColumnsToFit) {
gridApi.value.sizeColumnsToFit()
}
}, 100)
}
}
const exportToPDF = () => {
if (!gridApi.value) {
console.error('Grid API not available')
return
}
try {
const doc = new jsPDF()
const rowDataForPDF = []
const headers = []
columnDefs.value.forEach(col => {
if (col.headerName && col.field && col.field !== 'action') {
headers.push(col.headerName)
}
})
gridApi.value.forEachNodeAfterFilterAndSort(node => {
const row = []
columnDefs.value.forEach(col => {
if (col.field && col.field !== 'action') {
let value = node.data[col.field] || ''
if (col.field === 'salary' && value) {
value = `$${Math.floor(Number(value)).toLocaleString()}`
} else if (col.field === 'startDate' && value) {
const date = new Date(value)
if (!isNaN(date.getTime())) {
const day = date.getDate().toString().padStart(2, '0')
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const year = date.getFullYear()
value = `${day}/${month}/${year}`
}
} else if (col.field === 'status') {
const statusMap = {
0: 'Applied',
1: 'Current',
2: 'Professional',
3: 'Rejected',
4: 'Resigned'
}
value = statusMap[value] || 'Applied'
}
row.push(value)
}
})
rowDataForPDF.push(row)
})
autoTable(doc, {
head: [headers],
body: rowDataForPDF,
styles: {
fontSize: 8,
cellPadding: 2
},
headStyles: {
fillColor: [41, 128, 185],
textColor: 255,
fontStyle: 'bold'
},
alternateRowStyles: {
fillColor: [245, 245, 245]
},
margin: { top: 20 }
})
doc.save(`data-table-${new Date().toISOString().split('T')[0]}.pdf`)
console.log('PDF exported successfully')
} catch (error) {
console.error('Error exporting PDF:', error)
}
}
</script>
<template>
<v-card class="elevation-2">
<DataTableHeader
:is-mobile="isMobile"
:is-tablet="isTablet"
:quick-filter="quickFilter"
@update:quick-filter="handleQuickFilterUpdate"
@export-csv="exportToCSV"
@export-excel="exportToExcel"
@export-pdf="exportToPDF"
/>
<v-divider />
<v-card-text class="pa-0">
<AgGridVue
class="vuetify-grid ag-theme-alpine-dark"
:style="`height:${isMobile ? '400px' : '600px'}; width:100%`"
:columnDefs="columnDefs"
:rowData="rowData"
:defaultColDef="defaultColDef"
:gridOptions="gridOptions"
@grid-ready="onGridReady"
/>
</v-card-text>
<UserDetailsDialog
v-model="showDetailsDialog"
:selected-row-data="selectedRowData"
:is-mobile="isMobile"
@save-user="handleSaveUser"
/>
<ConfirmDeleteDialog
v-model="showDeleteDialog"
:selected-row-data="deleteRowData"
:is-mobile="isMobile"
@confirm="confirmDelete"
@cancel="cancelDelete"
/>
</v-card>
</template>