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.
 
 
 

522 lines
25 KiB

@{
ViewData["Title"] = "测试客户端配置";
var testConfig = ViewBag.TestConfig as LTEMvcApp.Models.ClientConfig;
// 只保留不含 EVENT 的日志层
var allLayers = LTEMvcApp.Models.LogLayerTypes.AllLayers.Where(l => l != "EVENT").ToArray();
var allIMSLayers = LTEMvcApp.Models.LogLayerTypes.AllIMSLayers.Where(l => l != "EVENT").ToArray(); // 暂时使用AllLayers,后续可以扩展
var layerConfigs = testConfig?.Logs?.Layers ?? new Dictionary<string, LTEMvcApp.Models.LogLayerConfig>();
}
<style>
/* 页面整体布局 */
.config-container {
max-height: calc(100vh - 280px);
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 表单容器 */
.config-form {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 0.75rem;
}
/* 自定义滚动条 */
.config-form::-webkit-scrollbar {
width: 6px;
}
.config-form::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.config-form::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
.config-form::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* 表单样式 */
.form-group {
margin-bottom: 0.75rem;
}
.form-group label {
font-weight: 600;
color: #495057;
margin-bottom: 0.25rem;
font-size: 0.9rem;
}
.form-control {
border-radius: 0.375rem;
border: 1px solid #ced4da;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
padding: 0.375rem 0.75rem;
}
.form-control:focus {
border-color: #80bdff;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
/* 表格样式 */
.table-responsive {
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.table {
margin-bottom: 0;
flex: 1;
font-size: 0.85rem;
}
.table th {
background-color: #343a40;
color: white;
font-weight: 600;
border: none;
position: sticky;
top: 0;
z-index: 10;
padding: 0.5rem;
}
.table td {
vertical-align: middle;
border-color: #dee2e6;
padding: 0.5rem;
}
/* 按钮样式 */
.btn {
border-radius: 0.375rem;
font-weight: 500;
transition: all 0.2s;
padding: 0.375rem 0.75rem;
font-size: 0.9rem;
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.form-check {
margin-bottom: 0.5rem;
}
.form-check-input:checked {
background-color: #007bff;
border-color: #007bff;
}
.section-title {
color: #495057;
font-weight: 600;
margin-bottom: 0.5rem;
padding-bottom: 0.25rem;
border-bottom: 2px solid #e9ecef;
font-size: 1rem;
}
/* 按钮区域 */
.button-area {
flex-shrink: 0;
background: white;
border-top: 1px solid #dee2e6;
padding: 0.5rem 0.75rem;
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
/* 响应式调整 */
@@media (max-width: 768px) {
.config-container {
max-height: calc(100vh - 240px);
}
.button-area {
padding: 0.4rem 0.6rem;
}
.config-form {
padding: 0.6rem;
}
}
@@media (max-width: 576px) {
.config-container {
max-height: calc(100vh - 220px);
}
.button-area {
padding: 0.3rem 0.5rem;
}
.config-form {
padding: 0.5rem;
}
.btn {
font-size: 0.8rem;
padding: 0.3rem 0.6rem;
}
}
/* 日志层配置容器 */
.logs-config-section {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.logs-config-content {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
</style>
<div class="container">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-cog"></i> 测试客户端配置
</h3>
</div>
<div class="card-body p-0">
<div class="config-container">
<form id="testClientConfigForm" class="config-form">
<!-- 基本配置 -->
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">客户端名称</label>
<input type="text" class="form-control" id="name" name="name" value="@testConfig?.Name" required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="address">服务器地址</label>
<input type="text" class="form-control" id="address" name="address" value="@testConfig?.Address" placeholder="192.168.13.12:9001">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password" name="password" value="@testConfig?.Password">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="reconnectDelay">重连延迟 (毫秒)</label>
<input type="number" class="form-control" id="reconnectDelay" name="reconnectDelay" value="@testConfig?.ReconnectDelay">
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-12 d-flex align-items-center flex-wrap">
<div class="form-check form-check-inline mr-3">
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" @(testConfig?.Enabled == true ? "checked" : "")>
<label class="form-check-label" for="enabled">启用</label>
</div>
<div class="form-check form-check-inline mr-3">
<input type="checkbox" class="form-check-input" id="ssl" name="ssl" @(testConfig?.Ssl == true ? "checked" : "")>
<label class="form-check-label" for="ssl">使用SSL</label>
</div>
<div class="form-check form-check-inline mr-3">
<input type="checkbox" class="form-check-input" id="readonly" name="readonly" @(testConfig?.Readonly == true ? "checked" : "")>
<label class="form-check-label" for="readonly">只读模式</label>
</div>
<div class="form-check form-check-inline mr-3">
<input type="radio" class="form-check-input" id="mode_ran" name="mode" value="ran" @(testConfig?.Mode == "ran" ? "checked" : "")>
<label class="form-check-label" for="mode_ran">RAN</label>
</div>
<div class="form-check form-check-inline">
<input type="radio" class="form-check-input" id="mode_ims" name="mode" value="ims" @(testConfig?.Mode == "ims" ? "checked" : "")>
<label class="form-check-label" for="mode_ims">IMS</label>
</div>
</div>
</div>
<!-- 日志层配置表格 -->
<div class="row logs-config-section">
<div class="col-md-12">
<div class="d-flex justify-content-between align-items-center mb-2 px-3 py-2" style="background: #f8f9fa; border-radius: 0.5rem; border: 1px solid #e9ecef;">
<h5 class="section-title mb-0" style="font-size: 1.1rem; color: #343a40;">
<i class="fas fa-layer-group"></i> 日志层配置
</h5>
<button type="submit" class="btn btn-primary" form="testClientConfigForm" style="min-width: 110px;">
<i class="fas fa-save"></i> 保存配置
</button>
</div>
<div class="logs-config-content">
<div class="table-responsive">
<table class="table table-bordered table-sm">
<thead class="table-dark">
<tr>
<th>日志层</th>
<th>过滤器</th>
<th>级别</th>
<th>最大大小</th>
<th>包含负载</th>
</tr>
</thead>
<tbody id="layersTableBody">
<!-- RAN 模式下的日志层 -->
<tbody id="ranLayers" class="mode-layers" style="">
@foreach (var layer in allLayers)
{
var config = layerConfigs.ContainsKey(layer) ? layerConfigs[layer] : new LTEMvcApp.Models.LogLayerConfig();
<tr>
<td><strong>@layer</strong></td>
<td>
<select class="form-control form-control-sm" name="layers[@layer][filter]">
@foreach (var logLevel in LTEMvcApp.Models.LogLayerTypes.LogLevels)
{
if (logLevel == config.Filter)
{
<option value="@logLevel" selected>@logLevel.ToUpper()</option>
}
else
{
<option value="@logLevel">@logLevel.ToUpper()</option>
}
}
</select>
</td>
<td>
<select class="form-control form-control-sm" name="layers[@layer][level]">
@foreach (var logLevel in LTEMvcApp.Models.LogLayerTypes.LogLevels)
{
if (logLevel == config.Level)
{
<option value="@logLevel" selected>@logLevel.ToUpper()</option>
}
else
{
<option value="@logLevel">@logLevel.ToUpper()</option>
}
}
</select>
</td>
<td>
<input type="number" class="form-control form-control-sm" name="layers[@layer][max_size]" value="@config.MaxSize" min="1" max="1000">
</td>
<td>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="layers[@layer][payload]" @(config.Payload ? "checked" : "")>
</div>
</td>
</tr>
}
</tbody>
<!-- IMS 模式下的日志层 -->
<tbody id="imsLayers" class="mode-layers" style="display: none;">
@foreach (var layer in allIMSLayers)
{
var config = layerConfigs.ContainsKey(layer) ? layerConfigs[layer] : new LTEMvcApp.Models.LogLayerConfig();
<tr>
<td><strong>@layer</strong></td>
<td>
<select class="form-control form-control-sm" name="layers[@layer][filter]">
@foreach (var logLevel in LTEMvcApp.Models.LogLayerTypes.LogLevels)
{
if (logLevel == config.Filter)
{
<option value="@logLevel" selected>@logLevel.ToUpper()</option>
}
else
{
<option value="@logLevel">@logLevel.ToUpper()</option>
}
}
</select>
</td>
<td>
<select class="form-control form-control-sm" name="layers[@layer][level]">
@foreach (var logLevel in LTEMvcApp.Models.LogLayerTypes.LogLevels)
{
if (logLevel == config.Level)
{
<option value="@logLevel" selected>@logLevel.ToUpper()</option>
}
else
{
<option value="@logLevel">@logLevel.ToUpper()</option>
}
}
</select>
</td>
<td>
<input type="number" class="form-control form-control-sm" name="layers[@layer][max_size]" value="@config.MaxSize" min="1" max="1000">
</td>
<td>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="layers[@layer][payload]" @(config.Payload ? "checked" : "")>
</div>
</td>
</tr>
}
</tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
$(document).ready(function() {
$('#testClientConfigForm').on('submit', function(e) {
e.preventDefault();
saveTestClientConfig();
});
// 监听模式切换
$('input[name="mode"]').on('change', function() {
var selectedMode = $(this).val();
$('.mode-layers').hide();
$('#' + selectedMode + 'Layers').show();
});
// 页面加载时根据当前模式显示对应日志层
var initialMode = $('input[name="mode"]:checked').val();
$('.mode-layers').hide();
$('#' + initialMode + 'Layers').show();
// 监听地址输入框变化,自动查询配置
$('#address').on('blur', function() {
var address = $(this).val().trim();
if (address) {
loadConfigByAddress(address);
}
});
});
// 根据地址加载配置
function loadConfigByAddress(address) {
$.ajax({
url: '/api/testconfig/address/' + encodeURIComponent(address),
type: 'GET',
success: function(config) {
if (config) {
// 填充表单
$('#name').val(config.name);
$('#password').val(config.password);
$('#reconnectDelay').val(config.reconnectDelay);
$('#enabled').prop('checked', config.enabled);
$('#ssl').prop('checked', config.ssl);
$('#readonly').prop('checked', config.readonly);
// 设置模式
if (config.mode) {
$('input[name="mode"][value="' + config.mode + '"]').prop('checked', true).trigger('change');
}
// 填充日志层配置
if (config.logs && config.logs.layers) {
Object.keys(config.logs.layers).forEach(function(layer) {
var layerConfig = config.logs.layers[layer];
$(`select[name="layers[${layer}][level]"]`).val(layerConfig.level);
$(`select[name="layers[${layer}][filter]"]`).val(layerConfig.filter);
$(`input[name="layers[${layer}][max_size]"]`).val(layerConfig.maxSize);
$(`input[name="layers[${layer}][payload]"]`).prop('checked', layerConfig.payload);
});
}
console.log('已加载配置:', config.name);
}
},
error: function(xhr) {
if (xhr.status === 404) {
console.log('未找到该地址的配置,将创建新配置');
} else {
console.error('查询配置失败:', xhr.responseText);
}
}
});
}
function saveTestClientConfig() {
var formData = {
name: $('#name').val(),
address: $('#address').val(),
password: $('#password').val(),
reconnectDelay: parseInt($('#reconnectDelay').val()) || 15000,
enabled: $('#enabled').is(':checked'),
ssl: $('#ssl').is(':checked'),
readonly: $('#readonly').is(':checked'),
mode: $('input[name="mode"]:checked').val(),
logs: {
layers: {}
}
};
// 根据当前模式获取日志层
var selectedMode = $('input[name="mode"]:checked').val();
var layers = selectedMode === 'ims' ? @Html.Raw(System.Text.Json.JsonSerializer.Serialize(allIMSLayers)) : @Html.Raw(System.Text.Json.JsonSerializer.Serialize(allLayers));
layers.forEach(function(layer) {
var level = $(`select[name="layers[${layer}][level]"]`).val();
var filter = $(`select[name="layers[${layer}][filter]"]`).val();
var maxSize = parseInt($(`input[name="layers[${layer}][max_size]"]`).val()) || 1;
var payload = $(`input[name="layers[${layer}][payload]"]`).is(':checked');
formData.logs.layers[layer] = {
level: level,
maxSize: maxSize,
payload: payload,
filter: filter
};
});
$.ajax({
url: '/api/testconfig/default',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(formData),
success: function(response) {
alert('配置保存成功!');
location.reload();
},
error: function(xhr) {
alert('保存配置失败:' + xhr.responseText);
}
});
}
</script>
}