diff --git a/utils/discrete_material_plan_cleaner.py b/utils/discrete_material_plan_cleaner.py index 28e30ea..18a8347 100644 --- a/utils/discrete_material_plan_cleaner.py +++ b/utils/discrete_material_plan_cleaner.py @@ -24,11 +24,12 @@ from db.materials_to_delete import get_materials_to_delete # --- 日志配置 --- logging.basicConfig( level=logging.INFO, - format='%(asctime)s [%(levelname)s] %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' + format="%(asctime)s [%(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", ) logger = logging.getLogger(__name__) + class DiscreteMaterialPlanCleaner: """离散备料计划维护数据清理器""" @@ -44,9 +45,12 @@ class DiscreteMaterialPlanCleaner: def _log(self, message, level="info"): """统一日志输出控制""" if self.verbose: - if level == "info": logger.info(message) - elif level == "warn": logger.warning(message) - elif level == "error": logger.error(message) + if level == "info": + logger.info(message) + elif level == "warn": + logger.warning(message) + elif level == "error": + logger.error(message) def _is_button_enabled(self, button_locator): """判定按钮是否可用""" @@ -58,9 +62,12 @@ class DiscreteMaterialPlanCleaner: def _get_input_value(self, container, label_regex): """通用辅助函数:根据 Label 正则获取 Input 的值""" - return container.locator("div").filter( - has_text=re.compile(label_regex, re.MULTILINE) - ).locator("input").first.input_value() + return ( + container.locator("div") + .filter(has_text=re.compile(label_regex, re.MULTILINE)) + .locator("input") + .first.input_value() + ) def preload_data(self): """批量预取数据库数据""" @@ -74,7 +81,9 @@ class DiscreteMaterialPlanCleaner: """读取文件并查询生产订单号""" production_ids = read_production_ids(production_id_file) order_ids = query_production_order_numbers(production_ids) - self._log(f"读取到 {len(production_ids)} 个总排号 -> 匹配到 {len(order_ids)} 个生产订单号") + self._log( + f"读取到 {len(production_ids)} 个总排号 -> 匹配到 {len(order_ids)} 个生产订单号" + ) return order_ids def process_order(self, inner_frame, order_id, order_index, page1): @@ -88,7 +97,7 @@ class DiscreteMaterialPlanCleaner: loading_locator = inner_frame.locator("div").filter(has_text="加载中").nth(1) try: loading_locator.wait_for(state="visible", timeout=3000) - loading_locator.wait_for(state="hidden", timeout=60000) + loading_locator.wait_for(state="hidden", timeout=60000) except TimeoutError: pass @@ -103,32 +112,42 @@ class DiscreteMaterialPlanCleaner: detail_inner_frame = detail_main_frame.locator("#mainiframe").content_frame # 5. 提取订单状态信息 - plan_code_locator = detail_inner_frame.get_by_text(re.compile(r"^离散备料计划维护:")) + plan_code_locator = detail_inner_frame.get_by_text( + re.compile(r"^离散备料计划维护:") + ) plan_code_locator.wait_for(state="visible", timeout=15000) - - detail_count_text = detail_inner_frame.get_by_text(re.compile(r"^详细信息 \(\d+\)$")).inner_text() + + detail_count_text = detail_inner_frame.get_by_text( + re.compile(r"^详细信息 \(\d+\)$") + ).inner_text() detail_count = int(re.search(r"\((\d+)\)", detail_count_text).group(1)) - - status_text = detail_inner_frame.get_by_text(re.compile(r"^备料状态:.+$")).inner_text() - detail_status = re.search(r"备料状态:(.+)$", status_text.replace("\n", "")).group(1) + + status_text = detail_inner_frame.get_by_text( + re.compile(r"^备料状态:.+$") + ).inner_text() + detail_status = re.search( + r"备料状态:(.+)$", status_text.replace("\n", "") + ).group(1) # 6. 执行清理逻辑 - if detail_status == "审批通过": - if detail_count >0: + if detail_status == "审批通过": + if detail_count > 0: # --- 点击修改并等待状态切换 (保留原逻辑) --- detail_inner_frame.get_by_role("button", name="修改").click() - + # 关键判断:等待保存按钮出现,确认进入编辑模式 - save_button_locator = detail_inner_frame.get_by_role("button", name="保存") + save_button_locator = detail_inner_frame.get_by_role( + "button", name="保存" + ) save_button_locator.wait_for(state="visible", timeout=10000) self._log("已进入编辑模式(保存按钮已就绪)") # --------------------------------------- detail_inner_frame.get_by_text("展开").first.click() - + child_form = detail_inner_frame.locator(".card-table-side-box") button_wrapper = child_form.locator(".button-wrapper") - + delete_row_btn = button_wrapper.get_by_role("button", name="删行") next_btn = button_wrapper.locator(".icon-jiantouyou") collapse_btn = button_wrapper.locator(".icon-celashouqi") @@ -138,7 +157,7 @@ class DiscreteMaterialPlanCleaner: # 稳定性检查:等待行号更新 current_row = self._get_input_value(child_form, r"^行号$") if current_row == last_row_number: - time.sleep(0.5) + time.sleep(0.5) material_code = self._get_input_value(child_form, r"^材料编码") material_name = self._get_input_value(child_form, r"^材料名称") @@ -153,14 +172,16 @@ class DiscreteMaterialPlanCleaner: else: self._log(f"⚠️ 待发数量为 {pending_qty},跳过删除", "warn") else: - self._log(f"物料 {material_name} ({material_code}) 不在删除列表中,不做处理") + self._log( + f"物料 {material_name} ({material_code}) 不在删除列表中,不做处理" + ) if self._is_button_enabled(next_btn): last_row_number = current_row next_btn.click() else: break collapse_btn.click() - + # 执行最终保存逻辑(如业务需要) # save_button_locator.click() else: @@ -176,7 +197,7 @@ class DiscreteMaterialPlanCleaner: inner_frame.locator(".search-name-wrapper > .iconfont").click() inner_frame.get_by_text("订单号查询").click() inner_frame.get_by_role("tab", name="全部").click() - + # 填充每页显示条数(5000条测试值) input_el = inner_frame.locator("#rc_select_0") input_el.fill("5000") @@ -196,8 +217,8 @@ class DiscreteMaterialPlanCleaner: ignore_https_errors=True, ) - self._log("="*30 + " 开始清理任务 " + "="*30) - + self._log("=" * 30 + " 开始清理任务 " + "=" * 30) + # 进入功能页面 main_frame.locator("i").first.click() with page.expect_popup() as page1_info: @@ -207,7 +228,9 @@ class DiscreteMaterialPlanCleaner: # 定位主 Iframe work_main_frame = page1.locator("#forwardFrame").content_frame inner_frame = work_main_frame.locator("#mainiframe").content_frame - inner_frame.locator("#hot-key-head_list").wait_for(state="visible", timeout=15000) + inner_frame.locator("#hot-key-head_list").wait_for( + state="visible", timeout=15000 + ) self.setup_query_interface(inner_frame) order_ids = self.get_production_order_numbers(production_id_file) @@ -219,13 +242,14 @@ class DiscreteMaterialPlanCleaner: self.process_order(inner_frame, order_id, index, page1) except Exception as e: self._log(f"处理单号 {order_id} 时发生异常: {e}", "error") - continue # 单个失败不影响整体执行 + continue # 单个失败不影响整体执行 # 登出清理 logout(work_main_frame, verbose=self.verbose) context.close() browser.close() - self._log("="*30 + " 任务全部完成 " + "="*30) + self._log("=" * 30 + " 任务全部完成 " + "=" * 30) + def main(): # 路径配置 @@ -236,11 +260,12 @@ def main(): username="BLDpengqiangqiang", password="your_password_here", manager_name="彭羽", - headless=False + headless=False, ) - + cleaner.clean(id_file) input("执行完毕,按回车键退出程序...") + if __name__ == "__main__": - main() \ No newline at end of file + main()