feat(extractor): add operation history tracking

Add a new operation history feature for the extractor module that tracks
all extraction operations with persistent database storage.

Features:
- Records extraction operations with batch tracking (UUID-based)
- Preserves production ID to order number mapping
- Shows batch statistics (orders, records, success/failure counts)
- Expandable details for each batch showing individual order records
- User-based permission: Admin sees all records, User sees own records only
- Delete functionality with permission validation

Database:
- New ExtractorOperationHistory table schema
- Supports both SQL Server and MySQL
- Indexed on BatchId, UserId, and OperationTime

Files:
- Add DAO class for history operations
- Add IPC handler with permission checks
- Add preload API wrapper
- Add React modal component with expandable batch details
- Integrate history recording into extractor handler
- Add operation history button to ExtractorPage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-03-31 15:22:53 +08:00
parent dd2cf1c576
commit 557ed174c3
11 changed files with 1342 additions and 6 deletions

View File

@@ -3,6 +3,7 @@ import { ErpAuthService } from '../services/erp/erp-auth'
import { ExtractorService } from '../services/erp/extractor'
import { OrderNumberResolver } from '../services/erp/order-resolver'
import { create, type IDatabaseService } from '../services/database'
import { ExtractorOperationHistoryDAO } from '../services/database/extractor-operation-history-dao'
import { createLogger } from '../services/logger'
import { logAudit } from '../services/logger/audit-logger'
import { SessionManager } from '../services/user/session-manager'
@@ -12,6 +13,7 @@ import type { ExtractorInput, ExtractorResult, ExtractionProgress } from '../typ
import { UserErpConfigService } from '../services/user/user-erp-config-service'
import { ConfigManager } from '../services/config/config-manager'
import { IPC_CHANNELS } from '../../shared/ipc-channels'
import { randomUUID } from 'crypto'
const log = createLogger('ExtractorHandler')
@@ -141,6 +143,29 @@ export function registerExtractorHandlers(): void {
log.info('Resolved order numbers', { count: validOrderNumbers.length })
// Initialize operation history recording
const currentUser = SessionManager.getInstance().getUserInfo()
const historyDao = new ExtractorOperationHistoryDAO()
const batchId = randomUUID()
// Save order records to history (preserve productionId -> orderNumber mapping)
if (currentUser) {
const orderRecords = mappings.map((m) => ({
productionId: m.productionId || null,
orderNumber: m.orderNumber || m.input
}))
await historyDao.insertBatchRecords(
batchId,
currentUser.id,
currentUser.username,
orderRecords
)
log.info('Operation history batch created', {
batchId,
recordCount: orderRecords.length
})
}
// Log deduplication summary
sendLog(sender, 'info', dedupReport.summary)
@@ -223,11 +248,22 @@ export function registerExtractorHandlers(): void {
})
}
// Update operation history batch status
if (currentUser) {
const status: 'success' | 'failed' | 'partial' =
result.errors.length > 0 && result.recordCount > 0
? 'partial'
: result.errors.length > 0
? 'failed'
: 'success'
await historyDao.updateBatchStatus(batchId, status, result.recordCount)
log.info('Operation history batch status updated', { batchId, status })
}
// Audit log: EXTRACT (non-blocking)
const os = await import('os')
const currentUser = SessionManager.getInstance().getUserInfo()
if (currentUser) {
const status: 'success' | 'failure' | 'partial' =
const auditStatus: 'success' | 'failure' | 'partial' =
result.errors.length > 0 && result.recordCount > 0
? 'partial'
: result.errors.length > 0
@@ -237,7 +273,7 @@ export function registerExtractorHandlers(): void {
username: currentUser.username,
computerName: os.hostname(),
resource: 'MATERIAL_PLAN',
status,
status: auditStatus,
metadata: {
orderCount: validOrderNumbers.length,
recordCount: result.recordCount,