feat: 对话历史页面租户分组展示功能
- 新增 ConversationHistoryManager.get_tenant_summary() 按租户聚合会话统计 - get_sessions_paginated() 和 get_conversation_analytics() 增加 tenant_id 过滤 - 新增 GET /api/conversations/tenants 租户汇总端点 - sessions 和 analytics API 端点支持 tenant_id 查询参数 - 前端实现租户卡片列表视图和租户详情会话表格视图 - 实现面包屑导航、搜索范围限定、统计面板上下文切换 - 会话删除后自动检测空租户并返回列表视图 - dashboard.html 添加租户视图 DOM 容器 - 交互模式与知识库租户分组视图保持一致
This commit is contained in:
@@ -14,7 +14,7 @@ from ..core.database import db_manager
|
||||
from ..core.models import Conversation, WorkOrder, WorkOrderSuggestion, KnowledgeEntry, ChatSession
|
||||
from ..core.redis_manager import redis_manager
|
||||
from src.config.unified_config import get_config
|
||||
from sqlalchemy import and_, or_, desc
|
||||
from sqlalchemy import and_, or_, desc, func, case
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -634,7 +634,8 @@ class ConversationHistoryManager:
|
||||
def get_conversation_analytics(
|
||||
self,
|
||||
work_order_id: Optional[int] = None,
|
||||
days: int = 7
|
||||
days: int = 7,
|
||||
tenant_id: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""获取对话分析数据(包含AI建议统计)"""
|
||||
try:
|
||||
@@ -652,6 +653,8 @@ class ConversationHistoryManager:
|
||||
conv_query = session.query(Conversation)
|
||||
if work_order_id:
|
||||
conv_query = conv_query.filter(Conversation.work_order_id == work_order_id)
|
||||
if tenant_id is not None:
|
||||
conv_query = conv_query.filter(Conversation.tenant_id == tenant_id)
|
||||
|
||||
conversations = conv_query.filter(
|
||||
Conversation.timestamp >= cutoff_date
|
||||
@@ -718,6 +721,49 @@ class ConversationHistoryManager:
|
||||
logger.error(f"获取对话分析数据失败: {e}")
|
||||
return {}
|
||||
|
||||
# ==================== 租户汇总方法 ====================
|
||||
|
||||
def get_tenant_summary(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
按 tenant_id 聚合 ChatSession,返回租户汇总列表。
|
||||
按 last_active_time 降序排列。
|
||||
数据库异常或无记录时返回空列表。
|
||||
"""
|
||||
try:
|
||||
with db_manager.get_session() as session:
|
||||
results = session.query(
|
||||
ChatSession.tenant_id,
|
||||
func.count(ChatSession.id).label('session_count'),
|
||||
func.coalesce(func.sum(ChatSession.message_count), 0).label('message_count'),
|
||||
func.sum(
|
||||
case(
|
||||
(ChatSession.status == 'active', 1),
|
||||
else_=0
|
||||
)
|
||||
).label('active_session_count'),
|
||||
func.max(ChatSession.updated_at).label('last_active_time')
|
||||
).group_by(
|
||||
ChatSession.tenant_id
|
||||
).order_by(
|
||||
desc('last_active_time')
|
||||
).all()
|
||||
|
||||
summary = []
|
||||
for row in results:
|
||||
summary.append({
|
||||
'tenant_id': row.tenant_id,
|
||||
'session_count': row.session_count,
|
||||
'message_count': int(row.message_count),
|
||||
'active_session_count': int(row.active_session_count),
|
||||
'last_active_time': row.last_active_time.isoformat() if row.last_active_time else None
|
||||
})
|
||||
|
||||
return summary
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取租户汇总失败: {e}")
|
||||
return []
|
||||
|
||||
# ==================== 会话管理方法 ====================
|
||||
|
||||
def get_sessions_paginated(
|
||||
@@ -726,13 +772,17 @@ class ConversationHistoryManager:
|
||||
per_page: int = 20,
|
||||
status: Optional[str] = None,
|
||||
search: str = '',
|
||||
date_filter: str = ''
|
||||
date_filter: str = '',
|
||||
tenant_id: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""分页获取会话列表"""
|
||||
try:
|
||||
with db_manager.get_session() as session:
|
||||
query = session.query(ChatSession)
|
||||
|
||||
if tenant_id is not None:
|
||||
query = query.filter(ChatSession.tenant_id == tenant_id)
|
||||
|
||||
if status:
|
||||
query = query.filter(ChatSession.status == status)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user