init 全新仓库,清除全部历史
This commit is contained in:
@@ -0,0 +1,776 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>企业运维告警监控平台</title>
|
||||
<!-- 运维图标库 -->
|
||||
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
|
||||
<script src="/static/js/echarts.min.js"></script>
|
||||
<script src="/static/js/jquery.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f7f8fc;
|
||||
font-family: "Inter", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
color: #1d2939;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 顶部导航栏 企业深蓝主色调 */
|
||||
.header {
|
||||
background-color: #152c5b;
|
||||
color: #ffffff;
|
||||
padding: 18px 36px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 12px rgba(21, 44, 91, 0.12);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.header h1 i {
|
||||
font-size: 24px;
|
||||
color: #36d399;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.update-time {
|
||||
color: #cbd5e1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.refresh-btn, .export-btn {
|
||||
border: none;
|
||||
padding: 8px 18px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: all 0.24s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: #fff;
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
}
|
||||
.refresh-btn:hover {
|
||||
background-color: rgba(255,255,255,0.18);
|
||||
}
|
||||
|
||||
.export-btn {
|
||||
background-color: #10b981;
|
||||
color: #fff;
|
||||
}
|
||||
.export-btn:hover {
|
||||
background-color: #059669;
|
||||
}
|
||||
|
||||
/* 导出遮罩 */
|
||||
.mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.45);
|
||||
display: none;
|
||||
z-index: 999;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.mask-box {
|
||||
background: #fff;
|
||||
padding: 28px 36px;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,0.15);
|
||||
}
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-top-color: #152c5b;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 主容器 */
|
||||
.container {
|
||||
padding: 32px 36px;
|
||||
max-width: 1700px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* 统计卡片模块 改为5列布局 */
|
||||
.stat-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 28px;
|
||||
box-shadow: 0 2px 16px rgba(21, 44, 91, 0.06);
|
||||
border: 1px solid #eef2fb;
|
||||
transition: transform 0.24s ease, box-shadow 0.24s ease;
|
||||
}
|
||||
.stat-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(21, 44, 91, 0.1);
|
||||
}
|
||||
|
||||
.stat-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.stat-title {
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
}
|
||||
.stat-icon {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* 五类卡片主题色 */
|
||||
.stat-card.fire .stat-icon {
|
||||
background-color: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
.stat-card.active .stat-icon {
|
||||
background-color: #fef3c7;
|
||||
color: #d97706;
|
||||
}
|
||||
.stat-card.resolve .stat-icon {
|
||||
background-color: #dcfce7;
|
||||
color: #16a34a;
|
||||
}
|
||||
.stat-card.instance .stat-icon {
|
||||
background-color: #dbeafe;
|
||||
color: #2563eb;
|
||||
}
|
||||
.stat-card.rate .stat-icon {
|
||||
background-color: #ffedd5;
|
||||
color: #ea580c;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
color: #152c5b;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.stat-card.active .stat-value {
|
||||
color: #d97706;
|
||||
}
|
||||
.stat-sub {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
/* 图表模块 */
|
||||
.chart-section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.chart-card {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 28px;
|
||||
box-shadow: 0 2px 16px rgba(21, 44, 91, 0.06);
|
||||
border: 1px solid #eef2fb;
|
||||
}
|
||||
.chart-title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #152c5b;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 14px;
|
||||
border-bottom: 1px solid #eef2fb;
|
||||
}
|
||||
.chart-title-wrap i {
|
||||
color: #2563eb;
|
||||
font-size: 20px;
|
||||
}
|
||||
#chart1 {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 活跃告警面板(新增) */
|
||||
.active-alert-section {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 28px;
|
||||
box-shadow: 0 2px 16px rgba(21, 44, 91, 0.06);
|
||||
border: 1px solid #fecdd3;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.table-header-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 14px;
|
||||
border-bottom: 1px solid #eef2fb;
|
||||
}
|
||||
.table-title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #152c5b;
|
||||
}
|
||||
.table-title-wrap i {
|
||||
color: #2563eb;
|
||||
font-size: 20px;
|
||||
}
|
||||
.table-count {
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* 历史全量告警面板 */
|
||||
.table-section {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 28px;
|
||||
box-shadow: 0 2px 16px rgba(21, 44, 91, 0.06);
|
||||
border: 1px solid #eef2fb;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
th {
|
||||
background-color: #f8fafc;
|
||||
color: #475569;
|
||||
font-weight: 600;
|
||||
padding: 14px 16px;
|
||||
text-align: left;
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
th i {
|
||||
margin-right: 6px;
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
td {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
color: #334155;
|
||||
}
|
||||
tbody tr {
|
||||
transition: background 0.2s;
|
||||
}
|
||||
tbody tr:hover {
|
||||
background-color: #f8fafc;
|
||||
}
|
||||
tbody tr:nth-child(even) {
|
||||
background-color: #fbfcfe;
|
||||
}
|
||||
|
||||
/* 状态标签 */
|
||||
.status-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 5px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-tag.fire {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
.status-tag.resolve {
|
||||
background: #dcfce7;
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
/* 告警级别标签 */
|
||||
.severity-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 10px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.severity-critical { background: #fee2e2; color: #dc2626; }
|
||||
.severity-warning { background: #ffedd5; color: #ea580c; }
|
||||
.severity-info { background: #dbeafe; color: #2563eb; }
|
||||
|
||||
/* 空数据 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 70px 20px;
|
||||
color: #94a3b8;
|
||||
font-size: 15px;
|
||||
}
|
||||
.empty-state .empty-icon {
|
||||
font-size: 52px;
|
||||
margin-bottom: 16px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 1400px) {
|
||||
.stat-cards {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.header {
|
||||
padding: 16px 20px;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
.stat-cards {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导出加载遮罩 -->
|
||||
<div class="mask" id="exportMask">
|
||||
<div class="mask-box">
|
||||
<span class="loading"></span>
|
||||
<span>正在生成CSV报表,请稍候...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 顶部导航 -->
|
||||
<div class="header">
|
||||
<h1><i class="fa fa-bell"></i>企业运维告警监控平台</h1>
|
||||
<div class="header-right">
|
||||
<span class="update-time"><i class="fa fa-clock-o"></i>系统实时时间:<span id="updateTime">--</span></span>
|
||||
<button class="refresh-btn" onclick="loadAllData()"><i class="fa fa-refresh"></i>刷新数据</button>
|
||||
<button class="export-btn" onclick="exportCsv()"><i class="fa fa-download"></i>导出CSV报表</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- 统计卡片区域 新增【当前活跃告警】 -->
|
||||
<div class="stat-cards">
|
||||
<div class="stat-card fire">
|
||||
<div class="stat-header">
|
||||
<div class="stat-title">今日触发告警</div>
|
||||
<div class="stat-icon"><i class="fa fa-exclamation-triangle"></i></div>
|
||||
</div>
|
||||
<div class="stat-value" id="fire">0</div>
|
||||
<div class="stat-sub">Total Firing Today</div>
|
||||
</div>
|
||||
<!-- 新增:当前未恢复活跃告警 -->
|
||||
<div class="stat-card active">
|
||||
<div class="stat-header">
|
||||
<div class="stat-title">当前未恢复告警</div>
|
||||
<div class="stat-icon"><i class="fa fa-bolt"></i></div>
|
||||
</div>
|
||||
<div class="stat-value" id="activeAlert">0</div>
|
||||
<div class="stat-sub">Unresolved Now</div>
|
||||
</div>
|
||||
<div class="stat-card resolve">
|
||||
<div class="stat-header">
|
||||
<div class="stat-title">今日恢复告警</div>
|
||||
<div class="stat-icon"><i class="fa fa-check-circle"></i></div>
|
||||
</div>
|
||||
<div class="stat-value" id="resolve">0</div>
|
||||
<div class="stat-sub">Resolved Today</div>
|
||||
</div>
|
||||
<div class="stat-card instance">
|
||||
<div class="stat-header">
|
||||
<div class="stat-title">故障实例总数</div>
|
||||
<div class="stat-icon"><i class="fa fa-server"></i></div>
|
||||
</div>
|
||||
<div class="stat-value" id="instance">0</div>
|
||||
<div class="stat-sub">Affected Host Instance</div>
|
||||
</div>
|
||||
<div class="stat-card rate">
|
||||
<div class="stat-header">
|
||||
<div class="stat-title">告警恢复率</div>
|
||||
<div class="stat-icon"><i class="fa fa-line-chart"></i></div>
|
||||
</div>
|
||||
<div class="stat-value" id="rate">0%</div>
|
||||
<div class="stat-sub">Daily Recovery Rate</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TOP10图表区域 -->
|
||||
<div class="chart-section">
|
||||
<div class="chart-card">
|
||||
<div class="chart-title-wrap">
|
||||
<i class="fa fa-bar-chart"></i>今日告警频次 TOP 10
|
||||
</div>
|
||||
<div id="chart1"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增:当前未恢复活跃告警列表 -->
|
||||
<div class="active-alert-section">
|
||||
<div class="table-header-wrap">
|
||||
<div class="table-title-wrap">
|
||||
<i class="fa fa-exclamation-circle"></i>当前未恢复活跃告警
|
||||
</div>
|
||||
<div class="table-count">共 <span id="activeCount">0</span> 条未恢复故障</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:90px"><i class="fa fa-tag"></i>告警状态</th>
|
||||
<th><i class="fa fa-bullhorn"></i>告警名称</th>
|
||||
<th><i class="fa fa-desktop"></i>实例地址</th>
|
||||
<th style="width:110px"><i class="fa fa-signal"></i>告警级别</th>
|
||||
<th style="width:180px"><i class="fa fa-calendar"></i>故障发生时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="active-table-body">
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon"><i class="fa fa-check"></i></div>
|
||||
<div>当前无未恢复告警,系统运行正常</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 原有:今日全量告警明细列表 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header-wrap">
|
||||
<div class="table-title-wrap">
|
||||
<i class="fa fa-list-alt"></i>今日全量告警明细列表
|
||||
</div>
|
||||
<div class="table-count">共 <span id="totalCount">0</span> 条告警记录</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:90px"><i class="fa fa-tag"></i>告警状态</th>
|
||||
<th><i class="fa fa-bullhorn"></i>告警名称</th>
|
||||
<th><i class="fa fa-desktop"></i>实例地址</th>
|
||||
<th style="width:110px"><i class="fa fa-signal"></i>告警级别</th>
|
||||
<th style="width:180px"><i class="fa fa-calendar"></i>故障发生时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="table-body">
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon"><i class="fa fa-folder-open-o"></i></div>
|
||||
<div>暂无今日告警数据</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const api = "http://10.150.117.190:8080/api/oldapi.php";
|
||||
let chartInstance = null;
|
||||
let allAlertList = [];
|
||||
|
||||
// 时间格式化
|
||||
function formatTime(dateStr) {
|
||||
if (!dateStr || dateStr === '0001-01-01 00:00:00' || dateStr === null) return '-';
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
// 告警级别标签
|
||||
function getSeverityTag(severity) {
|
||||
const s = (severity || '').toLowerCase();
|
||||
if (s === 'critical') return `<span class="severity-tag severity-critical">严重</span>`;
|
||||
if (s === 'warning') return `<span class="severity-tag severity-warning">警告</span>`;
|
||||
if (s === 'info') return `<span class="severity-tag severity-info">信息</span>`;
|
||||
return `<span class="severity-tag severity-info">${severity || '-'}</span>`;
|
||||
}
|
||||
|
||||
// 筛选未恢复告警逻辑:同一条告警有触发无恢复则判定为活跃故障
|
||||
function getUnresolvedAlert(list) {
|
||||
// 建立指纹映射
|
||||
let fireMap = new Map();
|
||||
let resolveSet = new Set();
|
||||
list.forEach(item => {
|
||||
const key = `${item.alert_name}|${item.instance}`;
|
||||
if(item.alert_type === 1){
|
||||
fireMap.set(key, item);
|
||||
}else{
|
||||
resolveSet.add(key);
|
||||
}
|
||||
});
|
||||
// 过滤只存在触发、无恢复记录的告警
|
||||
let activeList = [];
|
||||
fireMap.forEach((val, key) => {
|
||||
if(!resolveSet.has(key)){
|
||||
activeList.push(val);
|
||||
}
|
||||
});
|
||||
return activeList;
|
||||
}
|
||||
|
||||
// 渲染活跃未恢复告警表格
|
||||
function renderActiveTable(activeList) {
|
||||
$("#activeCount").text(activeList.length);
|
||||
if (activeList.length === 0) {
|
||||
$("#active-table-body").html(`
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon"><i class="fa fa-check"></i></div>
|
||||
<div>当前无未恢复告警,系统运行正常</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`);
|
||||
return;
|
||||
}
|
||||
let html = "";
|
||||
activeList.forEach(row => {
|
||||
const typeText = `<span class="status-tag fire"><i class="fa fa-bolt"></i>触发</span>`;
|
||||
html += `<tr>
|
||||
<td>${typeText}</td>
|
||||
<td style="font-weight:500;color:#152c5b">${row.alert_name || '-'}</td>
|
||||
<td style="font-family:Consolas,monospace;font-size:13px">${row.instance || '-'}</td>
|
||||
<td>${getSeverityTag(row.severity)}</td>
|
||||
<td style="color:#475569">${formatTime(row.receive_time)}</td>
|
||||
</tr>`;
|
||||
});
|
||||
$("#active-table-body").html(html);
|
||||
$("#activeAlert").text(activeList.length);
|
||||
}
|
||||
|
||||
// 1、顶部统计卡片
|
||||
function loadStats() {
|
||||
$.getJSON(api + "?act=day_total", function(res) {
|
||||
const fire = parseInt(res.fire_count) || 0;
|
||||
const resolve = parseInt(res.resolve_count) || 0;
|
||||
const instance = parseInt(res.instance_num) || 0;
|
||||
const rate = fire > 0 ? Math.round((resolve / fire) * 100) : 0;
|
||||
|
||||
$("#fire").text(fire);
|
||||
$("#resolve").text(resolve);
|
||||
$("#instance").text(instance);
|
||||
$("#rate").text(rate + "%");
|
||||
}).fail(function() {
|
||||
$("#fire").text("-");
|
||||
$("#resolve").text("-");
|
||||
$("#instance").text("-");
|
||||
$("#rate").text("-");
|
||||
});
|
||||
}
|
||||
|
||||
// 2、TOP告警柱状图
|
||||
function loadChart() {
|
||||
$.getJSON(api + "?act=top_alert", function(list) {
|
||||
if (!chartInstance) {
|
||||
chartInstance = echarts.init(document.getElementById("chart1"));
|
||||
window.addEventListener("resize", () => chartInstance.resize());
|
||||
}
|
||||
const names = list.map(item => item.alert_name);
|
||||
const counts = list.map(item => item.cnt);
|
||||
|
||||
chartInstance.setOption({
|
||||
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
|
||||
grid: { left: "3%", right: "4%", bottom: "15%", top: "8%", containLabel: true },
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: names,
|
||||
axisLabel: { rotate: 28, fontSize: 12, color: "#64748b" },
|
||||
axisLine: { lineStyle: { color: "#e2e8f0" } },
|
||||
axisTick: { show: false }
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
name: "告警次数",
|
||||
nameTextStyle: { color: "#64748b", fontSize: 13 },
|
||||
axisLabel: { color: "#64748b", fontSize: 12 },
|
||||
splitLine: { lineStyle: { color: "#f1f5f9", type: "dashed" } },
|
||||
axisLine: { show: false }
|
||||
},
|
||||
series: [{
|
||||
type: "bar",
|
||||
data: counts,
|
||||
barWidth: "46%",
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "#3b82f6" },
|
||||
{ offset: 1, color: "#1d4ed8" }
|
||||
]),
|
||||
borderRadius: [5,5,0,0]
|
||||
},
|
||||
label: { show: true, position: "top", fontSize:12, color:"#334155" }
|
||||
}]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 3、告警明细表格 + 同步计算活跃未恢复告警
|
||||
function loadTable() {
|
||||
$.getJSON(api + "?act=log_list", function(list) {
|
||||
allAlertList = list;
|
||||
$("#totalCount").text(list.length);
|
||||
// 计算并渲染当前未恢复告警
|
||||
const activeList = getUnresolvedAlert(list);
|
||||
renderActiveTable(activeList);
|
||||
|
||||
// 渲染今日全量明细
|
||||
if (list.length === 0) {
|
||||
$("#table-body").html(`
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon"><i class="fa fa-folder-open-o"></i></div>
|
||||
<div>暂无今日告警数据</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`);
|
||||
return;
|
||||
}
|
||||
let html = "";
|
||||
list.forEach(row => {
|
||||
const typeText = row.alert_type == 1
|
||||
? `<span class="status-tag fire"><i class="fa fa-bolt"></i>触发</span>`
|
||||
: `<span class="status-tag resolve"><i class="fa fa-check"></i>恢复</span>`;
|
||||
|
||||
html += `<tr>
|
||||
<td>${typeText}</td>
|
||||
<td style="font-weight:500;color:#152c5b">${row.alert_name || '-'}</td>
|
||||
<td style="font-family:Consolas,monospace;font-size:13px">${row.instance || '-'}</td>
|
||||
<td>${getSeverityTag(row.severity)}</td>
|
||||
<td style="color:#475569">${formatTime(row.receive_time)}</td>
|
||||
</tr>`;
|
||||
});
|
||||
$("#table-body").html(html);
|
||||
}).fail(() => {
|
||||
$("#table-body").html(`
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="empty-state" style="color:#dc2626">
|
||||
<div class="empty-icon"><i class="fa fa-exclamation-circle"></i></div>
|
||||
<div>接口数据加载失败,请检查后端服务</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`);
|
||||
// 活跃表格同步清空
|
||||
$("#active-table-body").html(`
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="empty-state" style="color:#dc2626">
|
||||
<div class="empty-icon"><i class="fa fa-exclamation-circle"></i></div>
|
||||
<div>数据加载失败</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`);
|
||||
$("#activeAlert").text("-");
|
||||
});
|
||||
}
|
||||
|
||||
// 实时更新时钟(每秒执行)
|
||||
function updateTime() {
|
||||
const now = new Date();
|
||||
const Y = now.getFullYear();
|
||||
const M = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const D = String(now.getDate()).padStart(2, '0');
|
||||
const h = String(now.getHours()).padStart(2, '0');
|
||||
const m = String(now.getMinutes()).padStart(2, '0');
|
||||
const s = String(now.getSeconds()).padStart(2, '0');
|
||||
$("#updateTime").text(`${Y}-${M}-${D} ${h}:${m}:${s}`);
|
||||
}
|
||||
|
||||
// 全量加载数据
|
||||
function loadAllData() {
|
||||
loadStats();
|
||||
loadChart();
|
||||
loadTable();
|
||||
updateTime();
|
||||
}
|
||||
|
||||
// ====================== 导出CSV函数 ======================
|
||||
function exportCsv(){
|
||||
const mask = $("#exportMask");
|
||||
mask.css("display","flex");
|
||||
window.location.href = api + "?act=export_csv";
|
||||
setTimeout(()=>mask.hide(),5000);
|
||||
}
|
||||
|
||||
// 初始化
|
||||
$(function() {
|
||||
loadAllData();
|
||||
// 页面数据60秒刷新一次
|
||||
setInterval(loadAllData, 60000);
|
||||
// 实时时钟每秒刷新
|
||||
setInterval(updateTime, 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user