using Prism.Commands; using Prism.Events; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Input; using System.Windows.Media; using Txgy.EWS.Client.Common; using Txgy.EWS.Client.Common.MessageEvents; using Txgy.EWS.Client.Entity; namespace Txgy.EWS.Client.SysModule.ViewModels { public class SystemSettingsViewModel : BindableBase { private const string AdvancedSettingsTargetView = "SystemSettingsAdvanced"; private static readonly string[] AdvancedSettingsFallbackTargetViews = { "MenuManagementView", "RoleManagementView", "UserManagementView" }; private readonly IEventAggregator _eventAggregator; private string _statusMessage; private Brush _statusBrush = Brushes.Gray; public SystemSettingsViewModel(IEventAggregator eventAggregator) { _eventAggregator = eventAggregator; CanEditAdvancedSettings = HasAdvancedSettingsPermission(); ReloadFromConfig(); } public string ConfigPath => BusinessConfigManager.ConfigPath; public string StatusMessage { get => _statusMessage; set => SetProperty(ref _statusMessage, value); } public Brush StatusBrush { get => _statusBrush; set => SetProperty(ref _statusBrush, value); } public bool CanEditAdvancedSettings { get; } public Visibility AdvancedSettingsVisibility => CanEditAdvancedSettings ? Visibility.Visible : Visibility.Collapsed; public string ApiDomain { get; set; } public string AlarmSetting { get; set; } public string AlarmLevelConfig { get; set; } public string ReportEventLevelSetting { get; set; } public string WorkAreaFilePath { get; set; } public string StationsCsvFilePath { get; set; } public string CadDwgFilePath { get; set; } public string DwgJsonSetting { get; set; } public string WavesMseedFilePath { get; set; } public string WavesTxtFilePath { get; set; } public string LocalSqLiteDb { get; set; } public string DwgSettings { get; set; } public string CadSettingsFileName { get; set; } public bool IsDesign { get; set; } public bool IsRealtime { get; set; } public string RefreshInterval { get; set; } public string DataLookbackHours { get; set; } public string DataCacheTimeLenMins { get; set; } public string TencentMySql { get; set; } public string RealtimeResultTable { get; set; } public string RealtimeWaveDataTable { get; set; } public string RealtimeFocalmechanismTable { get; set; } public string PostResultTable { get; set; } public string PostWaveDataTable { get; set; } public string PostFocalmechanismTable { get; set; } public string CommpanyName { get; set; } public string SystemNameCn { get; set; } public string SystemNameEn { get; set; } public string WorkAreaName { get; set; } public string SystemShortName { get; set; } public string DailyReportStartTime { get; set; } public string DailyReportPlanOffsetX { get; set; } public string DailyReportPlanOffsetY { get; set; } public string BaseX { get; set; } public string BaseY { get; set; } public string BaseZ { get; set; } public ICommand ReloadCommand => new DelegateCommand(ReloadFromConfig); public ICommand ApplyCommand => new DelegateCommand(ApplyConfig); private void ReloadFromConfig() { try { Load(BusinessConfigManager.Read()); SetStatus("已读取最新配置", Brushes.Gray); } catch (Exception ex) { SetStatus($"读取配置失败:{ex.Message}", Brushes.Red); } } private void ApplyConfig() { try { var previousConfig = BusinessConfigManager.Current; var config = BuildConfig(previousConfig); var savedConfig = BusinessConfigManager.Save(config); var shouldReloadWarningData = ShouldReloadWarningData(previousConfig, savedConfig); GlobalConfig.ApplyBusinessConfig(savedConfig); _eventAggregator.GetEvent().Publish(savedConfig); if (shouldReloadWarningData) { _eventAggregator.GetEvent().Publish(); } Load(savedConfig); SetStatus($"配置已应用:{DateTime.Now:HH:mm:ss}", Brushes.Green); } catch (Exception ex) { SetStatus($"应用失败:{ex.Message}", Brushes.Red); } } private bool ShouldReloadWarningData(BusinessConfig previousConfig, BusinessConfig savedConfig) { if (previousConfig?.Runtime == null || savedConfig?.Runtime == null) { return false; } return previousConfig.Runtime.DataLookbackHours != savedConfig.Runtime.DataLookbackHours; } private void Load(BusinessConfig config) { ApiDomain = config.Endpoints.ApiDomain; AlarmSetting = config.Paths.AlarmSetting; AlarmLevelConfig = config.Paths.AlarmLevelConfig; ReportEventLevelSetting = config.Paths.ReportEventLevelSetting; WorkAreaFilePath = config.Paths.WorkAreaFilePath; StationsCsvFilePath = config.Paths.StationsCsvFilePath; CadDwgFilePath = config.Paths.CadDwgFilePath; DwgJsonSetting = config.Paths.DwgJsonSetting; WavesMseedFilePath = config.Paths.WavesMseedFilePath; WavesTxtFilePath = config.Paths.WavesTxtFilePath; LocalSqLiteDb = config.Paths.LocalSqLiteDb; DwgSettings = config.Paths.DwgSettings; CadSettingsFileName = config.Paths.CadSettingsFileName; IsDesign = config.Runtime.IsDesign; IsRealtime = config.Runtime.IsRealtime; RefreshInterval = config.Runtime.RefreshInterval.ToString(CultureInfo.InvariantCulture); DataLookbackHours = config.Runtime.DataLookbackHours.ToString("0.##", CultureInfo.InvariantCulture); DataCacheTimeLenMins = config.Runtime.DataCacheTimeLenMins.ToString(CultureInfo.InvariantCulture); TencentMySql = GetConnection(config, "TencetnMySQL"); RealtimeResultTable = config.Database.Tables.RealtimeResultTable; RealtimeWaveDataTable = config.Database.Tables.RealtimeWaveDataTable; RealtimeFocalmechanismTable = config.Database.Tables.RealtimeFocalmechanismTable; PostResultTable = config.Database.Tables.PostResultTable; PostWaveDataTable = config.Database.Tables.PostWaveDataTable; PostFocalmechanismTable = config.Database.Tables.PostFocalmechanismTable; CommpanyName = config.Branding.CommpanyName; SystemNameCn = config.Branding.SystemNameCn; SystemNameEn = config.Branding.SystemNameEn; WorkAreaName = config.Branding.WorkAreaName; SystemShortName = config.Branding.SystemShortName; DailyReportStartTime = config.Report.DailyReportStartTime; DailyReportPlanOffsetX = config.Report.DailyReportPlanOffsetX.ToString(CultureInfo.InvariantCulture); DailyReportPlanOffsetY = config.Report.DailyReportPlanOffsetY.ToString(CultureInfo.InvariantCulture); BaseX = config.Coordinates.BaseX.ToString(CultureInfo.InvariantCulture); BaseY = config.Coordinates.BaseY.ToString(CultureInfo.InvariantCulture); BaseZ = config.Coordinates.BaseZ.ToString(CultureInfo.InvariantCulture); RaiseAllSettingPropertiesChanged(); } private BusinessConfig BuildConfig(BusinessConfig currentConfig) { DateTime.Parse(Require(DailyReportStartTime, "日报起始时间")); var dataLookbackHours = ParseDouble(DataLookbackHours, "数据回看时长"); DataCacheTimeLenMins = ((int)Math.Round(dataLookbackHours * 60.0)).ToString(CultureInfo.InvariantCulture); var endpointSettings = BuildEndpointSettings(currentConfig); var databaseSettings = BuildDatabaseSettings(currentConfig); return new BusinessConfig { Endpoints = endpointSettings, Paths = new PathSettings { AlarmSetting = Require(AlarmSetting, "报警配置"), AlarmLevelConfig = Require(AlarmLevelConfig, "报警等级配置"), ReportEventLevelSetting = Require(ReportEventLevelSetting, "报表事件分级"), WorkAreaFilePath = Require(WorkAreaFilePath, "工区配置"), StationsCsvFilePath = Require(StationsCsvFilePath, "台站 CSV"), CadDwgFilePath = Require(CadDwgFilePath, "CAD DWG"), 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) }, Runtime = new RuntimeSettings { IsDesign = CanEditAdvancedSettings ? IsDesign : currentConfig.Runtime.IsDesign, IsRealtime = CanEditAdvancedSettings ? IsRealtime : currentConfig.Runtime.IsRealtime, RefreshInterval = ParseInt(RefreshInterval, "刷新间隔"), DataLookbackHours = dataLookbackHours, DataCacheTimeLenMins = ParseInt(DataCacheTimeLenMins, "数据缓存时长") }, Database = databaseSettings, Branding = new BrandingSettings { CommpanyName = Require(CommpanyName, "公司名称"), SystemNameCn = Require(SystemNameCn, "系统中文名"), SystemNameEn = Require(SystemNameEn, "系统英文名"), WorkAreaName = Require(WorkAreaName, "工区名称"), SystemShortName = Require(SystemShortName, "系统简称") }, Report = new ReportSettings { DailyReportStartTime = DailyReportStartTime.Trim(), DailyReportPlanOffsetX = ParseDouble(DailyReportPlanOffsetX, "平面图横向偏移"), DailyReportPlanOffsetY = ParseDouble(DailyReportPlanOffsetY, "平面图纵向偏移") }, Coordinates = new CoordinateSettings { BaseX = ParseDouble(BaseX, "BaseX"), BaseY = ParseDouble(BaseY, "BaseY"), BaseZ = ParseDouble(BaseZ, "BaseZ") } }; } private EndpointSettings BuildEndpointSettings(BusinessConfig currentConfig) { return new EndpointSettings { ApiDomain = CanEditAdvancedSettings ? Require(ApiDomain, "API 域名") : currentConfig.Endpoints.ApiDomain }; } private DatabaseSettings BuildDatabaseSettings(BusinessConfig currentConfig) { if (!CanEditAdvancedSettings) { return new DatabaseSettings { Connections = new Dictionary { { "TencetnMySQL", GetConnection(currentConfig, "TencetnMySQL") } }, Tables = CopyTableSettings(currentConfig.Database.Tables) }; } return new DatabaseSettings { Connections = new Dictionary { { "TencetnMySQL", Require(TencentMySql, "腾讯 MySQL") } }, Tables = new TableSettings { RealtimeResultTable = Require(RealtimeResultTable, "实时结果表"), RealtimeWaveDataTable = Require(RealtimeWaveDataTable, "实时波形表"), RealtimeFocalmechanismTable = Require(RealtimeFocalmechanismTable, "实时震源机制表"), PostResultTable = Require(PostResultTable, "后处理结果表"), PostWaveDataTable = Require(PostWaveDataTable, "后处理波形表"), PostFocalmechanismTable = Require(PostFocalmechanismTable, "后处理震源机制表") } }; } private TableSettings CopyTableSettings(TableSettings source) { return new TableSettings { RealtimeResultTable = source.RealtimeResultTable, RealtimeWaveDataTable = source.RealtimeWaveDataTable, RealtimeFocalmechanismTable = source.RealtimeFocalmechanismTable, PostResultTable = source.PostResultTable, PostWaveDataTable = source.PostWaveDataTable, PostFocalmechanismTable = source.PostFocalmechanismTable }; } private string GetConnection(BusinessConfig config, string name) { if (config.Database.Connections != null && config.Database.Connections.TryGetValue(name, out var value)) { return value; } return string.Empty; } private bool HasAdvancedSettingsPermission() { var menus = GlobalData.CurrentUserInfo?.Menus; if (menus == null) { return false; } return ContainsTargetView(menus, AdvancedSettingsTargetView) || AdvancedSettingsFallbackTargetViews.Any(targetView => ContainsTargetView(menus, targetView)); } private bool ContainsTargetView(IEnumerable menus, string targetView) { return menus.Any(menu => string.Equals(menu.TargetView, targetView, StringComparison.OrdinalIgnoreCase)); } private string Require(string value, string name) { if (string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException($"{name}不能为空"); } return value.Trim(); } private string EmptyToNull(string value) { return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); } private int ParseInt(string value, string name) { if (!int.TryParse(Require(value, name), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { throw new InvalidOperationException($"{name}必须是整数"); } return result; } private double ParseDouble(string value, string name) { if (!double.TryParse(Require(value, name), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { throw new InvalidOperationException($"{name}必须是数字"); } return result; } private void SetStatus(string message, Brush brush) { StatusMessage = message; StatusBrush = brush; } private void RaiseAllSettingPropertiesChanged() { RaisePropertyChanged(nameof(ApiDomain)); RaisePropertyChanged(nameof(AlarmSetting)); RaisePropertyChanged(nameof(AlarmLevelConfig)); RaisePropertyChanged(nameof(ReportEventLevelSetting)); RaisePropertyChanged(nameof(WorkAreaFilePath)); RaisePropertyChanged(nameof(StationsCsvFilePath)); RaisePropertyChanged(nameof(CadDwgFilePath)); RaisePropertyChanged(nameof(DwgJsonSetting)); RaisePropertyChanged(nameof(WavesMseedFilePath)); RaisePropertyChanged(nameof(WavesTxtFilePath)); RaisePropertyChanged(nameof(LocalSqLiteDb)); RaisePropertyChanged(nameof(DwgSettings)); RaisePropertyChanged(nameof(CadSettingsFileName)); RaisePropertyChanged(nameof(IsDesign)); RaisePropertyChanged(nameof(IsRealtime)); RaisePropertyChanged(nameof(RefreshInterval)); RaisePropertyChanged(nameof(DataLookbackHours)); RaisePropertyChanged(nameof(DataCacheTimeLenMins)); RaisePropertyChanged(nameof(TencentMySql)); RaisePropertyChanged(nameof(RealtimeResultTable)); RaisePropertyChanged(nameof(RealtimeWaveDataTable)); RaisePropertyChanged(nameof(RealtimeFocalmechanismTable)); RaisePropertyChanged(nameof(PostResultTable)); RaisePropertyChanged(nameof(PostWaveDataTable)); RaisePropertyChanged(nameof(PostFocalmechanismTable)); RaisePropertyChanged(nameof(CommpanyName)); RaisePropertyChanged(nameof(SystemNameCn)); RaisePropertyChanged(nameof(SystemNameEn)); RaisePropertyChanged(nameof(WorkAreaName)); RaisePropertyChanged(nameof(SystemShortName)); RaisePropertyChanged(nameof(DailyReportStartTime)); RaisePropertyChanged(nameof(DailyReportPlanOffsetX)); RaisePropertyChanged(nameof(DailyReportPlanOffsetY)); RaisePropertyChanged(nameof(BaseX)); RaisePropertyChanged(nameof(BaseY)); RaisePropertyChanged(nameof(BaseZ)); } } }