Files
myaps_api/static/monitor/index.html
T

722 lines
44 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title data-i18n-page-title="page.title">MyAPI 系统监控面板</title>
<link rel="icon" href="/static/swagger/favicon.png" type="image/png">
<link rel="stylesheet" href="/static/monitor/css/monitor.css">
<link rel="stylesheet" href="/static/monitor/lib/prism.min.css">
<script src="/static/monitor/lib/chart.min.js"></script>
<script src="/static/monitor/lib/prism.min.js"></script>
<script src="/static/monitor/lib/prism-json.min.js"></script>
<script src="/static/lib/i18n/i18n.js"></script>
</head>
<body>
<div class="container">
<header class="header">
<nav class="nav-menu">
<a href="#" class="nav-item active" data-page="overview" data-i18n="monitor.nav.overview">📊 Overview</a>
<a href="#" class="nav-item" data-page="database" data-i18n="monitor.nav.database">🗃️ 数据库<span id="database-badge" class="nav-badge" style="display: none;"></span></a>
<a href="#" class="nav-item" data-page="event-helpers" data-i18n="monitor.nav.events">☎️ 事件处理</a>
<a href="#" class="nav-item" data-page="scheduler" data-i18n="monitor.nav.scheduler">⏰ 定时任务</a>
<a href="#" class="nav-item" data-page="api-requests" data-i18n="monitor.nav.http_requests">📥 接收请求<span id="api-requests-badge" class="nav-badge" style="display: none;"></span></a>
<a href="#" class="nav-item" data-page="outbound-requests" data-i18n="monitor.nav.outbound_requests">📤 发送请求<span id="outbound-requests-badge" class="nav-badge" style="display: none;"></span></a>
<a href="#" class="nav-item" data-page="logs" data-i18n="monitor.nav.logs">📋 日志<span id="logs-badge" class="nav-badge" style="display: none;"></span></a>
</nav>
<div class="header-info">
<select id="lang-selector" class="lang-selector" onchange="i18n.switchLanguage(this.value)">
<option value="zh-CN">🇨🇳 中文</option>
<option value="en-US">🇺🇸 English</option>
<option value="de-DE">🇩🇪 Deutsch</option>
</select>
<span id="status-indicator" class="status healthy" data-i18n="monitor.status.healthy">● 系统正常</span>
<span id="last-update"><span data-i18n="monitor.other.last_update">最后更新</span>&nbsp;&nbsp;--</span>
<button id="refresh-btn" class="btn btn-primary" onclick="refreshAll()" data-i18n="monitor.btn.refresh">刷新</button>
</div>
</header>
<!-- Overview 页面 -->
<main class="main-content page-content active" id="page-overview">
<!-- 资源监控卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.resource">资源使用</h2>
<span class="badge" id="resource-badge" data-i18n="monitor.status.running">运行中</span>
</div>
<div class="card-body">
<div class="metrics-grid">
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.cpu">CPU 使用率</div>
<div class="metric-value" id="cpu-value">--%</div>
<div class="progress-bar">
<div class="progress-fill" id="cpu-bar"></div>
</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.memory">内存使用</div>
<div class="metric-value" id="memory-value">
<span id="memory-usage">-- MB</span>
<span id="memory-percent" class="memory-percent">--%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="memory-bar"></div>
</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.threads">线程数</div>
<div class="metric-value" id="threads-value">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.uptime">运行时间</div>
<div class="metric-value" id="uptime-value">--</div>
</div>
</div>
<div class="chart-container">
<canvas id="resource-chart"></canvas>
</div>
</div>
</section>
<!-- 数据库状态卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.db_status">账套状态</h2>
<span class="badge" id="db-badge" data-i18n="monitor.status.checking">检查中</span>
</div>
<div class="card-body">
<div class="db-summary" id="db-summary">
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.total_connections">总连接数</span>
<span class="summary-value" id="db-total">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.healthy">健康</span>
<span class="summary-value healthy" id="db-healthy">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.unhealthy">异常</span>
<span class="summary-value error" id="db-unhealthy">--</span>
</div>
</div>
<div class="db-list" id="db-list">
<!-- 动态生成数据库连接列表 -->
</div>
</div>
</section>
<!-- 提醒信息卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.recent_alerts">最近告警</h2>
<button class="btn btn-small" onclick="clearAlerts()" data-i18n="monitor.btn.clear">清空</button>
</div>
<div class="card-body">
<div class="alert-list" id="alert-list">
<!-- 动态生成告警列表 -->
</div>
</div>
</section>
<!-- 接收请求卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.api_requests">接收请求</h2>
<span class="badge" id="http-badge" data-i18n="monitor.status.running">监控中</span>
</div>
<div class="card-body">
<div class="http-summary" id="http-summary">
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.requests_total">总请求数</span>
<span class="summary-value" id="http-total">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.error_rate">错误率</span>
<span class="summary-value" id="http-error-rate">--%</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.avg_time">平均响应</span>
<span class="summary-value" id="http-avg-time">--ms</span>
</div>
<div class="summary-item">
<span class="summary-label">QPS</span>
<span class="summary-value" id="http-rpm">--</span>
</div>
</div>
</div>
</section>
<!-- 发送请求卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.outbound_requests">发送请求</h2>
<span class="badge" id="outbound-badge" data-i18n="monitor.status.running">监控中</span>
</div>
<div class="card-body">
<div class="outbound-summary" id="outbound-summary">
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.requests_total">总请求数</span>
<span class="summary-value" id="outbound-total">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.error_rate">错误率</span>
<span class="summary-value" id="outbound-error-rate">--%</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.avg_time">平均响应</span>
<span class="summary-value" id="outbound-avg">--ms</span>
</div>
</div>
</div>
</section>
<!-- 定时任务监控卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.scheduler">定时任务</h2>
<span class="badge" id="scheduler-badge" data-i18n="monitor.status.checking">检查中</span>
</div>
<div class="card-body">
<div class="scheduler-info" id="scheduler-info">
<div class="info-item">
<span class="info-label" data-i18n="monitor.metric.scheduler_status">调度器状态</span>
<span class="info-value" id="scheduler-status">--</span>
</div>
<div class="info-item">
<span class="info-label" data-i18n="monitor.metric.job_count">任务数量</span>
<span class="info-value" id="job-count">--</span>
</div>
</div>
</div>
</section>
</main>
<!-- 数据库页面 -->
<main class="main-content page-content" id="page-database">
<!-- 数据库详细信息卡片 -->
<section class="card full-width">
<div class="card-header">
<h2 data-i18n="monitor.card.mysql">MySQL</h2>
<span class="badge" id="db-detail-badge" data-i18n="monitor.status.checking">检查中</span>
</div>
<div class="card-body">
<!-- 数据库详细信息 -->
<div class="db-detail-table-container">
<table class="db-detail-table" id="db-detail-table">
<thead>
<tr>
<th data-i18n="monitor.col.db_name">账套名称</th>
<th data-i18n="monitor.metric.connection_status">连接状态</th>
<th data-i18n="monitor.col.last_check">最后检查</th>
<th data-i18n="monitor.col.current_connections">当前连接</th>
<th data-i18n="monitor.col.max_connections">最大连接</th>
<th data-i18n="monitor.col.min_connections">最小连接</th>
<th data-i18n="monitor.col.idle_connections">空闲连接</th>
<th data-i18n="monitor.col.used_connections">使用中连接</th>
<th data-i18n="monitor.col.usage">使用率</th>
<th data-i18n="monitor.col.processed_records">处理记录</th>
<th data-i18n="monitor.col.count">次数</th>
</tr>
</thead>
<tbody id="db-detail-tbody">
<!-- 动态生成数据库详细信息 -->
</tbody>
</table>
</div>
</div>
</section>
<!-- Redis 监控卡片 -->
<section class="card full-width">
<div class="card-header">
<h2 data-i18n="monitor.card.redis">Redis</h2>
<span class="badge" id="redis-badge" data-i18n="monitor.status.checking">检查中</span>
</div>
<div class="card-body">
<div class="redis-metrics-grid">
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.connection_status">连接状态</div>
<div class="metric-value" id="redis-status">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.host">主机</div>
<div class="metric-value" id="redis-host">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.port">端口</div>
<div class="metric-value" id="redis-port">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.database">数据库</div>
<div class="metric-value" id="redis-db">--</div>
</div>
</div>
<div class="redis-pool-metrics">
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.used_connections">使用连接数</div>
<div class="metric-value" id="redis-connections-used">0</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.max_connections">最大连接数</div>
<div class="metric-value" id="redis-connections-max">0</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.connection_usage">连接使用率</div>
<div class="metric-value" id="redis-connection-usage">0%</div>
</div>
</div>
<div class="redis-buffer-metrics">
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.buffer_size">缓冲大小</div>
<div class="metric-value" id="redis-buffer-size">0</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.buffer_threshold">缓冲阈值</div>
<div class="metric-value" id="redis-buffer-threshold">0</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.buffer_usage">缓冲使用率</div>
<div class="metric-value" id="redis-buffer-usage">0%</div>
</div>
</div>
<div class="chart-container">
<h3 data-i18n="monitor.chart.redis_connections">Redis 连接池使用情况</h3>
<canvas id="redis-connections-chart"></canvas>
</div>
<div class="chart-container">
<h3 data-i18n="monitor.chart.redis_buffer">Redis 缓冲大小变化</h3>
<canvas id="redis-buffer-chart"></canvas>
</div>
</div>
</section>
</main>
<!-- 接收请求页面 -->
<main class="main-content page-content" id="page-api-requests">
<section class="card full-width">
<div class="card-header">
<h2 data-i18n="monitor.card.http_requests_log">接收请求记录</h2>
<div class="card-actions">
<div class="date-selector" style="display: none;">
<label for="api-date-picker">选择日期:</label>
<input type="date" id="api-date-picker" value="">
<button class="btn btn-sm" onclick="fetchRequestsByDate()">查询</button>
</div>
<div class="toggle-switch">
<label>
<input type="checkbox" id="show-api-internal-requests" onchange="toggleAPIIntternalRequests()">
<span class="toggle-slider"></span>
<span data-i18n="monitor.other.show_internal">显示内部请求</span>
</label>
</div>
<button class="btn btn-sm" onclick="refreshAPIRequests()" data-i18n="monitor.btn.refresh">刷新</button>
<button class="btn btn-sm btn-secondary" onclick="resetAPIStats()" data-i18n="monitor.btn.reset_stats">重置统计</button>
</div>
</div>
<div class="card-body">
<div class="api-requests-table-container">
<table class="api-requests-table" id="api-requests-table">
<thead>
<tr>
<th data-i18n="monitor.col.index">序号</th>
<th data-i18n="monitor.col.timestamp">时间戳</th>
<th data-i18n="monitor.col.method">方法</th>
<th data-i18n="monitor.col.path">端点</th>
<th data-i18n="monitor.col.query_params">查询参数</th>
<th data-i18n="monitor.col.status">状态码</th>
<th data-i18n="monitor.col.duration">响应时间</th>
<th data-i18n="monitor.col.client_ip">客户端IP</th>
<th data-i18n="monitor.col.error_message">错误信息</th>
</tr>
</thead>
<tbody id="api-requests-tbody">
</tbody>
</table>
</div>
<!-- 接收请求详情模态对话框 -->
<div class="modal" id="api-request-modal" style="display: none;">
<div class="modal-overlay" onclick="hideRequestDetail()"></div>
<div class="modal-content">
<div class="modal-header">
<h3>请求详情</h3>
<button class="btn btn-small close-btn" onclick="hideRequestDetail()">×</button>
</div>
<div class="modal-body">
<div class="api-detail-content">
<div class="api-detail-section">
<h4>请求信息</h4>
<div class="api-detail-info" id="api-detail-request-info"></div>
</div>
<div class="api-detail-bodies">
<div class="api-detail-section">
<div class="section-header">
<h4>请求体</h4>
<div class="section-actions">
<button class="btn btn-small" onclick="highlightRequestBody()">高亮</button>
<button class="btn btn-small" onclick="copyRequestBody()">复制</button>
</div>
</div>
<pre class="api-detail-body"><code class="language-json" id="api-detail-request-body"></code></pre>
</div>
<div class="api-detail-section">
<div class="section-header">
<h4>响应体</h4>
<div class="section-actions">
<button class="btn btn-small" onclick="highlightResponseBody()">高亮</button>
<button class="btn btn-small" onclick="copyResponseBody()">复制</button>
</div>
</div>
<pre class="api-detail-body"><code class="language-json" id="api-detail-response-body"></code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<!-- 定时任务页面 -->
<main class="main-content page-content" id="page-scheduler">
<section class="card full-width">
<div class="card-header">
<h2 data-i18n="monitor.card.scheduler_detail">定时任务详情</h2>
<span class="badge" id="scheduler-detail-badge" data-i18n="monitor.status.checking">检查中</span>
<button class="btn btn-small" onclick="refreshSchedulerPage()" data-i18n="monitor.btn.refresh">刷新</button>
</div>
<div class="card-body">
<div class="scheduler-detail-grid" id="scheduler-detail-grid">
<!-- 动态生成定时任务详细信息 -->
</div>
</div>
</section>
</main>
<!-- 发送请求页面 -->
<main class="main-content page-content" id="page-outbound-requests">
<section class="card full-width">
<div class="card-header">
<h2 data-i18n="monitor.card.outbound_requests_log">发送请求记录</h2>
<div class="card-actions">
<div class="date-selector" style="display: none;">
<label for="outbound-date-picker">选择日期:</label>
<input type="date" id="outbound-date-picker" value="">
<button class="btn btn-sm" onclick="fetchOutboundRequestsByDate()">查询</button>
</div>
<div class="toggle-switch">
<label>
<input type="checkbox" id="show-internal-requests" onchange="toggleInternalRequests()">
<span class="toggle-slider"></span>
<span data-i18n="monitor.other.show_internal">显示内部请求</span>
</label>
</div>
<button class="btn btn-sm" onclick="refreshOutboundRequests()" data-i18n="monitor.btn.refresh">刷新</button>
<button class="btn btn-sm btn-secondary" onclick="resetOutboundStats()" data-i18n="monitor.btn.reset_stats">重置统计</button>
</div>
</div>
<div class="card-body">
<div class="outbound-requests-container">
<table class="outbound-requests-table">
<thead>
<tr>
<th data-i18n="monitor.col.index">序号</th>
<th data-i18n="monitor.col.timestamp">时间戳</th>
<th data-i18n="monitor.col.method">方法</th>
<th data-i18n="monitor.col.url">URL</th>
<th data-i18n="monitor.col.status">状态码</th>
<th data-i18n="monitor.col.duration">响应时间</th>
<th data-i18n="monitor.col.module">模块</th>
<th data-i18n="monitor.col.error_message">错误信息</th>
</tr>
</thead>
<tbody id="outbound-requests-table">
<!-- 动态生成发送请求记录 -->
</tbody>
</table>
</div>
</div>
</section>
</main>
<!-- 日志页面 -->
<main class="main-content page-content" id="page-logs">
<!-- 原有日志记录卡片 -->
<section class="card full-width">
<div class="card-header">
<h2>Warning & Error</h2>
<div class="log-page-controls">
<button class="btn btn-primary" onclick="window.open('/monitor/live-logs', '_blank')" data-i18n="monitor.btn.live_logs">实时日志</button>
<button class="btn btn-primary" onclick="window.open('/monitor/history-logs', '_blank')" data-i18n="monitor.btn.history_query">历史查询</button>
<div class="toggle-switch">
<label>
<input type="checkbox" id="show-read-logs" onchange="toggleReadLogs()">
<span class="toggle-slider"></span>
<span data-i18n="monitor.other.show_read">显示已读</span>
</label>
</div>
<select id="log-page-level" onchange="fetchLogsPage()">
<option value="" data-i18n="monitor.filter.all_logs">全部日志</option>
<option value="error">错误日志</option>
<option value="warning">警告日志</option>
</select>
<button class="btn btn-small" onclick="markAllLogsAsRead()" data-i18n="monitor.btn.mark_all_read">标记全部已读</button>
<button class="btn btn-small" onclick="clearReadStatus()" data-i18n="monitor.btn.clear_read_status">清空已读状态</button>
<button class="btn btn-small" onclick="refreshLogsPage()" data-i18n="monitor.btn.refresh">刷新</button>
</div>
</div>
<div class="card-body">
<div class="logs-table-container">
<table class="logs-table" id="logs-table">
<thead>
<tr>
<th data-i18n="monitor.col.index">序号</th>
<th data-i18n="monitor.col.time">时间</th>
<th data-i18n="monitor.col.level">级别</th>
<th data-i18n="monitor.col.module">模块</th>
<th data-i18n="monitor.col.message">消息</th>
<th data-i18n="monitor.col.is_read">已读</th>
</tr>
</thead>
<tbody id="logs-tbody">
<!-- 动态生成日志记录 -->
</tbody>
</table>
</div>
</div>
</section>
</main>
<!-- 事件处理页面 -->
<main class="main-content page-content" id="page-event-helpers">
<!-- 事件监听卡片 -->
<section class="card full-width">
<div class="card-header">
<h2 data-i18n="monitor.card.event_listener">事件监听</h2>
<div class="events-actions">
<button class="btn btn-small" onclick="refreshEventStats()" data-i18n="monitor.btn.refresh">刷新</button>
<button class="btn btn-small" onclick="flushAllEvents()" data-i18n="monitor.btn.flush_all">立即刷新所有</button>
<button class="btn btn-small btn-secondary" onclick="resetEventStats()" data-i18n="monitor.btn.reset_stats">重置统计</button>
</div>
</div>
<div class="card-body">
<div class="events-summary" id="events-summary">
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.events_received">总接收事件</span>
<span class="summary-value" id="events-total-received">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.events_processed">已处理事件</span>
<span class="summary-value healthy" id="events-total-processed">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.events_interrupted">中断处理</span>
<span class="summary-value error" id="events-total-failed">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.pending">待处理</span>
<span class="summary-value" id="events-total-pending">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.overall_success_rate">整体成功率</span>
<span class="summary-value" id="events-success-rate">--%</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.active_event_types">活跃事件类型</span>
<span class="summary-value" id="events-active-types">--</span>
</div>
<!-- 背压监控 -->
<div class="summary-item" id="backpressure-summary" style="display: none;">
<span class="summary-label" data-i18n="monitor.metric.backpressure_status">背压状态</span>
<span class="summary-value" id="backpressure-status">正常</span>
</div>
<div class="summary-item" id="backpressure-pending" style="display: none;">
<span class="summary-label" data-i18n="monitor.metric.backpressure_pending">待处理事件</span>
<span class="summary-value" id="backpressure-pending-count">--</span>
</div>
<div class="summary-item" id="backpressure-percent" style="display: none;">
<span class="summary-label" data-i18n="monitor.metric.backpressure_usage">背压使用率</span>
<span class="summary-value" id="backpressure-usage">--%</span>
</div>
<!-- 事件循环健康状态 -->
<div class="summary-item" id="event-loop-status" style="display: none;">
<span class="summary-label" data-i18n="monitor.metric.event_loop_status">事件循环状态</span>
<span class="summary-value" id="event-loop-health">正常</span>
</div>
</div>
<div class="events-table-container">
<table class="events-table" id="events-table">
<thead>
<tr>
<th data-i18n="monitor.col.description">描述</th>
<th data-i18n="monitor.col.total_received">总接收</th>
<th data-i18n="monitor.col.pending">待处理</th>
<th data-i18n="monitor.col.processed">已处理</th>
<th data-i18n="monitor.col.interrupted">中断</th>
<th data-i18n="monitor.col.completion_rate">完成率</th>
<th data-i18n="monitor.col.avg_latency">平均延迟</th>
<th data-i18n="monitor.col.operation">操作</th>
<th data-i18n="monitor.col.last_action">最后动作</th>
<th data-i18n="monitor.col.status">状态</th>
<th data-i18n="monitor.col.operation">操作</th>
</tr>
</thead>
<tbody id="events-tbody">
<!-- 动态生成事件统计列表 -->
</tbody>
</table>
</div>
</div>
</section>
<!-- 下半部分:左边是回调跟踪器和事件去重器,右边是DeadLetter队列 -->
<div class="event-helpers-layout">
<!-- 左边:回调跟踪器和事件去重器 -->
<div class="left-column">
<!-- 回调跟踪器卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.callback_tracker">回调跟踪器</h2>
<span class="badge" id="callback-badge" data-i18n="monitor.status.monitoring">监控中</span>
</div>
<div class="card-body">
<div class="metrics-grid">
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.pending_callbacks">待处理回调</div>
<div class="metric-value" id="callback-pending">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.max_retries">最大重试次数</div>
<div class="metric-value" id="callback-max-retries">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.pending_retries">待处理重试</div>
<div class="metric-value" id="callback-pending-retries">--</div>
</div>
</div>
</div>
</section>
<!-- 事件去重器卡片 -->
<section class="card">
<div class="card-header">
<h2 data-i18n="monitor.card.event_deduplicator">事件去重器</h2>
<span class="badge" id="deduplicator-badge" data-i18n="monitor.status.monitoring">监控中</span>
</div>
<div class="card-body">
<div class="metrics-grid">
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.total_entries">总存储条目</div>
<div class="metric-value" id="deduplicator-total">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.active_items">活跃项目</div>
<div class="metric-value" id="deduplicator-active">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.ttl_seconds">TTL (秒)</div>
<div class="metric-value" id="deduplicator-ttl">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.max_entries">最大条目</div>
<div class="metric-value" id="deduplicator-max">--</div>
</div>
</div>
</div>
</section>
</div>
<!-- 右边:DeadLetter队列 -->
<div class="right-column">
<section class="card dead-letter-card">
<div class="card-header">
<h2>Dead Letter Queue</h2>
<div class="dead-letter-actions">
<button class="btn btn-small" onclick="refreshDeadLetterStats()" data-i18n="monitor.btn.refresh">刷新</button>
<button class="btn btn-small btn-secondary" onclick="clearDeadLetters()" data-i18n="monitor.btn.clear">清空</button>
</div>
</div>
<div class="card-body">
<div class="metrics-grid">
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.pending_events">待写入事件</div>
<div class="metric-value" id="dlq-pending">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.total_events">总事件数</div>
<div class="metric-value" id="dlq-total">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.file_size">文件大小</div>
<div class="metric-value" id="dlq-file-size">--</div>
</div>
<div class="metric-item">
<div class="metric-label" data-i18n="monitor.metric.running_status">运行状态</div>
<div class="metric-value" id="dlq-running">--</div>
</div>
</div>
<div class="dead-letter-summary" id="dead-letter-summary" style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #e2e8f0;">
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.dl_total">DL总数</span>
<span class="summary-value" id="dead-letter-total">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.recent_dl">最近DL</span>
<span class="summary-value" id="dead-letter-recent">--</span>
</div>
<div class="summary-item">
<span class="summary-label" data-i18n="monitor.metric.process_success_rate">处理成功率</span>
<span class="summary-value" id="dead-letter-success-rate">--%</span>
</div>
</div>
<div class="dead-letter-table-container" style="margin-top: 15px;">
<table class="dead-letter-table" id="dead-letter-table">
<thead>
<tr>
<th data-i18n="monitor.col.id">ID</th>
<th data-i18n="monitor.col.event_type">事件类型</th>
<th data-i18n="monitor.col.time">时间</th>
<th data-i18n="monitor.col.database">数据库</th>
<th data-i18n="monitor.col.table"></th>
<th data-i18n="monitor.col.error_message">错误信息</th>
<th data-i18n="monitor.col.operation">操作</th>
</tr>
</thead>
<tbody id="dead-letter-tbody">
<!-- 动态生成DeadLetter列表 -->
</tbody>
</table>
</div>
</div>
</section>
</div>
</div>
</main>
<footer class="footer">
<p>&nbsp;</p>
</footer>
</main>
</div>
<!-- 超时提示模态框 -->
<div class="modal" id="inactivity-modal" style="display: none;">
<div class="modal-overlay"></div>
<div class="modal-content">
<div class="modal-header">
<h3>⌛ 监控已超时</h3>
</div>
<div class="modal-body">
<p>由于长时间未活动,监控已自动暂停以节省资源。</p>
<p>如需继续监控,请点击下方按钮恢复连接。</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" onclick="resumeMonitoring()">恢复连接</button>
</div>
</div>
</div>
<script src="/static/monitor/js/monitor.js"></script>
</body>
</html>