diff --git a/Txgy.EWS.Client.MainModule/ViewModels/TreeMenuViewModel.cs b/Txgy.EWS.Client.MainModule/ViewModels/TreeMenuViewModel.cs index a04b1b0..26e05da 100644 --- a/Txgy.EWS.Client.MainModule/ViewModels/TreeMenuViewModel.cs +++ b/Txgy.EWS.Client.MainModule/ViewModels/TreeMenuViewModel.cs @@ -16,6 +16,7 @@ namespace Txgy.EWS.Client.MainModule.ViewModels { private const string SystemSettingsTargetView = "SystemSettingsView"; private const string AdvancedSystemSettingsTargetView = "SystemSettingsAdvanced"; + private const string SystemSettingsMenuHeader = "参数设置"; public List Menus { get; set; } = new List(); @@ -53,7 +54,9 @@ namespace Txgy.EWS.Client.MainModule.ViewModels MenuItemModel mm = new MenuItemModel(_regionManager) { - MenuHeader = item.MenuHeader, + MenuHeader = string.Equals(item.TargetView, SystemSettingsTargetView, StringComparison.OrdinalIgnoreCase) + ? SystemSettingsMenuHeader + : item.MenuHeader, MenuIcon = item.MenuIcon, TargetView = item.TargetView }; @@ -73,7 +76,7 @@ namespace Txgy.EWS.Client.MainModule.ViewModels Menus.Add(new MenuItemModel(_regionManager) { - MenuHeader = "系统设置", + MenuHeader = SystemSettingsMenuHeader, MenuIcon = "\ue64c", TargetView = SystemSettingsTargetView, Children = new List() diff --git a/Txgy.EWS.Client.Start/config/client-settings.json b/Txgy.EWS.Client.Start/config/client-settings.json index 1483c46..a58b1d9 100644 --- a/Txgy.EWS.Client.Start/config/client-settings.json +++ b/Txgy.EWS.Client.Start/config/client-settings.json @@ -5,11 +5,11 @@ "paths": { "alarmSetting": "\\resources\\alarmsetting.json", "alarmLevelConfig": "\\resources\\alarmlevel.json", - "reportEventLevelSetting": "resources\\ReportEventLevelSettings.json", + "reportEventLevelSetting": "\\resources\\ReportEventLevelSettings.json", "workAreaFilePath": "\\resources\\WorkAreaSettings-N2107.json", "stationsCsvFilePath": "\\resources\\N2107_1116.csv", "cadDwgFilePath": "\\resources\\N2107_V2013_1117.dwg", - "dwgJsonSetting": "resources\\DwgSetting.json", + "dwgJsonSetting": "\\resources\\DwgSetting.json", "wavesMseedFilePath": "D:\\EwsCache\\Mseed", "wavesTxtFilePath": "D:\\EwsCache\\Txt", "localSqLiteDb": "EwsLocalSqLite.db", diff --git a/Txgy.EWS.Client.SysModule/Txgy.EWS.Client.SysModule.csproj b/Txgy.EWS.Client.SysModule/Txgy.EWS.Client.SysModule.csproj index 2c00a1a..195a13e 100644 --- a/Txgy.EWS.Client.SysModule/Txgy.EWS.Client.SysModule.csproj +++ b/Txgy.EWS.Client.SysModule/Txgy.EWS.Client.SysModule.csproj @@ -47,6 +47,7 @@ + ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll diff --git a/Txgy.EWS.Client.SysModule/ViewModels/SystemSettingsViewModel.cs b/Txgy.EWS.Client.SysModule/ViewModels/SystemSettingsViewModel.cs index 93a6f29..6d4c097 100644 --- a/Txgy.EWS.Client.SysModule/ViewModels/SystemSettingsViewModel.cs +++ b/Txgy.EWS.Client.SysModule/ViewModels/SystemSettingsViewModel.cs @@ -4,6 +4,7 @@ using Prism.Mvvm; using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Windows; using System.Windows.Input; @@ -11,12 +12,16 @@ using System.Windows.Media; using Txgy.EWS.Client.Common; using Txgy.EWS.Client.Common.MessageEvents; using Txgy.EWS.Client.Entity; +using Microsoft.Win32; +using Forms = System.Windows.Forms; namespace Txgy.EWS.Client.SysModule.ViewModels { public class SystemSettingsViewModel : BindableBase { private const string AdvancedSettingsTargetView = "SystemSettingsAdvanced"; + private const string ResourcesDirectoryName = "resources"; + private const string ResourcesRelativePrefix = "\\resources\\"; private static readonly string[] AdvancedSettingsFallbackTargetViews = { "MenuManagementView", @@ -27,6 +32,7 @@ namespace Txgy.EWS.Client.SysModule.ViewModels private readonly IEventAggregator _eventAggregator; private string _statusMessage; private Brush _statusBrush = Brushes.Gray; + private bool _canEditSystemSettings; public SystemSettingsViewModel(IEventAggregator eventAggregator) { @@ -51,6 +57,21 @@ namespace Txgy.EWS.Client.SysModule.ViewModels public bool CanEditAdvancedSettings { get; } public Visibility AdvancedSettingsVisibility => CanEditAdvancedSettings ? Visibility.Visible : Visibility.Collapsed; + public bool CanEditSystemSettings + { + get => _canEditSystemSettings; + set + { + if (SetProperty(ref _canEditSystemSettings, value)) + { + RaisePropertyChanged(nameof(SystemSettingsReadOnly)); + RaisePropertyChanged(nameof(SystemSettingsEditButtonText)); + } + } + } + + public bool SystemSettingsReadOnly => !CanEditSystemSettings; + public string SystemSettingsEditButtonText => CanEditSystemSettings ? "保存" : "高级修改"; public string ApiDomain { get; set; } public string AlarmSetting { get; set; } @@ -91,6 +112,10 @@ namespace Txgy.EWS.Client.SysModule.ViewModels public ICommand ReloadCommand => new DelegateCommand(ReloadFromConfig); public ICommand ApplyCommand => new DelegateCommand(ApplyConfig); + public ICommand BrowseResourceFileCommand => new DelegateCommand(BrowseResourceFile); + public ICommand BrowseLocalFileCommand => new DelegateCommand(BrowseLocalFile); + public ICommand BrowseFolderCommand => new DelegateCommand(BrowseFolder); + public ICommand ToggleSystemSettingsEditCommand => new DelegateCommand(ToggleSystemSettingsEdit); private void ReloadFromConfig() { @@ -106,6 +131,11 @@ namespace Txgy.EWS.Client.SysModule.ViewModels } private void ApplyConfig() + { + TryApplyConfig(); + } + + private bool TryApplyConfig() { try { @@ -121,11 +151,277 @@ namespace Txgy.EWS.Client.SysModule.ViewModels } Load(savedConfig); SetStatus($"配置已应用:{DateTime.Now:HH:mm:ss}", Brushes.Green); + return true; } catch (Exception ex) { SetStatus($"应用失败:{ex.Message}", Brushes.Red); + return false; + } + } + + private void ToggleSystemSettingsEdit() + { + if (CanEditSystemSettings) + { + if (TryApplyConfig()) + { + CanEditSystemSettings = false; + SetStatus($"系统参数已保存:{DateTime.Now:HH:mm:ss}", Brushes.Green); + } + return; + } + + var result = MessageBox.Show( + "系统参数会影响系统名称显示和缓存目录,是否确认修改系统参数?", + "高级修改", + MessageBoxButton.YesNo, + MessageBoxImage.Warning); + if (result != MessageBoxResult.Yes) + { + return; + } + + CanEditSystemSettings = true; + SetStatus("系统参数已解锁", Brushes.Gray); + } + + private void BrowseResourceFile(string targetName) + { + var resourcesDirectory = GetResourcesDirectory(); + if (!Directory.Exists(resourcesDirectory)) + { + SetStatus($"resources目录不存在:{resourcesDirectory}", Brushes.Red); + return; + } + + var dialog = new OpenFileDialog + { + CheckFileExists = true, + Multiselect = false, + Title = "选择resources目录下的文件", + Filter = GetFileFilter(targetName), + InitialDirectory = GetInitialDirectory(GetPathValue(targetName), true) + }; + + if (dialog.ShowDialog() != true) + { + return; + } + + if (!TryGetResourcesRelativePath(dialog.FileName, out var relativePath)) + { + SetStatus("请选择resources目录下的文件", Brushes.Red); + return; + } + + SetPathValue(targetName, relativePath); + SetStatus($"已选择:{relativePath}", Brushes.Gray); + } + + private void BrowseLocalFile(string targetName) + { + var dialog = new OpenFileDialog + { + CheckFileExists = true, + Multiselect = false, + Title = "选择文件", + Filter = GetFileFilter(targetName), + InitialDirectory = GetInitialDirectory(GetPathValue(targetName), false) + }; + + if (dialog.ShowDialog() != true) + { + return; + } + + SetPathValue(targetName, dialog.FileName); + SetStatus($"已选择:{dialog.FileName}", Brushes.Gray); + } + + private void BrowseFolder(string targetName) + { + using (var dialog = new Forms.FolderBrowserDialog()) + { + dialog.Description = "选择目录"; + dialog.SelectedPath = GetInitialDirectory(GetPathValue(targetName), false); + if (dialog.ShowDialog() != Forms.DialogResult.OK || string.IsNullOrWhiteSpace(dialog.SelectedPath)) + { + return; + } + + SetPathValue(targetName, dialog.SelectedPath); + SetStatus($"已选择:{dialog.SelectedPath}", Brushes.Gray); + } + } + + private string GetFileFilter(string targetName) + { + switch (targetName) + { + case nameof(StationsCsvFilePath): + return "CSV文件 (*.csv)|*.csv|所有文件 (*.*)|*.*"; + case nameof(CadDwgFilePath): + return "DWG文件 (*.dwg)|*.dwg|所有文件 (*.*)|*.*"; + case nameof(LocalSqLiteDb): + return "SQLite数据库 (*.db;*.sqlite;*.sqlite3)|*.db;*.sqlite;*.sqlite3|所有文件 (*.*)|*.*"; + case nameof(WorkAreaFilePath): + case nameof(DwgJsonSetting): + case nameof(AlarmSetting): + case nameof(AlarmLevelConfig): + case nameof(ReportEventLevelSetting): + return "JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*"; + default: + return "所有文件 (*.*)|*.*"; + } + } + + private string GetInitialDirectory(string currentPath, bool resourcesOnly) + { + if (resourcesOnly) + { + var resourceFilePath = ResolveAppRelativePath(currentPath); + if (!string.IsNullOrWhiteSpace(resourceFilePath) && File.Exists(resourceFilePath)) + { + return Path.GetDirectoryName(resourceFilePath); + } + + return GetResourcesDirectory(); } + + if (!string.IsNullOrWhiteSpace(currentPath)) + { + var path = ResolveAppRelativePath(currentPath); + if (Directory.Exists(path)) + { + return path; + } + + if (File.Exists(path)) + { + return Path.GetDirectoryName(path); + } + } + + return AppDomain.CurrentDomain.BaseDirectory; + } + + private string ResolveAppRelativePath(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return null; + } + + if (Path.IsPathRooted(path) && !path.StartsWith("\\", StringComparison.Ordinal)) + { + return path; + } + + return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path.TrimStart('\\', '/')); + } + + private string GetResourcesDirectory() + { + return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ResourcesDirectoryName); + } + + private bool TryGetResourcesRelativePath(string selectedFile, out string relativePath) + { + relativePath = null; + var resourcesDirectory = Path.GetFullPath(GetResourcesDirectory()) + .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar; + var filePath = Path.GetFullPath(selectedFile); + if (!filePath.StartsWith(resourcesDirectory, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var relativePart = filePath.Substring(resourcesDirectory.Length) + .Replace(Path.DirectorySeparatorChar, '\\') + .Replace(Path.AltDirectorySeparatorChar, '\\'); + relativePath = ResourcesRelativePrefix + relativePart; + return true; + } + + private string GetPathValue(string targetName) + { + switch (targetName) + { + case nameof(AlarmSetting): + return AlarmSetting; + case nameof(AlarmLevelConfig): + return AlarmLevelConfig; + case nameof(ReportEventLevelSetting): + return ReportEventLevelSetting; + case nameof(WorkAreaFilePath): + return WorkAreaFilePath; + case nameof(StationsCsvFilePath): + return StationsCsvFilePath; + case nameof(CadDwgFilePath): + return CadDwgFilePath; + case nameof(DwgJsonSetting): + return DwgJsonSetting; + case nameof(WavesMseedFilePath): + return WavesMseedFilePath; + case nameof(WavesTxtFilePath): + return WavesTxtFilePath; + case nameof(LocalSqLiteDb): + return LocalSqLiteDb; + case nameof(DwgSettings): + return DwgSettings; + case nameof(CadSettingsFileName): + return CadSettingsFileName; + default: + throw new InvalidOperationException($"未知的路径参数:{targetName}"); + } + } + + private void SetPathValue(string targetName, string value) + { + switch (targetName) + { + case nameof(AlarmSetting): + AlarmSetting = value; + break; + case nameof(AlarmLevelConfig): + AlarmLevelConfig = value; + break; + case nameof(ReportEventLevelSetting): + ReportEventLevelSetting = value; + break; + case nameof(WorkAreaFilePath): + WorkAreaFilePath = value; + break; + case nameof(StationsCsvFilePath): + StationsCsvFilePath = value; + break; + case nameof(CadDwgFilePath): + CadDwgFilePath = value; + break; + case nameof(DwgJsonSetting): + DwgJsonSetting = value; + break; + case nameof(WavesMseedFilePath): + WavesMseedFilePath = value; + break; + case nameof(WavesTxtFilePath): + WavesTxtFilePath = value; + break; + case nameof(LocalSqLiteDb): + LocalSqLiteDb = value; + break; + case nameof(DwgSettings): + DwgSettings = value; + break; + case nameof(CadSettingsFileName): + CadSettingsFileName = value; + break; + default: + throw new InvalidOperationException($"未知的路径参数:{targetName}"); + } + + RaisePropertyChanged(targetName); } private bool ShouldReloadWarningData(BusinessConfig previousConfig, BusinessConfig savedConfig) @@ -183,7 +479,7 @@ namespace Txgy.EWS.Client.SysModule.ViewModels { DateTime.Parse(Require(DailyReportStartTime, "日报起始时间")); - var dataLookbackHours = ParseDouble(DataLookbackHours, "数据回看时长"); + var dataLookbackHours = ParseDouble(DataLookbackHours, "数据时长"); DataCacheTimeLenMins = ((int)Math.Round(dataLookbackHours * 60.0)).ToString(CultureInfo.InvariantCulture); var endpointSettings = BuildEndpointSettings(currentConfig); var databaseSettings = BuildDatabaseSettings(currentConfig); @@ -197,14 +493,14 @@ namespace Txgy.EWS.Client.SysModule.ViewModels AlarmLevelConfig = Require(AlarmLevelConfig, "报警等级配置"), ReportEventLevelSetting = Require(ReportEventLevelSetting, "报表事件分级"), WorkAreaFilePath = Require(WorkAreaFilePath, "工区配置"), - StationsCsvFilePath = Require(StationsCsvFilePath, "台站 CSV"), + StationsCsvFilePath = Require(StationsCsvFilePath, "台站CSV"), CadDwgFilePath = Require(CadDwgFilePath, "CAD DWG"), - DwgJsonSetting = Require(DwgJsonSetting, "DWG 图层配置"), - WavesMseedFilePath = Require(WavesMseedFilePath, "Mseed 缓存目录"), - WavesTxtFilePath = Require(WavesTxtFilePath, "Txt 缓存目录"), + DwgJsonSetting = Require(DwgJsonSetting, "DWG图层设置"), + WavesMseedFilePath = Require(WavesMseedFilePath, "Mseed缓存目录"), + WavesTxtFilePath = Require(WavesTxtFilePath, "Txt缓存目录"), LocalSqLiteDb = CanEditAdvancedSettings ? Require(LocalSqLiteDb, "本地 SQLite") : currentConfig.Paths.LocalSqLiteDb, - DwgSettings = EmptyToNull(DwgSettings), - CadSettingsFileName = EmptyToNull(CadSettingsFileName) + DwgSettings = CanEditAdvancedSettings ? EmptyToNull(DwgSettings) : currentConfig.Paths.DwgSettings, + CadSettingsFileName = CanEditAdvancedSettings ? EmptyToNull(CadSettingsFileName) : currentConfig.Paths.CadSettingsFileName }, Runtime = new RuntimeSettings { diff --git a/Txgy.EWS.Client.SysModule/Views/SystemSettingsView.xaml b/Txgy.EWS.Client.SysModule/Views/SystemSettingsView.xaml index 3bd92c9..6c11ea2 100644 --- a/Txgy.EWS.Client.SysModule/Views/SystemSettingsView.xaml +++ b/Txgy.EWS.Client.SysModule/Views/SystemSettingsView.xaml @@ -25,17 +25,41 @@ + @@ -47,7 +71,7 @@ - + - + @@ -71,18 +95,56 @@ + + + + - - - - + + + + +