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

@@ -0,0 +1,142 @@
# Implementation Plan: 对话历史租户分组展示 (conversation-tenant-view)
## Overview
将对话历史页面从扁平会话列表改造为两层结构:第一层按 `tenant_id` 分组展示租户汇总卡片,第二层展示租户下的会话列表。改造涉及 ConversationHistoryManager 业务逻辑层、Flask API 层、前端 dashboard.js 三个层面。交互模式与知识库租户分组视图保持一致。
## Tasks
- [x] 1. ConversationHistoryManager 新增 get_tenant_summary 方法
- [x] 1.1 在 `src/dialogue/conversation_history.py` 中新增 `get_tenant_summary()` 方法
- 使用 SQLAlchemy `GROUP BY ChatSession.tenant_id` 聚合所有 ChatSession 记录
- 计算每个租户的 `session_count`(会话总数)、`message_count`消息总数sum of message_count`active_session_count`status=='active' 的会话数)、`last_active_time`max of updated_at
-`last_active_time` 降序排列
- 数据库异常时返回空列表 `[]`,记录 error 日志
- 无 ChatSession 记录时返回空列表 `[]`
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6_
- [ ]* 1.2 为 get_tenant_summary 编写属性测试
- **Property 1: Tenant summary aggregation correctness**
- **Property 2: Tenant summary sorted by last_active_time descending**
- 使用 `hypothesis` 生成随机 ChatSession 列表(混合 tenant_id、status、message_count验证聚合正确性和排序
- **Validates: Requirements 1.1, 1.2, 1.3, 1.4, 1.5**
- [x] 2. ConversationHistoryManager 现有方法增加 tenant_id 过滤
- [x] 2.1 为 `get_sessions_paginated()` 增加 `tenant_id` 可选参数
-`src/dialogue/conversation_history.py` 中修改方法签名,增加 `tenant_id: Optional[str] = None`
-`tenant_id` 不为 None 时,在查询中增加 `ChatSession.tenant_id == tenant_id` 过滤条件
- 返回结构不变,仅过滤范围缩小
- _Requirements: 2.1, 2.2, 2.3, 2.5_
- [ ]* 2.2 为 get_sessions_paginated 的 tenant_id 过滤编写属性测试
- **Property 3: Session filtering by tenant, status, and search**
- **Property 4: Pagination consistency with tenant filter**
- **Validates: Requirements 2.1, 2.2, 2.3**
- [x] 2.3 为 `get_conversation_analytics()` 增加 `tenant_id` 可选参数
-`tenant_id` 不为 None 时,所有统计查询增加 `ChatSession.tenant_id == tenant_id``Conversation.tenant_id == tenant_id` 过滤
- 返回结构不变
- _Requirements: 8.3, 8.4_
- [ ]* 2.4 为 get_conversation_analytics 的 tenant_id 过滤编写属性测试
- **Property 7: Analytics scoped to tenant**
- **Validates: Requirements 8.3, 8.4**
- [x] 3. Checkpoint - 确保后端业务逻辑层完成
- Ensure all tests pass, ask the user if questions arise.
- [x] 4. Conversations API 层新增和修改端点
- [x] 4.1 在 `src/web/blueprints/conversations.py` 中新增 `GET /api/conversations/tenants` 端点
- 调用 `history_manager.get_tenant_summary()` 返回租户汇总 JSON 数组
- 使用 try/except 包裹,异常时返回 HTTP 500
- _Requirements: 1.1, 1.5, 1.6, 1.7_
- [x] 4.2 修改 `GET /api/conversations/sessions` 端点,增加 `tenant_id` 查询参数支持
-`request.args` 获取 `tenant_id` 参数,传递给 `history_manager.get_sessions_paginated()`
- _Requirements: 2.1, 2.2, 2.3, 2.4_
- [x] 4.3 修改 `GET /api/conversations/analytics` 端点,增加 `tenant_id` 查询参数支持
-`request.args` 获取 `tenant_id` 参数,传递给 `history_manager.get_conversation_analytics()`
- _Requirements: 8.3, 8.4_
- [ ]* 4.4 为新增和修改的 API 端点编写单元测试
- 测试 `/api/conversations/tenants` 返回正确的汇总数据
- 测试各端点的 `tenant_id` 参数过滤行为
- 测试空数据和异常情况
- _Requirements: 1.1, 1.6, 1.7, 2.4_
- [x] 5. Checkpoint - 确保后端 API 层完成
- Ensure all tests pass, ask the user if questions arise.
- [x] 6. 前端 Tenant_List_View租户列表视图
- [x] 6.1 在 `src/web/static/js/dashboard.js` 中实现 `loadConversationTenantList()` 函数
- 请求 `GET /api/conversations/tenants` 获取租户汇总数据
- 渲染租户卡片列表,每张卡片展示 `tenant_id``session_count``message_count``active_session_count``last_active_time`
- 添加加载中 spinner 状态
- 无租户时展示空状态占位提示
- 卡片点击事件绑定,调用 `loadConversationTenantDetail(tenantId)`
- _Requirements: 3.1, 3.2, 3.3, 3.4_
- [x] 6.2 实现刷新按钮功能
- 在对话历史 tab 区域添加刷新按钮,点击时重新调用 `loadConversationTenantList()`
- _Requirements: 3.5_
- [x] 7. 前端 Tenant_Detail_View租户详情视图
- [x] 7.1 实现 `loadConversationTenantDetail(tenantId, page)` 函数
- 请求 `GET /api/conversations/sessions?tenant_id=X&page=P&per_page=N` 获取会话列表
- 渲染会话表格,展示 title、message_count、status、source、created_at、updated_at
- 实现分页控件
- 支持 status 和 date_filter 筛选
- _Requirements: 4.1, 4.2, 4.5, 4.6_
- [x] 7.2 实现面包屑导航 `renderConversationBreadcrumb(tenantId, sessionTitle)`
- 展示 "对话历史 > {tenant_id}" 面包屑(租户详情视图)
- 展示 "对话历史 > {tenant_id} > {session_title}" 面包屑(消息详情视图)
- 点击 "对话历史" 链接时调用 `loadConversationTenantList()` 返回租户列表视图
- 点击 "{tenant_id}" 链接时调用 `loadConversationTenantDetail(tenantId)` 返回租户详情视图
- 管理 `conversationCurrentTenantId` 状态变量控制视图层级
- _Requirements: 4.3, 4.4, 5.3, 5.4_
- [x] 7.3 在 Tenant_Detail_View 中集成会话管理操作
- 每行会话提供删除按钮,调用 `DELETE /api/conversations/sessions/<session_id>`
- 删除成功后刷新当前租户详情视图
- 删除所有会话后自动返回租户列表视图并移除空租户卡片
- 操作失败时通过 `showNotification` 展示错误提示
- _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5_
- [ ]* 7.4 为删除操作编写属性测试
- **Property 5: Session deletion removes session and all associated messages**
- **Validates: Requirements 6.2**
- [x] 8. 前端搜索和统计面板适配
- [x] 8.1 修改搜索功能 `searchConversationSessions()`
- 在 Tenant_Detail_View 中搜索时自动附加 `tenant_id` 参数
- 清空搜索时恢复当前租户的完整分页列表
- _Requirements: 7.1, 7.2, 7.3_
- [ ]* 8.2 为搜索范围限定编写属性测试
- **Property 6: Search results scoped to tenant**
- **Validates: Requirements 7.1, 7.2**
- [x] 8.3 修改 `loadConversationStats(tenantId)` 函数
-`conversationCurrentTenantId` 为 null 时请求全局统计
-`conversationCurrentTenantId` 有值时请求 `GET /api/conversations/analytics?tenant_id=X`
- _Requirements: 8.1, 8.2_
- [x] 9. 前端 HTML 模板更新
- [x] 9.1 在 `src/web/templates/dashboard.html``#conversation-history-tab` 区域添加必要的 DOM 容器
- 添加面包屑容器、租户卡片列表容器、租户详情容器
- 确保与现有 Bootstrap 5 样式一致,与知识库租户视图风格统一
- _Requirements: 3.1, 4.3_
- [x] 10. Final checkpoint - 确保所有功能集成完成
- Ensure all tests pass, ask the user if questions arise.
## Notes
- Tasks marked with `*` are optional and can be skipped for faster MVP
- Each task references specific requirements for traceability
- Checkpoints ensure incremental validation
- Property tests validate universal correctness properties from the design document
- 数据模型 `ChatSession``Conversation` 已有 `tenant_id` 字段且已建索引,无需数据库迁移
- 交互模式与知识库租户分组视图 (knowledge-tenant-view) 保持一致