diff --git a/app/__init__.py b/app/__init__.py index e6f0c79..2d5d58d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -123,24 +123,34 @@ def _configure_logging(app): def _register_error_handlers(app): """注册错误处理器""" - from flask import jsonify + from flask import jsonify, render_template, request, render_template @app.errorhandler(400) def bad_request(error): + if request.accepts('text/html'): + return render_template('errors/400.html', error=str(error)), 400 return jsonify({'error': 'Bad Request', 'message': str(error)}), 400 @app.errorhandler(401) def unauthorized(error): + if request.accepts('text/html'): + return render_template('errors/401.html', error=str(error)), 401 return jsonify({'error': 'Unauthorized', 'message': str(error)}), 401 @app.errorhandler(403) def forbidden(error): + if request.accepts('text/html'): + return render_template('errors/403.html', error=str(error)), 403 return jsonify({'error': 'Forbidden', 'message': str(error)}), 403 @app.errorhandler(404) def not_found(error): + if request.accepts('text/html'): + return render_template('errors/404.html', error=str(error)), 404 return jsonify({'error': 'Not Found', 'message': str(error)}), 404 @app.errorhandler(500) def internal_error(error): + if request.accepts('text/html'): + return render_template('errors/500.html', error=str(error)), 500 return jsonify({'error': 'Internal Server Error', 'message': str(error)}), 500 diff --git a/app/templates/config/channel_edit.html b/app/templates/config/channel_edit.html new file mode 100644 index 0000000..d183150 --- /dev/null +++ b/app/templates/config/channel_edit.html @@ -0,0 +1,232 @@ +{% extends "base.html" %} + +{% block title %}编辑频道 - 智队中枢{% endblock %} + +{% block content %} +
+ {# 页面头部 #} +
+
+ + + + + +
+

编辑频道配置

+

{{ config.name }}

+
+
+
+ + {# 表单 #} +
+ + + {# 基本信息 #} +
+
+

基本信息

+
+
+
+ + +

频道配置的唯一名称

+
+ +
+ + +

WebSocket 连接地址

+
+ +
+ +
+ + +
+

用于连接认证的 Token

+
+
+
+ + {# 连接配置 #} +
+
+

连接配置

+
+
+
+
+ + +

连接断开后的重连间隔

+
+
+ + +

心跳包发送间隔

+
+
+ +
+ +
+ +

启用后将自动连接到 Gateway

+
+
+
+
+ + {# 状态信息 #} +
+
+

状态信息

+
+
+
+
+
连接状态
+
+ {% if config.status == 'online' %} + + 在线 + {% else %} + + 离线 + {% endif %} +
+
+
+
最后连接
+
+ {{ config.last_connected.strftime('%Y-%m-%d %H:%M') if config.last_connected else '从未连接' }} +
+
+
+
更新时间
+
+ {{ config.updated_at.strftime('%Y-%m-%d %H:%M') if config.updated_at else '-' }} +
+
+
+ + {% if config.last_error %} +
+
+ + + +
+
最后错误
+
{{ config.last_error }}
+
+
+
+ {% endif %} +
+
+ + {# 操作按钮 #} +
+ +
+ 取消 + +
+
+
+
+ + +{% endblock %} diff --git a/app/templates/config/channels.html b/app/templates/config/channels.html index 403de45..9c252ae 100644 --- a/app/templates/config/channels.html +++ b/app/templates/config/channels.html @@ -148,20 +148,9 @@ }); } - // 编辑频道 + // 编辑频道 - 跳转到独立编辑页面 function editChannel(id) { - fetch(`/api/web/channels/${id}`) - .then(res => res.json()) - .then(data => { - document.getElementById('modal-title').textContent = '编辑配置'; - document.getElementById('channel-id').value = data.id; - document.getElementById('channel-name').value = data.name; - document.getElementById('channel-url').value = data.gateway_url; - document.getElementById('channel-reconnect').value = data.reconnect_interval; - document.getElementById('channel-heartbeat').value = data.heartbeat_interval; - document.getElementById('channel-enabled').checked = data.enabled; - showModal('channel-modal'); - }); + window.location.href = `/web/config/channels/${id}/edit`; } // 删除频道 diff --git a/app/templates/errors/401.html b/app/templates/errors/401.html new file mode 100644 index 0000000..2c7222f --- /dev/null +++ b/app/templates/errors/401.html @@ -0,0 +1,30 @@ + + + + + + 401 - 未授权 | 智队中枢 + + + + + +
+
401
+
+

未授权

+

请先登录后再访问此页面

+
+
+ + + 登录 + +
+
智队中枢 v0.7.0
+
+ + + diff --git a/app/templates/errors/403.html b/app/templates/errors/403.html new file mode 100644 index 0000000..b1dc297 --- /dev/null +++ b/app/templates/errors/403.html @@ -0,0 +1,30 @@ + + + + + + 403 - 禁止访问 | 智队中枢 + + + + + +
+
403
+
+

禁止访问

+

您没有权限访问此页面

+
+
+ + + 返回首页 + +
+
智队中枢 v0.7.0
+
+ + + diff --git a/app/templates/errors/404.html b/app/templates/errors/404.html new file mode 100644 index 0000000..310b795 --- /dev/null +++ b/app/templates/errors/404.html @@ -0,0 +1,104 @@ + + + + + + 404 - 页面未找到 | 智队中枢 + + {# Tailwind CSS #} + + + + + + +
+ {# 404 数字 #} +
+ 404 +
+ + {# 错误信息 #} +
+

页面未找到

+

抱歉,您访问的页面不存在或已被移除

+
+ + {# 操作按钮 #} +
+ + + + + 返回上一页 + + + + + + 返回首页 + +
+ + {# 建议 #} +
+

您可以尝试

+ +
+ + {# 页脚 #} +
+ 智队中枢 v0.7.0 | GitHub +
+
+ + + + diff --git a/app/templates/errors/500.html b/app/templates/errors/500.html new file mode 100644 index 0000000..e74e1c3 --- /dev/null +++ b/app/templates/errors/500.html @@ -0,0 +1,112 @@ + + + + + + 500 - 服务器错误 | 智队中枢 + + {# Tailwind CSS #} + + + + + + +
+ {# 500 数字 #} +
+ 500 +
+ + {# 错误信息 #} +
+

服务器错误

+

抱歉,服务器遇到了一个意外情况

+
+ + {# 操作按钮 #} +
+ + + + + + 返回首页 + +
+ + {# 错误详情 #} + {% if error %} +
+

错误信息

+
{{ error }}
+
+ {% endif %} + + {# 建议 #} +
+

如果问题持续存在

+ +
+ + {# 页脚 #} +
+ 智队中枢 v0.7.0 | GitHub +
+
+ + + + diff --git a/app/templates/monitor/session_detail.html b/app/templates/monitor/session_detail.html new file mode 100644 index 0000000..c1e6c19 --- /dev/null +++ b/app/templates/monitor/session_detail.html @@ -0,0 +1,187 @@ +{% extends "base.html" %} + +{% block title %}会话详情 - 智队中枢{% endblock %} + +{% block content %} +
+ {# 页面头部 #} +
+
+ + + + + +
+

会话详情

+

ID: {{ session.id }}

+
+
+
+ {% if session.status == 'active' %} + + {% endif %} + +
+
+ + {# 会话信息卡片 #} +
+
+
用户
+
+
+ + {{ session.user.username[0] if session.user else '?' }} + +
+ {{ session.user.username if session.user else '匿名用户' }} +
+
+
+
主 Agent
+
+ {{ session.primary_agent.name if session.primary_agent else '未分配' }} +
+
+
+
状态
+
+ {% if session.status == 'active' %} + + + 活跃 + + {% elif session.status == 'paused' %} + 暂停 + {% else %} + 已关闭 + {% endif %} +
+
+
+
消息数
+
{{ session.message_count }}
+
+
+ + {# 时间线 #} +
+
+

时间线

+
+
+
+
+
创建时间
+
{{ session.created_at.strftime('%Y-%m-%d %H:%M:%S') if session.created_at else '-' }}
+
+
+
+
最后活跃
+
{{ session.last_active_at.strftime('%Y-%m-%d %H:%M:%S') if session.last_active_at else '-' }}
+
+
+
+
更新时间
+
{{ session.updated_at.strftime('%Y-%m-%d %H:%M:%S') if session.updated_at else '-' }}
+
+
+
+
+ + {# 消息记录 #} +
+
+

消息记录

+ 共 {{ messages|length }} 条 +
+
+ {% if messages %} +
+ {% for msg in messages %} +
+
+
+ + {{ 'Agent' if msg.sender_type == 'agent' else ('用户' if msg.sender_type == 'user' else '系统') }} + + {{ msg.created_at.strftime('%H:%M:%S') if msg.created_at else '' }} + {% if msg.status == 'sent' %} + + + + {% elif msg.status == 'delivered' %} + + + + {% endif %} +
+
{{ msg.content }}
+ {% if msg.message_type == 'media' %} +
+ + + + + 媒体文件 + +
+ {% endif %} +
+
+ {% endfor %} +
+ {% else %} +
+
+ + + +
+

暂无消息

+
+ {% endif %} +
+
+
+ + +{% endblock %} diff --git a/app/web/routes.py b/app/web/routes.py index 0f38a11..0ea9777 100644 --- a/app/web/routes.py +++ b/app/web/routes.py @@ -57,3 +57,23 @@ def sessions(): agents = Agent.query.all() sessions = Session.query.order_by(Session.last_active_at.desc()).limit(50).all() return render_template('monitor/sessions.html', sessions=sessions, agents=agents) + + +@web_bp.route('/monitor/sessions/') +@jwt_required() +def session_detail(session_id): + """会话详情页面""" + session = Session.query.get_or_404(session_id) + messages = Message.query.filter_by(session_id=session_id).order_by( + Message.created_at.asc() + ).limit(200).all() + return render_template('monitor/session_detail.html', session=session, messages=messages) + + +@web_bp.route('/config/channels//edit') +@jwt_required() +def channel_edit(channel_id): + """编辑频道配置页面""" + from app.models.channel_config import ChannelConfig + config = ChannelConfig.query.get_or_404(channel_id) + return render_template('config/channel_edit.html', config=config)