From 8e6f70a67d9df315f9ba5d8ce3986830f28ba095 Mon Sep 17 00:00:00 2001 From: denglihong2007 <98096191+denglihong2007@users.noreply.github.com> Date: Thu, 1 Jan 2026 18:59:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=87=AA=E5=AE=9A=E4=B9=89=E7=AB=99?= =?UTF-8?q?=E5=8F=B0=E5=8D=A0=E7=94=A8=E5=9B=BE=E8=BD=A6=E6=AC=A1=E9=A2=9C?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CRSim.Core/CRSim.Core.csproj | 2 +- CRSim.Core/Converters/ColorJsonConverter.cs | 22 +++++++ CRSim.Core/Models/Json.cs | 8 +-- .../Models/PlatformDiagram/TrainColor.cs | 14 ++++ CRSim.Core/Models/Settings.cs | 16 +++++ CRSim.Core/Models/Simulator/Station.cs | 9 +-- CRSim.PlatformDiagram/PlatformDiagram.cs | 34 ++++------ .../CRSim.ScreenSimulator.csproj | 2 +- CRSim/CRSim.csproj | 14 ++-- CRSim/Converters/DrawingToUIColorConverter.cs | 24 +++++++ CRSim/Properties/GlobalUsing.cs | 1 + CRSim/Services/DialogService.cs | 27 +++++++- CRSim/Services/IDialogService.cs | 1 + .../PlatformDiagramPageViewModel.cs | 4 +- CRSim/ViewModels/SettingsPageViewModel.cs | 27 +++++--- .../DialogContents/CreateStationDialog.xaml | 4 +- .../CreateStationDialog.xaml.cs | 2 +- CRSim/Views/DialogContents/InputDialog.xaml | 4 +- .../Views/DialogContents/InputDialog.xaml.cs | 2 +- .../Views/DialogContents/PlatformDialog.xaml | 4 +- .../DialogContents/PlatformDialog.xaml.cs | 2 +- CRSim/Views/DialogContents/TextDialog.xaml | 4 +- CRSim/Views/DialogContents/TextDialog.xaml.cs | 2 +- .../DialogContents/TrainColorsDialog.xaml | 65 +++++++++++++++++++ .../DialogContents/TrainColorsDialog.xaml.cs | 55 ++++++++++++++++ .../DialogContents/TrainNumberStopDialog.xaml | 4 +- .../TrainNumberStopDialog.xaml.cs | 4 +- .../Views/DialogContents/TrainStopDialog.xaml | 4 +- .../DialogContents/TrainStopDialog.xaml.cs | 4 +- CRSim/Views/PlatformDiagramPage.xaml | 1 + CRSim/Views/SettingsPage.xaml | 6 ++ 31 files changed, 290 insertions(+), 82 deletions(-) create mode 100644 CRSim.Core/Converters/ColorJsonConverter.cs create mode 100644 CRSim.Core/Models/PlatformDiagram/TrainColor.cs create mode 100644 CRSim/Converters/DrawingToUIColorConverter.cs create mode 100644 CRSim/Views/DialogContents/TrainColorsDialog.xaml create mode 100644 CRSim/Views/DialogContents/TrainColorsDialog.xaml.cs diff --git a/CRSim.Core/CRSim.Core.csproj b/CRSim.Core/CRSim.Core.csproj index c7a5d96..403739f 100644 --- a/CRSim.Core/CRSim.Core.csproj +++ b/CRSim.Core/CRSim.Core.csproj @@ -14,7 +14,7 @@ - + diff --git a/CRSim.Core/Converters/ColorJsonConverter.cs b/CRSim.Core/Converters/ColorJsonConverter.cs new file mode 100644 index 0000000..258078b --- /dev/null +++ b/CRSim.Core/Converters/ColorJsonConverter.cs @@ -0,0 +1,22 @@ +using System.Drawing; +using System.Text.Json; +using System.Text.Json.Serialization; +namespace CRSim.Core.Converters +{ + public class ColorJsonConverter : JsonConverter + { + public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + // 从十六进制字符串(如 "#FF00BE")读取并转换回 Color + string? hex = reader.GetString(); + return hex == null ? Color.Empty : ColorTranslator.FromHtml(hex); + } + + public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options) + { + // 将 Color 转换为十六进制字符串格式写入 JSON + if (value.IsEmpty) writer.WriteNullValue(); + else writer.WriteStringValue($"#{value.R:X2}{value.G:X2}{value.B:X2}"); + } + } +} diff --git a/CRSim.Core/Models/Json.cs b/CRSim.Core/Models/Json.cs index 6e0ab43..14041fe 100644 --- a/CRSim.Core/Models/Json.cs +++ b/CRSim.Core/Models/Json.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CRSim.Core.Models +namespace CRSim.Core.Models { public class Json { diff --git a/CRSim.Core/Models/PlatformDiagram/TrainColor.cs b/CRSim.Core/Models/PlatformDiagram/TrainColor.cs new file mode 100644 index 0000000..a8e7070 --- /dev/null +++ b/CRSim.Core/Models/PlatformDiagram/TrainColor.cs @@ -0,0 +1,14 @@ +using CRSim.Core.Converters; +using System.Drawing; +using System.Text.Json.Serialization; + +namespace CRSim.Core.Models.PlatformDiagram +{ + public class TrainColor + { + public required string Prefix { get; set; } + + [JsonConverter(typeof(ColorJsonConverter))] + public required Color Color { get; set; } + } +} diff --git a/CRSim.Core/Models/Settings.cs b/CRSim.Core/Models/Settings.cs index aafc984..a5a47ff 100644 --- a/CRSim.Core/Models/Settings.cs +++ b/CRSim.Core/Models/Settings.cs @@ -1,5 +1,8 @@ using CRSim.Core.Abstractions; +using CRSim.Core.Converters; +using CRSim.Core.Models.PlatformDiagram; using CRSim.Core.Services; +using System.Drawing; using System.Text.Json.Serialization; namespace CRSim.Core.Models @@ -29,5 +32,18 @@ namespace CRSim.Core.Models public string UserKey { get; set; } = ""; public bool LoadTodayOnly { get; set; } = false; public bool ReopenUnclosedScreensOnLoad { get; set; } = true; + + public List TrainColors { get; set; } = + [ + new TrainColor { Prefix = "G", Color = Color.Magenta }, + new TrainColor { Prefix = "D", Color = Color.SteelBlue }, + new TrainColor { Prefix = "C", Color = Color.Teal }, + new TrainColor { Prefix = "T", Color = Color.Blue }, + new TrainColor { Prefix = "Z", Color = Color.SaddleBrown }, + new TrainColor { Prefix = "K", Color = Color.Red }, + new TrainColor { Prefix = "Y", Color = Color.Red }, + new TrainColor { Prefix = "L", Color = Color.Green }, + new TrainColor { Prefix = "默认", Color = Color.Green } + ]; } } diff --git a/CRSim.Core/Models/Simulator/Station.cs b/CRSim.Core/Models/Simulator/Station.cs index c45fb08..bcd2273 100644 --- a/CRSim.Core/Models/Simulator/Station.cs +++ b/CRSim.Core/Models/Simulator/Station.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; - -namespace CRSim.Core.Models +namespace CRSim.Core.Models { public class Station { diff --git a/CRSim.PlatformDiagram/PlatformDiagram.cs b/CRSim.PlatformDiagram/PlatformDiagram.cs index d6ab7df..f94bb0b 100644 --- a/CRSim.PlatformDiagram/PlatformDiagram.cs +++ b/CRSim.PlatformDiagram/PlatformDiagram.cs @@ -1,5 +1,6 @@ -// Trigger CI build +using CRSim.Core.Abstractions; using CRSim.Core.Models; +using CRSim.Core.Models.PlatformDiagram; using iText.IO.Font; using iText.Kernel.Colors; using iText.Kernel.Font; @@ -15,7 +16,7 @@ namespace CRSim.PlatformDiagram { public class Generator { - public static void Generate(Station station, string savePath, float pageWidth) + public static void Generate(Station station, string savePath, float pageWidth,List trainColors) { float Padding = 40; float HeaderHeight = 16; @@ -168,27 +169,14 @@ namespace CRSim.PlatformDiagram TimeSpan arrival = (TimeSpan)(train.ArrivalTime ?? train.DepartureTime - fixedDuration); TimeSpan departure = (TimeSpan)(train.DepartureTime ?? train.ArrivalTime + fixedDuration); - var trainColors = new Dictionary - { - { "G", "FF00BE" }, // pink - { "D", "004C99" }, // deep blue - { "C", "009999" }, // cyan - { "T", "0000FF" }, // blue - { "Z", "804000" }, // brown - { "K", "FF0000" }, // red - { "Y", "FF0000" }, // red - { "L", "008000" }, // dark green - { "default", "008000" } // dark green - }; - string firstChar = train.Number[..1].ToUpper(); - string colorHex = trainColors.TryGetValue(firstChar, out string? value) ? value : trainColors["default"]; - var color = new DeviceRgb( - Convert.ToInt32(colorHex[..2], 16), - Convert.ToInt32(colorHex.Substring(2, 2), 16), - Convert.ToInt32(colorHex.Substring(4, 2), 16) - ); - canvas.SetFillColor(color); - canvas.SetStrokeColor(color); + var matchedColor = trainColors + .Where(tc => train.Number.StartsWith(tc.Prefix)) + .OrderByDescending(tc => tc.Prefix.Length) + .FirstOrDefault(); + var color = matchedColor?.Color ?? trainColors.FirstOrDefault(x => x.Prefix == "默认").Color; + Color itextColor = new DeviceRgb(color.R, color.G, color.B); + canvas.SetFillColor(itextColor); + canvas.SetStrokeColor(itextColor); // 检查是否跨零点 if (departure < arrival) diff --git a/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj b/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj index e3a4558..b2c2b72 100644 --- a/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj +++ b/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj @@ -18,7 +18,7 @@ - + diff --git a/CRSim/CRSim.csproj b/CRSim/CRSim.csproj index 10c8c93..da95ca0 100644 --- a/CRSim/CRSim.csproj +++ b/CRSim/CRSim.csproj @@ -12,6 +12,7 @@ true enable preview + true @@ -40,13 +41,14 @@ - - - - + + + + + - - + + diff --git a/CRSim/Converters/DrawingToUIColorConverter.cs b/CRSim/Converters/DrawingToUIColorConverter.cs new file mode 100644 index 0000000..079efe1 --- /dev/null +++ b/CRSim/Converters/DrawingToUIColorConverter.cs @@ -0,0 +1,24 @@ +using Microsoft.UI.Xaml.Data; +namespace CRSim.Converters +{ + public partial class DrawingToUIColorConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + if (value is System.Drawing.Color sColor) + { + return Windows.UI.Color.FromArgb(sColor.A, sColor.R, sColor.G, sColor.B); + } + return Windows.UI.Color.FromArgb(0,0,0,0); + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + if (value is Windows.UI.Color wColor) + { + return System.Drawing.Color.FromArgb(wColor.A, wColor.R, wColor.G, wColor.B); + } + return System.Drawing.Color.FromArgb(0, 0, 0, 0); + } + } +} diff --git a/CRSim/Properties/GlobalUsing.cs b/CRSim/Properties/GlobalUsing.cs index 3e4086d..1e77abc 100644 --- a/CRSim/Properties/GlobalUsing.cs +++ b/CRSim/Properties/GlobalUsing.cs @@ -28,6 +28,7 @@ global using CRSim.PlatformDiagram; global using CRSim.WebsiteSimulator; global using CRSim.Core.Utils; global using CRSim.Core.Models; +global using CRSim.Core.Models.PlatformDiagram; global using CRSim.Core.Services; global using CRSim.Core.Abstractions; diff --git a/CRSim/Services/DialogService.cs b/CRSim/Services/DialogService.cs index 9956f19..19b5ec9 100644 --- a/CRSim/Services/DialogService.cs +++ b/CRSim/Services/DialogService.cs @@ -1,7 +1,5 @@ -using CRSim.Core.Models; +using CRSim.Views.DialogContents; using Microsoft.Win32; -using Windows.Storage; -using Windows.Storage.Pickers; namespace CRSim.Services { @@ -275,5 +273,28 @@ namespace CRSim.Services } return null; } + + public async Task?> EditTrainColorsAsync(List trainColors) + { + ContentDialog dialog = new() + { + XamlRoot = XamlRoot, + Style = Application.Current.Resources["DefaultContentDialogStyle"] as Style, + Title = "编辑颜色配置", + PrimaryButtonText = "确定", + CloseButtonText = "取消", + DefaultButton = ContentDialogButton.Primary, + IsPrimaryButtonEnabled = false + }; + var trainColorsDialog = new TrainColorsDialog(trainColors, isValid => dialog.IsPrimaryButtonEnabled = isValid); + dialog.Content = trainColorsDialog; + var result = await dialog.ShowAsync(); + if (result == ContentDialogResult.Primary) + { + var inputDialog = dialog.Content as TrainColorsDialog; + return [.. inputDialog.TrainColors]; + } + return null; + } } } diff --git a/CRSim/Services/IDialogService.cs b/CRSim/Services/IDialogService.cs index 1468e9c..33e4236 100644 --- a/CRSim/Services/IDialogService.cs +++ b/CRSim/Services/IDialogService.cs @@ -14,6 +14,7 @@ Task GetInputTrainStopAsync(List waitingAreas, List platforms); Task EditInputTrainStopAsync(List waitingAreas, List platforms, TrainStop trainStop); Task?> GetInputPlatformAsync(); + Task?> EditTrainColorsAsync(List trainColors); XamlRoot? XamlRoot { get; set; } } } diff --git a/CRSim/ViewModels/PlatformDiagramPageViewModel.cs b/CRSim/ViewModels/PlatformDiagramPageViewModel.cs index 2900902..caa0d5f 100644 --- a/CRSim/ViewModels/PlatformDiagramPageViewModel.cs +++ b/CRSim/ViewModels/PlatformDiagramPageViewModel.cs @@ -3,6 +3,8 @@ public partial class PlatformDiagramPageViewModel(IDialogService _dialogService, IDatabaseService _databaseService) : ObservableObject { public string PageTitle = "生成站台占用图"; + private readonly ISettingsService _settingsService = App.GetService(); + public Station? SelectedStation; public List Stations => _databaseService.GetAllStations(); @@ -35,7 +37,7 @@ public partial class PlatformDiagramPageViewModel(IDialogService _dialogService, } var path = _dialogService.SaveFile(".pdf", $"{SelectedStation.Name}站台占用图"); if(string.IsNullOrEmpty(path) || SelectedStation == null) return; - await Task.Run(() => Generator.Generate(SelectedStation, path,PageWidth)); + await Task.Run(() => Generator.Generate(SelectedStation, path,PageWidth, _settingsService.GetSettings().TrainColors)); } public static bool CheckStation(Station station,out string detail) diff --git a/CRSim/ViewModels/SettingsPageViewModel.cs b/CRSim/ViewModels/SettingsPageViewModel.cs index 20cf36d..06b62a0 100644 --- a/CRSim/ViewModels/SettingsPageViewModel.cs +++ b/CRSim/ViewModels/SettingsPageViewModel.cs @@ -1,10 +1,4 @@ -using Downloader; -using System.Diagnostics; -using System.Diagnostics.Metrics; -using System.IO.Packaging; -using System.Reflection; -using System.Security.Policy; -using Windows.System; +using Windows.System; namespace CRSim.ViewModels { @@ -62,6 +56,10 @@ namespace CRSim.ViewModels [ObservableProperty] public partial bool ReopenUnclosedScreensOnLoad { get; set; } + + [ObservableProperty] + public partial List TrainColors { get; set; } + #endregion public SettingsPageViewModel(ISettingsService settingsService, IDatabaseService databaseService, IDialogService dialogService, INetworkService networkService) { @@ -69,10 +67,8 @@ namespace CRSim.ViewModels _databaseService = databaseService; _dialogService = dialogService; _networkService = networkService; - var version = Assembly.GetExecutingAssembly().GetName().Version; - AppVersion = $"Version {version}"; + AppVersion = $"Version {App.AppVersion}"; LoadSettings(); - } private void LoadSettings() @@ -89,6 +85,7 @@ namespace CRSim.ViewModels UserKey = _settings.UserKey; LoadTodayOnly = _settings.LoadTodayOnly; ReopenUnclosedScreensOnLoad = _settings.ReopenUnclosedScreensOnLoad; + TrainColors = _settings.TrainColors; } [RelayCommand] @@ -105,6 +102,7 @@ namespace CRSim.ViewModels _settings.LoadTodayOnly = LoadTodayOnly; _settings.ReopenUnclosedScreensOnLoad = ReopenUnclosedScreensOnLoad; _settings.Api = Api; + _settings.TrainColors = TrainColors; _settingsService.SaveSettings(); } private static void UpdateSettings(string input, bool allowNegative, Action updateAction) @@ -155,5 +153,14 @@ namespace CRSim.ViewModels _databaseService.ImportData(path); await _databaseService.SaveData(); } + [RelayCommand] + public async Task EditTrainColors() + { + var trainColors = await _dialogService.EditTrainColorsAsync(TrainColors); + if (trainColors is not null) + { + TrainColors = trainColors; + } + } } } \ No newline at end of file diff --git a/CRSim/Views/DialogContents/CreateStationDialog.xaml b/CRSim/Views/DialogContents/CreateStationDialog.xaml index 0d38f1d..1ed0317 100644 --- a/CRSim/Views/DialogContents/CreateStationDialog.xaml +++ b/CRSim/Views/DialogContents/CreateStationDialog.xaml @@ -1,9 +1,9 @@ diff --git a/CRSim/Views/DialogContents/CreateStationDialog.xaml.cs b/CRSim/Views/DialogContents/CreateStationDialog.xaml.cs index a5aa66b..b96e8c7 100644 --- a/CRSim/Views/DialogContents/CreateStationDialog.xaml.cs +++ b/CRSim/Views/DialogContents/CreateStationDialog.xaml.cs @@ -1,4 +1,4 @@ -namespace CRSim.Views; +namespace CRSim.Views.DialogContents; public sealed partial class CreateStationDialog : Page { diff --git a/CRSim/Views/DialogContents/InputDialog.xaml b/CRSim/Views/DialogContents/InputDialog.xaml index a298cd9..89b4e67 100644 --- a/CRSim/Views/DialogContents/InputDialog.xaml +++ b/CRSim/Views/DialogContents/InputDialog.xaml @@ -1,9 +1,9 @@ diff --git a/CRSim/Views/DialogContents/InputDialog.xaml.cs b/CRSim/Views/DialogContents/InputDialog.xaml.cs index d5de69f..5636866 100644 --- a/CRSim/Views/DialogContents/InputDialog.xaml.cs +++ b/CRSim/Views/DialogContents/InputDialog.xaml.cs @@ -1,4 +1,4 @@ -namespace CRSim.Views; +namespace CRSim.Views.DialogContents; public sealed partial class InputDialog : Page { public string InputText { get; set; } diff --git a/CRSim/Views/DialogContents/PlatformDialog.xaml b/CRSim/Views/DialogContents/PlatformDialog.xaml index 7291872..f92f70d 100644 --- a/CRSim/Views/DialogContents/PlatformDialog.xaml +++ b/CRSim/Views/DialogContents/PlatformDialog.xaml @@ -1,9 +1,9 @@ diff --git a/CRSim/Views/DialogContents/PlatformDialog.xaml.cs b/CRSim/Views/DialogContents/PlatformDialog.xaml.cs index 58a32c9..c7028ef 100644 --- a/CRSim/Views/DialogContents/PlatformDialog.xaml.cs +++ b/CRSim/Views/DialogContents/PlatformDialog.xaml.cs @@ -1,4 +1,4 @@ -namespace CRSim.Views; +namespace CRSim.Views.DialogContents; public sealed partial class PlatformDialog : Page { private readonly Action _onValidityChanged; diff --git a/CRSim/Views/DialogContents/TextDialog.xaml b/CRSim/Views/DialogContents/TextDialog.xaml index 61163c3..3d27cb4 100644 --- a/CRSim/Views/DialogContents/TextDialog.xaml +++ b/CRSim/Views/DialogContents/TextDialog.xaml @@ -1,9 +1,9 @@ diff --git a/CRSim/Views/DialogContents/TextDialog.xaml.cs b/CRSim/Views/DialogContents/TextDialog.xaml.cs index 0879263..9a9a7bb 100644 --- a/CRSim/Views/DialogContents/TextDialog.xaml.cs +++ b/CRSim/Views/DialogContents/TextDialog.xaml.cs @@ -1,4 +1,4 @@ -namespace CRSim.Views; +namespace CRSim.Views.DialogContents; public sealed partial class TextDialog : Page { private string _text { get; set; } diff --git a/CRSim/Views/DialogContents/TrainColorsDialog.xaml b/CRSim/Views/DialogContents/TrainColorsDialog.xaml new file mode 100644 index 0000000..3ab600d --- /dev/null +++ b/CRSim/Views/DialogContents/TrainColorsDialog.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CRSim/Views/DialogContents/TrainColorsDialog.xaml.cs b/CRSim/Views/DialogContents/TrainColorsDialog.xaml.cs new file mode 100644 index 0000000..1fb652a --- /dev/null +++ b/CRSim/Views/DialogContents/TrainColorsDialog.xaml.cs @@ -0,0 +1,55 @@ +using System.Drawing; + +namespace CRSim.Views.DialogContents; +public sealed partial class TrainColorsDialog : Page +{ + public ObservableCollection TrainColors = []; + + private readonly Action _onValidityChanged; + + public TrainColorsDialog(List trainColors, Action onValidityChanged) + { + TrainColors = new ObservableCollection(trainColors); + InitializeComponent(); + _onValidityChanged = onValidityChanged; + Validate(this, EventArgs.Empty); + } + + private void Add(object sender, RoutedEventArgs e) + { + TrainColors.Add(new TrainColor() { Color = Color.Red, Prefix = string.Empty }); + Validate(this, EventArgs.Empty); + } + + private void Delete(object sender, RoutedEventArgs e) + { + if (TrainColorsGrid.SelectedValue is TrainColor trainColor && trainColor.Prefix != "默认") + { + TrainColors.Remove(trainColor); + } + Validate(this, EventArgs.Empty); + } + + private void Reset(object sender, RoutedEventArgs e) + { + TrainColors.Clear(); + foreach (var trainColor in new Settings().TrainColors) + { + TrainColors.Add(trainColor); + } + Validate(this, EventArgs.Empty); + } + + private void Validate(object sender, object e) + { + if(TrainColorsGrid is null) { return; } //检查是否初始化完成 + if (TrainColors.Any(x => x.Prefix == string.Empty) || TrainColors.GroupBy(x => x.Prefix).Any(g => g.Count() > 1) || !TrainColors.Any(x=>x.Prefix=="默认")) + { + _onValidityChanged(false); + } + else + { + _onValidityChanged(true); + } + } +} diff --git a/CRSim/Views/DialogContents/TrainNumberStopDialog.xaml b/CRSim/Views/DialogContents/TrainNumberStopDialog.xaml index 0fd6ca5..56c8670 100644 --- a/CRSim/Views/DialogContents/TrainNumberStopDialog.xaml +++ b/CRSim/Views/DialogContents/TrainNumberStopDialog.xaml @@ -1,9 +1,9 @@ + diff --git a/CRSim/Views/SettingsPage.xaml b/CRSim/Views/SettingsPage.xaml index 58cfdc3..0eaad48 100644 --- a/CRSim/Views/SettingsPage.xaml +++ b/CRSim/Views/SettingsPage.xaml @@ -85,6 +85,12 @@ + + + +