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:
2026-04-01 16:11:02 +08:00
parent e14e3ee7a5
commit 7013e9db70
27 changed files with 2753 additions and 276 deletions

View File

@@ -662,19 +662,22 @@
</div>
</div>
<div class="mb-2">
<small class="text-white-50">当前状态: <span id="agent-current-state">空闲</span></small>
</div>
<div class="mb-2">
<small class="text-white-50">活跃目标: <span id="agent-active-goals">0</span></small>
<small class="text-white-50">运行状态: <span id="agent-current-state" class="badge bg-success">active</span></small>
</div>
<div class="mb-2">
<small class="text-white-50">可用工具: <span id="agent-available-tools">0</span></small>
</div>
<div class="mb-2">
<small class="text-white-50">最大工具轮次: <span id="agent-max-rounds">5</span></small>
</div>
<div class="mb-2">
<small class="text-white-50">执行历史: <span id="agent-history-count">0</span></small>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<h5><i class="fas fa-tools me-2"></i>工具管理</h5>
<h5><i class="fas fa-tools me-2"></i>ReAct 工具列表</h5>
</div>
<div class="card-body">
<div id="tools-list">
@@ -684,23 +687,6 @@
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5><i class="fas fa-plus me-2"></i>添加自定义工具</h5>
</div>
<div class="card-body">
<div class="mb-3">
<input type="text" class="form-control" id="tool-name" placeholder="工具名称">
</div>
<div class="mb-3">
<textarea class="form-control" id="tool-description" rows="3" placeholder="工具描述"></textarea>
</div>
<button class="btn btn-primary w-100" id="register-tool">
<i class="fas fa-plus me-1"></i>注册工具
</button>
</div>
</div>
</div>
<div class="col-md-8">
@@ -892,22 +878,27 @@
<!-- 知识库标签页 -->
<div id="knowledge-tab" class="tab-content" style="display: none;">
<!-- 面包屑导航 -->
<div id="knowledge-breadcrumb" class="mb-3"></div>
<div class="row mb-4">
<div class="col-md-8">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="fas fa-database me-2"></i>知识库管理</h5>
<div class="btn-group">
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addKnowledgeModal">
<div class="btn-group" id="knowledge-action-buttons">
<button class="btn btn-outline-secondary btn-sm" id="knowledge-refresh-btn" onclick="dashboard.refreshKnowledge()">
<i class="fas fa-sync-alt me-1"></i>刷新
</button>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addKnowledgeModal" style="display:none" id="knowledge-add-btn">
<i class="fas fa-plus me-1"></i>添加知识
</button>
<button class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#uploadFileModal">
<button class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#uploadFileModal" style="display:none" id="knowledge-upload-btn">
<i class="fas fa-upload me-1"></i>上传文件
</button>
</div>
</div>
<div class="card-body">
<div class="mb-3">
<div class="mb-3" id="knowledge-search-bar" style="display:none">
<div class="input-group">
<input type="text" class="form-control" id="knowledge-search" placeholder="搜索知识库...">
<button class="btn btn-outline-secondary" id="search-knowledge">
@@ -915,13 +906,26 @@
</button>
</div>
</div>
<div id="knowledge-list">
<!-- 租户卡片列表容器 -->
<div id="knowledge-tenant-list" class="row">
<div class="loading-spinner">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<div id="knowledge-pagination" class="mt-3">
<!-- 分页控件将在这里显示 -->
<!-- 租户详情容器 -->
<div id="knowledge-tenant-detail" style="display:none">
<div class="d-flex gap-2 mb-3" id="knowledge-filter-bar">
<select class="form-select form-select-sm" id="knowledge-category-filter" style="width:auto" onchange="dashboard.applyKnowledgeFilters()">
<option value="">全部分类</option>
</select>
<select class="form-select form-select-sm" id="knowledge-verified-filter" style="width:auto" onchange="dashboard.applyKnowledgeFilters()">
<option value="">全部状态</option>
<option value="true">已验证</option>
<option value="false">未验证</option>
</select>
</div>
<div id="knowledge-list"></div>
<div id="knowledge-pagination" class="mt-3"></div>
</div>
</div>
</div>
@@ -943,7 +947,7 @@
<div class="mb-3">
<small class="text-muted">平均置信度</small>
<div class="progress">
<div class="progress-bar" id="knowledge-confidence" role="progressbar" style="width: 0%"></div>
<div class="progress-bar" id="knowledge-confidence-bar" role="progressbar" style="width: 0%"></div>
</div>
</div>
</div>
@@ -1252,6 +1256,8 @@
<!-- 对话历史标签页 -->
<div id="conversation-history-tab" class="tab-content" style="display: none;">
<!-- 面包屑导航 -->
<div id="conversation-breadcrumb" class="mb-3"></div>
<div class="row mb-4">
<div class="col-md-8">
<div class="card">
@@ -1267,38 +1273,40 @@
</div>
</div>
<div class="card-body">
<div class="mb-3">
<div class="row">
<div class="col-md-4">
<input type="text" class="form-control" id="conversation-search" placeholder="搜索对话内容...">
</div>
<div class="col-md-3">
<select class="form-select" id="conversation-user-filter">
<option value="">全部用户</option>
</select>
</div>
<div class="col-md-3">
<select class="form-select" id="conversation-date-filter">
<option value="">全部时间</option>
<option value="today">今天</option>
<option value="week">本周</option>
<option value="month">本月</option>
</select>
</div>
<div class="col-md-2">
<button class="btn btn-outline-secondary w-100" onclick="dashboard.filterConversations()">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</div>
<div id="conversation-list">
<!-- 租户卡片列表容器 -->
<div id="conversation-tenant-list" class="row">
<div class="loading-spinner">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<div id="conversations-pagination" class="mt-3">
<!-- 分页控件将在这里显示 -->
<!-- 租户详情容器 -->
<div id="conversation-tenant-detail" style="display:none">
<div class="d-flex gap-2 mb-3">
<select class="form-select form-select-sm" id="conversation-status-filter" style="width:auto" onchange="dashboard.loadConversationTenantDetail(dashboard.conversationCurrentTenantId)">
<option value="">全部</option>
<option value="active">活跃</option>
<option value="ended">已结束</option>
</select>
<select class="form-select form-select-sm" id="conversation-detail-date-filter" style="width:auto" onchange="dashboard.loadConversationTenantDetail(dashboard.conversationCurrentTenantId)">
<option value="">全部时间</option>
<option value="today">今天</option>
<option value="week">本周</option>
<option value="month">本月</option>
</select>
<div class="input-group input-group-sm" style="width:auto">
<input type="text" class="form-control" id="conversation-search" placeholder="搜索会话...">
<button class="btn btn-outline-secondary" onclick="dashboard.filterConversations()">
<i class="fas fa-search"></i>
</button>
</div>
</div>
<div id="conversation-session-list"></div>
<div id="conversation-session-pagination" class="mt-3"></div>
</div>
<!-- 保留原有容器用于向后兼容 -->
<div id="conversation-list" style="display:none">
</div>
<div id="conversations-pagination" class="mt-3" style="display:none">
</div>
</div>
</div>
@@ -2085,6 +2093,21 @@
<!-- 系统信息显示 -->
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header">
<h5><i class="fas fa-building me-2"></i>租户与模型信息</h5>
</div>
<div class="card-body">
<table class="table table-sm mb-0">
<tr><td class="text-muted" style="width:40%">租户ID</td><td id="setting-tenant-id">-</td></tr>
<tr><td class="text-muted">LLM Provider</td><td id="setting-llm-provider">-</td></tr>
<tr><td class="text-muted">LLM Model</td><td id="setting-llm-model">-</td></tr>
<tr><td class="text-muted">LLM Base URL</td><td id="setting-llm-base-url" style="word-break:break-all">-</td></tr>
<tr><td class="text-muted">Embedding</td><td id="setting-embedding-status">-</td></tr>
<tr><td class="text-muted">Redis</td><td id="setting-redis-status">-</td></tr>
</table>
</div>
</div>
<div class="card">
<div class="card-header">
<h5><i class="fas fa-info-circle me-2"></i><span data-i18n="settings-system-info">系统信息</span></h5>