Browse Source

的撒大

feature/MultiClientLog
root 1 month ago
parent
commit
b2d5031d98
  1. 41
      LTEMvcApp/Controllers/HomeController.cs
  2. 68
      LTEMvcApp/Controllers/IpGroupController.cs
  3. 50
      LTEMvcApp/Models/NetworkConfig.cs
  4. 218
      LTEMvcApp/Views/Home/Index.cshtml
  5. 160
      LTEMvcApp/Views/Home/NetworkConfig.cshtml

41
LTEMvcApp/Controllers/HomeController.cs

@ -10,11 +10,13 @@ public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly WebSocketManagerService _webSocketManager;
private readonly HttpClientService _httpClientService;
public HomeController(ILogger<HomeController> logger, WebSocketManagerService webSocketManager)
public HomeController(ILogger<HomeController> logger, WebSocketManagerService webSocketManager, HttpClientService httpClientService)
{
_logger = logger;
_webSocketManager = webSocketManager;
_httpClientService = httpClientService;
}
public IActionResult Index()
@ -36,9 +38,37 @@ public class HomeController : Controller
var ipGroups = ProcessIpGroups(allTestClients);
ViewBag.IpGroups = ipGroups;
// 网络配置将通过JavaScript异步加载,不阻塞页面渲染
ViewBag.NetworkConfigs = new List<NetworkConfig>();
return View();
}
/// <summary>
/// 获取网络配置
/// </summary>
private async Task<List<NetworkConfig>> GetNetworkConfigs(string ip, string port)
{
try
{
var apiUrl = $"http://{ip}:{port}/api/v1/NetworkConfig";
var response = await _httpClientService.GetAsync<NetworkConfigResponse>(apiUrl);
if (response.IsSuccess)
{
return response.Data;
}
_logger.LogWarning("获取网络配置失败: {Response}", response);
return new List<NetworkConfig>();
}
catch (Exception ex)
{
_logger.LogError(ex, "获取网络配置异常: {Ip}:{Port}", ip, port);
return new List<NetworkConfig>();
}
}
/// <summary>
/// 处理IP分组数据
/// </summary>
@ -255,4 +285,13 @@ public class HomeController : Controller
{
return View();
}
public IActionResult NetworkConfig()
{
// 获取所有测试客户端配置和状态
var allTestClients = _webSocketManager.GetAllTestClientsWithState();
var ipGroups = ProcessIpGroups(allTestClients);
ViewBag.IpGroups = ipGroups;
return View();
}
}

68
LTEMvcApp/Controllers/IpGroupController.cs

@ -161,6 +161,74 @@ namespace LTEMvcApp.Controllers
return NotFound($"未找到IP地址为 {ip} 的Key配置");
}
}
/// <summary>
/// 获取网络配置列表
/// </summary>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <returns>网络配置列表</returns>
[HttpGet("network-config")]
public async Task<ActionResult> GetNetworkConfigs([FromQuery] string ip, [FromQuery] string port)
{
try
{
var apiUrl = $"http://{ip}:{port}/api/v1/NetworkConfig";
_logger.LogInformation("获取网络配置: {ApiUrl}", apiUrl);
var response = await _httpClientService.GetAsync<NetworkConfigResponse>(apiUrl);
_logger.LogInformation("网络配置获取成功");
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取网络配置失败: {Ip}:{Port}", ip, port);
return BadRequest($"获取网络配置失败: {ex.Message}");
}
}
/// <summary>
/// 添加网络配置(转发)
/// </summary>
[HttpPost("network-config")]
public async Task<ActionResult> AddNetworkConfig([FromQuery] string ip, [FromQuery] string port, [FromBody] object config)
{
if (string.IsNullOrEmpty(ip) || string.IsNullOrEmpty(port))
return BadRequest("ip和port不能为空");
try
{
var apiUrl = $"http://{ip}:{port}/api/v1/NetworkConfig";
var response = await _httpClientService.PostJsonAsync(apiUrl, config);
return Content(response, "application/json");
}
catch (Exception ex)
{
_logger.LogError(ex, "添加网络配置失败: {Ip}:{Port}", ip, port);
return BadRequest($"添加网络配置失败: {ex.Message}");
}
}
/// <summary>
/// 删除网络配置(转发)
/// </summary>
[HttpDelete("network-config/{configKey}")]
public async Task<ActionResult> DeleteNetworkConfig(string configKey, [FromQuery] string ip, [FromQuery] string port)
{
if (string.IsNullOrEmpty(ip) || string.IsNullOrEmpty(port))
return BadRequest("ip和port不能为空");
try
{
var apiUrl = $"http://{ip}:{port}/api/v1/NetworkConfig/{configKey}";
var response = await _httpClientService.DeleteAsync(apiUrl);
return Content(response, "application/json");
}
catch (Exception ex)
{
_logger.LogError(ex, "删除网络配置失败: {Ip}:{Port}", ip, port);
return BadRequest($"删除网络配置失败: {ex.Message}");
}
}
}
/// <summary>

50
LTEMvcApp/Models/NetworkConfig.cs

@ -0,0 +1,50 @@
namespace LTEMvcApp.Models
{
/// <summary>
/// 网络配置响应
/// </summary>
public class NetworkConfigResponse
{
public List<NetworkConfig> Data { get; set; } = new();
public bool IsSuccess { get; set; }
public string Message { get; set; } = string.Empty;
public string ErrorCode { get; set; } = string.Empty;
public int StatusCode { get; set; }
}
/// <summary>
/// 网络配置
/// </summary>
public class NetworkConfig
{
/// <summary>
/// 配置键
/// </summary>
public string ConfigKey { get; set; } = string.Empty;
/// <summary>
/// RAN配置路径
/// </summary>
public string RagConfig { get; set; } = string.Empty;
/// <summary>
/// 核心或IMS配置
/// </summary>
public List<object> CoreOrImsConfigs { get; set; } = new();
/// <summary>
/// APN
/// </summary>
public string Apn { get; set; } = string.Empty;
/// <summary>
/// 频段列表
/// </summary>
public List<string> Band { get; set; } = new();
/// <summary>
/// 注释
/// </summary>
public string Comment { get; set; } = string.Empty;
}
}

218
LTEMvcApp/Views/Home/Index.cshtml

@ -178,11 +178,14 @@
<table class="table table-striped projects client-table">
<thead>
<tr>
<th style="width: 25%">AgentIP</th>
<th style="width: 25%">AgentPort</th>
<th style="width: 10%">Key</th>
<th style="width: 20%">AgentIP</th>
<th style="width: 15%">AgentPort</th>
<th style="width: 15%">Key</th>
<th style="width: 10%">apn</th>
<th style="width: 10%">band</th>
<th style="width: 10%">comment</th>
<th style="width: 10%">状态</th>
<th style="width: 16%" class="text-center">操作</th>
<th style="width: 10%" class="text-center">操作</th>
</tr>
</thead>
<tbody>
@ -194,10 +197,21 @@
<td>@group.Ip</td>
<td>@group.Port</td>
<td>
<input type="text" class="form-control form-control-sm"
value="@group.Key"
placeholder="输入Key"
onchange="updateGroupKey('@group.Ip', this.value)">
<select class="form-control form-control-sm network-config-select"
data-ip="@group.Ip"
data-port="@group.Port"
onchange="updateGroupKey('@group.Ip', this.value)">
<option value="">加载中...</option>
</select>
</td>
<td class="apn-cell" data-ip="@group.Ip">
<!-- 异步加载 -->
</td>
<td class="band-cell" data-ip="@group.Ip">
<!-- 异步加载 -->
</td>
<td class="comment-cell" data-ip="@group.Ip">
<!-- 异步加载 -->
</td>
<td>
@if (group.State == "运行")
@ -214,12 +228,17 @@
}
</td>
<td class="project-actions text-right">
<a class="btn btn-primary btn-sm" href="#" onclick="startIpGroup('@group.Ip')">
<i class="fas fa-play"></i> 启动网络
</a>
<a class="btn btn-danger btn-sm" href="#" onclick="stopIpGroup('@group.Ip')">
<i class="fas fa-stop"></i> 停止网络
</a>
<div class="btn-group d-inline-flex" role="group">
<a class="btn btn-outline-success btn-sm" href="#" title="启动网络" onclick="startIpGroup('@group.Ip')">
<i class="fas fa-play"></i>
</a>
<a class="btn btn-outline-danger btn-sm" href="#" title="停止网络" onclick="stopIpGroup('@group.Ip')">
<i class="fas fa-stop"></i>
</a>
<a class="btn btn-outline-primary btn-sm" href="@Url.Action("NetworkConfig", "Home", new { ip = group.Ip, port = group.Port })" title="添加/管理网络配置">
<i class="fas fa-plus"></i>
</a>
</div>
</td>
</tr>
}
@ -333,8 +352,121 @@
</div>
</div>
<!-- 添加网络配置模态框 -->
<div class="modal fade" id="addNetworkConfigModal" tabindex="-1" role="dialog" aria-labelledby="addNetworkConfigModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addNetworkConfigModalLabel">添加网络配置</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="addNetworkConfigForm">
<input type="hidden" name="ip" />
<input type="hidden" name="port" />
<div class="form-group">
<label>Key</label>
<input type="text" class="form-control" name="configKey" required />
</div>
<div class="form-group">
<label>RagConfig</label>
<input type="text" class="form-control" name="ragConfig" />
</div>
<div class="form-group">
<label>APN</label>
<input type="text" class="form-control" name="apn" />
</div>
<div class="form-group">
<label>Band(逗号分隔)</label>
<input type="text" class="form-control" name="band" />
</div>
<div class="form-group">
<label>Comment</label>
<input type="text" class="form-control" name="comment" />
</div>
<!-- coreOrImsConfigs 可扩展为复杂表单,这里先省略 -->
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" onclick="submitAddNetworkConfig()">添加</button>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
// 页面加载完成后异步初始化网络配置下拉框
$(document).ready(function() {
// 延迟加载,避免阻塞页面渲染
setTimeout(function() {
loadAllNetworkConfigs();
}, 100);
});
function loadAllNetworkConfigs() {
$('.network-config-select').each(function() {
var select = $(this);
var ip = select.data('ip');
var port = select.data('port');
// 从服务器获取当前保存的Key
$.ajax({
url: '/api/ipgroup/key/' + encodeURIComponent(ip),
type: 'GET',
timeout: 5000, // 5秒超时
success: function(keyResponse) {
var currentKey = keyResponse.key || '';
loadNetworkConfigs(select, ip, port, currentKey);
},
error: function() {
// 如果获取Key失败,使用空字符串
loadNetworkConfigs(select, ip, port, '');
}
});
});
}
function loadNetworkConfigs(selectElement, ip, port, currentKey) {
$.ajax({
url: '/api/ipgroup/network-config',
type: 'GET',
data: { ip: ip, port: port },
timeout: 10000, // 10秒超时
success: function(response) {
if (response.isSuccess && response.data) {
// 清空现有选项并设置默认选项
selectElement.empty();
selectElement.append('<option value="">请选择Key</option>');
// 添加网络配置选项
response.data.forEach(function(config) {
var selected = config.configKey === currentKey ? 'selected' : '';
selectElement.append('<option value="' + config.configKey + '" ' + selected + '>' + config.configKey + '</option>');
});
// 如果有当前选中的Key,更新对应的apn、band、comment
if (currentKey) {
updateNetworkConfigDisplay(ip, currentKey);
}
} else {
// 如果加载失败,显示错误状态
selectElement.empty();
selectElement.append('<option value="">加载失败</option>');
}
},
error: function(xhr, status, error) {
console.warn('加载网络配置失败:', ip + ':' + port, error);
// 显示加载失败状态
selectElement.empty();
selectElement.append('<option value="">加载失败</option>');
}
});
}
function startTestClient(address) {
$.ajax({
url: '/api/testconfig/start',
@ -393,6 +525,9 @@
console.log('IP组Key保存成功:', response);
// 可以显示一个小的成功提示
showToast('Key保存成功', 'success');
// 更新对应的apn、band、comment列
updateNetworkConfigDisplay(ip, key);
},
error: function(xhr) {
console.error('IP组Key保存失败:', xhr.responseText);
@ -401,6 +536,49 @@
});
}
function updateNetworkConfigDisplay(ip, key) {
// 获取当前行的端口信息
var row = $('tr').filter(function() {
return $(this).find('td:first').text().trim() === ip;
});
var port = row.find('td:eq(1)').text().trim(); // 第二列是端口
// 根据IP和端口获取网络配置数据
$.ajax({
url: '/api/ipgroup/network-config',
type: 'GET',
data: { ip: ip, port: port },
timeout: 10000, // 10秒超时
success: function(response) {
if (response.isSuccess && response.data) {
var selectedConfig = response.data.find(function(config) {
return config.configKey === key;
});
if (selectedConfig) {
// 更新apn列
$('.apn-cell[data-ip="' + ip + '"]').text(selectedConfig.apn || '');
// 更新band列
var bandText = selectedConfig.band ? selectedConfig.band.join(',') : '';
$('.band-cell[data-ip="' + ip + '"]').text(bandText);
// 更新comment列
$('.comment-cell[data-ip="' + ip + '"]').text(selectedConfig.comment || '');
}
}
},
error: function(xhr, status, error) {
console.warn('更新网络配置显示失败:', ip + ':' + port, error);
// 清空显示内容
$('.apn-cell[data-ip="' + ip + '"]').text('');
$('.band-cell[data-ip="' + ip + '"]').text('');
$('.comment-cell[data-ip="' + ip + '"]').text('');
}
});
}
function startIpGroup(ip) {
// 获取当前行的端口信息
var row = $('tr').filter(function() {
@ -408,12 +586,12 @@
});
var port = row.find('td:eq(1)').text().trim(); // 第二列是端口
var keyInput = row.find('input[type="text"]');
var key = keyInput.val().trim();
var keySelect = row.find('select');
var key = keySelect.val();
if (!key) {
alert('请先填写网络Key!');
keyInput.focus();
alert('请先选择网络Key!');
keySelect.focus();
return;
}
@ -487,5 +665,9 @@
$('.alert').fadeOut();
}, 3000);
}
$(function () {
$('[title]').tooltip({trigger: 'hover'});
});
</script>
}

160
LTEMvcApp/Views/Home/NetworkConfig.cshtml

@ -0,0 +1,160 @@
@{
ViewData["Title"] = "网络配置管理";
var ip = Context.Request.Query["ip"].ToString();
var port = Context.Request.Query["port"].ToString();
}
<div class="container mt-4">
<h2>网络配置管理 <span class="text-info">@ip:@port</span></h2>
<div class="row mb-3">
<div class="col-md-4">
<button class="btn btn-success" onclick="showAddConfigModal()">
<i class="fas fa-plus"></i> 添加网络配置
</button>
</div>
</div>
<div id="configTableContainer">
<!-- 配置表格将由JS动态填充 -->
</div>
</div>
<!-- 添加配置模态框 -->
<div class="modal fade" id="addConfigModal" tabindex="-1" role="dialog" aria-labelledby="addConfigModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addConfigModalLabel">添加网络配置</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="addConfigForm">
<div class="form-group">
<label>Key</label>
<input type="text" class="form-control" name="configKey" required />
</div>
<div class="form-group">
<label>RagConfig</label>
<input type="text" class="form-control" name="ragConfig" />
</div>
<div class="form-group">
<label>APN</label>
<input type="text" class="form-control" name="apn" />
</div>
<div class="form-group">
<label>Band(逗号分隔)</label>
<input type="text" class="form-control" name="band" />
</div>
<div class="form-group">
<label>Comment</label>
<input type="text" class="form-control" name="comment" />
</div>
<!-- coreOrImsConfigs 可扩展为复杂表单,这里先省略 -->
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" onclick="submitAddConfig()">添加</button>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
const ip = '@ip';
const port = '@port';
$(function() {
loadNetworkConfigs();
});
function loadNetworkConfigs() {
if (!ip || !port) {
$('#configTableContainer').html('<div class="alert alert-info">未指定Agent</div>');
return;
}
$.ajax({
url: '/api/ipgroup/network-config',
type: 'GET',
data: { ip, port },
success: function(res) {
if (res.isSuccess && res.data) {
renderConfigTable(res.data);
} else {
$('#configTableContainer').html('<div class="alert alert-warning">加载失败</div>');
}
},
error: function() {
$('#configTableContainer').html('<div class="alert alert-danger">加载失败</div>');
}
});
}
function renderConfigTable(data) {
let html = `<table class="table table-bordered"><thead><tr>
<th>Key</th><th>APN</th><th>Band</th><th>Comment</th><th>操作</th>
</tr></thead><tbody>`;
if (data.length === 0) {
html += '<tr><td colspan="5" class="text-center">暂无数据</td></tr>';
} else {
data.forEach(item => {
html += `<tr>
<td>${item.configKey}</td>
<td>${item.apn || ''}</td>
<td>${item.band ? item.band.join(',') : ''}</td>
<td>${item.comment || ''}</td>
<td><button class="btn btn-danger btn-sm" onclick="deleteConfig('${item.configKey}')"><i class='fas fa-trash'></i> 删除</button></td>
</tr>`;
});
}
html += '</tbody></table>';
$('#configTableContainer').html(html);
}
function showAddConfigModal() {
$('#addConfigForm')[0].reset();
$('#addConfigModal').modal('show');
}
function submitAddConfig() {
const form = $('#addConfigForm');
const data = {
configKey: form.find('[name="configKey"]').val(),
ragConfig: form.find('[name="ragConfig"]').val(),
apn: form.find('[name="apn"]').val(),
band: form.find('[name="band"]').val().split(',').map(x => x.trim()).filter(x => x),
comment: form.find('[name="comment"]').val(),
coreOrImsConfigs: [] // 可扩展
};
$.ajax({
url: `/api/ipgroup/network-config?ip=${ip}&port=${port}`,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(res) {
$('#addConfigModal').modal('hide');
loadNetworkConfigs();
},
error: function() {
alert('添加失败');
}
});
}
function deleteConfig(configKey) {
if (!confirm('确定要删除该配置吗?')) return;
$.ajax({
url: `/api/ipgroup/network-config/${encodeURIComponent(configKey)}?ip=${ip}&port=${port}`,
type: 'DELETE',
success: function() {
loadNetworkConfigs();
},
error: function() {
alert('删除失败');
}
});
}
</script>
}
Loading…
Cancel
Save