feat(chat): 聊天消息预览

This commit is contained in:
xingc
2025-05-15 22:48:58 +08:00
parent 7b86e482fb
commit 00ef8d8971
3 changed files with 72 additions and 25 deletions

View File

@@ -25,6 +25,11 @@ class Paginated(BaseModel, Generic[T]):
page_size: int = 15
class PaginatedCursor(Paginated):
cursor: int = None
next_page: bool = None,
class SupportPlatformType(enum.Enum):
PSA = 'psa'
BGS = 'bgs'

View File

@@ -34,7 +34,7 @@ chat_router = APIRouter(prefix='/chat', tags=['聊天模块'])
@chat_router.get(
'/all/', summary='获取所有聊天',
response_model=base_schema.BaseResponse[
base_schema.Paginated[
base_schema.PaginatedCursor[
List[schema.ChatUnreadOut]
]
]
@@ -72,6 +72,7 @@ async def get_all_chats(
return {
'data': {
'list': unread_messages_chats_count,
'next_page': (page * page_size) < total,
'total': total,
'page': page,
'page_size': page_size,
@@ -82,7 +83,7 @@ async def get_all_chats(
@chat_router.get(
'/{chat_guid}/messages/', summary='获取单个聊天的历史消息',
response_model=base_schema.BaseResponse[
base_schema.Paginated[
base_schema.PaginatedCursor[
List[schema.MessageOut]
]
]
@@ -111,14 +112,15 @@ async def get_single_chat_messages(
conditions
)
)
total = await db_session.execute(total_stmt)
total_result = await db_session.execute(total_stmt)
total = total_result.scalar()
# 分页记录查询
stmt = (
select(Message)
.where(conditions)
.order_by(Message.created_at.desc())
.limit(page_size).offset((page - 1) * page_size)
.options(selectinload(Message.user), selectinload(Message.chat))
.order_by(Message.id.desc()).
limit(page_size).offset((page - 1) * page_size)
)
records = await db_session.execute(stmt)
results = [
@@ -133,7 +135,9 @@ async def get_single_chat_messages(
return {
'data': {
'list': results,
'total': total.scalar(),
'cursor': results[-1].get('id'),
'next_page': (page * page_size) < total,
'total': total,
'page': page,
'page_size': page_size,
},
@@ -250,7 +254,7 @@ async def get_chat_websocket(
websocket.user_id = login_user.user_id
await socket_manager.add_user_socket_connection(user_id, websocket)
ratelimit = WebSocketRateLimiter(times=50, seconds=10, callback=websocket_callback)
ratelimit = WebSocketRateLimiter(times=30, seconds=10, callback=websocket_callback)
current_user = await CRUD(db_session, User).get(filters={'user_id': login_user.user_id})
if chats := await get_user_active_direct_chats(db_session, current_user=current_user):
for chat_guid in chats:

View File

@@ -41,16 +41,12 @@ async def get_user_active_direct_chats(
return None
async def get_unread_messages_per_chat(
db_session: AsyncSession, chats: list[Chat], login_user: LoginUser
) -> list[dict]:
"""获取聊天未读消息数"""
unread_messages_info_per_chat: dict[int, dict] = {chat.id: {'message_count': 0} for chat in chats}
async def get_chat_unread_messages_count(db_session: AsyncSession, login_user: LoginUser, chats):
"""查询未读消息的预览"""
# 查询消息情况
read_status_alias = aliased(ReadStatus)
query = (
select(Message.id, Message.chat_id, Message.content, Message.message_type, func.count().label("message_count"))
select(Message.chat_id, func.count().label("message_count"))
.join(
read_status_alias,
and_(read_status_alias.user_id == login_user.user_id, read_status_alias.chat_id == Message.chat_id),
@@ -59,29 +55,71 @@ async def get_unread_messages_per_chat(
and_(
Message.user_id != login_user.user_id,
Message.id > func.coalesce(read_status_alias.last_read_message_id, 0),
Message.chat_id.in_(unread_messages_info_per_chat),
Message.chat_id.in_(chats),
)
)
.order_by(Message.created_at.desc())
.group_by(Message.chat_id)
)
result = await db_session.execute(query)
unread_messages_info = result.fetchall()
return unread_messages_info
for messages_info in unread_messages_info:
unread_messages_info_per_chat[messages_info[1]] = {
'message': {
'id': messages_info[0],
'message_type': messages_info[3],
'content': messages_info[2],
},
'message_count': messages_info[4],
async def get_chat_messages_preview(db_session: AsyncSession, chats):
"""查询未读消息的预览"""
latest_subquery = (
select(
Message.chat_id,
func.max(Message.created_at).label("max_created")
)
.group_by(Message.chat_id)
.subquery()
)
LatestMessage = aliased(Message)
query = (
select(LatestMessage)
.join(latest_subquery,
(LatestMessage.chat_id == latest_subquery.c.chat_id) &
(LatestMessage.created_at == latest_subquery.c.max_created))
)
result = await db_session.execute(query)
unread_messages_info = result.scalars().all()
return unread_messages_info
async def get_unread_messages_per_chat(
db_session: AsyncSession, chats: list[Chat], login_user: LoginUser
) -> list[dict]:
"""获取聊天未读消息数和消息预览"""
messages_info_per_chat: dict[int, dict] = {chat.id: {'message_count': 0} for chat in chats}
# 未读消息数和预览
unread_messages_count = await get_chat_unread_messages_count(
db_session, login_user, messages_info_per_chat
)
for messages_info in unread_messages_count:
messages_info_per_chat[messages_info[0]] = {
'message_count': messages_info[1],
}
# 已读消息预览
no_unread_message_chats = [
chat_id
for chat_id, message_info in messages_info_per_chat.items() if message_info.get('message') is None
]
messages_info = await get_chat_messages_preview(db_session, no_unread_message_chats)
for message_info in messages_info:
messages_info_per_chat[message_info.chat_id].update({
'message': message_info
})
results = []
for chat in chats:
users = [user for user in await chat.awaitable_attrs.users if user.user_id != login_user.user_id]
messages_info = unread_messages_info_per_chat[chat.id]
messages_info = messages_info_per_chat[chat.id]
results.append(dict(
chat_guid=chat.guid,
created_at=format_date(chat.created_at),