feat: 2026-07-11 全量更新 - 代办集成+会议室预定+知识迭代修复+UI统一+Bug修复
== 已部署上线 (9项) == - 代办事项真实数据源集成 (企微审批API 8bug修复链) - H5/坐席端 Logo样式统一+绿色背景 - 视频引导页修复 (localStorage key v2) - 坐席端 v9 Vue版本修复 (ElMessage._context) - 截图按钮 v10 修复 (getDisplayMedia user gesture) - 扫码样式恢复+H5扫码登录跳转修复 - H5截图快捷键提示 == 代码完成待部署 (3项) == - 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查) - 会议室预定-小鱼易联终端 (40文件, 40/40测试通过) - IT资产升级审批推送 (asset_service.py) == 需求文档 (2项) == - 坐席端AI辅助消息框-PRD (4项新功能确认) - 坐席端布局优化建议 v2.0 (7天计划) == 新增文档 == - 日报-2026-07-11.md - 知识迭代Bug修复报告-20260711.md - 会议室预定-部署指南.md - CHANGELOG.md 更新 == 测试 == - test_todo_integration.py: 40/40 - test_meetingroom.py: 40/40 - test_bugfix_ki_suggestions.py: 21/21
This commit is contained in:
+42
-10
@@ -36,6 +36,7 @@ from app.api.agents import get_current_agent
|
||||
from app.dependencies import require_permission, get_current_user, UserInfo
|
||||
|
||||
from app.services.ws_manager import manager
|
||||
from app.services.session_service import SessionService
|
||||
from app.utils.response import AppException, ERR_CONVERSATION_NOT_FOUND, ERR_CONVERSATION_RESOLVED, success_response
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -43,6 +44,37 @@ logger = logging.getLogger(__name__)
|
||||
# 创建路由器
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
async def _enrich_message_with_avatar(msg_dict: dict, db: AsyncSession) -> dict:
|
||||
"""为消息字典补充 sender_avatar 字段。
|
||||
|
||||
根据 sender_type 决定头像来源:
|
||||
- ai: 使用静态 /duckula.webp
|
||||
- employee: 从 SessionService 获取员工头像
|
||||
- agent: 暂用占位符(坐席头像功能待实现)
|
||||
"""
|
||||
sender_type = msg_dict.get("sender_type", "")
|
||||
sender_id = msg_dict.get("sender_id", "")
|
||||
|
||||
if sender_type == "ai":
|
||||
msg_dict["sender_avatar"] = "/duckula.webp"
|
||||
elif sender_type == "employee" and sender_id:
|
||||
try:
|
||||
session_svc = SessionService(db=db)
|
||||
avatar_url = await session_svc._get_employee_avatar(sender_id)
|
||||
msg_dict["sender_avatar"] = avatar_url
|
||||
except Exception as e:
|
||||
logger.warning(f"获取员工头像失败: employee_id={sender_id}, error={e}")
|
||||
msg_dict["sender_avatar"] = ""
|
||||
elif sender_type == "agent":
|
||||
# 坐席头像暂用默认头像
|
||||
msg_dict["sender_avatar"] = ""
|
||||
else:
|
||||
msg_dict["sender_avatar"] = ""
|
||||
|
||||
return msg_dict
|
||||
|
||||
|
||||
# 文件大小限制:10MB
|
||||
MAX_FILE_SIZE = 10 * 1024 * 1024
|
||||
|
||||
@@ -122,8 +154,8 @@ async def list_messages(
|
||||
msg.is_read = True
|
||||
await db.flush()
|
||||
|
||||
# 转换为响应格式
|
||||
items = [MessageResponse.model_validate(m).model_dump() for m in messages]
|
||||
# 转换为响应格式(补充发送者头像)
|
||||
items = [await _enrich_message_with_avatar(MessageResponse.model_validate(m).model_dump(), db) for m in messages]
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
@@ -241,8 +273,8 @@ async def send_message(
|
||||
# 做什么:构建 new_message 事件,推送给会话的员工
|
||||
# 为什么:实现双通道推送(企微消息 + WebSocket),H5 用户可以实时收到消息
|
||||
try:
|
||||
# 构建消息载荷
|
||||
msg_payload = MessageResponse.model_validate(message).model_dump()
|
||||
# 构建消息载荷(补充发送者头像)
|
||||
msg_payload = await _enrich_message_with_avatar(MessageResponse.model_validate(message).model_dump(), db)
|
||||
msg_payload["message_id"] = msg_payload["id"]
|
||||
|
||||
# 构建 WebSocket 事件
|
||||
@@ -258,8 +290,8 @@ async def send_message(
|
||||
# WebSocket 推送失败不阻塞响应(员工可能未打开H5页面)
|
||||
logger.warning(f"WebSocket消息推送失败(H5用户可能不在线): {e}")
|
||||
|
||||
# 转换为响应格式
|
||||
response_data = MessageResponse.model_validate(message).model_dump()
|
||||
# 转换为响应格式(补充发送者头像)
|
||||
response_data = await _enrich_message_with_avatar(MessageResponse.model_validate(message).model_dump(), db)
|
||||
return success_response(data=response_data)
|
||||
|
||||
|
||||
@@ -316,8 +348,8 @@ async def poll_messages(
|
||||
msg.is_read = True
|
||||
await db.flush()
|
||||
|
||||
# 转换为响应格式
|
||||
items = [MessageResponse.model_validate(m).model_dump() for m in messages]
|
||||
# 转换为响应格式(补充发送者头像)
|
||||
items = [await _enrich_message_with_avatar(MessageResponse.model_validate(m).model_dump(), db) for m in messages]
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
@@ -669,8 +701,8 @@ async def search_messages(
|
||||
result = await db.execute(stmt)
|
||||
messages = list(result.scalars().all())
|
||||
|
||||
# 转换为响应格式
|
||||
items = [MessageResponse.model_validate(m).model_dump() for m in messages]
|
||||
# 转换为响应格式(补充发送者头像)
|
||||
items = [await _enrich_message_with_avatar(MessageResponse.model_validate(m).model_dump(), db) for m in messages]
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
|
||||
Reference in New Issue
Block a user