This commit is contained in:
aaron 2025-03-30 12:08:07 +08:00
parent f843a4ceb1
commit c907b1518c
3 changed files with 178 additions and 23 deletions

View File

@ -18,6 +18,7 @@ from sqlalchemy.orm import Session
from app.core.response import error_response, success_response, ResponseModel
from pydantic import BaseModel
from app.models.wecom_external_chat import WecomExternalChatDB, WecomExternalChatInfo, WecomExternalChatMemberDB, WecomExternalChatMemberInfo
from datetime import datetime
router = APIRouter()
@ -133,27 +134,81 @@ async def wechat_corp_callback(
update_detail = msg_root.find('UpdateDetail').text
join_user_id = None
if update_detail == 'add_member' and msg_root.find('JoinScene') is not None:
quit_user_ids = []
# 处理成员加入事件
if update_detail == 'add_member':
logger.info(f"有新成员加入群聊")
# 获取加入的成员ID
join_user_id_elem = msg_root.find('JoinUserID')
if join_user_id_elem is not None:
join_user_id = join_user_id_elem.text
join_scene_elem = msg_root.find('JoinScene')
join_scene = int(join_scene_elem.text) if join_scene_elem is not None else 0
logger.info(f"加入场景: {join_scene}")
logger.info(f"chat_id: {chat_id}, change_type: {change_type}, update_detail: {update_detail}, join_user_id: {join_user_id}")
# 处理群聊变更事件
# 获取加入成员列表
mem_change_list = msg_root.find('MemChangeList')
if mem_change_list is not None:
for item in mem_change_list.findall('Item'):
join_user_id = item.text
if join_user_id:
logger.info(f"从MemChangeList中获取到新加入成员: {join_user_id}")
# 处理群聊变更事件 - 添加单个成员
await wecom_client.handle_chat_change_event(
chat_id=chat_id,
change_type=change_type,
update_detail=update_detail,
join_user_id=join_user_id
)
if update_detail == 'add_member' and join_user_id:
logger.info(f"发送欢迎消息到群聊:{chat_id}")
await wecom_client.send_welcome_message(chat_id)
# 兼容旧格式如果找不到MemChangeList尝试JoinUserID
elif msg_root.find('JoinUserID') is not None:
join_user_id = msg_root.find('JoinUserID').text
if join_user_id:
logger.info(f"从JoinUserID中获取到新加入成员: {join_user_id}")
# 处理群聊变更事件 - 添加单个成员
await wecom_client.handle_chat_change_event(
chat_id=chat_id,
change_type=change_type,
update_detail=update_detail,
join_user_id=join_user_id
)
logger.info(f"发送欢迎消息到群聊:{chat_id}")
await wecom_client.send_welcome_message(chat_id)
# 处理成员离开事件
elif update_detail == 'del_member':
logger.info(f"有成员离开群聊")
quit_scene_elem = msg_root.find('QuitScene')
quit_scene = int(quit_scene_elem.text) if quit_scene_elem is not None else 0
# 获取离开成员列表
mem_change_list = msg_root.find('MemChangeList')
if mem_change_list is not None:
for item in mem_change_list.findall('Item'):
quit_user_id = item.text
if quit_user_id:
quit_user_ids.append(quit_user_id)
# 处理成员离开
await wecom_client.handle_chat_change_event(
chat_id=chat_id,
change_type=change_type,
update_detail=update_detail,
join_user_id=quit_user_id # 复用这个参数名来表示离开的用户ID
)
logger.info(f"离开场景: {quit_scene}, 离开成员: {quit_user_ids}")
logger.info(f"chat_id: {chat_id}, change_type: {change_type}, update_detail: {update_detail}, join_user_id: {join_user_id}, quit_user_ids: {quit_user_ids}")
# 处理其他群聊变更事件不是add_member和del_member
if update_detail != 'add_member' and update_detail != 'del_member':
# 其他群聊变更事件
await wecom_client.handle_chat_change_event(
chat_id=chat_id,
change_type=change_type,
update_detail=update_detail
)
return Response(content="success", media_type="text/plain")
except Exception as e:
@ -307,6 +362,23 @@ async def chat_dashboard(
text-decoration: none;
}
.btn:hover { background-color: #286090; }
.stats {
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.stat-item {
display: inline-block;
margin-right: 30px;
font-size: 16px;
}
.stat-number {
font-size: 24px;
font-weight: bold;
color: #337ab7;
}
</style>
<script>
function loadMembers(chatId) {
@ -359,11 +431,49 @@ async def chat_dashboard(
alert('同步失败');
});
}
function getChatStats() {
fetch(`/api/wecom/chat-stats`)
.then(response => response.json())
.then(data => {
if (data.code === 0) {
const stats = data.data;
document.getElementById('total-chats').innerText = stats.total_chats;
document.getElementById('total-members').innerText = stats.total_members;
document.getElementById('active-chats').innerText = stats.active_chats;
} else {
console.error('获取统计数据失败:', data.message);
}
})
.catch(error => {
console.error('Error:', error);
});
}
// 页面加载完成后获取统计数据
window.onload = function() {
getChatStats();
};
</script>
</head>
<body>
<div class="container">
<h1>企业微信外部群聊信息</h1>
<div class="stats">
<div class="stat-item">
<div>总群聊数</div>
<div class="stat-number" id="total-chats">-</div>
</div>
<div class="stat-item">
<div>总成员数</div>
<div class="stat-number" id="total-members">-</div>
</div>
<div class="stat-item">
<div>活跃群聊数</div>
<div class="stat-number" id="active-chats">-</div>
</div>
</div>
"""
if not chats:
@ -393,3 +503,39 @@ async def chat_dashboard(
"""
return Response(content=html, media_type="text/html")
@router.get("/chat-stats", response_model=ResponseModel)
async def get_chat_stats(
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
"""获取企业微信外部群聊统计数据"""
try:
# 检查是否为管理员
if current_user.userid != settings.PLATFORM_USER_ID:
return error_response(code=403, message="权限不足")
# 计算统计数据
total_chats = db.query(WecomExternalChatDB).count()
active_chats = db.query(WecomExternalChatDB).filter(WecomExternalChatDB.is_active == True).count()
total_members = db.query(WecomExternalChatMemberDB).count()
# 获取今日新增成员数
today = datetime.now().date()
today_start = datetime.combine(today, datetime.min.time())
today_members = db.query(WecomExternalChatMemberDB).filter(
WecomExternalChatMemberDB.join_time >= today_start
).count()
# 返回统计数据
stats = {
"total_chats": total_chats,
"active_chats": active_chats,
"total_members": total_members,
"today_members": today_members
}
return success_response(message="获取统计数据成功", data=stats)
except Exception as e:
logger.exception("获取统计数据异常")
return error_response(code=500, message=f"获取统计数据失败: {str(e)}")

View File

@ -249,7 +249,7 @@ class WecomClient:
chat_id: 群聊ID
change_type: 变更类型 create/update/dismiss
update_detail: 变更详情 add_member/del_member/change_owner/change_name/change_notice
join_user_id: 加入的用户ID
join_user_id: 加入/离开的用户ID
Returns:
bool: 处理是否成功
@ -278,7 +278,7 @@ class WecomClient:
member_count=len(chat_info.get("member_list", [])),
notice=chat_info.get("notice")
)
chat_db = WecomExternalChatDB(**chat_create.dict())
chat_db = WecomExternalChatDB(**chat_create.model_dump())
db.add(chat_db)
db.commit()
@ -306,7 +306,7 @@ class WecomClient:
name=user_info.get("name") if user_info else None,
unionid=user_info.get("unionid") if user_info else None
)
member_db = WecomExternalChatMemberDB(**member_create.dict())
member_db = WecomExternalChatMemberDB(**member_create.model_dump())
db.add(member_db)
db.commit()
@ -330,7 +330,7 @@ class WecomClient:
member_count=len(chat_info.get("member_list", [])),
notice=chat_info.get("notice")
)
chat_db = WecomExternalChatDB(**chat_create.dict())
chat_db = WecomExternalChatDB(**chat_create.model_dump())
db.add(chat_db)
db.commit()
@ -354,7 +354,7 @@ class WecomClient:
name=user_info.get("name") if user_info else None,
unionid=user_info.get("unionid") if user_info else None
)
member_db = WecomExternalChatMemberDB(**member_create.dict())
member_db = WecomExternalChatMemberDB(**member_create.model_dump())
db.add(member_db)
db.commit()
@ -378,6 +378,8 @@ class WecomClient:
if not join_user_id:
return False
logger.info(f"处理成员离开群聊事件: 群ID={chat_id}, 成员ID={join_user_id}")
# 删除成员记录
member_db = db.query(WecomExternalChatMemberDB).filter(
WecomExternalChatMemberDB.chat_id == chat_id,
@ -385,14 +387,20 @@ class WecomClient:
).first()
if member_db:
logger.info(f"从数据库中删除成员记录: {member_db.user_id}, 姓名: {member_db.name}")
db.delete(member_db)
db.commit()
else:
logger.warning(f"未找到要删除的成员记录: chat_id={chat_id}, user_id={join_user_id}")
# 更新群成员数量
chat_db = db.query(WecomExternalChatDB).filter(WecomExternalChatDB.chat_id == chat_id).first()
if chat_db:
chat_db.member_count = max(0, chat_db.member_count - 1)
logger.info(f"更新群成员数量: {chat_db.member_count}")
db.commit()
else:
logger.warning(f"未找到群聊记录: chat_id={chat_id}")
return True
@ -403,6 +411,7 @@ class WecomClient:
if chat_db:
chat_db.is_active = False
db.commit()
logger.info(f"群聊解散: {chat_id}")
return True

Binary file not shown.