From 6e04f21b10043525a7b5d2fa16fc47b9a8dcf088 Mon Sep 17 00:00:00 2001 From: Misaka Date: Tue, 31 Mar 2026 20:42:22 +0800 Subject: [PATCH] fix(extractor): track per-order RecordCount in operation history Previously updateBatchStatus wrote the batch-level total recordCount to every row, causing the detail view to show misleading identical counts. Now mergeFiles collects per-order material counts, the handler writes each order's count individually via updateRecordStatus, and batch aggregation uses SUM instead of MAX for accurate totals. Co-Authored-By: Claude Opus 4.6 --- src/main/ipc/extractor-handler.ts | 9 ++- .../extractor-operation-history-dao.ts | 70 ++++++++++--------- src/main/services/erp/extractor.ts | 27 +++++-- src/main/types/extractor.types.ts | 2 + 4 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/main/ipc/extractor-handler.ts b/src/main/ipc/extractor-handler.ts index 7e6aa40..4ec64b8 100644 --- a/src/main/ipc/extractor-handler.ts +++ b/src/main/ipc/extractor-handler.ts @@ -256,7 +256,14 @@ export function registerExtractorHandlers(): void { : result.errors.length > 0 ? 'failed' : 'success' - await historyDao.updateBatchStatus(batchId, status, result.recordCount) + + // Write per-order record counts + for (const { orderNumber, recordCount } of result.orderRecordCounts) { + await historyDao.updateRecordStatus(batchId, orderNumber, status, undefined, recordCount) + } + + // Update batch status without recordCount (per-order counts are set individually) + await historyDao.updateBatchStatus(batchId, status) log.info('Operation history batch status updated', { batchId, status }) } diff --git a/src/main/services/database/extractor-operation-history-dao.ts b/src/main/services/database/extractor-operation-history-dao.ts index 40c1901..eb992d4 100644 --- a/src/main/services/database/extractor-operation-history-dao.ts +++ b/src/main/services/database/extractor-operation-history-dao.ts @@ -160,43 +160,27 @@ export class ExtractorOperationHistoryDAO { * Update the status of all records in a batch * @param batchId - Batch identifier * @param status - New status (success, failed, partial) - * @param recordCount - Total record count for the batch * @returns Update result */ async updateBatchStatus( batchId: string, - status: string, - recordCount: number | null + status: string ): Promise { try { const dbService = await this.getDatabaseService() const tableName = this.getTableName() const isSqlServer = dbService.type === 'sqlserver' - const placeholder = isSqlServer ? '@p0' : '?' - let sqlString: string - let params: (string | number | null)[] - - if (recordCount !== null) { - sqlString = ` - UPDATE ${tableName} - SET Status = ${isSqlServer ? '@p0' : '?'}, - RecordCount = ${isSqlServer ? '@p1' : '?'} - WHERE BatchId = ${isSqlServer ? '@p2' : '?'} - ` - params = isSqlServer ? [status, recordCount, batchId] : [status, recordCount, batchId] - } else { - sqlString = ` - UPDATE ${tableName} - SET Status = ${placeholder} - WHERE BatchId = ${isSqlServer ? '@p1' : '?'} - ` - params = isSqlServer ? [status, batchId] : [status, batchId] - } + const sqlString = ` + UPDATE ${tableName} + SET Status = ${isSqlServer ? '@p0' : '?'} + WHERE BatchId = ${isSqlServer ? '@p1' : '?'} + ` + const params = [status, batchId] await dbService.query(sqlString, params) - log.info('Batch status updated', { batchId, status, recordCount }) + log.info('Batch status updated', { batchId, status }) return { success: true, updatedCount: 1 } } catch (error) { log.error('Update batch status error', { @@ -208,33 +192,51 @@ export class ExtractorOperationHistoryDAO { } /** - * Update a single record's status and error message + * Update a single record's status, error message, and optional record count * @param batchId - Batch identifier * @param orderNumber - Order number * @param status - New status * @param errorMessage - Optional error message + * @param recordCount - Optional per-order record count * @returns True if successful */ async updateRecordStatus( batchId: string, orderNumber: string, status: string, - errorMessage?: string + errorMessage?: string, + recordCount?: number ): Promise { try { const dbService = await this.getDatabaseService() const tableName = this.getTableName() const isSqlServer = dbService.type === 'sqlserver' - const sqlString = ` - UPDATE ${tableName} - SET Status = ${isSqlServer ? '@p0' : '?'}, - ErrorMessage = ${isSqlServer ? '@p1' : '?'} - WHERE BatchId = ${isSqlServer ? '@p2' : '?'} - AND OrderNumber = ${isSqlServer ? '@p3' : '?'} - ` + let sqlString: string + let params: (string | number | null)[] - await dbService.query(sqlString, [status, errorMessage || null, batchId, orderNumber]) + if (recordCount !== undefined) { + sqlString = ` + UPDATE ${tableName} + SET Status = ${isSqlServer ? '@p0' : '?'}, + ErrorMessage = ${isSqlServer ? '@p1' : '?'}, + RecordCount = ${isSqlServer ? '@p2' : '?'} + WHERE BatchId = ${isSqlServer ? '@p3' : '?'} + AND OrderNumber = ${isSqlServer ? '@p4' : '?'} + ` + params = [status, errorMessage || null, recordCount, batchId, orderNumber] + } else { + sqlString = ` + UPDATE ${tableName} + SET Status = ${isSqlServer ? '@p0' : '?'}, + ErrorMessage = ${isSqlServer ? '@p1' : '?'} + WHERE BatchId = ${isSqlServer ? '@p2' : '?'} + AND OrderNumber = ${isSqlServer ? '@p3' : '?'} + ` + params = [status, errorMessage || null, batchId, orderNumber] + } + + await dbService.query(sqlString, params) return true } catch (error) { diff --git a/src/main/services/erp/extractor.ts b/src/main/services/erp/extractor.ts index 1bc5be8..27a0d7f 100644 --- a/src/main/services/erp/extractor.ts +++ b/src/main/services/erp/extractor.ts @@ -46,7 +46,8 @@ export class ExtractorService { downloadedFiles: [], mergedFile: null, recordCount: 0, - errors: [] + errors: [], + orderRecordCounts: [] } try { @@ -79,6 +80,7 @@ export class ExtractorService { const mergeResult = await this.mergeFiles(result.downloadedFiles) result.mergedFile = mergeResult.mergedFile result.recordCount = mergeResult.recordCount + result.orderRecordCounts = mergeResult.orderRecordCounts // Add merge error to result if any if (mergeResult.error) { @@ -123,9 +125,14 @@ export class ExtractorService { */ private async mergeFiles( filePaths: string[] - ): Promise<{ mergedFile: string | null; recordCount: number; error?: string }> { + ): Promise<{ + mergedFile: string | null + recordCount: number + error?: string + orderRecordCounts: Array<{ orderNumber: string; recordCount: number }> + }> { if (filePaths.length === 0) { - return { mergedFile: null, recordCount: 0 } + return { mergedFile: null, recordCount: 0, orderRecordCounts: [] } } log.info('Starting merge', { fileCount: filePaths.length }) @@ -154,15 +161,21 @@ export class ExtractorService { // Calculate total record count (total material rows) let recordCount = 0 + const orderRecordCounts: Array<{ orderNumber: string; recordCount: number }> = [] for (const order of allOrders) { - recordCount += order.materials.length + const count = order.materials.length + recordCount += count + orderRecordCounts.push({ + orderNumber: order.orderInfo.productionOrder || '', + recordCount: count + }) } log.info('Merge summary', { orderCount: allOrders.length, recordCount }) if (recordCount === 0) { log.warn('No records found in any downloaded files') - return { mergedFile: null, recordCount: 0 } + return { mergedFile: null, recordCount: 0, orderRecordCounts } } // Generate output filename with timestamp @@ -178,13 +191,13 @@ export class ExtractorService { log.info('Saving merged file', { outputPath }) await this.saveMergedOrders(allOrders, outputPath) log.info('Merged file saved successfully', { recordCount }) - return { mergedFile: outputPath, recordCount } + return { mergedFile: outputPath, recordCount, orderRecordCounts } } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error) const errorStack = error instanceof Error ? error.stack : '' log.error('Failed to save merged file', { error: errorMsg, stack: errorStack }) // Return parsed record count and error info even if save fails - return { mergedFile: null, recordCount, error: `保存合并文件失败:${errorMsg}` } + return { mergedFile: null, recordCount, orderRecordCounts, error: `保存合并文件失败:${errorMsg}` } } } diff --git a/src/main/types/extractor.types.ts b/src/main/types/extractor.types.ts index a6009c1..ccfc58d 100644 --- a/src/main/types/extractor.types.ts +++ b/src/main/types/extractor.types.ts @@ -43,6 +43,8 @@ export interface ExtractorResult { errors: string[] /** Database import result (only populated if mergedFile was created) */ importResult?: ImportResult + /** Per-order material row counts */ + orderRecordCounts: Array<{ orderNumber: string; recordCount: number }> } export interface OrderInfo {