184 lines
5.9 KiB
JavaScript
184 lines
5.9 KiB
JavaScript
layui.use(['layer'], function(){
|
||
var layer = layui.layer;
|
||
var $ = layui.$;
|
||
|
||
// 初始化图表
|
||
var registerTrendChart = echarts.init(document.getElementById('register-trend'));
|
||
var deviceTypesChart = echarts.init(document.getElementById('device-types'));
|
||
|
||
// 加载统计数据
|
||
function loadStats() {
|
||
fetch('/api/dashboard/stats', {
|
||
credentials: 'include',
|
||
headers: {
|
||
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
||
}
|
||
})
|
||
.then(response => {
|
||
if (response.status === 401) {
|
||
window.location.href = '/login';
|
||
throw new Error('认证失败');
|
||
}
|
||
return response.json();
|
||
})
|
||
.then(result => {
|
||
if (result.error) {
|
||
layer.msg(result.error);
|
||
return;
|
||
}
|
||
|
||
// 更新统计数据
|
||
updateStats(result.data);
|
||
// 更新图表
|
||
updateCharts(result.data);
|
||
// 更新系统状态
|
||
updateSystemStatus(result.data);
|
||
})
|
||
.catch(error => {
|
||
layer.msg('加载统计数据失败:' + error.message);
|
||
});
|
||
}
|
||
|
||
// 更新统计数据
|
||
function updateStats(data) {
|
||
$('#total-devices').text(data.total_devices);
|
||
$('#total-licenses').text(data.total_licenses);
|
||
$('#online-devices').text(data.online_devices);
|
||
$('#expired-devices').text(data.expired_devices);
|
||
$('#today-new').text(data.today_new);
|
||
$('#unused-licenses').text(data.unused_licenses);
|
||
|
||
// 计算比率
|
||
var activeRate = data.total_devices > 0 ?
|
||
((data.online_devices / data.total_devices) * 100).toFixed(1) : 0;
|
||
var expiredRate = data.total_devices > 0 ?
|
||
((data.expired_devices / data.total_devices) * 100).toFixed(1) : 0;
|
||
|
||
$('#active-rate').text(activeRate + '%');
|
||
$('#expired-rate').text(expiredRate + '%');
|
||
}
|
||
|
||
// 更新图表
|
||
function updateCharts(data) {
|
||
// 设备注册趋势图
|
||
var trendOption = {
|
||
title: {
|
||
text: '最近7天设备注册趋势'
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis'
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
data: data.trend_dates
|
||
},
|
||
yAxis: {
|
||
type: 'value'
|
||
},
|
||
series: [{
|
||
name: '新增设备',
|
||
type: 'line',
|
||
smooth: true,
|
||
data: data.trend_counts,
|
||
itemStyle: {
|
||
color: '#009688'
|
||
},
|
||
areaStyle: {
|
||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||
offset: 0,
|
||
color: 'rgba(0, 150, 136, 0.3)'
|
||
}, {
|
||
offset: 1,
|
||
color: 'rgba(0, 150, 136, 0.1)'
|
||
}])
|
||
}
|
||
}]
|
||
};
|
||
registerTrendChart.setOption(trendOption);
|
||
|
||
// 设备类型分布图
|
||
var typesOption = {
|
||
title: {
|
||
text: '设备类型分布'
|
||
},
|
||
tooltip: {
|
||
trigger: 'item',
|
||
formatter: '{b}: {c} ({d}%)'
|
||
},
|
||
series: [{
|
||
type: 'pie',
|
||
radius: ['50%', '70%'],
|
||
avoidLabelOverlap: false,
|
||
itemStyle: {
|
||
borderRadius: 10,
|
||
borderColor: '#fff',
|
||
borderWidth: 2
|
||
},
|
||
label: {
|
||
show: false,
|
||
position: 'center'
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
show: true,
|
||
fontSize: '20',
|
||
fontWeight: 'bold'
|
||
}
|
||
},
|
||
labelLine: {
|
||
show: false
|
||
},
|
||
data: data.device_types.map(item => ({
|
||
name: item.type,
|
||
value: item.count
|
||
}))
|
||
}]
|
||
};
|
||
deviceTypesChart.setOption(typesOption);
|
||
}
|
||
|
||
// 更新系统状态
|
||
function updateSystemStatus(data) {
|
||
$('#cpu-usage').text(data.cpu_usage + '%');
|
||
$('#memory-usage').text(data.memory_usage + '%');
|
||
$('#disk-usage').text(data.disk_usage + '%');
|
||
$('#uptime').text(formatDuration(data.uptime));
|
||
$('#load-avg').text(data.load_avg.join(' '));
|
||
$('#network-traffic').text(formatBytes(data.network_traffic) + '/s');
|
||
$('#online-users').text(data.online_users);
|
||
$('#last-update').text(new Date().toLocaleString());
|
||
}
|
||
|
||
// 格式化时间
|
||
function formatDuration(seconds) {
|
||
var days = Math.floor(seconds / 86400);
|
||
var hours = Math.floor((seconds % 86400) / 3600);
|
||
var minutes = Math.floor((seconds % 3600) / 60);
|
||
var parts = [];
|
||
if (days > 0) parts.push(days + '天');
|
||
if (hours > 0) parts.push(hours + '小时');
|
||
if (minutes > 0) parts.push(minutes + '分钟');
|
||
return parts.join(' ') || '0分钟';
|
||
}
|
||
|
||
// 格式化字节大小
|
||
function formatBytes(bytes) {
|
||
if (bytes === 0) return '0 B';
|
||
var k = 1024;
|
||
var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||
var i = Math.floor(Math.log(bytes) / Math.log(k));
|
||
return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i];
|
||
}
|
||
|
||
// 初始加载
|
||
loadStats();
|
||
|
||
// 定时刷新(每30秒)
|
||
setInterval(loadStats, 30000);
|
||
|
||
// 窗口大小改变时重绘图表
|
||
window.onresize = function() {
|
||
registerTrendChart.resize();
|
||
deviceTypesChart.resize();
|
||
};
|
||
});
|