You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

344 lines
15 KiB

@{
ViewData["Title"] = "统计数据";
}
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">LTE统计数据监控</h3>
<div class="card-tools">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="refreshStats()">
<i class="fas fa-sync-alt"></i> 刷新
</button>
<button type="button" class="btn btn-sm btn-outline-danger" onclick="clearStats()">
<i class="fas fa-trash"></i> 清空
</button>
<button type="button" class="btn btn-sm btn-outline-info" onclick="toggleSSE()">
<i class="fas fa-broadcast-tower"></i> <span id="sseToggleText">启动SSE</span>
</button>
</div>
</div>
<div class="card-body">
<!-- 统计摘要 -->
<div class="row mb-3">
<div class="col-md-3">
<div class="info-box">
<span class="info-box-icon bg-info"><i class="fas fa-server"></i></span>
<div class="info-box-content">
<span class="info-box-text">客户端数量</span>
<span class="info-box-number" id="clientCount">0</span>
</div>
</div>
</div>
<div class="col-md-3">
<div class="info-box">
<span class="info-box-icon bg-success"><i class="fas fa-database"></i></span>
<div class="info-box-content">
<span class="info-box-text">队列大小</span>
<span class="info-box-number" id="queueCount">0</span>
</div>
</div>
</div>
<div class="col-md-3">
<div class="info-box">
<span class="info-box-icon bg-warning"><i class="fas fa-clock"></i></span>
<div class="info-box-content">
<span class="info-box-text">最后更新</span>
<span class="info-box-number" id="lastUpdate">-</span>
</div>
</div>
</div>
<div class="col-md-3">
<div class="info-box">
<span class="info-box-icon bg-primary"><i class="fas fa-signal"></i></span>
<div class="info-box-content">
<span class="info-box-text">SSE状态</span>
<span class="info-box-number" id="sseStatus">未连接</span>
</div>
</div>
</div>
</div>
<!-- 客户端选择 -->
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="clientSelect">选择客户端:</label>
<select class="form-control" id="clientSelect" onchange="loadClientStats()">
<option value="">所有客户端</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="refreshInterval">刷新间隔 (秒):</label>
<input type="number" class="form-control" id="refreshInterval" value="5" min="1" max="60" onchange="updateRefreshInterval()">
</div>
</div>
</div>
<!-- 统计数据表格 -->
<div class="table-responsive">
<table class="table table-bordered table-striped" id="statsTable">
<thead>
<tr>
<th>客户端</th>
<th>实例ID</th>
<th>CPU使用率</th>
<th>小区数量</th>
<th>RF端口</th>
<th>消息ID</th>
<th>持续时间</th>
<th>接收时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="statsTableBody">
<!-- 数据将通过JavaScript动态填充 -->
</tbody>
</table>
</div>
<!-- 小区详细信息 -->
<div class="row mt-4" id="cellDetails" style="display: none;">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">小区详细信息 - <span id="selectedClientName"></span></h4>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered table-striped" id="cellTable">
<thead>
<tr>
<th>小区ID</th>
<th>下行比特率</th>
<th>上行比特率</th>
<th>下行使用率(平均)</th>
<th>上行使用率(平均)</th>
<th>UE数量(平均)</th>
<th>ERAB数量(平均)</th>
<th>调度用户(下行)</th>
<th>调度用户(上行)</th>
</tr>
</thead>
<tbody id="cellTableBody">
<!-- 小区数据将通过JavaScript动态填充 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
let sseConnection = null;
let refreshTimer = null;
let currentStats = {};
// 页面加载完成后初始化
$(document).ready(function() {
loadSummary();
loadAllStats();
startRefreshTimer();
});
// 加载统计摘要
function loadSummary() {
$.get('/Statistics/GetSummary', function(response) {
if (response.success) {
$('#clientCount').text(response.data.clientCount || 0);
$('#queueCount').text(response.data.totalStatsCount || 0);
if (response.data.lastUpdateTime) {
$('#lastUpdate').text(new Date(response.data.lastUpdateTime).toLocaleString());
}
}
});
}
// 加载所有统计数据
function loadAllStats() {
$.get('/Statistics/GetAllClientStats', function(response) {
if (response.success) {
currentStats = response.data;
updateStatsTable();
updateClientSelect();
}
});
}
// 更新统计表格
function updateStatsTable() {
const tbody = $('#statsTableBody');
tbody.empty();
Object.keys(currentStats).forEach(clientName => {
const stats = currentStats[clientName];
const row = `
<tr>
<td>${clientName}</td>
<td>${stats.instanceId || '-'}</td>
<td>${(stats.cpu?.global || 0).toFixed(2)}%</td>
<td>${Object.keys(stats.cells || {}).length}</td>
<td>${Object.keys(stats.rfPorts || {}).length}</td>
<td>${stats.messageId || '-'}</td>
<td>${(stats.duration || 0).toFixed(2)}s</td>
<td>${new Date(stats.receivedAt).toLocaleString()}</td>
<td>
<button class="btn btn-sm btn-info" onclick="showCellDetails('${clientName}')">
<i class="fas fa-eye"></i> 查看小区
</button>
</td>
</tr>
`;
tbody.append(row);
});
}
// 更新客户端选择下拉框
function updateClientSelect() {
const select = $('#clientSelect');
select.find('option:not(:first)').remove();
Object.keys(currentStats).forEach(clientName => {
select.append(`<option value="${clientName}">${clientName}</option>`);
});
}
// 显示小区详细信息
function showCellDetails(clientName) {
const stats = currentStats[clientName];
if (!stats || !stats.cells) return;
$('#selectedClientName').text(clientName);
const tbody = $('#cellTableBody');
tbody.empty();
Object.keys(stats.cells).forEach(cellId => {
const cell = stats.cells[cellId];
const row = `
<tr>
<td>${cellId}</td>
<td>${(cell.dlBitrate || 0).toFixed(2)}</td>
<td>${(cell.ulBitrate || 0).toFixed(2)}</td>
<td>${(cell.dlUseAvg || 0).toFixed(2)}%</td>
<td>${(cell.ulUseAvg || 0).toFixed(2)}%</td>
<td>${(cell.ueCountAvg || 0).toFixed(0)}</td>
<td>${(cell.erabCountAvg || 0).toFixed(0)}</td>
<td>${(cell.dlSchedUsersAvg || 0).toFixed(0)}</td>
<td>${(cell.ulSchedUsersAvg || 0).toFixed(0)}</td>
</tr>
`;
tbody.append(row);
});
$('#cellDetails').show();
}
// 加载指定客户端的统计数据
function loadClientStats() {
const clientName = $('#clientSelect').val();
if (!clientName) {
loadAllStats();
return;
}
$.get(`/Statistics/GetClientStats?clientName=${encodeURIComponent(clientName)}`, function(response) {
if (response.success) {
currentStats = { [clientName]: response.data };
updateStatsTable();
}
});
}
// 刷新统计数据
function refreshStats() {
loadSummary();
loadAllStats();
}
// 清空统计数据
function clearStats() {
if (confirm('确定要清空所有统计数据吗?')) {
$.post('/Statistics/ClearStats', function(response) {
if (response.success) {
alert('统计数据已清空');
refreshStats();
} else {
alert('清空失败: ' + response.message);
}
});
}
}
// 切换SSE连接
function toggleSSE() {
if (sseConnection) {
sseConnection.close();
sseConnection = null;
$('#sseToggleText').text('启动SSE');
$('#sseStatus').text('未连接').removeClass('text-success').addClass('text-danger');
} else {
startSSE();
$('#sseToggleText').text('停止SSE');
$('#sseStatus').text('已连接').removeClass('text-danger').addClass('text-success');
}
}
// 启动SSE连接
function startSSE() {
sseConnection = new EventSource('/Statistics/SSEStats');
sseConnection.onmessage = function(event) {
try {
const data = JSON.parse(event.data);
if (data.type === 'stats_update') {
currentStats = data.data;
updateStatsTable();
loadSummary();
}
} catch (e) {
console.error('解析SSE数据失败:', e);
}
};
sseConnection.onerror = function(event) {
console.error('SSE连接错误:', event);
$('#sseStatus').text('连接错误').removeClass('text-success').addClass('text-danger');
};
}
// 启动刷新定时器
function startRefreshTimer() {
const interval = $('#refreshInterval').val() * 1000;
if (refreshTimer) {
clearInterval(refreshTimer);
}
refreshTimer = setInterval(refreshStats, interval);
}
// 更新刷新间隔
function updateRefreshInterval() {
startRefreshTimer();
}
// 页面卸载时清理资源
$(window).on('beforeunload', function() {
if (sseConnection) {
sseConnection.close();
}
if (refreshTimer) {
clearInterval(refreshTimer);
}
});
</script>
}