加入群成员列表功能
This commit is contained in:
@@ -125,3 +125,25 @@ def api_contacts_public():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取公共好友信息失败: {e}")
|
logger.error(f"获取公共好友信息失败: {e}")
|
||||||
return jsonify({"success": False, "error": str(e)}), 500
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
|
|
||||||
|
@contacts_bp.route('/api/group_members/<roomid>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def api_group_members(roomid):
|
||||||
|
"""获取指定群的成员列表API
|
||||||
|
|
||||||
|
Args:
|
||||||
|
roomid: 群ID
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
server = current_app.dashboard_server
|
||||||
|
group_members = server.contact_manager.get_group_members(roomid)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"data": {
|
||||||
|
"members": group_members
|
||||||
|
}
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取群成员列表失败: {e}")
|
||||||
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
@@ -197,12 +197,48 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 群组详情对话框 -->
|
<!-- 群组详情对话框 -->
|
||||||
<el-dialog title="群组详情" {% raw %}:visible.sync="groupDetailDialogVisible"{% endraw %} width="50%">
|
<el-dialog title="群组详情" {% raw %}:visible.sync="groupDetailDialogVisible"{% endraw %} width="70%">
|
||||||
<el-descriptions {% raw %}:column="1"{% endraw %} border>
|
<el-descriptions {% raw %}:column="1"{% endraw %} border>
|
||||||
<el-descriptions-item label="群ID">{% raw %}{{ currentGroup.wxid }}{% endraw %}</el-descriptions-item>
|
<el-descriptions-item label="群ID">{% raw %}{{ currentGroup.wxid }}{% endraw %}</el-descriptions-item>
|
||||||
<el-descriptions-item label="群名称">{% raw %}{{ currentGroup.name }}{% endraw %}</el-descriptions-item>
|
<el-descriptions-item label="群名称">{% raw %}{{ currentGroup.name }}{% endraw %}</el-descriptions-item>
|
||||||
<!-- 可以添加更多群组相关信息 -->
|
<!-- 可以添加更多群组相关信息 -->
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
|
<!-- 群成员列表 -->
|
||||||
|
<div style="margin-top: 20px;">
|
||||||
|
<div class="section-title">
|
||||||
|
<h3>群成员列表</h3>
|
||||||
|
<el-input
|
||||||
|
placeholder="搜索群成员..."
|
||||||
|
{% raw %}v-model="groupMemberSearchQuery"{% endraw %}
|
||||||
|
style="width: 200px; float: right; margin-bottom: 10px;"
|
||||||
|
clearable>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
{% raw %}:data="filteredGroupMembers"{% endraw %}
|
||||||
|
style="width: 100%"
|
||||||
|
border
|
||||||
|
{% raw %}v-loading="groupMembersLoading"{% endraw %}>
|
||||||
|
<el-table-column type="index" width="50"></el-table-column>
|
||||||
|
<el-table-column prop="wxid" label="成员ID" width="220"></el-table-column>
|
||||||
|
<el-table-column prop="name" label="成员昵称"></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 群成员分页 -->
|
||||||
|
<div class="pagination-container" {% raw %}v-if="groupMembersList.length > 10"{% endraw %}>
|
||||||
|
<el-pagination
|
||||||
|
{% raw %}@size-change="handleGroupMembersSizeChange"
|
||||||
|
@current-change="handleGroupMembersCurrentChange"
|
||||||
|
:current-page="groupMembersCurrentPage"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
:page-size="groupMembersPageSize"{% endraw %}
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
{% raw %}:total="groupMembersList.length"{% endraw %}>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 用户详情对话框 -->
|
<!-- 用户详情对话框 -->
|
||||||
@@ -263,7 +299,13 @@
|
|||||||
currentGroup: {},
|
currentGroup: {},
|
||||||
currentUser: {},
|
currentUser: {},
|
||||||
currentOfficial: {},
|
currentOfficial: {},
|
||||||
currentPublic: {}
|
currentPublic: {},
|
||||||
|
// 新增群成员相关数据
|
||||||
|
groupMembersList: [],
|
||||||
|
groupMembersCurrentPage: 1,
|
||||||
|
groupMembersPageSize: 10,
|
||||||
|
groupMemberSearchQuery: '',
|
||||||
|
groupMembersLoading: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -436,6 +478,7 @@
|
|||||||
viewGroupDetails(group) {
|
viewGroupDetails(group) {
|
||||||
this.currentGroup = group;
|
this.currentGroup = group;
|
||||||
this.groupDetailDialogVisible = true;
|
this.groupDetailDialogVisible = true;
|
||||||
|
this.loadGroupMembers(group.wxid);
|
||||||
},
|
},
|
||||||
viewUserDetails(user) {
|
viewUserDetails(user) {
|
||||||
this.currentUser = user;
|
this.currentUser = user;
|
||||||
@@ -448,6 +491,38 @@
|
|||||||
viewPublicDetails(publicFriend) {
|
viewPublicDetails(publicFriend) {
|
||||||
this.currentPublic = publicFriend;
|
this.currentPublic = publicFriend;
|
||||||
this.publicDetailDialogVisible = true;
|
this.publicDetailDialogVisible = true;
|
||||||
|
},
|
||||||
|
// 添加加载群成员的方法
|
||||||
|
loadGroupMembers(roomid) {
|
||||||
|
this.groupMembersLoading = true;
|
||||||
|
this.groupMembersList = [];
|
||||||
|
this.groupMembersCurrentPage = 1;
|
||||||
|
|
||||||
|
axios.get(`/contacts/api/group_members/${roomid}`)
|
||||||
|
.then(response => {
|
||||||
|
if (response.data.success) {
|
||||||
|
const members = response.data.data.members;
|
||||||
|
this.groupMembersList = Object.entries(members).map(([wxid, name]) => ({
|
||||||
|
wxid,
|
||||||
|
name
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('加载群成员数据失败:', error);
|
||||||
|
this.$message.error('加载群成员数据失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.groupMembersLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 群成员分页方法
|
||||||
|
handleGroupMembersSizeChange(size) {
|
||||||
|
this.groupMembersPageSize = size;
|
||||||
|
},
|
||||||
|
handleGroupMembersCurrentChange(page) {
|
||||||
|
this.groupMembersCurrentPage = page;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -472,5 +547,18 @@
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
.section-title {
|
||||||
|
margin: 20px 0 15px 0;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.section-title h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
4
robot.py
4
robot.py
@@ -58,7 +58,7 @@ class Robot(Job):
|
|||||||
# 初始化联系人管理器并设置联系人
|
# 初始化联系人管理器并设置联系人
|
||||||
self.contact_manager = ContactManager.get_instance()
|
self.contact_manager = ContactManager.get_instance()
|
||||||
self.allContacts = self.get_all_contacts()
|
self.allContacts = self.get_all_contacts()
|
||||||
self.contact_manager.set_contacts(self.allContacts, self.wcf.get_friends())
|
self.contact_manager.set_contacts(self.allContacts, self.wcf)
|
||||||
|
|
||||||
self.LOG.info(f"DB+REDIS 连接池开始初始化")
|
self.LOG.info(f"DB+REDIS 连接池开始初始化")
|
||||||
# 使用单例模式获取实例
|
# 使用单例模式获取实例
|
||||||
@@ -545,5 +545,5 @@ class Robot(Job):
|
|||||||
def refresh_contacts(self):
|
def refresh_contacts(self):
|
||||||
"""刷新联系人信息"""
|
"""刷新联系人信息"""
|
||||||
self.allContacts = self.get_all_contacts()
|
self.allContacts = self.get_all_contacts()
|
||||||
self.contact_manager.refresh_contacts(self.allContacts, self.wcf.get_friends())
|
self.contact_manager.refresh_contacts(self.allContacts, self.wcf)
|
||||||
self.LOG.info("联系人信息已刷新")
|
self.LOG.info("联系人信息已刷新")
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Dict, Optional, List, Tuple
|
from typing import Dict, Optional, List, Tuple
|
||||||
|
|
||||||
|
from wcferry import Wcf
|
||||||
|
|
||||||
|
|
||||||
class ContactManager:
|
class ContactManager:
|
||||||
"""联系人管理器单例类"""
|
"""联系人管理器单例类"""
|
||||||
@@ -17,6 +19,7 @@ class ContactManager:
|
|||||||
_initialized = False
|
_initialized = False
|
||||||
_logger = logging.getLogger("ContactManager")
|
_logger = logging.getLogger("ContactManager")
|
||||||
_friends: List[Dict] = []
|
_friends: List[Dict] = []
|
||||||
|
_group_contacts_friends: Dict[str, Dict[str, str]] = {}
|
||||||
# 定义公共好友列表
|
# 定义公共好友列表
|
||||||
_PUBLIC_FRIENDS = {
|
_PUBLIC_FRIENDS = {
|
||||||
'fmessage': '朋友推荐消息',
|
'fmessage': '朋友推荐消息',
|
||||||
@@ -46,7 +49,7 @@ class ContactManager:
|
|||||||
cls._instance = ContactManager()
|
cls._instance = ContactManager()
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def set_contacts(self, contacts: Dict[str, str], friends: List[Dict]) -> None:
|
def set_contacts(self, contacts: Dict[str, str], wcf: Wcf) -> None:
|
||||||
"""设置联系人字典
|
"""设置联系人字典
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -62,12 +65,12 @@ class ContactManager:
|
|||||||
"gender": gender}
|
"gender": gender}
|
||||||
"""
|
"""
|
||||||
self._contacts = contacts
|
self._contacts = contacts
|
||||||
self._friends = friends
|
self._friends = wcf.get_friends()
|
||||||
self._logger.info(f"联系人信息已更新,共 {len(contacts)} 个联系人")
|
self._logger.info(f"联系人信息已更新,共 {len(contacts)} 个联系人")
|
||||||
# 分类联系人
|
# 分类联系人
|
||||||
self._classify_contacts()
|
self._classify_contacts(wcf)
|
||||||
|
|
||||||
def _classify_contacts(self) -> None:
|
def _classify_contacts(self, wcf: Wcf) -> None:
|
||||||
"""将联系人分类为群组、个人联系人、公共好友和公众号"""
|
"""将联系人分类为群组、个人联系人、公共好友和公众号"""
|
||||||
self._group_contacts = {}
|
self._group_contacts = {}
|
||||||
self._personal_contacts = {}
|
self._personal_contacts = {}
|
||||||
@@ -84,6 +87,9 @@ class ContactManager:
|
|||||||
# 判断是否为群组(wxid以@chatroom结尾)
|
# 判断是否为群组(wxid以@chatroom结尾)
|
||||||
elif wxid.endswith('@chatroom'):
|
elif wxid.endswith('@chatroom'):
|
||||||
self._group_contacts[wxid] = nickname
|
self._group_contacts[wxid] = nickname
|
||||||
|
# 如果是群,这处理群列表内容
|
||||||
|
self._group_contacts_friends[wxid] = wcf.get_chatroom_members(wxid)
|
||||||
|
|
||||||
# # 其他为普通好友和群成员
|
# # 其他为普通好友和群成员
|
||||||
# else:
|
# else:
|
||||||
# self._personal_contacts[wxid] = nickname
|
# self._personal_contacts[wxid] = nickname
|
||||||
@@ -147,6 +153,28 @@ class ContactManager:
|
|||||||
"""
|
"""
|
||||||
return self._contacts.get(wxid, wxid)
|
return self._contacts.get(wxid, wxid)
|
||||||
|
|
||||||
|
def get_group_name(self, roomid: str, wxid: str) -> str:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
roomid: 群ID
|
||||||
|
wxid: 微信ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
对应的昵称,如果不存在则返回wxid本身
|
||||||
|
"""
|
||||||
|
return self._group_contacts_friends.get(roomid, "").get(wxid, "未知昵称")
|
||||||
|
|
||||||
|
def get_group_members(self, roomid: str) -> Dict[str, str]:
|
||||||
|
"""获取指定群的成员列表
|
||||||
|
|
||||||
|
Args:
|
||||||
|
roomid: 群ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
群成员字典,格式为 {"wxid": "NickName"}
|
||||||
|
"""
|
||||||
|
return self._group_contacts_friends.get(roomid, {})
|
||||||
|
|
||||||
def update_contact(self, wxid: str, nickname: str) -> None:
|
def update_contact(self, wxid: str, nickname: str) -> None:
|
||||||
"""更新单个联系人信息
|
"""更新单个联系人信息
|
||||||
|
|
||||||
@@ -166,26 +194,28 @@ class ContactManager:
|
|||||||
self._personal_contacts[wxid] = nickname
|
self._personal_contacts[wxid] = nickname
|
||||||
self._logger.debug(f"已更新联系人: {wxid} -> {nickname}")
|
self._logger.debug(f"已更新联系人: {wxid} -> {nickname}")
|
||||||
|
|
||||||
def refresh_contacts(self, new_contacts: Dict[str, str], friends: List[Dict]) -> None:
|
def refresh_contacts(self, new_contacts: Dict[str, str], wcf: Wcf) -> None:
|
||||||
"""刷新联系人信息
|
"""刷新联系人信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
new_contacts: 新的联系人字典
|
new_contacts: 新的联系人字典
|
||||||
friends: 好友清单 contact = {
|
wcf :wcf
|
||||||
"wxid": cnt.get("wxid", ""),
|
|
||||||
"code": cnt.get("code", ""),
|
|
||||||
"remark": cnt.get("remark", ""),
|
|
||||||
"name": cnt.get("name", ""),
|
|
||||||
"country": cnt.get("country", ""),
|
|
||||||
"province": cnt.get("province", ""),
|
|
||||||
"city": cnt.get("city", ""),
|
|
||||||
"gender": gender}
|
|
||||||
"""
|
"""
|
||||||
self._contacts = new_contacts
|
self._contacts = new_contacts
|
||||||
self._friends = friends
|
# friends: 好友清单 contact = {
|
||||||
|
# "wxid": cnt.get("wxid", ""),
|
||||||
|
# "code": cnt.get("code", ""),
|
||||||
|
# "remark": cnt.get("remark", ""),
|
||||||
|
# "name": cnt.get("name", ""),
|
||||||
|
# "country": cnt.get("country", ""),
|
||||||
|
# "province": cnt.get("province", ""),
|
||||||
|
# "city": cnt.get("city", ""),
|
||||||
|
# "gender": gender}
|
||||||
|
self._friends = wcf.get_friends()
|
||||||
self._logger.info(f"联系人信息已刷新,共 {len(new_contacts)} 个联系人")
|
self._logger.info(f"联系人信息已刷新,共 {len(new_contacts)} 个联系人")
|
||||||
# 重新分类联系人
|
# 重新分类联系人
|
||||||
self._classify_contacts()
|
self._classify_contacts(wcf)
|
||||||
|
|
||||||
def get_contact_statistics(self) -> Tuple[int, int, int, int, int]:
|
def get_contact_statistics(self) -> Tuple[int, int, int, int, int]:
|
||||||
"""获取联系人统计信息
|
"""获取联系人统计信息
|
||||||
|
|||||||
Reference in New Issue
Block a user