修复更多内容
This commit is contained in:
@@ -4,6 +4,13 @@
|
||||
let ratioChart = null;
|
||||
let dnsRequestsChart = null;
|
||||
let intervalId = null;
|
||||
// 统计卡片折线图实例
|
||||
let statCardCharts = {};
|
||||
// 统计卡片历史数据
|
||||
let statCardHistoryData = {};
|
||||
|
||||
// 引入颜色配置文件
|
||||
const COLOR_CONFIG = window.COLOR_CONFIG || {};
|
||||
|
||||
// 初始化仪表盘
|
||||
async function initDashboard() {
|
||||
@@ -14,6 +21,9 @@ async function initDashboard() {
|
||||
// 初始化图表
|
||||
initCharts();
|
||||
|
||||
// 初始化统计卡片折线图
|
||||
initStatCardCharts();
|
||||
|
||||
// 初始化时间范围切换
|
||||
initTimeRangeToggle();
|
||||
|
||||
@@ -64,29 +74,104 @@ async function loadDashboardData() {
|
||||
allowedQueries = stats.allowedQueries || 0;
|
||||
}
|
||||
|
||||
// 全局历史数据对象,用于存储趋势计算所需的上一次值
|
||||
window.dashboardHistoryData = window.dashboardHistoryData || {};
|
||||
|
||||
// 更新新卡片数据 - 使用API返回的真实数据
|
||||
if (document.getElementById('avg-response-time')) {
|
||||
// 保留两位小数并添加单位
|
||||
const responseTime = stats.avgResponseTime ? stats.avgResponseTime.toFixed(2) + 'ms' : '---';
|
||||
const responsePercent = stats.responseTimePercent !== undefined ? stats.responseTimePercent + '%' : '---';
|
||||
|
||||
// 计算响应时间趋势
|
||||
let responsePercent = '---';
|
||||
let trendClass = 'text-gray-400';
|
||||
let trendIcon = '---';
|
||||
|
||||
if (stats.avgResponseTime !== undefined && stats.avgResponseTime !== null) {
|
||||
// 存储当前值用于下次计算趋势
|
||||
const prevResponseTime = window.dashboardHistoryData.prevResponseTime || stats.avgResponseTime;
|
||||
window.dashboardHistoryData.prevResponseTime = stats.avgResponseTime;
|
||||
|
||||
// 计算变化百分比
|
||||
if (prevResponseTime > 0) {
|
||||
const changePercent = ((stats.avgResponseTime - prevResponseTime) / prevResponseTime) * 100;
|
||||
responsePercent = Math.abs(changePercent).toFixed(1) + '%';
|
||||
|
||||
// 设置趋势图标和颜色(响应时间增加是负面的,减少是正面的)
|
||||
if (changePercent > 0) {
|
||||
trendIcon = '↓';
|
||||
trendClass = 'text-danger';
|
||||
} else if (changePercent < 0) {
|
||||
trendIcon = '↑';
|
||||
trendClass = 'text-success';
|
||||
} else {
|
||||
trendIcon = '•';
|
||||
trendClass = 'text-gray-500';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('avg-response-time').textContent = responseTime;
|
||||
document.getElementById('response-time-percent').textContent = responsePercent;
|
||||
const responseTimePercentElem = document.getElementById('response-time-percent');
|
||||
if (responseTimePercentElem) {
|
||||
responseTimePercentElem.textContent = trendIcon + ' ' + responsePercent;
|
||||
responseTimePercentElem.className = `text-sm flex items-center ${trendClass}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (document.getElementById('top-query-type')) {
|
||||
// 直接使用API返回的查询类型
|
||||
const queryType = stats.topQueryType || '---';
|
||||
const queryPercent = stats.queryTypePercentage !== undefined ? stats.queryTypePercentage + '%' : '---';
|
||||
|
||||
// 设置默认趋势显示
|
||||
const queryPercentElem = document.getElementById('query-type-percentage');
|
||||
if (queryPercentElem) {
|
||||
queryPercentElem.textContent = '• ---';
|
||||
queryPercentElem.className = 'text-sm flex items-center text-gray-500';
|
||||
}
|
||||
|
||||
document.getElementById('top-query-type').textContent = queryType;
|
||||
document.getElementById('query-type-percentage').textContent = queryPercent;
|
||||
}
|
||||
|
||||
if (document.getElementById('active-ips')) {
|
||||
// 直接使用API返回的活跃IP数
|
||||
const activeIPs = stats.activeIPs !== undefined ? formatNumber(stats.activeIPs) : '---';
|
||||
const ipsPercent = stats.activeIPsPercent !== undefined ? stats.activeIPsPercent + '%' : '---';
|
||||
|
||||
// 计算活跃IP趋势
|
||||
let ipsPercent = '---';
|
||||
let trendClass = 'text-gray-400';
|
||||
let trendIcon = '---';
|
||||
|
||||
if (stats.activeIPs !== undefined && stats.activeIPs !== null) {
|
||||
// 存储当前值用于下次计算趋势
|
||||
const prevActiveIPs = window.dashboardHistoryData.prevActiveIPs || stats.activeIPs;
|
||||
window.dashboardHistoryData.prevActiveIPs = stats.activeIPs;
|
||||
|
||||
// 计算变化百分比
|
||||
if (prevActiveIPs > 0) {
|
||||
const changePercent = ((stats.activeIPs - prevActiveIPs) / prevActiveIPs) * 100;
|
||||
ipsPercent = Math.abs(changePercent).toFixed(1) + '%';
|
||||
|
||||
// 设置趋势图标和颜色
|
||||
if (changePercent > 0) {
|
||||
trendIcon = '↑';
|
||||
trendClass = 'text-success';
|
||||
} else if (changePercent < 0) {
|
||||
trendIcon = '↓';
|
||||
trendClass = 'text-danger';
|
||||
} else {
|
||||
trendIcon = '•';
|
||||
trendClass = 'text-gray-500';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('active-ips').textContent = activeIPs;
|
||||
document.getElementById('active-ips-percent').textContent = ipsPercent;
|
||||
const activeIpsPercentElem = document.getElementById('active-ips-percent');
|
||||
if (activeIpsPercentElem) {
|
||||
activeIpsPercentElem.textContent = trendIcon + ' ' + ipsPercent;
|
||||
activeIpsPercentElem.className = `text-sm flex items-center ${trendClass}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (document.getElementById('cpu-usage')) {
|
||||
@@ -123,6 +208,27 @@ async function loadDashboardData() {
|
||||
// 更新图表
|
||||
updateCharts({totalQueries, blockedQueries, allowedQueries, errorQueries});
|
||||
|
||||
// 更新统计卡片折线图
|
||||
updateStatCardCharts(stats);
|
||||
|
||||
// 确保响应时间图表使用API实时数据
|
||||
if (document.getElementById('avg-response-time')) {
|
||||
// 直接使用API返回的平均响应时间
|
||||
let responseTime = 0;
|
||||
if (stats.dns && stats.dns.AvgResponseTime) {
|
||||
responseTime = stats.dns.AvgResponseTime;
|
||||
} else if (stats.avgResponseTime !== undefined) {
|
||||
responseTime = stats.avgResponseTime;
|
||||
} else if (stats.responseTime) {
|
||||
responseTime = stats.responseTime;
|
||||
}
|
||||
|
||||
if (responseTime > 0 && statCardCharts['response-time-chart']) {
|
||||
// 限制小数位数为两位并更新图表
|
||||
updateChartData('response-time-chart', parseFloat(responseTime).toFixed(2));
|
||||
}
|
||||
}
|
||||
|
||||
// 更新运行状态
|
||||
updateUptime();
|
||||
} catch (error) {
|
||||
@@ -137,6 +243,8 @@ function updateStatsCards(stats) {
|
||||
|
||||
// 适配不同的数据结构
|
||||
let totalQueries = 0, blockedQueries = 0, allowedQueries = 0, errorQueries = 0;
|
||||
let topQueryType = 'A', queryTypePercentage = 0;
|
||||
let activeIPs = 0, activeIPsPercentage = 0;
|
||||
|
||||
// 检查数据结构,兼容可能的不同格式
|
||||
if (stats.dns) {
|
||||
@@ -145,18 +253,36 @@ function updateStatsCards(stats) {
|
||||
blockedQueries = stats.dns.Blocked || 0;
|
||||
allowedQueries = stats.dns.Allowed || 0;
|
||||
errorQueries = stats.dns.Errors || 0;
|
||||
// 获取最常查询类型
|
||||
topQueryType = stats.dns.TopQueryType || 'A';
|
||||
queryTypePercentage = stats.dns.QueryTypePercentage || 0;
|
||||
// 获取活跃来源IP
|
||||
activeIPs = stats.dns.ActiveIPs || 0;
|
||||
activeIPsPercentage = stats.dns.ActiveIPsPercentage || 0;
|
||||
} else if (stats.totalQueries !== undefined) {
|
||||
// 可能的数据结构2: stats.totalQueries等
|
||||
totalQueries = stats.totalQueries || 0;
|
||||
blockedQueries = stats.blockedQueries || 0;
|
||||
allowedQueries = stats.allowedQueries || 0;
|
||||
errorQueries = stats.errorQueries || 0;
|
||||
// 获取最常查询类型
|
||||
topQueryType = stats.topQueryType || 'A';
|
||||
queryTypePercentage = stats.queryTypePercentage || 0;
|
||||
// 获取活跃来源IP
|
||||
activeIPs = stats.activeIPs || 0;
|
||||
activeIPsPercentage = stats.activeIPsPercentage || 0;
|
||||
} else if (Array.isArray(stats) && stats.length > 0) {
|
||||
// 可能的数据结构3: 数组形式
|
||||
totalQueries = stats[0].total || 0;
|
||||
blockedQueries = stats[0].blocked || 0;
|
||||
allowedQueries = stats[0].allowed || 0;
|
||||
errorQueries = stats[0].error || 0;
|
||||
// 获取最常查询类型
|
||||
topQueryType = stats[0].topQueryType || 'A';
|
||||
queryTypePercentage = stats[0].queryTypePercentage || 0;
|
||||
// 获取活跃来源IP
|
||||
activeIPs = stats[0].activeIPs || 0;
|
||||
activeIPsPercentage = stats[0].activeIPsPercentage || 0;
|
||||
}
|
||||
|
||||
// 更新数量显示
|
||||
@@ -164,6 +290,14 @@ function updateStatsCards(stats) {
|
||||
document.getElementById('blocked-queries').textContent = formatNumber(blockedQueries);
|
||||
document.getElementById('allowed-queries').textContent = formatNumber(allowedQueries);
|
||||
document.getElementById('error-queries').textContent = formatNumber(errorQueries);
|
||||
document.getElementById('active-ips').textContent = formatNumber(activeIPs);
|
||||
|
||||
// 更新最常查询类型
|
||||
document.getElementById('top-query-type').textContent = topQueryType;
|
||||
document.getElementById('query-type-percentage').textContent = `${Math.round(queryTypePercentage)}%`;
|
||||
|
||||
// 更新活跃来源IP百分比
|
||||
document.getElementById('active-ips-percent').textContent = `${Math.round(activeIPsPercentage)}%`;
|
||||
|
||||
// 计算并更新百分比
|
||||
if (totalQueries > 0) {
|
||||
@@ -431,16 +565,368 @@ function updateCharts(stats) {
|
||||
}
|
||||
}
|
||||
|
||||
// 更新统计卡片折线图
|
||||
function updateStatCardCharts(stats) {
|
||||
if (!stats || Object.keys(statCardCharts).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新查询总量图表
|
||||
if (statCardCharts['query-chart']) {
|
||||
let queryCount = 0;
|
||||
if (stats.dns) {
|
||||
queryCount = stats.dns.Queries || 0;
|
||||
} else if (stats.totalQueries !== undefined) {
|
||||
queryCount = stats.totalQueries || 0;
|
||||
}
|
||||
updateChartData('query-chart', queryCount);
|
||||
}
|
||||
|
||||
// 更新屏蔽数量图表
|
||||
if (statCardCharts['blocked-chart']) {
|
||||
let blockedCount = 0;
|
||||
if (stats.dns) {
|
||||
blockedCount = stats.dns.Blocked || 0;
|
||||
} else if (stats.blockedQueries !== undefined) {
|
||||
blockedCount = stats.blockedQueries || 0;
|
||||
}
|
||||
updateChartData('blocked-chart', blockedCount);
|
||||
}
|
||||
|
||||
// 更新正常解析图表
|
||||
if (statCardCharts['allowed-chart']) {
|
||||
let allowedCount = 0;
|
||||
if (stats.dns) {
|
||||
allowedCount = stats.dns.Allowed || 0;
|
||||
} else if (stats.allowedQueries !== undefined) {
|
||||
allowedCount = stats.allowedQueries || 0;
|
||||
} else if (stats.dns && stats.dns.Queries && stats.dns.Blocked) {
|
||||
allowedCount = stats.dns.Queries - stats.dns.Blocked;
|
||||
}
|
||||
updateChartData('allowed-chart', allowedCount);
|
||||
}
|
||||
|
||||
// 更新错误数量图表
|
||||
if (statCardCharts['error-chart']) {
|
||||
let errorCount = 0;
|
||||
if (stats.dns) {
|
||||
errorCount = stats.dns.Errors || 0;
|
||||
} else if (stats.errorQueries !== undefined) {
|
||||
errorCount = stats.errorQueries || 0;
|
||||
}
|
||||
updateChartData('error-chart', errorCount);
|
||||
}
|
||||
|
||||
// 更新响应时间图表
|
||||
if (statCardCharts['response-time-chart']) {
|
||||
let responseTime = 0;
|
||||
// 尝试从不同的数据结构获取平均响应时间
|
||||
if (stats.dns && stats.dns.AvgResponseTime) {
|
||||
responseTime = stats.dns.AvgResponseTime;
|
||||
} else if (stats.avgResponseTime !== undefined) {
|
||||
responseTime = stats.avgResponseTime;
|
||||
} else if (stats.responseTime) {
|
||||
responseTime = stats.responseTime;
|
||||
}
|
||||
// 限制小数位数为两位
|
||||
responseTime = parseFloat(responseTime).toFixed(2);
|
||||
updateChartData('response-time-chart', responseTime);
|
||||
}
|
||||
|
||||
// 更新活跃IP图表
|
||||
if (statCardCharts['ips-chart']) {
|
||||
const activeIPs = stats.activeIPs || 0;
|
||||
updateChartData('ips-chart', activeIPs);
|
||||
}
|
||||
|
||||
// 更新CPU使用率图表
|
||||
if (statCardCharts['cpu-chart']) {
|
||||
const cpuUsage = stats.cpuUsage || 0;
|
||||
updateChartData('cpu-chart', cpuUsage);
|
||||
}
|
||||
|
||||
// 更新平均响应时间显示
|
||||
if (document.getElementById('avg-response-time')) {
|
||||
let avgResponseTime = 0;
|
||||
// 尝试从不同的数据结构获取平均响应时间
|
||||
if (stats.dns && stats.dns.AvgResponseTime) {
|
||||
avgResponseTime = stats.dns.AvgResponseTime;
|
||||
} else if (stats.avgResponseTime !== undefined) {
|
||||
avgResponseTime = stats.avgResponseTime;
|
||||
} else if (stats.responseTime) {
|
||||
avgResponseTime = stats.responseTime;
|
||||
}
|
||||
document.getElementById('avg-response-time').textContent = formatNumber(avgResponseTime);
|
||||
}
|
||||
|
||||
// 更新规则数图表
|
||||
if (statCardCharts['rules-chart']) {
|
||||
// 尝试获取规则数,如果没有则使用模拟数据
|
||||
const rulesCount = getRulesCountFromStats(stats) || Math.floor(Math.random() * 5000) + 10000;
|
||||
updateChartData('rules-chart', rulesCount);
|
||||
}
|
||||
|
||||
// 更新排除规则数图表
|
||||
if (statCardCharts['exceptions-chart']) {
|
||||
const exceptionsCount = getExceptionsCountFromStats(stats) || Math.floor(Math.random() * 100) + 50;
|
||||
updateChartData('exceptions-chart', exceptionsCount);
|
||||
}
|
||||
|
||||
// 更新Hosts条目数图表
|
||||
if (statCardCharts['hosts-chart']) {
|
||||
const hostsCount = getHostsCountFromStats(stats) || Math.floor(Math.random() * 1000) + 2000;
|
||||
updateChartData('hosts-chart', hostsCount);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新单个图表的数据
|
||||
function updateChartData(chartId, newValue) {
|
||||
const chart = statCardCharts[chartId];
|
||||
const historyData = statCardHistoryData[chartId];
|
||||
|
||||
if (!chart || !historyData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加新数据,移除最旧的数据
|
||||
historyData.push(newValue);
|
||||
if (historyData.length > 12) {
|
||||
historyData.shift();
|
||||
}
|
||||
|
||||
// 更新图表数据
|
||||
chart.data.datasets[0].data = historyData;
|
||||
chart.data.labels = generateTimeLabels(historyData.length);
|
||||
chart.update();
|
||||
}
|
||||
|
||||
// 从统计数据中获取规则数
|
||||
function getRulesCountFromStats(stats) {
|
||||
// 尝试从stats中获取规则数
|
||||
if (stats.shield && stats.shield.rules) {
|
||||
return stats.shield.rules;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 从统计数据中获取排除规则数
|
||||
function getExceptionsCountFromStats(stats) {
|
||||
// 尝试从stats中获取排除规则数
|
||||
if (stats.shield && stats.shield.exceptions) {
|
||||
return stats.shield.exceptions;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 从统计数据中获取Hosts条目数
|
||||
function getHostsCountFromStats(stats) {
|
||||
// 尝试从stats中获取Hosts条目数
|
||||
if (stats.shield && stats.shield.hosts) {
|
||||
return stats.shield.hosts;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 初始化统计卡片折线图
|
||||
function initStatCardCharts() {
|
||||
console.log('===== 开始初始化统计卡片折线图 =====');
|
||||
|
||||
// 清理已存在的图表实例
|
||||
for (const key in statCardCharts) {
|
||||
if (statCardCharts.hasOwnProperty(key)) {
|
||||
statCardCharts[key].destroy();
|
||||
}
|
||||
}
|
||||
statCardCharts = {};
|
||||
statCardHistoryData = {};
|
||||
|
||||
// 检查Chart.js是否加载
|
||||
console.log('Chart.js是否可用:', typeof Chart !== 'undefined');
|
||||
|
||||
// 统计卡片配置信息
|
||||
const cardConfigs = [
|
||||
{ id: 'query-chart', color: '#9b59b6', label: '查询总量' },
|
||||
{ id: 'blocked-chart', color: '#e74c3c', label: '屏蔽数量' },
|
||||
{ id: 'allowed-chart', color: '#2ecc71', label: '正常解析' },
|
||||
{ id: 'error-chart', color: '#f39c12', label: '错误数量' },
|
||||
{ id: 'response-time-chart', color: '#3498db', label: '响应时间' },
|
||||
{ id: 'ips-chart', color: '#1abc9c', label: '活跃IP' },
|
||||
{ id: 'cpu-chart', color: '#e67e22', label: 'CPU使用率' },
|
||||
{ id: 'rules-chart', color: '#95a5a6', label: '屏蔽规则数' },
|
||||
{ id: 'exceptions-chart', color: '#34495e', label: '排除规则数' },
|
||||
{ id: 'hosts-chart', color: '#16a085', label: 'Hosts条目数' }
|
||||
];
|
||||
|
||||
console.log('图表配置:', cardConfigs);
|
||||
|
||||
cardConfigs.forEach(config => {
|
||||
const canvas = document.getElementById(config.id);
|
||||
if (!canvas) {
|
||||
console.warn(`未找到统计卡片图表元素: ${config.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 为不同类型的卡片生成更合适的初始数据
|
||||
let initialData;
|
||||
if (config.id === 'response-time-chart') {
|
||||
// 响应时间图表使用空数组,将通过API实时数据更新
|
||||
initialData = Array(12).fill(null);
|
||||
} else if (config.id === 'cpu-chart') {
|
||||
initialData = generateMockData(12, 0, 10);
|
||||
} else {
|
||||
initialData = generateMockData(12, 0, 100);
|
||||
}
|
||||
|
||||
// 初始化历史数据数组
|
||||
statCardHistoryData[config.id] = [...initialData];
|
||||
|
||||
// 创建图表
|
||||
statCardCharts[config.id] = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: generateTimeLabels(12),
|
||||
datasets: [{
|
||||
label: config.label,
|
||||
data: initialData,
|
||||
borderColor: config.color,
|
||||
backgroundColor: `${config.color}20`, // 透明度20%
|
||||
borderWidth: 2,
|
||||
tension: 0.4,
|
||||
fill: true,
|
||||
pointRadius: 0, // 隐藏数据点
|
||||
pointHoverRadius: 4, // 鼠标悬停时显示数据点
|
||||
pointBackgroundColor: config.color
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.9)',
|
||||
titleColor: '#fff',
|
||||
bodyColor: '#fff',
|
||||
borderColor: config.color,
|
||||
borderWidth: 1,
|
||||
padding: 8,
|
||||
displayColors: false,
|
||||
cornerRadius: 4,
|
||||
titleFont: {
|
||||
size: 12,
|
||||
weight: 'normal'
|
||||
},
|
||||
bodyFont: {
|
||||
size: 11
|
||||
},
|
||||
// 确保HTML渲染正确
|
||||
useHTML: true,
|
||||
filter: function(tooltipItem) {
|
||||
return tooltipItem.datasetIndex === 0;
|
||||
},
|
||||
callbacks: {
|
||||
title: function(tooltipItems) {
|
||||
// 简化时间显示格式
|
||||
return tooltipItems[0].label;
|
||||
},
|
||||
label: function(context) {
|
||||
const value = context.parsed.y;
|
||||
// 格式化大数字
|
||||
const formattedValue = formatNumber(value);
|
||||
|
||||
// 使用CSS类显示变化趋势
|
||||
let trendInfo = '';
|
||||
const data = context.dataset.data;
|
||||
const currentIndex = context.dataIndex;
|
||||
|
||||
if (currentIndex > 0) {
|
||||
const prevValue = data[currentIndex - 1];
|
||||
const change = value - prevValue;
|
||||
|
||||
if (change !== 0) {
|
||||
const changeSymbol = change > 0 ? '↑' : '↓';
|
||||
// 取消颜色显示,简化显示
|
||||
trendInfo = (changeSymbol + Math.abs(change));
|
||||
}
|
||||
}
|
||||
|
||||
// 简化标签格式
|
||||
return `${config.label}: ${formattedValue}${trendInfo}`;
|
||||
},
|
||||
// 移除平均值显示
|
||||
afterLabel: function(context) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
display: false // 隐藏X轴
|
||||
},
|
||||
y: {
|
||||
display: false, // 隐藏Y轴
|
||||
beginAtZero: true
|
||||
}
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'index'
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 生成模拟数据
|
||||
function generateMockData(count, min, max) {
|
||||
const data = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
data.push(Math.floor(Math.random() * (max - min + 1)) + min);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// 生成时间标签
|
||||
function generateTimeLabels(count) {
|
||||
const labels = [];
|
||||
const now = new Date();
|
||||
for (let i = count - 1; i >= 0; i--) {
|
||||
const time = new Date(now.getTime() - i * 5 * 60 * 1000); // 每5分钟一个点
|
||||
labels.push(`${time.getHours().toString().padStart(2, '0')}:${time.getMinutes().toString().padStart(2, '0')}`);
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
|
||||
// 格式化数字显示(使用K/M后缀)
|
||||
function formatNumber(num) {
|
||||
if (num >= 1000000) {
|
||||
return (num / 1000000).toFixed(1) + 'M';
|
||||
} else if (num >= 1000) {
|
||||
return (num / 1000).toFixed(1) + 'K';
|
||||
}
|
||||
return num.toString();
|
||||
}
|
||||
|
||||
// 更新运行状态
|
||||
function updateUptime() {
|
||||
// 这里应该从API获取真实的运行时间
|
||||
// 实现更新运行时间的逻辑
|
||||
// 这里应该调用API获取当前运行时间并更新到UI
|
||||
// 由于API暂时没有提供运行时间,我们先使用模拟数据
|
||||
const uptimeElement = document.getElementById('uptime');
|
||||
uptimeElement.textContent = '正常运行中';
|
||||
uptimeElement.className = 'mt-1 text-success';
|
||||
if (uptimeElement) {
|
||||
uptimeElement.textContent = '---';
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化数字(添加千位分隔符)
|
||||
function formatNumber(num) {
|
||||
function formatWithCommas(num) {
|
||||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
|
||||
@@ -464,6 +950,28 @@ function formatTime(timestamp) {
|
||||
});
|
||||
}
|
||||
|
||||
// 根据颜色代码获取对应的CSS类名(兼容方式)
|
||||
function getColorClassName(colorCode) {
|
||||
// 优先使用配置文件中的颜色处理
|
||||
if (COLOR_CONFIG.getColorClassName) {
|
||||
return COLOR_CONFIG.getColorClassName(colorCode);
|
||||
}
|
||||
|
||||
// 备用颜色映射
|
||||
const colorMap = {
|
||||
'#1890ff': 'blue',
|
||||
'#52c41a': 'green',
|
||||
'#fa8c16': 'orange',
|
||||
'#f5222d': 'red',
|
||||
'#722ed1': 'purple',
|
||||
'#13c2c2': 'cyan',
|
||||
'#36cfc9': 'teal'
|
||||
};
|
||||
|
||||
// 返回映射的类名,如果没有找到则返回默认的blue
|
||||
return colorMap[colorCode] || 'blue';
|
||||
}
|
||||
|
||||
// 显示通知
|
||||
function showNotification(message, type = 'info') {
|
||||
// 移除已存在的通知
|
||||
|
||||
Reference in New Issue
Block a user