|
|
@@ -66,22 +66,22 @@ public partial class DeviceDetailsWindow : Window
|
|
|
var interfaces = await _serverApiService.GetInterfacesAsync(_baseAddress, _password, _localIPv4);
|
|
|
if (interfaces is null)
|
|
|
{
|
|
|
- ShowStatusMessage("设备已连接,但暂时无法读取 Linux 接口列表。", StatusMessageType.Warning);
|
|
|
+ ShowStatusMessage("设备已连接,但暂时无法读取 Linux 网口列表。", StatusMessageType.Warning);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SetConfigStateMessage($"当前管理接口:{interfaces.ManagementInterface}。正在读取全部接口配置。", false);
|
|
|
- foreach (var info in interfaces.Interfaces)
|
|
|
+ SetConfigStateMessage($"当前管理网口:{interfaces.ManagementInterface}。正在读取全部网口配置。", false);
|
|
|
+ for (var i = 0; i < interfaces.Interfaces.Count; i++)
|
|
|
{
|
|
|
- var editor = new InterfaceEditor(info);
|
|
|
+ var editor = new InterfaceEditor(interfaces.Interfaces[i], i + 1);
|
|
|
_interfaces.Add(editor);
|
|
|
await LoadRemoteInterfaceConfigAsync(editor);
|
|
|
}
|
|
|
|
|
|
_configValidated = false;
|
|
|
_configDirty = false;
|
|
|
- SetConfigStateMessage("已读取全部接口配置。", false);
|
|
|
- ShowStatusMessage("已读取全部接口配置。", StatusMessageType.Success);
|
|
|
+ SetConfigStateMessage("已读取全部网口配置。", false);
|
|
|
+ ShowStatusMessage("已读取全部网口配置。", StatusMessageType.Success);
|
|
|
}
|
|
|
|
|
|
private void ClearDetails()
|
|
|
@@ -96,7 +96,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
{
|
|
|
var hostPart = string.IsNullOrWhiteSpace(hostname) ? _remoteHost : $"{hostname} ({_remoteHost})";
|
|
|
var versionPart = string.IsNullOrWhiteSpace(serverVersion) ? string.Empty : $" - Server {serverVersion}";
|
|
|
- Title = string.IsNullOrWhiteSpace(hostPart) ? $"设备信息与接口配置{versionPart}" : $"设备信息与接口配置 - {hostPart}{versionPart}";
|
|
|
+ Title = string.IsNullOrWhiteSpace(hostPart) ? $"设备信息与网口配置{versionPart}" : $"设备信息与网口配置 - {hostPart}{versionPart}";
|
|
|
}
|
|
|
|
|
|
private static string GetRemoteHost(string baseAddress)
|
|
|
@@ -116,7 +116,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
var result = await _serverApiService.GetInterfaceConfigAsync(_baseAddress, _password, _localIPv4, editor.SystemName);
|
|
|
if (!result.Success || result.Data is null)
|
|
|
{
|
|
|
- ShowStatusMessage($"读取目标接口 {editor.SystemName} 配置失败:{result.Message}", StatusMessageType.Error);
|
|
|
+ ShowStatusMessage($"读取目标网口 {editor.DisplayLabel} 配置失败:{result.Message}", StatusMessageType.Error);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -173,7 +173,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SetBusyState(true, "正在刷新全部接口配置...");
|
|
|
+ SetBusyState(true, "正在刷新全部网口配置...");
|
|
|
try
|
|
|
{
|
|
|
foreach (var editor in _interfaces)
|
|
|
@@ -183,8 +183,8 @@ public partial class DeviceDetailsWindow : Window
|
|
|
|
|
|
_configValidated = false;
|
|
|
_configDirty = false;
|
|
|
- SetConfigStateMessage("已刷新全部接口配置。", false);
|
|
|
- ShowStatusMessage("已刷新全部接口配置。", StatusMessageType.Success);
|
|
|
+ SetConfigStateMessage("已刷新全部网口配置。", false);
|
|
|
+ ShowStatusMessage("已刷新全部网口配置。", StatusMessageType.Success);
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
@@ -229,7 +229,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
var errors = result.Data.Errors.Count > 0 ? $" 错误:{string.Join(";", result.Data.Errors)}" : string.Empty;
|
|
|
SetConfigStateMessage(_configValidated ? "配置已校验通过,可以应用。" : "配置校验未通过,请修正后重新校验。", !_configValidated);
|
|
|
ShowStatusMessage(
|
|
|
- _configValidated ? $"全部接口校验通过,可应用配置。{warnings}" : $"校验失败。{errors}{warnings}",
|
|
|
+ _configValidated ? $"全部网口校验通过,可应用配置。{warnings}" : $"校验失败。{errors}{warnings}",
|
|
|
_configValidated ? StatusMessageType.Success : StatusMessageType.Error);
|
|
|
}
|
|
|
else
|
|
|
@@ -256,7 +256,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
|
|
|
var changeSummary = FormatChangeSummary();
|
|
|
var confirmMessage = string.IsNullOrWhiteSpace(changeSummary)
|
|
|
- ? "将要一次性应用以下接口配置:\n\n" + FormatConfigSummary(request) + "\n\n请确认是否继续。"
|
|
|
+ ? "将要一次性应用以下网口配置:\n\n" + FormatConfigSummary(request) + "\n\n请确认是否继续。"
|
|
|
: "将要一次性应用以下已修改配置:\n\n" + changeSummary + "\n\n完整目标配置:\n\n" + FormatConfigSummary(request) + "\n\n请确认是否继续。";
|
|
|
if (MessageBox.Show(this, confirmMessage, "确认应用配置", MessageBoxButton.OKCancel, MessageBoxImage.Question) != MessageBoxResult.OK)
|
|
|
{
|
|
|
@@ -492,7 +492,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
|
|
|
if (result.Count == 0)
|
|
|
{
|
|
|
- ShowStatusMessage("接口配置不能为空。", StatusMessageType.Error);
|
|
|
+ ShowStatusMessage("网口配置不能为空。", StatusMessageType.Error);
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
@@ -506,7 +506,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
var routes = Array.Empty<RemoteInterfaceRouteConfig>();
|
|
|
if (!dhcp4)
|
|
|
{
|
|
|
- if (editor.Addresses.All(item => string.IsNullOrWhiteSpace(item.IP) && string.IsNullOrWhiteSpace(item.Mask)))
|
|
|
+ if (editor.Addresses.Count == 0)
|
|
|
{
|
|
|
ShowStatusMessage($"{editor.SystemName}:IP 地址不能为空,至少需要填写一行地址。", StatusMessageType.Error);
|
|
|
return null;
|
|
|
@@ -525,7 +525,12 @@ public partial class DeviceDetailsWindow : Window
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var dns = editor.Dns.Select(item => item.Address.Trim()).Where(item => item != string.Empty).ToArray();
|
|
|
+ if (!TryBuildDns(editor, out var dns, out var dnsError))
|
|
|
+ {
|
|
|
+ ShowStatusMessage($"{editor.SystemName}:{dnsError}", StatusMessageType.Error);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
return new RemoteInterfaceConfig
|
|
|
{
|
|
|
Interface = editor.SystemName,
|
|
|
@@ -579,7 +584,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
private static string FormatConfigSummary(IReadOnlyList<RemoteInterfaceConfig> configs)
|
|
|
{
|
|
|
return string.Join(Environment.NewLine + Environment.NewLine, configs.Select(item =>
|
|
|
- $"接口:{item.Interface}\n" +
|
|
|
+ $"网口:{item.Interface}\n" +
|
|
|
$"模式:{(item.Dhcp4 ? "DHCP 自动获取" : "静态 IPv4")}\n" +
|
|
|
$"IP:{(item.Dhcp4 ? "自动获取" : FormatAddresses(item.Addresses))}\n" +
|
|
|
$"路由:{(item.Dhcp4 ? "自动获取" : FormatRoutes(item.Routes))}\n" +
|
|
|
@@ -612,13 +617,16 @@ public partial class DeviceDetailsWindow : Window
|
|
|
private bool TryBuildAddresses(InterfaceEditor editor, out RemoteInterfaceAddressConfig[] addresses, out string error)
|
|
|
{
|
|
|
var result = new List<RemoteInterfaceAddressConfig>();
|
|
|
- foreach (var row in editor.Addresses)
|
|
|
+ for (var i = 0; i < editor.Addresses.Count; i++)
|
|
|
{
|
|
|
+ var row = editor.Addresses[i];
|
|
|
var ip = row.IP.Trim();
|
|
|
var maskText = row.Mask.Trim();
|
|
|
if (ip == string.Empty && maskText == string.Empty)
|
|
|
{
|
|
|
- continue;
|
|
|
+ addresses = [];
|
|
|
+ error = $"第 {i + 1} 行 IP 配置为空,请填写或删除该行。";
|
|
|
+ return false;
|
|
|
}
|
|
|
if (ip.Contains('/'))
|
|
|
{
|
|
|
@@ -651,8 +659,14 @@ public partial class DeviceDetailsWindow : Window
|
|
|
}
|
|
|
|
|
|
addresses = result.ToArray();
|
|
|
+ if (addresses.Length == 0)
|
|
|
+ {
|
|
|
+ error = "IP 地址不能为空,至少需要填写一行地址。";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
error = string.Empty;
|
|
|
- return addresses.Length > 0;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
private bool TryBuildRoutes(InterfaceEditor editor, out RemoteInterfaceRouteConfig[] routes, out string error)
|
|
|
@@ -671,14 +685,17 @@ public partial class DeviceDetailsWindow : Window
|
|
|
}
|
|
|
if (editor.CustomRoutesEnabled)
|
|
|
{
|
|
|
- foreach (var row in editor.Routes)
|
|
|
+ for (var i = 0; i < editor.Routes.Count; i++)
|
|
|
{
|
|
|
+ var row = editor.Routes[i];
|
|
|
var to = row.To.Trim();
|
|
|
var maskText = row.Mask.Trim();
|
|
|
var via = row.Via.Trim();
|
|
|
if (to == string.Empty && maskText == string.Empty && via == string.Empty)
|
|
|
{
|
|
|
- continue;
|
|
|
+ routes = [];
|
|
|
+ error = $"自定义路由第 {i + 1} 行为空,请填写或删除该行。";
|
|
|
+ return false;
|
|
|
}
|
|
|
if (to.Contains('/'))
|
|
|
{
|
|
|
@@ -716,6 +733,27 @@ public partial class DeviceDetailsWindow : Window
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ private static bool TryBuildDns(InterfaceEditor editor, out string[] dns, out string error)
|
|
|
+ {
|
|
|
+ var result = new List<string>();
|
|
|
+ for (var i = 0; i < editor.Dns.Count; i++)
|
|
|
+ {
|
|
|
+ var address = editor.Dns[i].Address.Trim();
|
|
|
+ if (address == string.Empty)
|
|
|
+ {
|
|
|
+ dns = [];
|
|
|
+ error = $"DNS 第 {i + 1} 行为空,请填写或删除该行。";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ result.Add(address);
|
|
|
+ }
|
|
|
+
|
|
|
+ dns = result.ToArray();
|
|
|
+ error = string.Empty;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
private static bool TryParseAddresses(string text, out RemoteInterfaceAddressConfig[] addresses, out string error)
|
|
|
{
|
|
|
var result = new List<RemoteInterfaceAddressConfig>();
|
|
|
@@ -995,7 +1033,7 @@ public partial class DeviceDetailsWindow : Window
|
|
|
|
|
|
private string FormatChangedFields()
|
|
|
{
|
|
|
- var fields = _interfaces.Where(item => item.HasChanges).Select(item => $"{item.SystemName} 的 {item.ChangedFieldsText}");
|
|
|
+ var fields = _interfaces.Where(item => item.HasChanges).Select(item => $"{item.DisplayLabel} 的 {item.ChangedFieldsText}");
|
|
|
return string.Join(";", fields);
|
|
|
}
|
|
|
|
|
|
@@ -1148,14 +1186,16 @@ public partial class DeviceDetailsWindow : Window
|
|
|
private string[] _originalGatewayKeys = [];
|
|
|
private string[] _originalDnsKeys = [];
|
|
|
|
|
|
- public InterfaceEditor(RemoteInterfaceInfo info)
|
|
|
+ public InterfaceEditor(RemoteInterfaceInfo info, int displayIndex)
|
|
|
{
|
|
|
SystemName = info.SystemName;
|
|
|
+ DisplayLabel = $"网口{displayIndex}:{SystemName}";
|
|
|
StatusSummary = info.StatusSummary;
|
|
|
LinkUp = info.LinkUp;
|
|
|
}
|
|
|
|
|
|
public string SystemName { get; }
|
|
|
+ public string DisplayLabel { get; }
|
|
|
public string StatusSummary { get; }
|
|
|
public bool LinkUp { get; }
|
|
|
public ObservableCollection<EditableAddress> Addresses { get; } = [];
|
|
|
@@ -1218,14 +1258,14 @@ public partial class DeviceDetailsWindow : Window
|
|
|
|
|
|
public string FormatChangeSummary()
|
|
|
{
|
|
|
- var lines = new List<string> { $"接口:{SystemName}" };
|
|
|
+ var lines = new List<string> { DisplayLabel };
|
|
|
if (IsAddressModified)
|
|
|
{
|
|
|
- lines.Add($"IP:{FormatKeys(_originalAddressKeys)} -> {FormatKeys(GetAddressKeys())}");
|
|
|
+ lines.Add($"IP:{FormatAddressSummary(_originalDhcp4, _originalAddressKeys)} -> {FormatAddressSummary(Dhcp4, GetAddressKeys())}");
|
|
|
}
|
|
|
if (IsGatewayModified)
|
|
|
{
|
|
|
- lines.Add($"网关:{FormatKeys(_originalGatewayKeys)} -> {FormatKeys(GetGatewayKeys())}");
|
|
|
+ lines.Add($"网关:{FormatGatewaySummary(_originalDhcp4, _originalGatewayKeys)} -> {FormatGatewaySummary(Dhcp4, GetGatewayKeys())}");
|
|
|
}
|
|
|
if (IsDnsModified)
|
|
|
{
|
|
|
@@ -1270,6 +1310,16 @@ public partial class DeviceDetailsWindow : Window
|
|
|
return keys.Count == 0 ? "无" : string.Join(", ", keys);
|
|
|
}
|
|
|
|
|
|
+ private static string FormatAddressSummary(bool dhcp4, IReadOnlyList<string> keys)
|
|
|
+ {
|
|
|
+ return dhcp4 ? "自动获取" : FormatKeys(keys);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static string FormatGatewaySummary(bool dhcp4, IReadOnlyList<string> keys)
|
|
|
+ {
|
|
|
+ return dhcp4 ? "自动获取" : FormatKeys(keys);
|
|
|
+ }
|
|
|
+
|
|
|
private void SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
|
|
|
{
|
|
|
if (EqualityComparer<T>.Default.Equals(field, value))
|