前言
因为使用了uptimerobot监控了网站,所以之前写了个工具在工具箱里,但是每次想要知道最近网站运行状态都需要访问工具箱,就很麻烦
刚好在WordPress建站的时候就看到了张洪HEO的网站底部有个uptimekuma的运行状态显示
于是自己就想搞一个,切记,这不是基于uptimekuma的,而是基于uptimerobot的
效果

教程
首先,我们需要在source/_data文件夹中创建一个aside.yml文件,然后将如下代码放进去
- name: uptime
title: 服务状态
icon: fas fa-server
no_head: true
content_html: |
<div class="uptime-dashboard">
<div class="uptime-header">
<div class="uptime-title">
<i class="fas fa-chart-line"></i>
<span>实时监控</span>
</div>
<div class="uptime-summary" id="uptimeSummary">
<span class="summary-text">加载中...</span>
</div>
</div>
<div class="uptime-services" id="uptimeServices">
<!-- 动态内容将由JavaScript填充 -->
</div>
</div>
再然后进入到_config.solitude.yml中,将如下代码添加到extends的body中
- <script src="/js/uptime-status.js"></script>
看到这里相信不少人知道了,接下来我们需要在source文件夹的js文件夹中创建一个uptime-status.js文件
然后将如下代码放进去,其中的密钥要从Uptime Robot获取Read-only API key。
class UptimeStatus {
constructor() {
this.isInitialized = false;
this.apiKey = '';//你的api密钥
this.apiUrl = 'https://api.uptimerobot.com/v2/getMonitors';
this.config = {
statusText: {
normal: '正常',
warning: '异常',
error: '故障',
loading: '检查中...',
unknown: '未知',
noApi: '未配置API',
apiError: 'API错误',
networkError: '网络错误',
noService: '无监控服务'
}
};
this.init();
}
init() {
// 等待DOM加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.initStatus());
} else {
this.initStatus();
}
// Pjax兼容
document.addEventListener('pjax:complete', () => this.initStatus());
}
initStatus() {
const uptimeCard = document.querySelector('.uptime-dashboard');
if (!uptimeCard) return;
this.isInitialized = true;
this.fetchServices();
// 设置定时刷新
setInterval(() => {
if (this.isInitialized) {
this.fetchServices();
}
}, 30000); // 30秒刷新一次
}
async fetchServices() {
try {
// 获取服务列表和状态
const servicesData = await this.getServicesData();
if (servicesData && servicesData.length > 0) {
this.renderServices(servicesData);
this.updateSummary(servicesData);
} else {
console.warn('API返回的服务数据为空');
this.renderServices(this.getDefaultServices());
this.updateSummary([]);
}
} catch (error) {
console.error('获取服务状态失败:', error);
this.renderServices(this.getDefaultServices());
this.updateSummary([]);
}
}
async getServicesData() {
try {
console.log('正在调用UptimeRobot API...');
// 使用与用户提供的代码相同的请求方式
const requestData = {
api_key: this.apiKey,
format: "json",
logs: 1
};
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
console.log('API响应状态:', response.status);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('API返回数据:', data);
if (data.stat !== 'ok') {
throw new Error(`API error: ${data.error?.message || 'Unknown error'}`);
}
if (!data.monitors || data.monitors.length === 0) {
console.warn('API返回的monitors数组为空');
return [];
}
// 转换UptimeRobot数据格式
const services = data.monitors.map(monitor => ({
id: monitor.id,
name: monitor.friendly_name,
status: this.mapUptimeStatus(monitor.status),
uptime: parseFloat(monitor.all_time_uptime_ratio || '0'),
url: monitor.url
}));
console.log('转换后的服务数据:', services);
return services;
} catch (error) {
console.error('UptimeRobot API调用失败:', error);
throw error;
}
}
mapUptimeStatus(uptimeStatus) {
// UptimeRobot状态映射
// 0: paused, 1: not checked yet, 2: up, 8: seems down, 9: down
switch (uptimeStatus) {
case 2:
return 'normal';
case 8:
return 'warning';
case 9:
return 'error';
case 0:
return 'unknown';
default:
return 'loading';
}
}
getDefaultServices() {
return [
{
id: 'default',
name: '正在获取服务状态...',
status: 'loading',
uptime: 0,
url: '#'
}
];
}
renderServices(services) {
const container = document.getElementById('uptimeServices');
if (!container) return;
console.log('渲染服务数据:', services);
container.innerHTML = services.map(service => `
<div class="service-item" data-service="${service.id}">
<div class="service-name">${service.name}</div>
<div class="service-status">
<span class="status-indicator status-${service.status}"></span>
<span class="status-text">${this.getStatusText(service.status)}</span>
</div>
</div>
`).join('');
}
updateSummary(services) {
const summaryElement = document.getElementById('uptimeSummary');
if (!summaryElement) return;
if (services.length === 0) {
summaryElement.innerHTML = '<span class="summary-text">无监控服务</span>';
return;
}
const totalServices = services.length;
const normalServices = services.filter(s => s.status === 'normal').length;
const warningServices = services.filter(s => s.status === 'warning').length;
const errorServices = services.filter(s => s.status === 'error').length;
let summaryText = '';
if (errorServices > 0) {
summaryText = `${errorServices}个服务异常`;
} else if (warningServices > 0) {
summaryText = `${warningServices}个服务警告`;
} else if (normalServices === totalServices) {
summaryText = '所有服务正常';
} else {
summaryText = `${normalServices}/${totalServices}个服务正常`;
}
summaryElement.innerHTML = `<span class="summary-text">${summaryText}</span>`;
}
getStatusText(status) {
const statusMap = this.config.statusText;
return statusMap[status] || statusMap.unknown;
}
}
// 初始化
new UptimeStatus();
有人要问,代码中没有看到样式啊,接下来就是样式部分,在你的自定义css文件中添加如下代码
/* Uptime 服务状态样式 - 全新设计 */
.uptime-dashboard {
background: var(--card-bg);
border-radius: 12px;
padding: 16px;
color: var(--font-color);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
.uptime-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
position: relative;
z-index: 1;
.uptime-title {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
font-size: 14px;
i {
font-size: 16px;
color: rgba(255, 255, 255, 0.9);
}
}
.uptime-summary {
.summary-text {
font-size: 12px;
opacity: 0.9;
font-weight: 500;
}
}
}
.uptime-services {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px;
.service-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
background: var(--card-bg);
border-radius: 8px;
border: 1px solid #e5e7eb;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
background: var(--hover-bg);
}
.service-name {
font-size: 11px;
font-weight: 500;
color: var(--font-color);
line-height: 1.2;
word-break: break-word;
flex: 1;
margin-right: 8px;
}
.service-status {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
position: relative;
transition: all 0.3s ease;
&::after {
content: '';
position: absolute;
top: -1px;
left: -1px;
right: -1px;
bottom: -1px;
border-radius: 50%;
background: inherit;
opacity: 0.3;
filter: blur(2px);
}
&.status-normal {
background: #4ade80;
box-shadow: 0 0 0 1px rgba(74, 222, 128, 0.3);
}
&.status-warning {
background: #fbbf24;
box-shadow: 0 0 0 1px rgba(251, 191, 36, 0.3);
}
&.status-error {
background: #f87171;
box-shadow: 0 0 0 1px rgba(248, 113, 113, 0.3);
}
&.status-loading {
background: #60a5fa;
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
&.status-unknown {
background: #9ca3af;
box-shadow: 0 0 0 1px rgba(156, 163, 175, 0.3);
}
}
.status-text {
font-size: 9px;
font-weight: 600;
color: var(--font-color);
text-transform: uppercase;
letter-spacing: 0.3px;
}
}
/* 单数服务居中显示 */
&:last-child:nth-child(odd) {
grid-column: 1 / -1;
max-width: 50%;
justify-self: center;
}
}
}
}
/* 深色模式适配 */
[data-theme="dark"] .uptime-dashboard {
background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
.uptime-services .service-item {
background: rgba(255, 255, 255, 0.05);
border-color: rgba(255, 255, 255, 0.1);
&:hover {
background: rgba(255, 255, 255, 0.1);
}
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
最后将uptime放到_config.solitude.yml文件中的aside的home的noSticky中即可
至此,教程结束,一键三连就可以看到最终的效果啦