475 lines
22 KiB
HTML
475 lines
22 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>系统状态 - X-Request</title>
|
|||
|
|
<!-- 引入Tailwind CSS (离线版本) -->
|
|||
|
|
<script src="vendor/tailwind.min.js"></script>
|
|||
|
|
<!-- 引入内联 SVG 图标系统 (完全离线) -->
|
|||
|
|
<script src="vendor/icons.js"></script>
|
|||
|
|
<style>
|
|||
|
|
.inline-icon, .inline-emoji {
|
|||
|
|
display: inline-block;
|
|||
|
|
vertical-align: middle;
|
|||
|
|
}
|
|||
|
|
.inline-icon svg {
|
|||
|
|
width: 1em;
|
|||
|
|
height: 1em;
|
|||
|
|
fill: currentColor;
|
|||
|
|
}
|
|||
|
|
.inline-emoji {
|
|||
|
|
font-size: 1em;
|
|||
|
|
line-height: 1;
|
|||
|
|
}
|
|||
|
|
@keyframes spin {
|
|||
|
|
from { transform: rotate(0deg); }
|
|||
|
|
to { transform: rotate(360deg); }
|
|||
|
|
}
|
|||
|
|
.inline-icon[data-spin="true"], .inline-emoji[data-spin="true"] {
|
|||
|
|
animation: spin 1s linear infinite;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
<!-- 配置Tailwind -->
|
|||
|
|
<script>
|
|||
|
|
tailwind.config = {
|
|||
|
|
theme: {
|
|||
|
|
extend: {
|
|||
|
|
colors: {
|
|||
|
|
primary: '#3b82f6',
|
|||
|
|
secondary: '#8b5cf6',
|
|||
|
|
success: '#10b981',
|
|||
|
|
warning: '#f59e0b',
|
|||
|
|
danger: '#ef4444',
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
<style type="text/tailwindcss">
|
|||
|
|
@layer utilities {
|
|||
|
|
.content-auto {
|
|||
|
|
content-visibility: auto;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 全屏样式 */
|
|||
|
|
html, body {
|
|||
|
|
height: 100vh;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
body {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main {
|
|||
|
|
flex: 1;
|
|||
|
|
padding: 1rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.status-card {
|
|||
|
|
transition: all 0.3s ease;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.status-card:hover {
|
|||
|
|
transform: translateY(-2px);
|
|||
|
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.pulse-animation {
|
|||
|
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@keyframes pulse {
|
|||
|
|
0%, 100% {
|
|||
|
|
opacity: 1;
|
|||
|
|
}
|
|||
|
|
50% {
|
|||
|
|
opacity: .5;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body class="bg-gray-50 min-h-screen">
|
|||
|
|
<!-- 顶部导航栏 -->
|
|||
|
|
<nav class="bg-white shadow-md h-16">
|
|||
|
|
<div class="w-full mx-auto px-4 sm:px-6 lg:px-8">
|
|||
|
|
<div class="flex justify-between h-16 items-center">
|
|||
|
|
<div class="flex items-center">
|
|||
|
|
<div class="flex-shrink-0 flex items-center">
|
|||
|
|
<span class="text-3xl font-bold text-primary">X</span>
|
|||
|
|
<span class="ml-2 text-xl font-semibold text-gray-800">X-Request 管理系统</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="ml-6 flex items-center space-x-4">
|
|||
|
|
<a href="/" class="px-3 py-2 rounded-md text-sm font-medium text-gray-500 hover:text-primary hover:bg-primary/10 hover:border-b-2 hover:border-primary transition-colors">
|
|||
|
|
<i class="fa fa-home mr-1"></i> 首页
|
|||
|
|
</a>
|
|||
|
|
<a href="/log.html" class="px-3 py-2 rounded-md text-sm font-medium text-gray-500 hover:text-primary hover:bg-primary/10 hover:border-b-2 hover:border-primary transition-colors">
|
|||
|
|
<i class="fa fa-file-text mr-1"></i> 日志管理
|
|||
|
|
</a>
|
|||
|
|
<a href="/doc.html" class="px-3 py-2 rounded-md text-sm font-medium text-gray-500 hover:text-primary hover:bg-primary/10 hover:border-b-2 hover:border-primary transition-colors">
|
|||
|
|
<i class="fa fa-book mr-1"></i> 接口文档
|
|||
|
|
</a>
|
|||
|
|
<a href="/status.html" class="px-3 py-2 rounded-md text-sm font-medium text-primary bg-primary/10 border-b-2 border-primary">
|
|||
|
|
<i class="fa fa-heartbeat mr-1"></i> 系统状态
|
|||
|
|
</a>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="flex items-center space-x-4">
|
|||
|
|
<button id="refresh-btn" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors flex items-center">
|
|||
|
|
<i class="fa fa-refresh mr-2"></i>
|
|||
|
|
<span>刷新</span>
|
|||
|
|
</button>
|
|||
|
|
<a href="index.html" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition-colors flex items-center">
|
|||
|
|
<i class="fa fa-home mr-2"></i>
|
|||
|
|
<span>返回首页</span>
|
|||
|
|
</a>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</nav>
|
|||
|
|
|
|||
|
|
<!-- 主要内容 -->
|
|||
|
|
<main class="w-full px-4 sm:px-6 lg:px-8 py-4">
|
|||
|
|
<div class="max-w-6xl mx-auto">
|
|||
|
|
<!-- 健康检查卡片 -->
|
|||
|
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6 status-card">
|
|||
|
|
<div class="flex items-center justify-between mb-4">
|
|||
|
|
<h2 class="text-2xl font-bold text-gray-800 flex items-center">
|
|||
|
|
<i class="fa fa-heartbeat text-primary mr-3"></i>
|
|||
|
|
健康检查
|
|||
|
|
</h2>
|
|||
|
|
<div id="health-status" class="flex items-center">
|
|||
|
|
<span class="px-3 py-1 rounded-full text-sm font-medium bg-gray-200 text-gray-700">
|
|||
|
|
<i class="fa fa-spinner fa-spin mr-2"></i>
|
|||
|
|
检查中...
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div id="health-content" class="space-y-3">
|
|||
|
|
<div class="flex items-center justify-center py-8">
|
|||
|
|
<i class="fa fa-spinner fa-spin text-3xl text-primary"></i>
|
|||
|
|
<span class="ml-3 text-gray-600">正在加载健康检查信息...</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 应用信息卡片 -->
|
|||
|
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6 status-card">
|
|||
|
|
<div class="flex items-center justify-between mb-4">
|
|||
|
|
<h2 class="text-2xl font-bold text-gray-800 flex items-center">
|
|||
|
|
<i class="fa fa-info-circle text-primary mr-3"></i>
|
|||
|
|
应用信息
|
|||
|
|
</h2>
|
|||
|
|
<div class="text-sm text-gray-500">
|
|||
|
|
<i class="fa fa-clock-o mr-1"></i>
|
|||
|
|
<span id="last-updated">--</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div id="info-content" class="space-y-3">
|
|||
|
|
<div class="flex items-center justify-center py-8">
|
|||
|
|
<i class="fa fa-spinner fa-spin text-3xl text-primary"></i>
|
|||
|
|
<span class="ml-3 text-gray-600">正在加载应用信息...</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 系统状态卡片 -->
|
|||
|
|
<div class="bg-white rounded-lg shadow-md p-6 status-card">
|
|||
|
|
<div class="flex items-center justify-between mb-4">
|
|||
|
|
<h2 class="text-2xl font-bold text-gray-800 flex items-center">
|
|||
|
|
<i class="fa fa-server text-primary mr-3"></i>
|
|||
|
|
系统状态
|
|||
|
|
</h2>
|
|||
|
|
</div>
|
|||
|
|
<div id="system-content" class="space-y-3">
|
|||
|
|
<div class="flex items-center justify-center py-8">
|
|||
|
|
<i class="fa fa-spinner fa-spin text-3xl text-primary"></i>
|
|||
|
|
<span class="ml-3 text-gray-600">正在加载系统状态...</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</main>
|
|||
|
|
|
|||
|
|
<!-- 页脚 -->
|
|||
|
|
<footer class="bg-white border-t border-gray-200 py-4 mt-6">
|
|||
|
|
<div class="w-full mx-auto px-4 sm:px-6 lg:px-8 text-center text-sm text-gray-500">
|
|||
|
|
<p>X-Request © 2025</p>
|
|||
|
|
</div>
|
|||
|
|
</footer>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// 工具函数
|
|||
|
|
function formatTimestamp(timestamp) {
|
|||
|
|
if (!timestamp) return '--';
|
|||
|
|
const date = new Date(timestamp * 1000);
|
|||
|
|
return date.toLocaleString('zh-CN');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function formatDateTime(date) {
|
|||
|
|
return date.toLocaleString('zh-CN');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取健康检查信息
|
|||
|
|
async function fetchHealth() {
|
|||
|
|
try {
|
|||
|
|
const response = await fetch('/health');
|
|||
|
|
const data = await response.json();
|
|||
|
|
|
|||
|
|
const healthStatus = document.getElementById('health-status');
|
|||
|
|
const healthContent = document.getElementById('health-content');
|
|||
|
|
|
|||
|
|
if (data.status === 1 && data.response) {
|
|||
|
|
// 健康状态
|
|||
|
|
healthStatus.innerHTML = `
|
|||
|
|
<span class="px-3 py-1 rounded-full text-sm font-medium bg-success/20 text-success border border-success/30">
|
|||
|
|
<i class="fa fa-check-circle mr-2"></i>
|
|||
|
|
健康
|
|||
|
|
</span>
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
// 健康信息内容
|
|||
|
|
healthContent.innerHTML = `
|
|||
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|||
|
|
<div class="bg-success/5 border border-success/20 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-check-circle text-success text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">服务状态</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-2xl font-bold text-success">${data.response.status || 'healthy'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-primary/5 border border-primary/20 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-cog text-primary text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">服务名称</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${data.response.service || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="mt-4 pt-4 border-t border-gray-200">
|
|||
|
|
<div class="text-sm text-gray-500">
|
|||
|
|
<i class="fa fa-clock-o mr-1"></i>
|
|||
|
|
检查时间: ${data.time || '--'}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
} else {
|
|||
|
|
// 不健康状态
|
|||
|
|
healthStatus.innerHTML = `
|
|||
|
|
<span class="px-3 py-1 rounded-full text-sm font-medium bg-danger/20 text-danger border border-danger/30">
|
|||
|
|
<i class="fa fa-exclamation-circle mr-2"></i>
|
|||
|
|
异常
|
|||
|
|
</span>
|
|||
|
|
`;
|
|||
|
|
healthContent.innerHTML = `
|
|||
|
|
<div class="bg-danger/5 border border-danger/20 rounded-lg p-4">
|
|||
|
|
<p class="text-danger font-semibold">健康检查失败</p>
|
|||
|
|
<p class="text-sm text-gray-600 mt-2">${data.response?.error || '未知错误'}</p>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
const healthStatus = document.getElementById('health-status');
|
|||
|
|
const healthContent = document.getElementById('health-content');
|
|||
|
|
|
|||
|
|
healthStatus.innerHTML = `
|
|||
|
|
<span class="px-3 py-1 rounded-full text-sm font-medium bg-danger/20 text-danger border border-danger/30">
|
|||
|
|
<i class="fa fa-times-circle mr-2"></i>
|
|||
|
|
错误
|
|||
|
|
</span>
|
|||
|
|
`;
|
|||
|
|
healthContent.innerHTML = `
|
|||
|
|
<div class="bg-danger/5 border border-danger/20 rounded-lg p-4">
|
|||
|
|
<p class="text-danger font-semibold">无法获取健康检查信息</p>
|
|||
|
|
<p class="text-sm text-gray-600 mt-2">${error.message}</p>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取应用信息
|
|||
|
|
async function fetchInfo() {
|
|||
|
|
try {
|
|||
|
|
const response = await fetch('/info');
|
|||
|
|
const data = await response.json();
|
|||
|
|
|
|||
|
|
const infoContent = document.getElementById('info-content');
|
|||
|
|
|
|||
|
|
if (data.status === 1 && data.response) {
|
|||
|
|
const info = data.response;
|
|||
|
|
infoContent.innerHTML = `
|
|||
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|||
|
|
<div class="bg-primary/5 border border-primary/20 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-tag text-primary text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">应用名称</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${info.app_name || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-secondary/5 border border-secondary/20 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-code-fork text-secondary text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">版本号</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${info.version || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-${info.debug ? 'warning' : 'success'}/5 border border-${info.debug ? 'warning' : 'success'}/20 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-${info.debug ? 'bug' : 'shield'} text-${info.debug ? 'warning' : 'success'} text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">调试模式</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-${info.debug ? 'warning' : 'success'}">${info.debug ? '已启用' : '已禁用'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-server text-gray-600 text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">主机地址</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${info.host || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-plug text-gray-600 text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">端口号</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${info.port || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-link text-gray-600 text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">访问地址</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">http://${info.host === '0.0.0.0' ? 'localhost' : info.host}:${info.port || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="mt-4 pt-4 border-t border-gray-200">
|
|||
|
|
<div class="text-sm text-gray-500">
|
|||
|
|
<i class="fa fa-clock-o mr-1"></i>
|
|||
|
|
更新时间: ${data.time || '--'}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
} else {
|
|||
|
|
infoContent.innerHTML = `
|
|||
|
|
<div class="bg-danger/5 border border-danger/20 rounded-lg p-4">
|
|||
|
|
<p class="text-danger font-semibold">无法获取应用信息</p>
|
|||
|
|
<p class="text-sm text-gray-600 mt-2">${data.response?.error || '未知错误'}</p>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
const infoContent = document.getElementById('info-content');
|
|||
|
|
infoContent.innerHTML = `
|
|||
|
|
<div class="bg-danger/5 border border-danger/20 rounded-lg p-4">
|
|||
|
|
<p class="text-danger font-semibold">无法获取应用信息</p>
|
|||
|
|
<p class="text-sm text-gray-600 mt-2">${error.message}</p>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取系统状态
|
|||
|
|
async function fetchSystemStatus() {
|
|||
|
|
try {
|
|||
|
|
const response = await fetch('/monitoring/status');
|
|||
|
|
const data = await response.json();
|
|||
|
|
|
|||
|
|
const systemContent = document.getElementById('system-content');
|
|||
|
|
|
|||
|
|
if (data.success && data.data && data.data.system) {
|
|||
|
|
const system = data.data.system;
|
|||
|
|
systemContent.innerHTML = `
|
|||
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|||
|
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-desktop text-gray-600 text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">主机名</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${system.hostname || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-linux text-gray-600 text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">系统类型</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${system.system_type || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-python text-gray-600 text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">Python 版本</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${system.python_version || 'Unknown'}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|||
|
|
<div class="flex items-center mb-2">
|
|||
|
|
<i class="fa fa-clock-o text-gray-600 text-xl mr-2"></i>
|
|||
|
|
<span class="font-semibold text-gray-800">时间戳</span>
|
|||
|
|
</div>
|
|||
|
|
<p class="text-lg font-semibold text-gray-700">${formatTimestamp(system.timestamp)}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
} else {
|
|||
|
|
systemContent.innerHTML = `
|
|||
|
|
<div class="bg-warning/5 border border-warning/20 rounded-lg p-4">
|
|||
|
|
<p class="text-warning font-semibold">系统状态信息不可用</p>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
const systemContent = document.getElementById('system-content');
|
|||
|
|
systemContent.innerHTML = `
|
|||
|
|
<div class="bg-warning/5 border border-warning/20 rounded-lg p-4">
|
|||
|
|
<p class="text-warning font-semibold">无法获取系统状态</p>
|
|||
|
|
<p class="text-sm text-gray-600 mt-2">${error.message}</p>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 刷新所有信息
|
|||
|
|
async function refreshAll() {
|
|||
|
|
const lastUpdated = document.getElementById('last-updated');
|
|||
|
|
lastUpdated.textContent = formatDateTime(new Date());
|
|||
|
|
|
|||
|
|
await Promise.all([
|
|||
|
|
fetchHealth(),
|
|||
|
|
fetchInfo(),
|
|||
|
|
fetchSystemStatus()
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化
|
|||
|
|
async function init() {
|
|||
|
|
// 初始加载数据
|
|||
|
|
await refreshAll();
|
|||
|
|
|
|||
|
|
// 刷新按钮事件
|
|||
|
|
document.getElementById('refresh-btn').addEventListener('click', async () => {
|
|||
|
|
const btn = document.getElementById('refresh-btn');
|
|||
|
|
const icon = btn.querySelector('i');
|
|||
|
|
icon.classList.add('fa-spin');
|
|||
|
|
btn.disabled = true;
|
|||
|
|
|
|||
|
|
await refreshAll();
|
|||
|
|
|
|||
|
|
icon.classList.remove('fa-spin');
|
|||
|
|
btn.disabled = false;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 自动刷新(每30秒)
|
|||
|
|
setInterval(refreshAll, 30000);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 页面加载完成后初始化
|
|||
|
|
document.addEventListener('DOMContentLoaded', init);
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|