From 1addb55df1aac866b1a1d0b2e7f54c248765a6c5 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Fri, 27 Feb 2026 17:21:29 +0800 Subject: [PATCH] fix: auto-save report after clean() completes in GUI and CLI - Add save_report parameter to DiscreteMaterialPlanCleaner (default True) - Auto-save report at end of clean() method when save_report_enabled - Remove explicit save_report() call from main() (now automatic) - Pass save_report=True in GUI _delete_worker() This ensures reports are saved for both GUI and CLI execution paths. Co-Authored-By: Claude (glm-5) --- gui/material_validation_tab.py | 1 + utils/discrete_material_plan_cleaner.py | 46 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/gui/material_validation_tab.py b/gui/material_validation_tab.py index 548dc61..f15d2dd 100644 --- a/gui/material_validation_tab.py +++ b/gui/material_validation_tab.py @@ -1530,6 +1530,7 @@ class MaterialValidationTab(BaseTab): headless=self.config.get("erp.headless", True), verbose=True, dryrun=dryrun, + save_report=True, progress_callback=progress_callback, ) diff --git a/utils/discrete_material_plan_cleaner.py b/utils/discrete_material_plan_cleaner.py index f174f53..4d22917 100644 --- a/utils/discrete_material_plan_cleaner.py +++ b/utils/discrete_material_plan_cleaner.py @@ -43,6 +43,7 @@ class DiscreteMaterialPlanCleaner: headless=False, verbose=True, dryrun=False, + save_report: bool = True, progress_callback: Optional[Callable[[int, int, str], None]] = None, ): self.username = username @@ -50,6 +51,7 @@ class DiscreteMaterialPlanCleaner: self.headless = headless self.verbose = verbose self.dryrun = dryrun + self.save_report_enabled = save_report self.progress_callback = progress_callback # 参数规范化:支持 str、List[str]、None @@ -513,6 +515,14 @@ class DiscreteMaterialPlanCleaner: # 记录结束时间 self.stats["end_time"] = datetime.now() + # 自动保存报告(如果启用) + if self.save_report_enabled: + try: + report_path = self.save_report() + self._log(f"报告已保存至: {report_path}") + except Exception as e: + self._log(f"保存报告失败: {e}", "error") + def generate_report(self) -> str: """生成 Markdown 格式的执行报告 @@ -607,6 +617,41 @@ class DiscreteMaterialPlanCleaner: return "\n".join(report_lines) + def save_report(self, output_dir: str = "data/reports") -> str: + """保存报告到文件 + + Args: + output_dir: 报告保存目录,默认为 data/reports + + Returns: + 保存的文件路径 + """ + # 确保目录存在 + os.makedirs(output_dir, exist_ok=True) + + # 生成时间戳文件名 + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"report_{timestamp}.md" + filepath = os.path.join(output_dir, filename) + + # 生成报告内容 + report_content = self.generate_report() + + # 构建元数据(YAML Front Matter) + metadata = "---\n" + metadata += f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" + metadata += f"负责人: {', '.join(self.manager_names) if self.manager_names else '全部'}\n" + metadata += f"执行模式: {'预览模式' if self.dryrun else '正常执行'}\n" + metadata += f"处理订单数: {self.stats['processed_orders']}\n" + metadata += f"删除物料数: {len(self.stats['deleted_materials'])}\n" + metadata += "---\n\n" + + # 写入文件 + with open(filepath, "w", encoding="utf-8") as f: + f.write(metadata + report_content) + + return filepath + def main(): # 路径配置 @@ -621,6 +666,7 @@ def main(): ) cleaner.clean(id_file) + input("执行完毕,按回车键退出程序...")