Files
YG_FT_Platform/request/static/status.html

475 lines
22 KiB
HTML
Raw Normal View History

<!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>