From 921ca15be609ca1ede01590bf62fd2249af933d1 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Thu, 5 Mar 2026 11:15:44 +0800 Subject: [PATCH] feat: add execution report dialog for cleaner - Create ExecutionReportDialog component with Ant Design style - Replace native alert() with modal dialog after cleaner execution - Display orders processed, materials deleted/skipped statistics - Show error details in scrollable list - Support dry-run mode indicator --- .../src/components/ExecutionReportDialog.tsx | 411 ++++++++++++++++++ src/renderer/src/hooks/useCleaner.ts | 24 +- src/renderer/src/pages/CleanerPage.tsx | 17 + 3 files changed, 447 insertions(+), 5 deletions(-) create mode 100644 src/renderer/src/components/ExecutionReportDialog.tsx diff --git a/src/renderer/src/components/ExecutionReportDialog.tsx b/src/renderer/src/components/ExecutionReportDialog.tsx new file mode 100644 index 0000000..7c1e22f --- /dev/null +++ b/src/renderer/src/components/ExecutionReportDialog.tsx @@ -0,0 +1,411 @@ +/** + * Execution Report Dialog - Shows execution results after cleaner runs + * + * Displays: + * - Orders processed count + * - Materials deleted count + * - Materials skipped count + * - Error list (if any) + */ + +import React from 'react' +import { CheckCircle, XCircle, SkipForward, Package } from 'lucide-react' + +interface ExecutionReportDialogProps { + isOpen: boolean + onClose: () => void + ordersProcessed: number + materialsDeleted: number + materialsSkipped: number + errors?: string[] + dryRun?: boolean +} + +export const ExecutionReportDialog: React.FC = ({ + isOpen, + onClose, + ordersProcessed, + materialsDeleted, + materialsSkipped, + errors = [], + dryRun = false +}) => { + if (!isOpen) return null + + const hasErrors = errors.length > 0 + + return ( +
+
e.stopPropagation()}> +
+
+ {dryRun ? ( + + ) : hasErrors ? ( + + ) : ( + + )} +
+

+ {dryRun ? '预览执行报告' : hasErrors ? '执行完成 (有错误)' : '执行完成'} +

+

+ {dryRun + ? '预览模式 - 未实际删除数据' + : hasErrors + ? '部分操作未能完成,请查看下方错误信息' + : '所有操作已成功完成'} +

+
+ +
+
+
+
+ +
+
+
处理订单
+
{ordersProcessed}
+
+
+ +
+
+ +
+
+
{dryRun ? '拟删除物料' : '删除物料'}
+
{materialsDeleted}
+
+
+ +
+
+ +
+
+
跳过物料
+
{materialsSkipped}
+
+
+ + {hasErrors && ( +
+
+ +
+
+
错误数量
+
{errors.length}
+
+
+ )} +
+ + {hasErrors && ( +
+
错误详情
+
+ {errors.map((error, index) => ( +
+ + {error} +
+ ))} +
+
+ )} + + {!hasErrors && !dryRun && ( +
+ + 操作已成功完成,数据已同步到 ERP 系统 +
+ )} + + {!hasErrors && dryRun && ( +
+ + 预览模式结束,数据未实际修改。确认无误后可正式执行。 +
+ )} +
+ +
+ +
+ + +
+
+ ) +} + +export default ExecutionReportDialog diff --git a/src/renderer/src/hooks/useCleaner.ts b/src/renderer/src/hooks/useCleaner.ts index ae22084..6748b18 100644 --- a/src/renderer/src/hooks/useCleaner.ts +++ b/src/renderer/src/hooks/useCleaner.ts @@ -44,6 +44,15 @@ export function useCleaner() { // Material type management dialog state const [isTypeDialogOpen, setIsTypeDialogOpen] = useState(false) + // Execution report dialog state + const [isReportDialogOpen, setIsReportDialogOpen] = useState(false) + const [reportData, setReportData] = useState<{ + ordersProcessed: number + materialsDeleted: number + materialsSkipped: number + errors: string[] + } | null>(null) + // Execution settings state const [headless, setHeadless] = useState(() => { const saved = sessionStorage.getItem('cleaner_headless') @@ -246,11 +255,13 @@ export function useCleaner() { }) if (response.success && response.data) { - let msg = `清理执行完毕:\n处理订单: ${response.data.ordersProcessed}\n删除物料: ${response.data.materialsDeleted}\n跳过物料: ${response.data.materialsSkipped}` - if (response.data.errors.length) { - msg += `\n错误: ${response.data.errors.join(', ')}` - } - alert(msg) + setReportData({ + ordersProcessed: response.data.ordersProcessed, + materialsDeleted: response.data.materialsDeleted, + materialsSkipped: response.data.materialsSkipped, + errors: response.data.errors + }) + setIsReportDialogOpen(true) } else { throw new Error(response.error || '清理失败') } @@ -320,6 +331,9 @@ export function useCleaner() { showSettingsMenu, setShowSettingsMenu, filteredResults, + isReportDialogOpen, + setIsReportDialogOpen, + reportData, handleValidation, handleCheckboxToggle, handleConfirmDeletion, diff --git a/src/renderer/src/pages/CleanerPage.tsx b/src/renderer/src/pages/CleanerPage.tsx index 0d6ce14..3304b15 100644 --- a/src/renderer/src/pages/CleanerPage.tsx +++ b/src/renderer/src/pages/CleanerPage.tsx @@ -16,6 +16,7 @@ import { FileSpreadsheet } from 'lucide-react' import MaterialTypeManagementDialog from '../components/MaterialTypeManagementDialog' +import ExecutionReportDialog from '../components/ExecutionReportDialog' import { useCleaner } from '../hooks/useCleaner' const CleanerPage: React.FC = () => { @@ -43,6 +44,9 @@ const CleanerPage: React.FC = () => { showSettingsMenu, setShowSettingsMenu, filteredResults, + isReportDialogOpen, + setIsReportDialogOpen, + reportData, handleValidation, handleCheckboxToggle, handleConfirmDeletion, @@ -413,6 +417,19 @@ const CleanerPage: React.FC = () => { isAdmin={isAdmin} currentUsername={currentUsername} /> + + {/* Execution Report Dialog */} + {reportData && ( + setIsReportDialogOpen(false)} + ordersProcessed={reportData.ordersProcessed} + materialsDeleted={reportData.materialsDeleted} + materialsSkipped={reportData.materialsSkipped} + errors={reportData.errors} + dryRun={dryRun} + /> + )} ) }