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.
240 lines
11 KiB
240 lines
11 KiB
@{
|
|
ViewData["Title"] = "LTE WebSocket 客户端管理";
|
|
}
|
|
|
|
<div class="text-center">
|
|
<h1 class="display-4">LTE WebSocket 客户端管理</h1>
|
|
<p>基于 .NET 8 的 LTE WebSocket 客户端实现</p>
|
|
</div>
|
|
|
|
<!-- 消息提示 -->
|
|
@if (TempData["Message"] != null)
|
|
{
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
@TempData["Message"]
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
}
|
|
|
|
@if (TempData["Error"] != null)
|
|
{
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
@TempData["Error"]
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
}
|
|
|
|
<!-- 连接统计信息 -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">连接统计信息</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
@if (ViewBag.ConnectionStats != null)
|
|
{
|
|
var stats = ViewBag.ConnectionStats as LTEMvcApp.Services.ConnectionStatistics;
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="text-primary">@(stats?.TotalClients ?? 0)</h4>
|
|
<p class="text-muted">总客户端数</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="text-success">@(stats?.ConnectedClients ?? 0)</h4>
|
|
<p class="text-muted">已连接</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="text-warning">@(stats?.DisconnectedClients ?? 0)</h4>
|
|
<p class="text-muted">未连接</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="text-info">@(stats?.TotalLogs ?? 0)</h4>
|
|
<p class="text-muted">总日志数</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<p class="text-muted">暂无统计信息</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 客户端管理 -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">客户端管理</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- 快速操作按钮 -->
|
|
<div class="row mb-3">
|
|
<div class="col-md-12">
|
|
<form method="post" style="display: inline;">
|
|
<button type="submit" asp-action="AddTestClient" class="btn btn-primary me-2">
|
|
<i class="bi bi-plus-circle"></i> 添加测试客户端
|
|
</button>
|
|
</form>
|
|
<form method="post" style="display: inline;">
|
|
<button type="submit" asp-action="StartTestClient" class="btn btn-success me-2">
|
|
<i class="bi bi-play-circle"></i> 启动测试客户端
|
|
</button>
|
|
</form>
|
|
<form method="post" style="display: inline;">
|
|
<button type="submit" asp-action="StopTestClient" class="btn btn-danger me-2">
|
|
<i class="bi bi-stop-circle"></i> 停止测试客户端
|
|
</button>
|
|
</form>
|
|
<a href="@Url.Action("WebSocketTest")" class="btn btn-info">
|
|
<i class="bi bi-gear"></i> WebSocket 测试
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 客户端配置列表 -->
|
|
@if (ViewBag.ClientConfigs != null && ((List<LTEMvcApp.Models.ClientConfig>)ViewBag.ClientConfigs).Count > 0)
|
|
{
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>客户端名称</th>
|
|
<th>地址</th>
|
|
<th>状态</th>
|
|
<th>SSL</th>
|
|
<th>启用</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var config in ViewBag.ClientConfigs as List<LTEMvcApp.Models.ClientConfig>)
|
|
{
|
|
var stats = ViewBag.ConnectionStats as LTEMvcApp.Services.ConnectionStatistics;
|
|
var clientStates = stats?.ClientStates ?? new Dictionary<string, LTEMvcApp.Models.ClientState>();
|
|
var state = clientStates.GetValueOrDefault(config.Name, LTEMvcApp.Models.ClientState.Stop);
|
|
<tr>
|
|
<td>@config.Name</td>
|
|
<td>@(config.Ssl ? "wss://" : "ws://")@config.Address</td>
|
|
<td>
|
|
<span class="badge @(state == LTEMvcApp.Models.ClientState.Connected ? "bg-success" :
|
|
state == LTEMvcApp.Models.ClientState.Connecting ? "bg-warning" :
|
|
state == LTEMvcApp.Models.ClientState.Error ? "bg-danger" : "bg-secondary")">
|
|
@state
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<i class="bi @(config.Ssl ? "bi-check-circle-fill text-success" : "bi-x-circle-fill text-muted")"></i>
|
|
</td>
|
|
<td>
|
|
<i class="bi @(config.Enabled ? "bi-check-circle-fill text-success" : "bi-x-circle-fill text-muted")"></i>
|
|
</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm" role="group">
|
|
<button type="button" class="btn btn-outline-primary" onclick="startClient('@config.Name')">
|
|
<i class="bi bi-play"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-danger" onclick="stopClient('@config.Name')">
|
|
<i class="bi bi-stop"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info" onclick="viewLogs('@config.Name')">
|
|
<i class="bi bi-list-ul"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="text-center text-muted">
|
|
<i class="bi bi-info-circle" style="font-size: 2rem;"></i>
|
|
<p class="mt-2">暂无客户端配置</p>
|
|
<p>点击"添加测试客户端"按钮来创建第一个客户端配置</p>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- API 信息 -->
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">API 接口</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p>以下API接口可用于程序化控制WebSocket客户端:</p>
|
|
<ul class="list-unstyled">
|
|
<li><code>GET /api/websocket/clients</code> - 获取所有客户端状态</li>
|
|
<li><code>GET /api/websocket/configs</code> - 获取所有客户端配置</li>
|
|
<li><code>POST /api/websocket/configs</code> - 添加客户端配置</li>
|
|
<li><code>POST /api/websocket/clients/{name}/start</code> - 启动客户端</li>
|
|
<li><code>POST /api/websocket/clients/{name}/stop</code> - 停止客户端</li>
|
|
<li><code>GET /api/websocket/clients/{name}/logs</code> - 获取客户端日志</li>
|
|
<li><code>GET /api/websocket/statistics</code> - 获取连接统计信息</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
<script>
|
|
function startClient(clientName) {
|
|
fetch(`/api/websocket/clients/${encodeURIComponent(clientName)}/start`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
alert(data.message || '操作成功');
|
|
location.reload();
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('操作失败');
|
|
});
|
|
}
|
|
|
|
function stopClient(clientName) {
|
|
fetch(`/api/websocket/clients/${encodeURIComponent(clientName)}/stop`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
alert(data.message || '操作成功');
|
|
location.reload();
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('操作失败');
|
|
});
|
|
}
|
|
|
|
function viewLogs(clientName) {
|
|
window.open(`/api/websocket/clients/${encodeURIComponent(clientName)}/logs?limit=100`, '_blank');
|
|
}
|
|
</script>
|
|
}
|
|
|