diff --git a/admin/dashboard/blueprints/contacts.py b/admin/dashboard/blueprints/contacts.py index 1cff6fc..24b4a47 100644 --- a/admin/dashboard/blueprints/contacts.py +++ b/admin/dashboard/blueprints/contacts.py @@ -163,4 +163,21 @@ def api_group_members(roomid): }) except Exception as e: logger.error(f"获取群成员列表失败: {e}") - return jsonify({"success": False, "error": str(e)}), 500 \ No newline at end of file + return jsonify({"success": False, "error": str(e)}), 500 + + +@contacts_bp.route('/api/update', methods=['POST']) +@login_required +def api_contacts_update(): + """更新通讯录信息API""" + try: + server = current_app.dashboard_server + # 假设 contact_manager 有 update_contacts 方法用于同步通讯录 + result = server.robot.refresh_contacts_db() + if result: + return jsonify({"success": True, "message": "通讯录更新成功"}) + else: + return jsonify({"success": False, "message": "通讯录更新失败"}), 500 + except Exception as e: + logger.error(f"更新通讯录失败: {e}") + return jsonify({"success": False, "message": f"更新通讯录失败: {str(e)}"}), 500 \ No newline at end of file diff --git a/admin/dashboard/server.py b/admin/dashboard/server.py index e24903c..e0168ea 100644 --- a/admin/dashboard/server.py +++ b/admin/dashboard/server.py @@ -45,6 +45,7 @@ class DashboardServer: self.plugin_manager = robot_instance.plugin_manager self.plugin_registry = robot_instance.plugin_registry self.client: WechatAPIClient = robot_instance.ipad_bot + self.robot = robot_instance # # 设置用户信息 # self.user_data = { diff --git a/admin/dashboard/templates/contacts_management.html b/admin/dashboard/templates/contacts_management.html index b0d1b0c..f254354 100644 --- a/admin/dashboard/templates/contacts_management.html +++ b/admin/dashboard/templates/contacts_management.html @@ -17,6 +17,13 @@ {% raw %}@click="refreshContacts"{% endraw %}> 刷新数据 + + 更新通讯录 + { + if (res.data.success) { + this.$message.success('通讯录更新成功!'); + this.refreshContacts(); + } else { + this.$message.error(res.data.message || '通讯录更新失败'); + } + }) + .catch(() => { + this.$message.error('通讯录更新请求失败'); + }); + }, }); diff --git a/db/contacts_db.py b/db/contacts_db.py index 603de34..d019749 100644 --- a/db/contacts_db.py +++ b/db/contacts_db.py @@ -663,3 +663,66 @@ class ContactsDBOperator(BaseDBOperator): except Exception as e: self.LOG.error(f"删除群聊{chatroom_id}信息失败: {e}") return False + + #新增获取群列表接口 + def get_chatroom_list(self) -> List[dict]: + """获取群列表""" + try: + sql = "SELECT * FROM t_chatrooms" + results = self.execute_query(sql) + for result in results: + if result.get('member_list'): + result['member_list'] = json.loads(result['member_list']) + return results + except Exception as e: + self.LOG.error(f"获取群列表失败: {e}") + return [] + + #新增获取群成员列表接口 + def get_chatroom_member_list(self, chatroom_id: str) -> List[dict]: + """获取群成员列表""" + try: + sql = "SELECT * FROM t_chatroom_member WHERE chatroom_id = %s" + results = self.execute_query(sql, (chatroom_id,)) + return results + except Exception as e: + self.LOG.error(f"获取群{chatroom_id}成员列表失败: {e}") + return [] + + #新增获取群成员信息接口 + def get_chatroom_member_info(self, chatroom_id: str, wxid: str) -> Optional[dict]: + """获取群成员信息""" + try: + sql = "SELECT * FROM t_chatroom_member WHERE chatroom_id = %s AND wxid = %s LIMIT 1" + result = self.execute_query(sql, (chatroom_id, wxid), fetch_one=True) + return result + except Exception as e: + self.LOG.error(f"获取群{chatroom_id}成员{wxid}信息失败: {e}") + return None + + #新增群信息删除功能 + def delete_chatroom_member_info(self, chatroom_id: str, wxid: str) -> bool: + """删除群成员信息""" + try: + sql = "DELETE FROM t_chatroom_member WHERE chatroom_id = %s AND wxid = %s" + self.execute_update(sql, (chatroom_id, wxid)) + self.LOG.info(f"成功删除群{chatroom_id}成员{wxid}信息") + sql = "DELETE FROM t_chatrooms WHERE chatroom_id = %s" + self.execute_update(sql, (chatroom_id,)) + self.LOG.info(f"成功删除群聊 {chatroom_id} 信息") + return True + except Exception as e: + self.LOG.error(f"删除群{chatroom_id}信息失败: {e}") + return False + + #新增删除所有联系人功能 + def delete_all_contacts(self) -> bool: + """删除所有联系人信息""" + try: + sql = "DELETE FROM t_wechat_contacts" + self.execute_update(sql) + self.LOG.info(f"成功删除所有联系人信息") + return True + except Exception as e: + self.LOG.error(f"删除所有联系人信息失败: {e}") + return False \ No newline at end of file diff --git a/robot.py b/robot.py index 71518d4..845b9df 100644 --- a/robot.py +++ b/robot.py @@ -181,9 +181,7 @@ class Robot(Job): self.allContacts = self.get_all_contacts() self.contact_manager.set_contacts(self.allContacts) - # 开启自动心跳(作为后台任务) - heartbeat_task = asyncio.create_task(self._heartbeat_task()) - heartbeat_task_long = asyncio.create_task(self._heartbeat_task_long()) + self.message_storage = MessageStorage(self.ipad_bot) # 初始化消息工具类 - 使用联系人管理器 @@ -209,7 +207,9 @@ class Robot(Job): # 标记为运行中 self.ipad_running = True - + # 开启自动心跳(作为后台任务) + heartbeat_task = asyncio.create_task(self._heartbeat_task()) + heartbeat_task_long = asyncio.create_task(self._heartbeat_task_long()) # 开始处理消息 self.LOG.info("开始处理wechat_ipad消息") while self.ipad_running: @@ -276,6 +276,7 @@ class Robot(Job): self.ipad_config["wxid"] = self.ipad_bot.wxid self.ipad_config["device_name"] = device_name self.ipad_config["device_id"] = device_id + self.ipad_config["login_time"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) with open("wechat_ipad/config.toml", "w", encoding="utf-8") as f: toml.dump(self.ipad_config, f) @@ -298,7 +299,7 @@ class Robot(Job): async def _heartbeat_task(self): """wechat_ipad心跳任务""" self.LOG.info("开启wechat_ipad心跳!") - while True: + while self.ipad_running: try: success = await self.ipad_bot.heartbeat() if success: @@ -312,7 +313,7 @@ class Robot(Job): async def _heartbeat_task_long(self): """wechat_ipad心跳任务""" self.LOG.info("开启wechat_ipad长连接心跳!") - while True: + while self.ipad_running: try: success = await self.ipad_bot.heartbeat_long() if success: @@ -513,6 +514,69 @@ class Robot(Job): self.LOG.error(f"获取联系人信息失败: {e}") return {} + def refresh_contacts_db(self): + """刷新联系人信息""" + #获取用户所有的联系人,并保存到数据库 + self.LOG.info("开始刷新联系人信息") + #删除所有的联系人信息 + self.contacts_db.delete_all_contacts() + self.LOG.debug("已删除所有的联系人信息") + contacts = self.ipad_bot.get_contract_list() + self.LOG.debug(f"获取到的联系人数量:{len(contacts)}") + #获取联系人详细信息,get_contract_detail每次可以获取20个 + #每次获取20个,需要循环获取 + # 将联系人列表分成每组20个 + batch_size = 20 + for i in range(0, len(contacts), batch_size): + # 获取当前批次的联系人 + batch_contacts = contacts[i:i + batch_size] + # 获取这批联系人的详细信息 + contact_info = self.ipad_bot.get_contract_detail(batch_contacts) + self.LOG.debug(f"获取到的联系人详细信息数量:{len(contact_info)}") + self.contacts_db.save_contacts(contact_info,"friends") + + # 获取群聊列表 + groups = self.contacts_db.get_chatroom_list() + # 调用接口完成群成员信息获取与保存逻辑 + for group in groups: + # 调用接口获取群成员信息 + group_id = group["UserName"] + chatroom_info = self.ipad_bot.get_chatroom_info(group_id) + self.LOG.debug(f"获取到的群成员信息:{chatroom_info}") + if chatroom_info: + # 保存群信息到数据库 + self.contacts_db.save_chatroom_info(chatroom_info) + + # 保存群成员信息 + if "NewChatroomData" in chatroom_info and "ChatRoomMember" in chatroom_info["NewChatroomData"]: + member_list = chatroom_info["NewChatroomData"]["ChatRoomMember"] + self.contacts_db.save_chatroom_member_simple(group_id, member_list) + + # 更新联系人缓存 + for member in member_list: + wxid = "" + if isinstance(member.get("UserName"), dict): + wxid = member["UserName"].get("string", "") + else: + wxid = member.get("UserName", "") + + nick_name = "" + if isinstance(member.get("NickName"), dict): + nick_name = member["NickName"].get("string", "") + else: + nick_name = member.get("NickName", "") + + if wxid: + self.allContacts[wxid] = nick_name + + self.contact_manager.set_contacts(self.allContacts) + self.LOG.info(f"已更新群 {group_id} 的成员信息") + else: + self.LOG.error(f"获取群 {group_id} 信息失败,证明用户无该群信息,删除群的相关资料。") + #删除群数据库中的群信息 + self.contacts_db.delete_chatroom_member_info(group_id) + self.LOG.info("联系人信息刷新完成") + # ============================================== 业务内容========================================================== def news_baidu_report_auto(self) -> None: