diff --git a/.gitignore b/.gitignore index 375aa17..0221013 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,7 @@ cython_debug/ # Custom logs/ +logs2/ .claude/ # Project documentation diff --git a/config/config_task2.ini b/config/config_task2.ini index e5b5692..fdff294 100644 --- a/config/config_task2.ini +++ b/config/config_task2.ini @@ -10,4 +10,10 @@ docid = dcOsT3czWy0YEDg38vlDqwVCTjv0kzwC_GU2XmT9wSZctQ0ZJQUAV7vMQ3ljZx-n_NqxzEEY [Schedule] # 同步频率(分钟) -sync_interval = 15 +sync_interval = 1 + +[wework] +# 企业微信应用ID +agentid = 1000615 +# 接收人列表(用户ID,多个用|分隔,@all表示全部成员) +receivers = 046364 diff --git a/config/token_cache.json b/config/token_cache.json index 4e81afa..4f2fa75 100644 --- a/config/token_cache.json +++ b/config/token_cache.json @@ -1,4 +1,4 @@ { - "access_token": "OadV3tQWg6mWhvIU4fO5d56EkPyHxcygjX31jTd222norNXqKA9WRp7IzCiAMKmYfAp00N3esAoSx6SR3V0ywXU95xr2yy984mYxxYA1t5_GRQwnYZtMXz9h5U6W6Sk9vDz_aHVLEk69e8W4BZ0i_8XRrOWKci4Kox1IDWDVWcEEicyYu_v5-FmNBWIPaj0_ZdQD7B0wn_PcopGHEvsaJ9r5Y3gb9Ix4wQuAISzHMNM", - "fetch_time": 1767859873.4756753 + "access_token": "LsTV1Z6Ye4h2c77s1oKx4zasisAn4QiTbqXmZRUYchZRzp6Q_igpVWp22oEhv8rTHuYyB1LKfqhLjQ9qvgwU13fZns6t-aNBDMw00BBf76V2XqoKKXPHNQZGKQly8RH9NgFMoqfYiKeDnoCdbYnvRjgn8oYoc0AvnCu_qU9TdP8XJgLO01-inoLGSEdTLZnWXf90uf4RztU8xH1a7nuM1p31w58AT7iV3h8Uv9aPOe8", + "fetch_time": 1767954012.568217 } \ No newline at end of file diff --git a/logs2/api_log_2026-01-07.json b/logs2/api_log_2026-01-07.json deleted file mode 100644 index edac0c0..0000000 --- a/logs2/api_log_2026-01-07.json +++ /dev/null @@ -1,583 +0,0 @@ -{ - "records": [], -{ - "api_type": "test", - "operation": "task2/setup_test", - "timestamp": "2026-01-07 20:14:18", - "success": true, - "request": { - "test": "验证脚本测试" - }, - "response": { - "status": "success" - } -} , -{ - "api_type": "tapd", - "operation": "stories", - "timestamp": "2026-01-07 20:48:56", - "success": true, - "request": { - "url": "https://tapd-api.bilibili.co/tapd/stories", - "method": "GET", - "params": { - "workspace_id": "58335167", - "id": "1158335167004800796" - }, - "auth_user": "g41_tapd" - }, - "response": { - "status": 1, - "data": [ - { - "Story": { - "id": "1158335167004800796", - "workitem_type_id": "1158335167001002451", - "app_id": "1", - "name": "12月版本性能优化", - "description": "

【设计文档链接】


【需求文档链接】

", - "workspace_id": "58335167", - "creator": "星渊", - "created": "2025-12-19 15:24:53", - "modified": "2025-12-19 18:04:08", - "status": "status_13", - "step": "", - "owner": "星渊;", - "cc": "", - "begin": null, - "due": null, - "size": null, - "priority": "4", - "developer": "星渊;", - "iteration_id": "0", - "test_focus": "", - "type": "", - "source": "", - "module": "", - "version": "", - "completed": null, - "category_id": "1158335167001017101", - "path": "1158335167004800796:", - "parent_id": "0", - "children_id": "||1158335167004800798|1158335167004800799|1158335167004800802|1158335167004800828", - "ancestor_id": "1158335167004800796", - "level": "0", - "business_value": null, - "effort": null, - "effort_completed": "0", - "exceed": "0", - "remain": "0", - "release_id": "0", - "bug_id": "0", - "templated_id": "1158335167001006075", - "created_from": null, - "feature": "", - "label": "", - "progress": "100", - "is_archived": "0", - "tech_risk": null, - "flows": null, - "custom_field_one": "星渊;", - "custom_field_two": "", - "custom_field_three": "", - "custom_field_four": "", - "custom_field_five": "", - "custom_field_six": "", - "custom_field_seven": "", - "custom_field_eight": "", - "secret_root_id": "0", - "progress_manual": "0", - "custom_field_9": "", - "custom_field_10": "", - "custom_field_11": "", - "custom_field_12": "", - "custom_field_13": "", - "custom_field_14": "", - "custom_field_15": "", - "custom_field_16": "", - "custom_field_17": "", - "custom_field_18": "", - "custom_field_19": "", - "custom_field_20": "", - "custom_field_21": "", - "custom_field_22": "", - "custom_field_23": "", - "custom_field_24": "", - "custom_field_25": "", - "custom_field_26": "", - "custom_field_27": "", - "custom_field_28": "", - "custom_field_29": "", - "custom_field_30": "", - "custom_field_31": "", - "custom_field_32": "", - "custom_field_33": "", - "custom_field_34": "", - "custom_field_35": "", - "custom_field_36": "", - "custom_field_37": "", - "custom_field_38": "", - "custom_field_39": "", - "custom_field_40": "", - "custom_field_41": "", - "custom_field_42": "", - "custom_field_43": "", - "custom_field_44": "", - "custom_field_45": "", - "custom_field_46": "", - "custom_field_47": "", - "custom_field_48": "", - "custom_field_49": "", - "custom_field_50": "", - "custom_field_51": "", - "custom_field_52": "", - "custom_field_53": "", - "custom_field_54": "", - "custom_field_55": "", - "custom_field_56": "", - "custom_field_57": "", - "custom_field_58": "", - "custom_field_59": "", - "custom_field_60": "", - "custom_field_61": "", - "custom_field_62": "", - "custom_field_63": "", - "custom_field_64": "", - "custom_field_65": "", - "custom_field_66": "", - "custom_field_67": "", - "custom_field_68": "", - "custom_field_69": "", - "custom_field_70": "", - "custom_field_71": "", - "custom_field_72": "", - "custom_field_73": "", - "custom_field_74": "", - "custom_field_75": "", - "custom_field_76": "", - "custom_field_77": "", - "custom_field_78": "", - "custom_field_79": "", - "custom_field_80": "", - "custom_field_81": "", - "custom_field_82": "", - "custom_field_83": "", - "custom_field_84": "", - "custom_field_85": "", - "custom_field_86": "", - "custom_field_87": "", - "custom_field_88": "", - "custom_field_89": "", - "custom_field_90": "", - "custom_field_91": "", - "custom_field_92": "", - "custom_field_93": "", - "custom_field_94": "", - "custom_field_95": "", - "custom_field_96": "", - "custom_field_97": "", - "custom_field_98": "", - "custom_field_99": "", - "custom_field_100": "", - "custom_field_101": "", - "custom_field_102": "", - "custom_field_103": "", - "custom_field_104": "", - "custom_field_105": "", - "custom_field_106": "", - "custom_field_107": "", - "custom_field_108": "", - "custom_field_109": "", - "custom_field_110": "", - "custom_field_111": "", - "custom_field_112": "", - "custom_field_113": "", - "custom_field_114": "", - "custom_field_115": "", - "custom_field_116": "", - "custom_field_117": "", - "custom_field_118": "", - "custom_field_119": "", - "custom_field_120": "", - "custom_field_121": "", - "custom_field_122": "", - "custom_field_123": "", - "custom_field_124": "", - "custom_field_125": "", - "custom_field_126": "", - "custom_field_127": "", - "custom_field_128": "", - "custom_field_129": "", - "custom_field_130": "", - "custom_field_131": "", - "custom_field_132": "", - "custom_field_133": "", - "custom_field_134": "", - "custom_field_135": "", - "custom_field_136": "", - "custom_field_137": "", - "custom_field_138": "", - "custom_field_139": "", - "custom_field_140": "", - "custom_field_141": "", - "custom_field_142": "", - "custom_field_143": "", - "custom_field_144": "", - "custom_field_145": "", - "custom_field_146": "", - "custom_field_147": "", - "custom_field_148": "", - "custom_field_149": "", - "custom_field_150": "", - "custom_field_151": "", - "custom_field_152": "", - "custom_field_153": "", - "custom_field_154": "", - "custom_field_155": "", - "custom_field_156": "", - "custom_field_157": "", - "custom_field_158": "", - "custom_field_159": "", - "custom_field_160": "", - "custom_field_161": "", - "custom_field_162": "", - "custom_field_163": "", - "custom_field_164": "", - "custom_field_165": "", - "custom_field_166": "", - "custom_field_167": "", - "custom_field_168": "", - "custom_field_169": "", - "custom_field_170": "", - "custom_field_171": "", - "custom_field_172": "", - "custom_field_173": "", - "custom_field_174": "", - "custom_field_175": "", - "custom_field_176": "", - "custom_field_177": "", - "custom_field_178": "", - "custom_field_179": "", - "custom_field_180": "", - "custom_field_181": "", - "custom_field_182": "", - "custom_field_183": "", - "custom_field_184": "", - "custom_field_185": "", - "custom_field_186": "", - "custom_field_187": "", - "custom_field_188": "", - "custom_field_189": "", - "custom_field_190": "", - "custom_field_191": "", - "custom_field_192": "", - "custom_field_193": "", - "custom_field_194": "", - "custom_field_195": "", - "custom_field_196": "", - "custom_field_197": "", - "custom_field_198": "", - "custom_field_199": "", - "custom_field_200": "", - "custom_plan_field_1": "1158335167001033687", - "custom_plan_field_2": "0", - "custom_plan_field_3": "0", - "custom_plan_field_4": "0", - "custom_plan_field_5": "0", - "custom_plan_field_6": "0", - "custom_plan_field_7": "0", - "custom_plan_field_8": "0", - "custom_plan_field_9": "0", - "custom_plan_field_10": "0", - "priority_label": "High" - } - } - ], - "info": "success" - } -} , -{ - "api_type": "tapd", - "operation": "stories", - "timestamp": "2026-01-07 20:50:30", - "success": true, - "request": { - "url": "https://tapd-api.bilibili.co/tapd/stories", - "method": "GET", - "params": { - "workspace_id": "58335167", - "id": "1158335167004774712" - }, - "auth_user": "g41_tapd" - }, - "response": { - "status": 1, - "data": [ - { - "Story": { - "id": "1158335167004774712", - "workitem_type_id": "1158335167001002456", - "app_id": "1", - "name": "破绽-通用特效", - "description": "

https://doc.weixin.qq.com/sheet/e3_AfIAXgaSAKsCNYIUEmQnvQT6pAabt?scode=ANYAEAdoABEiTVm8UVASEAsgY6AKM&tab=4x5x07

", - "workspace_id": "58335167", - "creator": "Haoo", - "created": "2025-11-24 20:46:53", - "modified": "2025-12-08 14:26:37", - "status": "status_7", - "step": "", - "owner": "parkerluo;", - "cc": "", - "begin": null, - "due": "2025-12-31", - "size": null, - "priority": "2", - "developer": "", - "iteration_id": "0", - "test_focus": "", - "type": "", - "source": "", - "module": "", - "version": "", - "completed": null, - "category_id": "1158335167001017699", - "path": "1158335167004782406::1158335167004788137::1158335167004774712:", - "parent_id": "1158335167004788137", - "children_id": "|", - "ancestor_id": "1158335167004782406", - "level": "2", - "business_value": null, - "effort": null, - "effort_completed": "0", - "exceed": "0", - "remain": "0", - "release_id": "0", - "bug_id": "0", - "templated_id": "1158335167001006073", - "created_from": null, - "feature": "", - "label": "", - "progress": "0", - "is_archived": "0", - "tech_risk": null, - "flows": null, - "custom_field_one": "", - "custom_field_two": "", - "custom_field_three": "", - "custom_field_four": "", - "custom_field_five": "", - "custom_field_six": "", - "custom_field_seven": "", - "custom_field_eight": "", - "secret_root_id": "0", - "progress_manual": "0", - "custom_field_9": "", - "custom_field_10": "", - "custom_field_11": "", - "custom_field_12": "", - "custom_field_13": "", - "custom_field_14": "", - "custom_field_15": "", - "custom_field_16": "", - "custom_field_17": "", - "custom_field_18": "", - "custom_field_19": "", - "custom_field_20": "", - "custom_field_21": "", - "custom_field_22": "", - "custom_field_23": "", - "custom_field_24": "", - "custom_field_25": "", - "custom_field_26": "", - "custom_field_27": "", - "custom_field_28": "", - "custom_field_29": "", - "custom_field_30": "", - "custom_field_31": "", - "custom_field_32": "", - "custom_field_33": "", - "custom_field_34": "", - "custom_field_35": "", - "custom_field_36": "", - "custom_field_37": "", - "custom_field_38": "", - "custom_field_39": "", - "custom_field_40": "", - "custom_field_41": "", - "custom_field_42": "", - "custom_field_43": "", - "custom_field_44": "", - "custom_field_45": "", - "custom_field_46": "", - "custom_field_47": "", - "custom_field_48": "", - "custom_field_49": "", - "custom_field_50": "", - "custom_field_51": "", - "custom_field_52": "", - "custom_field_53": "", - "custom_field_54": "", - "custom_field_55": "", - "custom_field_56": "", - "custom_field_57": "", - "custom_field_58": "", - "custom_field_59": "", - "custom_field_60": "", - "custom_field_61": "", - "custom_field_62": "", - "custom_field_63": "", - "custom_field_64": "", - "custom_field_65": "", - "custom_field_66": "", - "custom_field_67": "", - "custom_field_68": "", - "custom_field_69": "", - "custom_field_70": "", - "custom_field_71": "", - "custom_field_72": "", - "custom_field_73": "", - "custom_field_74": "", - "custom_field_75": "", - "custom_field_76": "", - "custom_field_77": "", - "custom_field_78": "", - "custom_field_79": "", - "custom_field_80": "", - "custom_field_81": "", - "custom_field_82": "", - "custom_field_83": "", - "custom_field_84": "", - "custom_field_85": "", - "custom_field_86": "", - "custom_field_87": "", - "custom_field_88": "", - "custom_field_89": "", - "custom_field_90": "", - "custom_field_91": "", - "custom_field_92": "", - "custom_field_93": "", - "custom_field_94": "", - "custom_field_95": "", - "custom_field_96": "", - "custom_field_97": "", - "custom_field_98": "", - "custom_field_99": "", - "custom_field_100": "", - "custom_field_101": "", - "custom_field_102": "", - "custom_field_103": "", - "custom_field_104": "", - "custom_field_105": "", - "custom_field_106": "", - "custom_field_107": "", - "custom_field_108": "", - "custom_field_109": "", - "custom_field_110": "", - "custom_field_111": "", - "custom_field_112": "", - "custom_field_113": "", - "custom_field_114": "", - "custom_field_115": "", - "custom_field_116": "", - "custom_field_117": "", - "custom_field_118": "", - "custom_field_119": "", - "custom_field_120": "", - "custom_field_121": "", - "custom_field_122": "", - "custom_field_123": "", - "custom_field_124": "", - "custom_field_125": "", - "custom_field_126": "", - "custom_field_127": "", - "custom_field_128": "", - "custom_field_129": "", - "custom_field_130": "", - "custom_field_131": "", - "custom_field_132": "", - "custom_field_133": "", - "custom_field_134": "", - "custom_field_135": "", - "custom_field_136": "", - "custom_field_137": "", - "custom_field_138": "", - "custom_field_139": "", - "custom_field_140": "", - "custom_field_141": "", - "custom_field_142": "", - "custom_field_143": "", - "custom_field_144": "", - "custom_field_145": "", - "custom_field_146": "", - "custom_field_147": "", - "custom_field_148": "", - "custom_field_149": "", - "custom_field_150": "", - "custom_field_151": "", - "custom_field_152": "", - "custom_field_153": "", - "custom_field_154": "", - "custom_field_155": "", - "custom_field_156": "", - "custom_field_157": "", - "custom_field_158": "", - "custom_field_159": "", - "custom_field_160": "", - "custom_field_161": "", - "custom_field_162": "", - "custom_field_163": "", - "custom_field_164": "", - "custom_field_165": "", - "custom_field_166": "", - "custom_field_167": "", - "custom_field_168": "", - "custom_field_169": "", - "custom_field_170": "", - "custom_field_171": "", - "custom_field_172": "", - "custom_field_173": "", - "custom_field_174": "", - "custom_field_175": "", - "custom_field_176": "", - "custom_field_177": "", - "custom_field_178": "", - "custom_field_179": "", - "custom_field_180": "", - "custom_field_181": "", - "custom_field_182": "", - "custom_field_183": "", - "custom_field_184": "", - "custom_field_185": "", - "custom_field_186": "", - "custom_field_187": "", - "custom_field_188": "", - "custom_field_189": "", - "custom_field_190": "", - "custom_field_191": "", - "custom_field_192": "", - "custom_field_193": "", - "custom_field_194": "", - "custom_field_195": "", - "custom_field_196": "", - "custom_field_197": "", - "custom_field_198": "", - "custom_field_199": "", - "custom_field_200": "", - "custom_plan_field_1": "1158335167001033687", - "custom_plan_field_2": "0", - "custom_plan_field_3": "0", - "custom_plan_field_4": "0", - "custom_plan_field_5": "0", - "custom_plan_field_6": "0", - "custom_plan_field_7": "0", - "custom_plan_field_8": "0", - "custom_plan_field_9": "0", - "custom_plan_field_10": "0", - "priority_label": "Low" - } - } - ], - "info": "success" - } -} -]} \ No newline at end of file diff --git a/src/smartsheet.py b/src/smartsheet.py index 0f3a1fc..0d1f24a 100644 --- a/src/smartsheet.py +++ b/src/smartsheet.py @@ -60,6 +60,7 @@ class SmartSheetAPI: print("=" * 80) print(f"请求方法: {method}") print(f"请求URL: {self.BASE_URL}/{endpoint}") + print(f"完整URL(含参数): {url}") # 显示完整URL if data: import json print(f"请求数据:") diff --git a/src2/config.py b/src2/config.py index 821fda9..0dd1c46 100644 --- a/src2/config.py +++ b/src2/config.py @@ -76,12 +76,35 @@ class Task2ConfigManager(BaseConfigManager): return {'sync_interval': sync_interval} + def get_wework_config(self): + """ + 获取企业微信推送配置 + + Returns: + dict: 包含agentid和receivers的字典,如果配置不存在则返回None + """ + if not self.config.has_section('wework'): + return None + + agentid = self.config.get('wework', 'agentid', fallback='').strip() + receivers = self.config.get('wework', 'receivers', fallback='').strip() + + # 如果配置不完整,返回None + if not agentid or not receivers: + return None + + return { + 'agentid': agentid, + 'receivers': receivers + } + def get_all_config(self): """获取所有配置""" return { 'tapd': self.get_tapd_config(), 'smartsheet': self.get_smartsheet_config(), - 'schedule': self.get_schedule_config() + 'schedule': self.get_schedule_config(), + 'wework': self.get_wework_config() } def print_config(self): @@ -108,6 +131,14 @@ class Task2ConfigManager(BaseConfigManager): except ValueError as e: print(f"[Schedule] 配置错误: {e}") + wework_config = self.get_wework_config() + if wework_config: + print(f"[wework]") + print(f" agentid: {wework_config['agentid']}") + print(f" receivers: {wework_config['receivers']}") + else: + print(f"[wework] 未配置(推送功能将被禁用)") + print("======================\n") diff --git a/src2/notifier.py b/src2/notifier.py new file mode 100644 index 0000000..fe9b85e --- /dev/null +++ b/src2/notifier.py @@ -0,0 +1,106 @@ +""" +任务二企业微信消息推送模块 +用于发送同步失败通知 +""" + +import sys +from pathlib import Path +from typing import List, Dict +from datetime import datetime + +# 将项目根目录添加到 Python 路径 +project_root = Path(__file__).parent.parent +sys.path.insert(0, str(project_root)) + +from src.wework_notifier import WeWorkNotifier + + +def send_sync_failure_notification(access_token: str, agentid: str, + receivers: str, failed_records: List[Dict]) -> bool: + """ + 发送同步失败通知 + + Args: + access_token: 企业微信access_token + agentid: 应用ID + receivers: 接收人列表 + failed_records: 失败记录列表,每条记录包含: + - sheet_title: 子表标题 + - record_id: 记录ID + - tapd_link: TAPD链接 + - error_message: 失败原因 + + Returns: + bool: 是否发送成功 + """ + if not failed_records: + return True + + # 构造消息内容 + content = _build_sync_failure_message(failed_records) + + # 使用任务一的推送器发送消息 + notifier = WeWorkNotifier(access_token, agentid, receivers) + return notifier._send_text_message(content) + + +def _build_sync_failure_message(failed_records: List[Dict]) -> str: + """ + 构造同步失败消息内容(支持多子表分组) + + Args: + failed_records: 失败记录列表 + + Returns: + str: 格式化的消息内容 + """ + # 按子表分组 + records_by_sheet = {} + for record in failed_records: + sheet_title = record.get('sheet_title', '未知子表') + if sheet_title not in records_by_sheet: + records_by_sheet[sheet_title] = [] + records_by_sheet[sheet_title].append(record) + + # 消息头部 + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + total_count = len(failed_records) + sheet_count = len(records_by_sheet) + + lines = [ + "【autoTAPD 同步失败通知】", + f"时间: {timestamp}", + f"失败数量: {total_count} 条(来自 {sheet_count} 个子表)", + "", + "以下记录同步失败,请检查:", + "=" * 40 + ] + + # 按子表分组显示失败记录 + global_idx = 1 + for sheet_title, sheet_records in records_by_sheet.items(): + lines.append(f"\n【子表:{sheet_title}】") + lines.append("") + + for record in sheet_records: + record_id = record.get('record_id', '未知') + tapd_link = record.get('tapd_link', '(无链接)') + error_message = record.get('error_message', '未知错误') + + lines.append(f"[{global_idx}] 记录ID: {record_id}") + lines.append(f"TAPD链接: {tapd_link}") + lines.append(f"失败原因: {error_message}") + lines.append("") + + global_idx += 1 + + lines.append("=" * 40) + lines.append("系统将在下次同步时自动重试失败记录。") + + return "\n".join(lines) + + +if __name__ == "__main__": + print("=== 任务二推送模块 ===") + print("此模块提供同步失败通知功能") + print("请通过 sync_service 或 main.py 调用") diff --git a/src2/sync_service.py b/src2/sync_service.py index 9c3466f..07cbe32 100644 --- a/src2/sync_service.py +++ b/src2/sync_service.py @@ -112,6 +112,15 @@ class SyncService: result["success"] = True + # 3. 汇总所有失败记录并发送推送通知 + all_failed_records = [] + for sheet_result in result["sheet_results"]: + all_failed_records.extend(sheet_result.get("failed_records", [])) + + # 如果有失败记录,尝试发送推送通知 + if all_failed_records: + self._send_failure_notification(all_failed_records) + except Exception as e: result["error_message"] = str(e) print(f"\n✗ 同步失败: {e}") @@ -148,7 +157,8 @@ class SyncService: "records_synced": 0, "records_updated": 0, "records_failed": 0, - "details": [] + "details": [], + "failed_records": [] # 收集失败记录的详细信息 } try: @@ -188,6 +198,15 @@ class SyncService: sheet_result["records_failed"] += 1 failed_record_ids.append(record_info["record_id"]) + # 收集失败记录的详细信息用于推送 + failed_record = { + "sheet_title": sheet_title, + "record_id": record_info["record_id"], + "tapd_link": record_info.get("tapd_link", "(无链接)"), + "error_message": record_result.get("error_message", "未知错误") + } + sheet_result["failed_records"].append(failed_record) + # 4. 批量回写成功记录(业务字段 + 同步状态=成功) if success_records: print(f"\n正在回写 {len(success_records)} 条成功记录...") @@ -333,6 +352,50 @@ class SyncService: return False + def _send_failure_notification(self, failed_records: List[Dict]) -> None: + """ + 发送同步失败通知 + + Args: + failed_records: 失败记录列表 + """ + try: + # 获取企业微信配置 + wework_config = self.config.get('wework') + + if not wework_config: + print(" ℹ 未配置企业微信推送,跳过失败通知") + return + + agentid = wework_config.get('agentid') + receivers = wework_config.get('receivers') + + if not agentid or not receivers: + print(" ⚠ 企业微信推送配置不完整,跳过失败通知") + return + + # 发送推送通知 + print(f"\n正在发送同步失败通知...") + from src2.notifier import send_sync_failure_notification + + success = send_sync_failure_notification( + self.access_token, + agentid, + receivers, + failed_records + ) + + if success: + print(f" ✓ 失败通知已发送") + else: + print(f" ✗ 失败通知发送失败") + + except Exception as e: + print(f" ✗ 发送失败通知时出错: {e}") + if self.test_mode: + import traceback + traceback.print_exc() + def run_once(config_manager: Task2ConfigManager = None, access_token: str = None,