Enhance Excel export functionality in backend and frontend; implement Excel file generation and update download logic for correct file extension
This commit is contained in:
@@ -16,23 +16,23 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
|
||||||
"cors": "^2.8.5",
|
|
||||||
"helmet": "^7.1.0",
|
|
||||||
"morgan": "^1.10.0",
|
|
||||||
"dotenv": "^16.3.1",
|
|
||||||
"mysql2": "^3.6.5",
|
|
||||||
"sequelize": "^6.35.2",
|
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"cors": "^2.8.5",
|
||||||
"nodemailer": "^6.9.7",
|
|
||||||
"crypto": "^1.0.1",
|
"crypto": "^1.0.1",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"exceljs": "^4.4.0",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"express-session": "^1.18.0",
|
||||||
|
"helmet": "^7.1.0",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"morgan": "^1.10.0",
|
||||||
|
"mysql2": "^3.6.5",
|
||||||
|
"nodemailer": "^6.9.7",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-google-oauth20": "^2.0.0",
|
"passport-google-oauth20": "^2.0.0",
|
||||||
"express-session": "^1.18.0"
|
"sequelize": "^6.35.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^3.0.2"
|
"nodemon": "^3.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ExportController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exportiert Daten als Excel
|
* Exportiert Daten als Excel (.xlsx)
|
||||||
*/
|
*/
|
||||||
async exportExcel(req, res) {
|
async exportExcel(req, res) {
|
||||||
try {
|
try {
|
||||||
@@ -47,11 +47,11 @@ class ExportController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const excel = await ExportService.exportExcel(userId, startDate, endDate);
|
const buffer = await ExportService.exportExcel(userId, startDate, endDate);
|
||||||
|
|
||||||
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||||
res.setHeader('Content-Disposition', `attachment; filename="zeiterfassung_${startDate}_${endDate}.csv"`);
|
res.setHeader('Content-Disposition', `attachment; filename="zeiterfassung_${startDate}_${endDate}.xlsx"`);
|
||||||
res.send(excel);
|
res.send(buffer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fehler beim Excel-Export:', error);
|
console.error('Fehler beim Excel-Export:', error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
|
|||||||
@@ -29,17 +29,49 @@ class ExportService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exportiert Daten als Excel (CSV mit Excel-kompatiblem Encoding)
|
* Exportiert Daten als echte Excel-Datei (.xlsx)
|
||||||
* @param {number} userId - User-ID
|
* @param {number} userId - User-ID
|
||||||
* @param {string} startDate - Startdatum
|
* @param {string} startDate - Startdatum
|
||||||
* @param {string} endDate - Enddatum
|
* @param {string} endDate - Enddatum
|
||||||
* @returns {Promise<string>} Excel-kompatibles CSV mit BOM
|
* @returns {Promise<Buffer>} Excel-Datei als Buffer
|
||||||
*/
|
*/
|
||||||
async exportExcel(userId, startDate, endDate) {
|
async exportExcel(userId, startDate, endDate) {
|
||||||
const csv = await this.exportCSV(userId, startDate, endDate);
|
const ExcelJS = require('exceljs');
|
||||||
|
const data = await this._getExportData(userId, startDate, endDate);
|
||||||
|
|
||||||
// UTF-8 BOM für Excel
|
// Erstelle Workbook
|
||||||
return '\ufeff' + csv;
|
const workbook = new ExcelJS.Workbook();
|
||||||
|
const worksheet = workbook.addWorksheet('Zeiterfassung');
|
||||||
|
|
||||||
|
// Definiere Spalten
|
||||||
|
worksheet.columns = [
|
||||||
|
{ header: 'Datum', key: 'date', width: 12 },
|
||||||
|
{ header: 'Uhrzeit', key: 'time', width: 10 },
|
||||||
|
{ header: 'Aktivität', key: 'activity', width: 20 },
|
||||||
|
{ header: 'Gesamt-Netto-Arbeitszeit', key: 'netWorkTime', width: 25 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Style für Header
|
||||||
|
worksheet.getRow(1).font = { bold: true };
|
||||||
|
worksheet.getRow(1).fill = {
|
||||||
|
type: 'pattern',
|
||||||
|
pattern: 'solid',
|
||||||
|
fgColor: { argb: 'FFE0E0E0' }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Füge Daten hinzu
|
||||||
|
data.forEach(row => {
|
||||||
|
worksheet.addRow({
|
||||||
|
date: row.date,
|
||||||
|
time: row.time,
|
||||||
|
activity: row.activity,
|
||||||
|
netWorkTime: row.netWorkTime
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generiere Buffer
|
||||||
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -153,7 +153,11 @@ async function downloadFile(format) {
|
|||||||
const downloadUrl = window.URL.createObjectURL(blob)
|
const downloadUrl = window.URL.createObjectURL(blob)
|
||||||
const a = document.createElement('a')
|
const a = document.createElement('a')
|
||||||
a.href = downloadUrl
|
a.href = downloadUrl
|
||||||
a.download = `zeiterfassung_${form.value.startDate}_${form.value.endDate}.csv`
|
|
||||||
|
// Richtiger Dateiname je nach Format
|
||||||
|
const extension = format === 'excel' ? 'xlsx' : 'csv'
|
||||||
|
a.download = `zeiterfassung_${form.value.startDate}_${form.value.endDate}.${extension}`
|
||||||
|
|
||||||
document.body.appendChild(a)
|
document.body.appendChild(a)
|
||||||
a.click()
|
a.click()
|
||||||
document.body.removeChild(a)
|
document.body.removeChild(a)
|
||||||
|
|||||||
815
package-lock.json
generated
815
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user