feat: add export validation results to Excel feature
Add export functionality to CleanerPage that allows users to export the currently displayed validation results to an Excel file. - Add ExportResultItem and ExportResultResponse types - Create ResultExporter service using ExcelJS - Register cleaner:exportResults IPC handler - Add exportResults method to preload API - Connect export button in CleanerPage to export handler Export features: - Exports filtered results (respecting manager/visibility filters) - Includes selection status column - Saves to app data directory/exports/校验结果.xlsx Co-Authored-By: Claude (glm-5) <noreply@anthropic.com>
This commit is contained in:
113
src/main/services/excel/result-exporter.ts
Normal file
113
src/main/services/excel/result-exporter.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import ExcelJS from 'exceljs'
|
||||
import path from 'path'
|
||||
import { app } from 'electron'
|
||||
import fs from 'fs'
|
||||
import { createLogger } from '../logger'
|
||||
import type { ExportResultItem, ExportResultResponse } from '../../types/cleaner.types'
|
||||
|
||||
const log = createLogger('ResultExporter')
|
||||
|
||||
/**
|
||||
* Excel exporter for validation results
|
||||
* Exports filtered validation results to Excel file
|
||||
*/
|
||||
export class ResultExporter {
|
||||
private readonly exportDir: string
|
||||
private readonly fileName: string = '校验结果.xlsx'
|
||||
|
||||
constructor() {
|
||||
// Export to app directory/exports
|
||||
this.exportDir = path.join(app.getPath('userData'), 'exports')
|
||||
this.ensureExportDir()
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure export directory exists
|
||||
*/
|
||||
private ensureExportDir(): void {
|
||||
if (!fs.existsSync(this.exportDir)) {
|
||||
fs.mkdirSync(this.exportDir, { recursive: true })
|
||||
log.info('Created export directory', { path: this.exportDir })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export validation results to Excel
|
||||
* @param items - Validation result items to export
|
||||
* @returns Export result with file path or error
|
||||
*/
|
||||
async exportValidationResults(items: ExportResultItem[]): Promise<ExportResultResponse> {
|
||||
try {
|
||||
const filePath = path.join(this.exportDir, this.fileName)
|
||||
log.info('Exporting validation results', { count: items.length, path: filePath })
|
||||
|
||||
const workbook = new ExcelJS.Workbook()
|
||||
const worksheet = workbook.addWorksheet('校验结果')
|
||||
|
||||
// Define columns
|
||||
worksheet.columns = [
|
||||
{ header: '材料名称', key: 'materialName', width: 30 },
|
||||
{ header: '材料代码', key: 'materialCode', width: 20 },
|
||||
{ header: '规格', key: 'specification', width: 25 },
|
||||
{ header: '型号', key: 'model', width: 20 },
|
||||
{ header: '负责人', key: 'managerName', width: 15 },
|
||||
{ header: '勾选状态', key: 'isSelectedText', width: 12 },
|
||||
{ header: '是否标记删除', key: 'isMarkedForDeletionText', width: 14 }
|
||||
]
|
||||
|
||||
// Style header row
|
||||
const headerRow = worksheet.getRow(1)
|
||||
headerRow.font = { bold: true }
|
||||
headerRow.fill = {
|
||||
type: 'pattern',
|
||||
pattern: 'solid',
|
||||
fgColor: { argb: 'FFE0E0E0' }
|
||||
}
|
||||
headerRow.alignment = { horizontal: 'center' }
|
||||
|
||||
// Add data rows
|
||||
for (const item of items) {
|
||||
worksheet.addRow({
|
||||
materialName: item.materialName || '',
|
||||
materialCode: item.materialCode || '',
|
||||
specification: item.specification || '',
|
||||
model: item.model || '',
|
||||
managerName: item.managerName || '',
|
||||
isSelectedText: item.isSelected ? '是' : '否',
|
||||
isMarkedForDeletionText: item.isMarkedForDeletion ? '是' : '否'
|
||||
})
|
||||
}
|
||||
|
||||
// Style data rows
|
||||
for (let i = 2; i <= worksheet.rowCount; i++) {
|
||||
const row = worksheet.getRow(i)
|
||||
row.alignment = { vertical: 'middle' }
|
||||
|
||||
// Highlight selected items
|
||||
if (items[i - 2]?.isSelected) {
|
||||
row.fill = {
|
||||
type: 'pattern',
|
||||
pattern: 'solid',
|
||||
fgColor: { argb: 'FFE6F3FF' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save file
|
||||
await workbook.xlsx.writeFile(filePath)
|
||||
log.info('Export completed', { path: filePath, rows: items.length })
|
||||
|
||||
return {
|
||||
success: true,
|
||||
filePath
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
log.error('Export failed', { error: errorMessage })
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user