Files
pit-router/docs/WEB_UI_SPEC.md
yunxiafei 0003e5f69f docs: 新增 Web 管理界面技术方案
功能设计:
1. 智队频道插件配置管理
2. 一键测试频道插件连接
3. 会话监控与消息查看

技术栈:
- Jinja2 + HTMX + Tailwind CSS
- Chart.js 图表
- WebSocket 实时推送

预计开发时间: 6 天

作者: 小白 🐶
2026-03-14 22:06:31 +08:00

31 KiB
Raw Permalink Blame History

智队中枢 - Web 管理界面技术方案

智队中枢 Web UI 设计文档

📋 概述

为智队中枢添加 Web 管理界面,提供:

  1. 智队频道插件配置管理
  2. 一键测试频道插件连接
  3. 会话监控与消息查看

🏗️ 技术架构

整体架构

┌─────────────────────────────────────────────────────────────────────────────┐
│                        智队中枢 Web UI                                       │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │                        前端 (Jinja2 + HTMX + Tailwind)                │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐                    │  │
│  │  │  配置管理   │  │  连接测试   │  │  会话监控   │                    │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘                    │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                              │                                               │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │                        后端 API (Flask Blueprint)                     │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐                    │  │
│  │  │ /web/*      │  │ /api/web/*  │  │ /ws/*       │                    │  │
│  │  │ 页面路由    │  │ 数据接口    │  │ 实时推送    │                    │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘                    │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘

技术选型

层级 技术 说明
模板引擎 Jinja2 Flask 原生支持
交互增强 HTMX 无需写 JSHTML 属性驱动
样式框架 Tailwind CSS 快速构建 UI
图表 Chart.js 会话统计图表
实时更新 WebSocket 会话状态实时推送

📁 项目结构

pit-router/
├── app/
│   ├── web/                      # Web UI 模块 (新增)
│   │   ├── __init__.py           # Blueprint 注册
│   │   ├── routes.py             # 页面路由
│   │   ├── api.py                # 数据 API
│   │   └── utils.py              # 工具函数
│   ├── templates/                # 模板文件 (新增)
│   │   ├── base.html             # 基础模板
│   │   ├── index.html            # 首页/仪表盘
│   │   ├── config/               # 配置管理
│   │   │   ├── channels.html     # 频道配置列表
│   │   │   └── channel_edit.html # 频道配置编辑
│   │   ├── monitor/              # 会话监控
│   │   │   ├── sessions.html     # 会话列表
│   │   │   ├── session_detail.html # 会话详情
│   │   │   └── messages.html     # 消息查看
│   │   └── components/           # 组件模板
│   │       ├── navbar.html       # 导航栏
│   │       ├── sidebar.html      # 侧边栏
│   │       └── toast.html        # 提示消息
│   └── static/                   # 静态资源 (新增)
│       ├── css/
│       │   └── style.css         # 自定义样式
│       └── js/
│           └── app.js            # 自定义脚本
└── ...

🎨 页面设计

1. 首页/仪表盘

┌─────────────────────────────────────────────────────────────────────────────┐
│  智队中枢                                              [用户] [设置] [登出]  │
├──────────────┬──────────────────────────────────────────────────────────────┤
│              │                                                              │
│  📊 仪表盘   │   系统状态                                                   │
│  ────────    │   ┌────────────┐ ┌────────────┐ ┌────────────┐             │
│              │   │ 在线 Agent │ │ 活跃会话   │ │ 今日消息   │             │
│  ⚙️ 配置管理 │   │    5       │ │    12      │ │   1,234    │             │
│  └ 频道配置  │   └────────────┘ └────────────┘ └────────────┘             │
│              │                                                              │
│  📡 连接测试 │   会话趋势 (最近 24 小时)                                    │
│  └ 测试面板  │   ┌────────────────────────────────────────────────────┐   │
│              │   │     📈                                            │   │
│  👁️ 会话监控 │   │        ████                                       │   │
│  └ 会话列表  │   │     ████████    ████████                          │   │
│  └ 消息记录  │   │  ████████████████████████████████                 │   │
│              │   └────────────────────────────────────────────────────┘   │
│              │                                                              │
│              │   最近会话                                                   │
│              │   ┌────────────────────────────────────────────────────┐   │
│              │   │ 用户        Agent    消息数  状态    时间          │   │
│              │   │ yunxiafei   小白      15      活跃    2分钟前      │   │
│              │   │ xiaobai     小黑      8       活跃    5分钟前      │   │
│              │   │ test_user   小花      23      已关闭  1小时前      │   │
│              │   └────────────────────────────────────────────────────┘   │
└──────────────┴──────────────────────────────────────────────────────────────┘

2. 频道配置页面

┌─────────────────────────────────────────────────────────────────────────────┐
│  智队中枢 > 配置管理 > 频道配置                                               │
├──────────────┬──────────────────────────────────────────────────────────────┤
│              │                                                              │
│  📊 仪表盘   │   智队频道插件配置                      [+ 新增配置]        │
│  ────────    │   ┌────────────────────────────────────────────────────┐   │
│              │   │ 名称          Gateway URL        状态    操作      │   │
│  ⚙️ 配置管理 │   ├────────────────────────────────────────────────────┤   │
│  └ 频道配置  │   │ 默认频道      ws://localhost:18888  ✅ 在线  [编辑][测试] │
│              │   │ 工作频道      ws://work:18888      ⚠️ 离线  [编辑][测试] │
│  📡 连接测试 │   │ 测试频道      ws://test:18888      ✅ 在线  [编辑][测试] │
│  └ 测试面板  │   └────────────────────────────────────────────────────┘   │
│              │                                                              │
│  👁️ 会话监控 │   配置详情 (点击编辑后显示)                                  │
│  └ 会话列表  │   ┌────────────────────────────────────────────────────┐   │
│  └ 消息记录  │   │ Gateway URL:    [ws://localhost:18888         ]   │   │
│              │   │ Auth Token:     [••••••••••••••••              ]   │   │
│              │   │ 重连间隔:       [5000] 毫秒                      │   │
│              │   │ 心跳间隔:       [30000] 毫秒                     │   │
│              │   │ 启用状态:       [✓] 启用                         │   │
│              │   │                                                  │   │
│              │   │              [取消] [保存]                       │   │
│              │   └────────────────────────────────────────────────────┘   │
└──────────────┴──────────────────────────────────────────────────────────────┘

3. 连接测试页面

┌─────────────────────────────────────────────────────────────────────────────┐
│  智队中枢 > 连接测试                                                         │
├──────────────┬──────────────────────────────────────────────────────────────┤
│              │                                                              │
│  📊 仪表盘   │   连接测试                                                   │
│  ────────    │   ┌────────────────────────────────────────────────────┐   │
│              │   │ 选择频道:  [默认频道 ▼]                              │   │
│  ⚙️ 配置管理 │   │                                                      │   │
│  └ 频道配置  │   │              [🚀 开始测试]                           │   │
│              │   └────────────────────────────────────────────────────┘   │
│  📡 连接测试 │                                                              │
│  └ 测试面板  │   测试结果                                                   │
│              │   ┌────────────────────────────────────────────────────┐   │
│  👁️ 会话监控 │   │ ✅ WebSocket 连接成功                               │   │
│  └ 会话列表  │   │ ✅ 认证通过                                          │   │
│  └ 消息记录  │   │ ✅ 心跳响应正常                                      │   │
│              │   │ ✅ 消息收发测试通过                                  │   │
│              │   │                                                      │   │
│              │   │ 响应时间: 45ms                                       │   │
│              │   │ 测试时间: 2026-03-14 22:10:00                        │   │
│              │   └────────────────────────────────────────────────────┘   │
│              │                                                              │
│              │   测试日志                                                   │
│              │   ┌────────────────────────────────────────────────────┐   │
│              │   │ [INFO] 正在连接 ws://localhost:18888...             │   │
│              │   │ [INFO] WebSocket 连接已建立                         │   │
│              │   │ [INFO] 发送认证请求...                              │   │
│              │   │ [INFO] 认证成功: agent_id=xiaobai                  │   │
│              │   │ [INFO] 发送心跳...                                  │   │
│              │   │ [INFO] 心跳响应: pong                               │   │
│              │   │ [INFO] 发送测试消息...                              │   │
│              │   │ [INFO] 收到响应: Hello from Agent                   │   │
│              │   │ [INFO] 测试完成                                     │   │
│              │   └────────────────────────────────────────────────────┘   │
└──────────────┴──────────────────────────────────────────────────────────────┘

4. 会话监控页面

┌─────────────────────────────────────────────────────────────────────────────┐
│  智队中枢 > 会话监控                                                         │
├──────────────┬──────────────────────────────────────────────────────────────┤
│              │                                                              │
│  📊 仪表盘   │   会话列表                              [🔄 刷新]           │
│  ────────    │   ┌────────────────────────────────────────────────────┐   │
│              │   │ 筛选: Agent [全部▼] 状态 [全部▼] 时间 [今天▼]     │   │
│  ⚙️ 配置管理 │   ├────────────────────────────────────────────────────┤   │
│  └ 频道配置  │   │ ID            用户      Agent   消息  状态   时间  │   │
│              │   ├────────────────────────────────────────────────────┤   │
│  📡 连接测试 │   │ sess_001     yunxiafei 小白    15    🟢活跃  2分前│   │
│  └ 测试面板  │   │ sess_002     xiaobai   小黑    8     🟢活跃  5分前│   │
│              │   │ sess_003     test_user 小花    23    ⚪关闭  1时前│   │
│  👁️ 会话监控 │   │ sess_004     admin     小白    42    🟡暂停  2时前│   │
│  └ 会话列表  │   │ sess_005     guest     小花    3     🟢活跃  10分前│   │
│  └ 消息记录  │   └────────────────────────────────────────────────────┘   │
│              │                                                              │
│              │   会话详情: sess_001                                         │
│              │   ┌────────────────────────────────────────────────────┐   │
│              │   │ 用户: yunxiafei    Agent: 小白    状态: 🟢 活跃   │   │
│              │   │ 创建: 2026-03-14 20:00:00                         │   │
│              │   │ 最后活跃: 2026-03-14 22:08:00                      │   │
│              │   ├────────────────────────────────────────────────────┤   │
│              │   │ 消息记录:                                          │   │
│              │   │ ┌──────────────────────────────────────────────┐   │   │
│              │   │ │ [用户] 你好小白                              │   │   │
│              │   │ │ [小白] 你好!有什么可以帮你的?              │   │   │
│              │   │ │ [用户] 帮我写一个 Flask 应用                 │   │   │
│              │   │ │ [小白] 好的,我来帮你创建一个 Flask 应用...  │   │   │
│              │   │ │ ...                                          │   │   │
│              │   │ └──────────────────────────────────────────────┘   │   │
│              │   │                      [关闭会话] [导出记录]         │   │
│              │   └────────────────────────────────────────────────────┘   │
└──────────────┴──────────────────────────────────────────────────────────────┘

🔌 API 设计

Web UI 路由

方法 路径 说明
GET /web/ 首页/仪表盘
GET /web/config/channels 频道配置列表
GET /web/config/channels/new 新增频道配置
GET /web/config/channels/:id/edit 编辑频道配置
GET /web/test 连接测试页面
GET /web/monitor/sessions 会话监控列表
GET /web/monitor/sessions/:id 会话详情

Web UI 数据 API

方法 路径 说明
GET /api/web/stats 系统统计数据
GET /api/web/channels 频道配置列表
POST /api/web/channels 创建频道配置
PUT /api/web/channels/:id 更新频道配置
DELETE /api/web/channels/:id 删除频道配置
POST /api/web/channels/:id/test 测试频道连接
GET /api/web/sessions 会话列表 (带筛选)
GET /api/web/sessions/:id 会话详情
GET /api/web/sessions/:id/messages 会话消息
PUT /api/web/sessions/:id/close 关闭会话

🔧 核心实现

1. 频道配置数据模型

# app/models/channel_config.py

from app import db
from datetime import datetime
import uuid

class ChannelConfig(db.Model):
    """智队频道插件配置"""
    __tablename__ = 'channel_configs'
    
    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    name = db.Column(db.String(80), nullable=False, unique=True)
    gateway_url = db.Column(db.String(256), nullable=False)
    auth_token = db.Column(db.String(256), nullable=True)
    reconnect_interval = db.Column(db.Integer, default=5000)
    heartbeat_interval = db.Column(db.Integer, default=30000)
    enabled = db.Column(db.Boolean, default=True)
    
    # 状态
    status = db.Column(db.String(20), default='offline')
    last_connected = db.Column(db.DateTime, nullable=True)
    last_error = db.Column(db.Text, nullable=True)
    
    # 时间戳
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'gateway_url': self.gateway_url,
            'auth_token': '••••••••' if self.auth_token else None,
            'reconnect_interval': self.reconnect_interval,
            'heartbeat_interval': self.heartbeat_interval,
            'enabled': self.enabled,
            'status': self.status,
            'last_connected': self.last_connected.isoformat() if self.last_connected else None,
            'created_at': self.created_at.isoformat()
        }

2. 连接测试服务

# app/services/channel_tester.py

import asyncio
import websockets
import json
import time
from datetime import datetime

class ChannelTester:
    """频道连接测试器"""
    
    def __init__(self, config):
        self.config = config
        self.results = []
        self.start_time = None
    
    async def test_connection(self):
        """执行连接测试"""
        self.start_time = time.time()
        self.results = []
        
        try:
            # 1. WebSocket 连接测试
            await self._test_websocket()
            
            # 2. 认证测试
            await self._test_auth()
            
            # 3. 心跳测试
            await self._test_heartbeat()
            
            # 4. 消息收发测试
            await self._test_message()
            
        except Exception as e:
            self._log('ERROR', str(e))
        
        return {
            'success': all(r['success'] for r in self.results),
            'results': self.results,
            'response_time': int((time.time() - self.start_time) * 1000),
            'tested_at': datetime.utcnow().isoformat()
        }
    
    async def _test_websocket(self):
        """测试 WebSocket 连接"""
        self._log('INFO', f'正在连接 {self.config.gateway_url}...')
        
        try:
            self.ws = await websockets.connect(
                self.config.gateway_url,
                extra_headers={'Authorization': f'Bearer {self.config.auth_token}'}
            )
            self._log('INFO', 'WebSocket 连接已建立', success=True)
        except Exception as e:
            self._log('ERROR', f'连接失败: {e}', success=False)
            raise
    
    async def _test_auth(self):
        """测试认证"""
        self._log('INFO', '发送认证请求...')
        
        try:
            # 发送认证消息
            await self.ws.send(json.dumps({
                'type': 'auth',
                'token': self.config.auth_token
            }))
            
            # 等待响应
            response = await asyncio.wait_for(self.ws.recv(), timeout=10)
            data = json.loads(response)
            
            if data.get('type') == 'auth_success':
                self._log('INFO', f"认证成功: agent_id={data.get('agent_id')}", success=True)
            else:
                self._log('ERROR', f"认证失败: {data}", success=False)
                raise Exception('认证失败')
                
        except Exception as e:
            self._log('ERROR', f'认证错误: {e}', success=False)
            raise
    
    async def _test_heartbeat(self):
        """测试心跳"""
        self._log('INFO', '发送心跳...')
        
        try:
            await self.ws.send(json.dumps({'type': 'ping'}))
            response = await asyncio.wait_for(self.ws.recv(), timeout=10)
            data = json.loads(response)
            
            if data.get('type') == 'pong':
                self._log('INFO', '心跳响应: pong', success=True)
            else:
                self._log('WARNING', f'心跳响应异常: {data}', success=True)
                
        except Exception as e:
            self._log('ERROR', f'心跳错误: {e}', success=False)
    
    async def _test_message(self):
        """测试消息收发"""
        self._log('INFO', '发送测试消息...')
        
        try:
            test_msg = {
                'type': 'message',
                'content': '__TEST__'
            }
            await self.ws.send(json.dumps(test_msg))
            
            response = await asyncio.wait_for(self.ws.recv(), timeout=30)
            data = json.loads(response)
            
            self._log('INFO', f"收到响应: {data.get('content', data)[:50]}", success=True)
            
        except Exception as e:
            self._log('WARNING', f'消息测试跳过: {e}', success=True)
        
        await self.ws.close()
        self._log('INFO', '测试完成')
    
    def _log(self, level, message, success=None):
        """记录日志"""
        entry = {
            'level': level,
            'message': message,
            'timestamp': datetime.utcnow().isoformat(),
            'success': success if success is not None else level == 'INFO'
        }
        self.results.append(entry)

3. Web UI Blueprint

# app/web/routes.py

from flask import Blueprint, render_template, request, redirect, url_for
from app.models import Session, Agent, Gateway, Message
from app.models.channel_config import ChannelConfig
from app import db
from datetime import datetime, timedelta

web_bp = Blueprint('web', __name__, url_prefix='/web')

@web_bp.route('/')
def index():
    """首页/仪表盘"""
    # 统计数据
    stats = {
        'online_agents': Agent.query.filter_by(status='online').count(),
        'active_sessions': Session.query.filter_by(status='active').count(),
        'today_messages': Message.query.filter(
            Message.created_at >= datetime.utcnow() - timedelta(days=1)
        ).count()
    }
    
    # 最近会话
    recent_sessions = Session.query.order_by(
        Session.last_active_at.desc()
    ).limit(5).all()
    
    return render_template('index.html', 
                          stats=stats, 
                          recent_sessions=recent_sessions)

@web_bp.route('/config/channels')
def channels():
    """频道配置列表"""
    configs = ChannelConfig.query.all()
    return render_template('config/channels.html', configs=configs)

@web_bp.route('/config/channels/<id>/edit')
def channel_edit(id):
    """编辑频道配置"""
    config = ChannelConfig.query.get_or_404(id)
    return render_template('config/channel_edit.html', config=config)

@web_bp.route('/test')
def test():
    """连接测试页面"""
    configs = ChannelConfig.query.filter_by(enabled=True).all()
    return render_template('test/index.html', configs=configs)

@web_bp.route('/monitor/sessions')
def sessions():
    """会话监控"""
    status = request.args.get('status')
    agent_id = request.args.get('agent_id')
    
    query = Session.query
    
    if status:
        query = query.filter_by(status=status)
    if agent_id:
        query = query.filter_by(agent_id=agent_id)
    
    sessions = query.order_by(Session.last_active_at.desc()).all()
    agents = Agent.query.all()
    
    return render_template('monitor/sessions.html', 
                          sessions=sessions, 
                          agents=agents)

@web_bp.route('/monitor/sessions/<id>')
def session_detail(id):
    """会话详情"""
    session = Session.query.get_or_404(id)
    messages = Message.query.filter_by(session_id=id).order_by(
        Message.created_at.asc()
    ).limit(100).all()
    
    return render_template('monitor/session_detail.html',
                          session=session,
                          messages=messages)

📦 依赖更新

requirements.txt 新增

# Web UI
flask-htmx==0.3.0

📈 开发计划

Phase 5: Web UI 开发

任务 预计时间 说明
项目结构调整 0.5 天 创建 templates、static 目录
基础模板 0.5 天 base.html、导航、侧边栏
首页仪表盘 1 天 统计数据、图表
频道配置 1 天 CRUD、表单验证
连接测试 1 天 WebSocket 测试、日志显示
会话监控 1 天 列表、详情、实时更新
样式美化 0.5 天 Tailwind 样式优化
测试 0.5 天 功能测试

总计6 天


🎯 里程碑

阶段 功能 预计完成
M1 基础框架 + 首页 Day 2
M2 频道配置管理 Day 3
M3 连接测试 Day 4
M4 会话监控 Day 5
M5 样式优化 + 测试 Day 6

文档版本: v1.0 | 创建时间: 2026-03-14 | 作者: 小白 🐶