feat: revamp contacts chat workspace
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
import threading
|
||||
import xml.etree.ElementTree as ET
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from flask import Blueprint, render_template, jsonify, request, current_app
|
||||
from .auth import login_required
|
||||
@@ -64,6 +65,96 @@ def run_member_context_refresh_in_thread(func, *args, **kwargs):
|
||||
message_thread_pool.submit(run)
|
||||
|
||||
|
||||
def _safe_text(value):
|
||||
return "" if value is None else str(value)
|
||||
|
||||
|
||||
def _parse_app_message_payload(content: str):
|
||||
payload = {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"url": "",
|
||||
"app_type": ""
|
||||
}
|
||||
if not content:
|
||||
return payload
|
||||
|
||||
text = _safe_text(content).strip()
|
||||
if not text.startswith("<"):
|
||||
payload["description"] = text
|
||||
return payload
|
||||
|
||||
try:
|
||||
root = ET.fromstring(text)
|
||||
payload["title"] = _safe_text(root.findtext('.//title')).strip()
|
||||
payload["description"] = _safe_text(root.findtext('.//des')).strip()
|
||||
payload["url"] = _safe_text(root.findtext('.//url')).strip()
|
||||
payload["app_type"] = _safe_text(root.findtext('.//type')).strip()
|
||||
except Exception:
|
||||
payload["description"] = text
|
||||
return payload
|
||||
|
||||
|
||||
def _normalize_recent_message(server, raw_message: dict, chat_type: str, target_wxid: str):
|
||||
sender = _safe_text(raw_message.get("sender")).strip()
|
||||
message_type = str(raw_message.get("message_type", ""))
|
||||
content = _safe_text(raw_message.get("content")).strip()
|
||||
image_path = _safe_text(raw_message.get("image_path")).strip()
|
||||
attachment_url = _safe_text(raw_message.get("attachment_url")).strip()
|
||||
message_thumb = _safe_text(raw_message.get("message_thumb")).strip()
|
||||
self_wxid = _safe_text(getattr(server.robot, "wxid", "") or getattr(server.client, "wxid", "")).strip()
|
||||
|
||||
sender_name = sender or "未知发送者"
|
||||
if chat_type == "group":
|
||||
sender_name = server.contact_manager.get_group_name(target_wxid, sender) or sender_name
|
||||
elif sender:
|
||||
sender_name = server.contact_manager.get_nickname(sender) or sender_name
|
||||
|
||||
display_type = "text"
|
||||
display_content = content
|
||||
media_url = image_path or attachment_url or message_thumb
|
||||
link_payload = None
|
||||
|
||||
if message_type == "3":
|
||||
display_type = "image"
|
||||
display_content = content or "[图片]"
|
||||
elif message_type == "34":
|
||||
display_type = "voice"
|
||||
display_content = content or "[语音]"
|
||||
elif message_type == "43":
|
||||
display_type = "video"
|
||||
display_content = content or "[视频]"
|
||||
elif message_type == "49":
|
||||
app_payload = _parse_app_message_payload(content)
|
||||
if app_payload.get("url") or app_payload.get("title"):
|
||||
display_type = "link"
|
||||
link_payload = app_payload
|
||||
display_content = app_payload.get("title") or app_payload.get("description") or "[链接]"
|
||||
else:
|
||||
display_type = "text"
|
||||
display_content = app_payload.get("description") or content or "[应用消息]"
|
||||
elif message_type in {"10000", "10002"}:
|
||||
display_type = "system"
|
||||
display_content = content or "[系统消息]"
|
||||
|
||||
return {
|
||||
"timestamp": _safe_text(raw_message.get("timestamp")),
|
||||
"sender": sender,
|
||||
"sender_name": sender_name,
|
||||
"content": content,
|
||||
"message_type": message_type,
|
||||
"display_type": display_type,
|
||||
"display_content": display_content,
|
||||
"image_path": image_path,
|
||||
"attachment_url": attachment_url,
|
||||
"media_url": media_url,
|
||||
"message_thumb": message_thumb,
|
||||
"message_id": raw_message.get("message_id"),
|
||||
"link_payload": link_payload,
|
||||
"is_self": bool(self_wxid and sender == self_wxid)
|
||||
}
|
||||
|
||||
|
||||
# 联系人管理页面
|
||||
@contacts_bp.route('/')
|
||||
@login_required
|
||||
@@ -320,6 +411,44 @@ def api_contacts_update():
|
||||
return jsonify({"success": False, "message": f"更新通讯录失败: {str(e)}"}), 500
|
||||
|
||||
|
||||
@contacts_bp.route('/api/recent_messages', methods=['GET'])
|
||||
@login_required
|
||||
def api_recent_messages():
|
||||
"""获取最近聊天消息"""
|
||||
try:
|
||||
server = current_app.dashboard_server
|
||||
wxid = _safe_text(request.args.get("wxid")).strip()
|
||||
chat_type = _safe_text(request.args.get("chat_type")).strip() or "personal"
|
||||
limit = min(max(int(request.args.get("limit", 20)), 1), 50)
|
||||
|
||||
if not wxid:
|
||||
return jsonify({"success": False, "message": "缺少聊天对象"}), 400
|
||||
|
||||
if chat_type == "group":
|
||||
raw_messages = server.message_storage.get_recent_group_chat_messages(wxid, limit=limit)
|
||||
history_tip = f"最近 {limit} 条群消息"
|
||||
else:
|
||||
raw_messages = server.message_storage.get_recent_personal_messages(wxid, limit=limit)
|
||||
history_tip = f"最近 {limit} 条已归档消息(私聊历史可能不完整)"
|
||||
|
||||
messages = [
|
||||
_normalize_recent_message(server, item, chat_type, wxid)
|
||||
for item in raw_messages
|
||||
]
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"data": {
|
||||
"messages": messages,
|
||||
"chat_type": chat_type,
|
||||
"history_tip": history_tip
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.exception(f"获取最近聊天消息失败: {e}")
|
||||
return jsonify({"success": False, "message": str(e)}), 500
|
||||
|
||||
|
||||
@contacts_bp.route('/api/send_message', methods=['POST'])
|
||||
@login_required
|
||||
def api_send_message():
|
||||
|
||||
Reference in New Issue
Block a user