diff --git a/admin/dashboard/server.py b/admin/dashboard/server.py index 6622bc2..ed636b4 100644 --- a/admin/dashboard/server.py +++ b/admin/dashboard/server.py @@ -180,6 +180,90 @@ class DashboardServer: @login_required def robot_management(): return render_template('robot_management.html') + + # 添加通讯录管理页面路由 + @app.route('/contacts') + @login_required + def contacts_management(): + """通讯录管理页面""" + return render_template('contacts_management.html') + + # 添加通讯录相关API + @app.route('/api/contacts/all', methods=['GET']) + @login_required + def api_contacts_all(): + """获取所有联系人信息API""" + try: + contacts = self.contact_manager.get_contacts() + return jsonify({ + "success": True, + "data": { + "contacts": contacts + } + }) + except Exception as e: + self.logger.error(f"获取所有联系人信息失败: {e}") + return jsonify({"success": False, "error": str(e)}), 500 + + @app.route('/api/contacts/groups', methods=['GET']) + @login_required + def api_contacts_groups(): + """获取群组联系人信息API""" + try: + contacts = self.contact_manager.get_contacts() + group_contacts = {wxid: name for wxid, name in contacts.items() if '@@' in wxid or '@chatroom' in wxid} + + return jsonify({ + "success": True, + "data": { + "groups": group_contacts + } + }) + except Exception as e: + self.logger.error(f"获取群组联系人信息失败: {e}") + return jsonify({"success": False, "error": str(e)}), 500 + + @app.route('/api/contacts/personal', methods=['GET']) + @login_required + def api_contacts_personal(): + """获取个人联系人信息API""" + try: + contacts = self.contact_manager.get_contacts() + personal_contacts = {wxid: name for wxid, name in contacts.items() + if '@@' not in wxid and '@chatroom' not in wxid} + + return jsonify({ + "success": True, + "data": { + "personal": personal_contacts + } + }) + except Exception as e: + self.logger.error(f"获取个人联系人信息失败: {e}") + return jsonify({"success": False, "error": str(e)}), 500 + + @app.route('/api/contacts/statistics', methods=['GET']) + @login_required + def api_contacts_statistics(): + """获取联系人统计信息API""" + try: + contacts = self.contact_manager.get_contacts() + group_contacts = {wxid: name for wxid, name in contacts.items() + if '@@' in wxid or '@chatroom' in wxid} + personal_contacts = {wxid: name for wxid, name in contacts.items() + if '@@' not in wxid and '@chatroom' not in wxid} + + return jsonify({ + "success": True, + "data": { + "total": len(contacts), + "groups": len(group_contacts), + "personal": len(personal_contacts) + } + }) + except Exception as e: + self.logger.error(f"获取联系人统计信息失败: {e}") + return jsonify({"success": False, "error": str(e)}), 500 @app.route('/api/robot/groups') @login_required diff --git a/admin/dashboard/templates/base.html b/admin/dashboard/templates/base.html index eff0f98..9c675a7 100644 --- a/admin/dashboard/templates/base.html +++ b/admin/dashboard/templates/base.html @@ -143,6 +143,11 @@ 运行日志 + + + + 通讯录管理 + @@ -204,7 +209,8 @@ '5': '/errors', '6': '/robot_management', '7': '/messages', - '9': '/wx_logs' + '9': '/wx_logs', + '10': '/contacts' }; // 如果当前不在对应页面,则跳转 diff --git a/utils/wechat/contact_manager.py b/utils/wechat/contact_manager.py index 7994e61..7f7d2c1 100644 --- a/utils/wechat/contact_manager.py +++ b/utils/wechat/contact_manager.py @@ -3,13 +3,15 @@ 联系人管理器 - 提供全局访问联系人信息的单例类 """ import logging -from typing import Dict, Optional +from typing import Dict, Optional, List, Tuple class ContactManager: """联系人管理器单例类""" _instance = None _contacts: Dict[str, str] = {} + _group_contacts: Dict[str, str] = {} # 群组联系人 + _personal_contacts: Dict[str, str] = {} # 个人联系人 _initialized = False _logger = logging.getLogger("ContactManager") @@ -39,6 +41,22 @@ class ContactManager: """ self._contacts = contacts self._logger.info(f"联系人信息已更新,共 {len(contacts)} 个联系人") + # 分类联系人 + self._classify_contacts() + + def _classify_contacts(self) -> None: + """将联系人分类为群组和个人联系人""" + self._group_contacts = {} + self._personal_contacts = {} + + for wxid, nickname in self._contacts.items(): + # 微信群ID通常以@@开头 + if wxid.startswith('@@'): + self._group_contacts[wxid] = nickname + else: + self._personal_contacts[wxid] = nickname + + self._logger.info(f"联系人分类完成: {len(self._group_contacts)} 个群组, {len(self._personal_contacts)} 个个人联系人") def get_contacts(self) -> Dict[str, str]: """获取所有联系人 @@ -48,6 +66,22 @@ class ContactManager: """ return self._contacts + def get_group_contacts(self) -> Dict[str, str]: + """获取所有群组联系人 + + Returns: + 群组联系人字典,格式为 {"wxid": "GroupName"} + """ + return self._group_contacts + + def get_personal_contacts(self) -> Dict[str, str]: + """获取所有个人联系人 + + Returns: + 个人联系人字典,格式为 {"wxid": "NickName"} + """ + return self._personal_contacts + def get_nickname(self, wxid: str) -> str: """根据微信ID获取昵称 @@ -67,6 +101,11 @@ class ContactManager: nickname: 昵称 """ self._contacts[wxid] = nickname + # 更新分类 + if wxid.endswith('@chatroom'): + self._group_contacts[wxid] = nickname + else: + self._personal_contacts[wxid] = nickname self._logger.debug(f"已更新联系人: {wxid} -> {nickname}") def refresh_contacts(self, new_contacts: Dict[str, str]) -> None: @@ -76,4 +115,14 @@ class ContactManager: new_contacts: 新的联系人字典 """ self._contacts = new_contacts - self._logger.info(f"联系人信息已刷新,共 {len(new_contacts)} 个联系人") \ No newline at end of file + self._logger.info(f"联系人信息已刷新,共 {len(new_contacts)} 个联系人") + # 重新分类联系人 + self._classify_contacts() + + def get_contact_statistics(self) -> Tuple[int, int, int]: + """获取联系人统计信息 + + Returns: + 包含总联系人数、群组数和个人联系人数的元组 + """ + return len(self._contacts), len(self._group_contacts), len(self._personal_contacts) \ No newline at end of file