From 9ad7ea432ab2c6bf89589acf08113812cb3f3dfc Mon Sep 17 00:00:00 2001
From: denglihong2007 <98096191+denglihong2007@users.noreply.github.com>
Date: Sun, 10 Aug 2025 16:46:36 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20#141=20#202=20=E9=87=8D=E6=9E=84?=
=?UTF-8?q?=E6=A3=80=E7=A5=A8=E5=8F=A3/=E5=80=99=E8=BD=A6=E5=AE=A4?=
=?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CRSim.Core/CRSim.Core.csproj | 4 +-
CRSim.Core/Models/Simulator/TicketCheck.cs | 5 +-
CRSim.Core/Models/Simulator/TrainStop.cs | 4 +-
CRSim.Core/Models/Simulator/WaitingArea.cs | 8 +-
CRSim.Core/Services/DatabaseService.cs | 20 +-
.../Abstractions/IScreenViewModel.cs | 2 +-
.../CRSim.ScreenSimulator.csproj | 2 +-
CRSim.ScreenSimulator/Models/Session.cs | 2 +-
.../ViewModels/BaseScreenViewModel.cs | 22 +-
.../MetroPlatformScreenViewModel.cs | 2 +-
CRSim/App.xaml.cs | 46 +--
CRSim/CRSim.csproj | 4 +-
CRSim/Converters/ListToStringConverter.cs | 23 --
.../TicketChecksToStringConverter.cs | 27 ++
CRSim/MainWindow.xaml | 2 +-
CRSim/Models/CheckListItem.cs | 9 -
CRSim/Selectors/FileName.cs | 18 +
CRSim/Services/DialogService.cs | 96 ++---
CRSim/Services/IDialogService.cs | 11 +-
.../PluginManagementPageViewModel.cs | 4 +-
.../ScreenSimulatorPageViewModel.cs | 22 +-
CRSim/ViewModels/SettingsPageViewModel.cs | 4 +-
.../StationManagementPageViewModel.cs | 332 +++++++++++-------
CRSim/Views/DialogContents/InputDialog.xaml | 2 +-
.../Views/DialogContents/InputDialog.xaml.cs | 4 +-
.../DialogContents/TicketCheckDialog.xaml | 15 -
.../DialogContents/TicketCheckDialog.xaml.cs | 90 -----
.../Views/DialogContents/TrainStopDialog.xaml | 26 +-
.../DialogContents/TrainStopDialog.xaml.cs | 67 ++--
CRSim/Views/ScreenSimulatorPage.xaml | 2 +-
CRSim/Views/StartWindow.xaml.cs | 12 -
CRSim/Views/StationManagementPage.xaml | 94 ++---
Directory.Build.props | 2 +-
33 files changed, 450 insertions(+), 533 deletions(-)
delete mode 100644 CRSim/Converters/ListToStringConverter.cs
create mode 100644 CRSim/Converters/TicketChecksToStringConverter.cs
delete mode 100644 CRSim/Models/CheckListItem.cs
create mode 100644 CRSim/Selectors/FileName.cs
delete mode 100644 CRSim/Views/DialogContents/TicketCheckDialog.xaml
delete mode 100644 CRSim/Views/DialogContents/TicketCheckDialog.xaml.cs
diff --git a/CRSim.Core/CRSim.Core.csproj b/CRSim.Core/CRSim.Core.csproj
index df37937..c982424 100644
--- a/CRSim.Core/CRSim.Core.csproj
+++ b/CRSim.Core/CRSim.Core.csproj
@@ -13,8 +13,8 @@
-
-
+
+
diff --git a/CRSim.Core/Models/Simulator/TicketCheck.cs b/CRSim.Core/Models/Simulator/TicketCheck.cs
index 6404bdb..c6591d0 100644
--- a/CRSim.Core/Models/Simulator/TicketCheck.cs
+++ b/CRSim.Core/Models/Simulator/TicketCheck.cs
@@ -2,7 +2,8 @@
{
public class TicketCheck
{
- public string WaitingAreaName { get; set; }
+ public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
+ public override string ToString() => Name;
}
-}
+}
\ No newline at end of file
diff --git a/CRSim.Core/Models/Simulator/TrainStop.cs b/CRSim.Core/Models/Simulator/TrainStop.cs
index 9893649..dcd516f 100644
--- a/CRSim.Core/Models/Simulator/TrainStop.cs
+++ b/CRSim.Core/Models/Simulator/TrainStop.cs
@@ -15,9 +15,7 @@ namespace CRSim.Core.Models
[JsonConverter(typeof(TimeSpanJsonConverter))]
public TimeSpan? DepartureTime { get; set; }
- public List? TicketChecks { get; set; }
-
- public string? WaitingArea { get; set; }
+ public List? TicketCheckIds { get; set; }
public string? Origin { get; set; }
diff --git a/CRSim.Core/Models/Simulator/WaitingArea.cs b/CRSim.Core/Models/Simulator/WaitingArea.cs
index 440166f..0b96f71 100644
--- a/CRSim.Core/Models/Simulator/WaitingArea.cs
+++ b/CRSim.Core/Models/Simulator/WaitingArea.cs
@@ -1,14 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Collections.ObjectModel;
namespace CRSim.Core.Models
{
public class WaitingArea
{
public string Name { get; set; }
- public List TicketChecks { get; set; } = [];
+ public ObservableCollection TicketChecks { get; set; } = [];
}
}
diff --git a/CRSim.Core/Services/DatabaseService.cs b/CRSim.Core/Services/DatabaseService.cs
index 979945b..5ed5e23 100644
--- a/CRSim.Core/Services/DatabaseService.cs
+++ b/CRSim.Core/Services/DatabaseService.cs
@@ -20,21 +20,10 @@ namespace CRSim.Core.Services
{
try
{
- var json = File.ReadAllText(jsonFilePath).Replace("StationStop", "TrainStop");// 修复旧版本的数据
+ var json = File.ReadAllText(jsonFilePath).Replace("StationStop", "TrainStop");
var data = JsonSerializer.Deserialize(json,JsonContext.Default.Json);
_stations = data.Stations;
_trainNumbers = data.TrainNumbers;
-
- foreach (var station in _stations)
- {
- foreach(var trainStop in station.TrainStops)
- {
- if (trainStop.WaitingArea == null && trainStop.DepartureTime.HasValue)
- {
- trainStop.WaitingArea = station.WaitingAreas.Where(x => x.TicketChecks.Contains(trainStop.TicketChecks[0])).FirstOrDefault().Name;
- }
- }
- }// 修复旧版本的数据
}
catch
{
@@ -157,9 +146,9 @@ namespace CRSim.Core.Services
foreach (var ticketCheckName in ticketCheck.Split('|'))
{
- if (!string.IsNullOrWhiteSpace(ticketCheckName) && !waitingArea.TicketChecks.Contains(ticketCheckName))
+ if (!string.IsNullOrWhiteSpace(ticketCheckName) && !waitingArea.TicketChecks.Any(x => x.Name == ticketCheckName))
{
- waitingArea.TicketChecks.Add(ticketCheckName);
+ waitingArea.TicketChecks.Add(new TicketCheck { Name = ticketCheckName });
}
}
@@ -187,10 +176,9 @@ namespace CRSim.Core.Services
Number = data[0],
Terminal = data[3],
Origin = data[2],
- TicketChecks = [.. ticketCheck.Split('|')],
+ TicketCheckIds = [.. waitingArea.TicketChecks.Select(x=>x.Id)],
ArrivalTime = arrivalTime,
DepartureTime = departureTime,
- WaitingArea = waitingAreaName,
Platform = platform,
Length = data[0].StartsWith('G') || data[0].StartsWith('D') || data[0].StartsWith('C') ? Math.Abs(data[0].GetHashCode()) % 3 == 0 ? 8 : 16 : 18,
Landmark = data[8] + "色" ?? null,
diff --git a/CRSim.ScreenSimulator/Abstractions/IScreenViewModel.cs b/CRSim.ScreenSimulator/Abstractions/IScreenViewModel.cs
index 9f3f22d..7a961af 100644
--- a/CRSim.ScreenSimulator/Abstractions/IScreenViewModel.cs
+++ b/CRSim.ScreenSimulator/Abstractions/IScreenViewModel.cs
@@ -8,7 +8,7 @@ namespace CRSim.ScreenSimulator.Abstractions
{
ITimeService TimeService { get; }
Dispatcher UIDispatcher { get; set; }
- void LoadData(Station station, string ticketCheck, string platform);
+ void LoadData(Station station, TicketCheck? ticketCheck, string platform);
string? Text { get; set; }
Uri Video { get; set; }
int Location { get; set; }
diff --git a/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj b/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj
index 586c9c9..74ab5dc 100644
--- a/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj
+++ b/CRSim.ScreenSimulator/CRSim.ScreenSimulator.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/CRSim.ScreenSimulator/Models/Session.cs b/CRSim.ScreenSimulator/Models/Session.cs
index 1543667..6665abd 100644
--- a/CRSim.ScreenSimulator/Models/Session.cs
+++ b/CRSim.ScreenSimulator/Models/Session.cs
@@ -10,7 +10,7 @@ namespace CRSim.ScreenSimulator.Models
public string? Text { get; set; }
public Uri? Video { get; set; }
public Station? Station { get; set; }
- public string? TicketCheck { get; set; }
+ public TicketCheck? TicketCheck { get; set; }
public string? PlatformName { get; set; }
public int? Loaction { get; set; }
}
diff --git a/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs b/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs
index 9e5d0ed..5a6ee1d 100644
--- a/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs
+++ b/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs
@@ -1,10 +1,11 @@
using CommunityToolkit.Mvvm.ComponentModel;
-using CRSim.Core.Models;
-using CRSim.ScreenSimulator.Models;
-using System.Windows;
-using System.Collections.ObjectModel;
using CRSim.Core.Abstractions;
+using CRSim.Core.Models;
using CRSim.ScreenSimulator.Abstractions;
+using CRSim.ScreenSimulator.Models;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows;
namespace CRSim.ScreenSimulator.ViewModels
{
@@ -104,11 +105,11 @@ namespace CRSim.ScreenSimulator.ViewModels
OnPropertyChanged(nameof(ScreenB));
}
- public void LoadData(Station station, string ticketCheck, string platform)
+ public void LoadData(Station station, TicketCheck? ticketCheck, string platform)
{
ThisStation = station;
ThisPlatform = platform;
- if (ticketCheck != string.Empty) ThisTicketCheck = ticketCheck.Split(" - ")[1];//重复检票口名称的临时解决方案
+ ThisTicketCheck = ticketCheck?.Name;
var trains = station.TrainStops;
foreach (var trainNumber in trains)
{
@@ -117,7 +118,7 @@ namespace CRSim.ScreenSimulator.ViewModels
(StationType == StationType.Both ||
trainNumber.StationType == StationType.Both ||
StationType == trainNumber.StationType) &&
- (ticketCheck == string.Empty || (trainNumber.WaitingArea==ticketCheck.Split(" - ")[0] && trainNumber.TicketChecks.Contains(ticketCheck.Split(" - ")[1]))) &&//重复检票口名称的临时解决方案
+ (ticketCheck == null || trainNumber.TicketCheckIds.Contains(ticketCheck.Id)) &&
(platform == string.Empty || trainNumber.Platform == platform))
{
var now = TimeService.GetDateTimeNow();
@@ -138,8 +139,11 @@ namespace CRSim.ScreenSimulator.ViewModels
Origin = trainNumber.Origin,
ArrivalTime = AdjustTime(trainNumber.ArrivalTime),
DepartureTime = AdjustTime(trainNumber.DepartureTime),
- TicketChecks = trainNumber.TicketChecks,
- WaitingArea = trainNumber.StationType == StationType.Arrival ? string.Empty : trainNumber.WaitingArea,
+ TicketChecks = [.. station.WaitingAreas
+ .SelectMany(w => w.TicketChecks)
+ .Where(tc => trainNumber.TicketCheckIds.Contains(tc.Id))
+ .Select(tc => tc.Name)],
+ WaitingArea = trainNumber.StationType == StationType.Arrival ? string.Empty : string.Join(" ", station.WaitingAreas.Where(x => x.TicketChecks.Any(y => trainNumber.TicketCheckIds.Contains(y.Id))).Select(x=>x.Name)),
Platform = trainNumber.Platform,
Length = trainNumber.Length,
Landmark = trainNumber.Landmark,
diff --git a/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs b/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs
index 20c6f24..b0db7f8 100644
--- a/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs
+++ b/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs
@@ -44,7 +44,7 @@ namespace CRSim.ScreenSimulator.ViewModels
OnPropertyChanged(nameof(FirstTrain));
OnPropertyChanged(nameof(SecondTrain));
}
- public void LoadData(Station station, string _ticketCheck, string platform)
+ public void LoadData(Station station, TicketCheck? _ticketCheck, string platform)
{
var trains = station.TrainStops;
foreach (var trainNumber in trains)
diff --git a/CRSim/App.xaml.cs b/CRSim/App.xaml.cs
index a7a68ee..afbee34 100644
--- a/CRSim/App.xaml.cs
+++ b/CRSim/App.xaml.cs
@@ -1,4 +1,6 @@
-namespace CRSim
+using System.Diagnostics;
+
+namespace CRSim
{
public partial class App : Application
{
@@ -7,12 +9,11 @@
public string[] commandLineArgs;
public CommandLineOptions parsedOptions;
public static string AppVersion { get; set; } = Assembly.GetAssembly(typeof(App)).GetName().Version.ToString();
- private Mutex mutex;
+ private readonly Mutex mutex;
public App()
{
- bool isNewInstance;
- mutex = new Mutex(true,"CRSim",out isNewInstance);
+ mutex = new Mutex(true, "CRSim", out bool isNewInstance);
if (!isNewInstance)
{
Environment.Exit(0);
@@ -52,49 +53,34 @@
InitializeComponent();
}
- protected override void OnLaunched(LaunchActivatedEventArgs args)
+ protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
- ShowSplashScreen();
- }
-
- private void ShowSplashScreen()
- {
- var splashScreenWindow = AppHost.Services.GetService();
- splashScreenWindow.SplashScreenClosed += OnSplashScreenClosed;
+ var splashScreenWindow = AppHost.Services.GetRequiredService();
splashScreenWindow.Activate();
- _ = PerformInitializationAsync(splashScreenWindow);
+ await PerformInitializationAsync(splashScreenWindow);
+ MainWindow = AppHost.Services.GetRequiredService();
+ MainWindow.Activate();
+ splashScreenWindow.Close();
}
- private static async Task PerformInitializationAsync(StartWindow splashScreen)
+ private static async Task PerformInitializationAsync(StartWindow startWindow)
{
try
{
- var startWindow = AppHost.Services.GetService();
- await Task.Delay(2000);
+ if(!Debugger.IsAttached) await Task.Delay(2000);
startWindow.Status = "正在加载设置...";
AppHost.Services.GetService().LoadSettings();
- await Task.Delay(500);
+ if (!Debugger.IsAttached) await Task.Delay(500);
startWindow.Status = "正在加载数据库...";
AppHost.Services.GetService().ImportData(AppPaths.ConfigFilePath);
- await Task.Delay(500);
+ if (!Debugger.IsAttached) await Task.Delay(500);
startWindow.Status = new[] { "正在控票…", "正在关闭垃圾桶盖…", "正在刷绿车底…", "正在准备降弓用刑…" }[new Random().Next(4)];
- await Task.Delay(500);
+ if (!Debugger.IsAttached) await Task.Delay(500);
}
catch (Exception ex)
{
Console.WriteLine($"初始化错误: {ex.Message}");
}
- finally
- {
- splashScreen.CompleteInitialization();
- }
- }
-
- private void OnSplashScreenClosed(object sender, EventArgs e)
- {
- var mainWindow = AppHost.Services.GetService();
- mainWindow.Activate();
- MainWindow = mainWindow;
}
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
diff --git a/CRSim/CRSim.csproj b/CRSim/CRSim.csproj
index cf1d521..bd782c0 100644
--- a/CRSim/CRSim.csproj
+++ b/CRSim/CRSim.csproj
@@ -55,8 +55,8 @@
-
-
+
+
diff --git a/CRSim/Converters/ListToStringConverter.cs b/CRSim/Converters/ListToStringConverter.cs
deleted file mode 100644
index abf61b9..0000000
--- a/CRSim/Converters/ListToStringConverter.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using Microsoft.UI.Xaml.Data;
-
-namespace CRSim.Converters
-{
- public partial class ListToStringConverter : IValueConverter
- {
- public string Separator { get; set; } = ""; // 默认分隔符是双引号间隔
- public object Convert(object value, Type targetType, object parameter, string language)
- {
- if (value is List ticketChecks)
- {
- // 使用自定义的 Separator 将字符串连接
- return string.Join(Separator, ticketChecks);
- }
- return string.Empty;
- }
- public object ConvertBack(object value, Type targetType, object parameter, string language)
- {
- // 通常不需要实现 ConvertBack
- return null;
- }
- }
-}
diff --git a/CRSim/Converters/TicketChecksToStringConverter.cs b/CRSim/Converters/TicketChecksToStringConverter.cs
new file mode 100644
index 0000000..9e94aba
--- /dev/null
+++ b/CRSim/Converters/TicketChecksToStringConverter.cs
@@ -0,0 +1,27 @@
+using Microsoft.UI.Xaml.Data;
+
+namespace CRSim.Converters
+{
+ public partial class TicketChecksToStringConverter : IValueConverter
+ {
+ public string Separator { get; set; } = "";
+ public ObservableCollection WaitingAreas { get; set; } = [];
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ if (value is List ticketCheckIds)
+ {
+ var ticketChecks = WaitingAreas
+ .SelectMany(w => w.TicketChecks
+ .Where(tc => ticketCheckIds.Contains(tc.Id))
+ .Select(tc => $"{w.Name}|{tc.Name}"));
+ return string.Join(Separator, ticketChecks);
+
+ }
+ return string.Empty;
+ }
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/CRSim/MainWindow.xaml b/CRSim/MainWindow.xaml
index 64f11a4..1d246d0 100644
--- a/CRSim/MainWindow.xaml
+++ b/CRSim/MainWindow.xaml
@@ -26,7 +26,7 @@
-
+
diff --git a/CRSim/Models/CheckListItem.cs b/CRSim/Models/CheckListItem.cs
deleted file mode 100644
index b4e85e3..0000000
--- a/CRSim/Models/CheckListItem.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace CRSim.Models
-{
- public partial class CheckListItem : ObservableObject
- {
- [ObservableProperty]
- public partial bool IsSelected { get; set; }
- public string Name { get; set; }
- }
-}
diff --git a/CRSim/Selectors/FileName.cs b/CRSim/Selectors/FileName.cs
new file mode 100644
index 0000000..32dde24
--- /dev/null
+++ b/CRSim/Selectors/FileName.cs
@@ -0,0 +1,18 @@
+namespace CRSim.Selectors
+{
+ public partial class TreeViewTemplateSelector : DataTemplateSelector
+ {
+ public DataTemplate WaitingAreaTemplate { get; set; }
+ public DataTemplate TicketCheckTemplate { get; set; }
+
+ protected override DataTemplate SelectTemplateCore(object item)
+ {
+ return item switch
+ {
+ WaitingArea => WaitingAreaTemplate,
+ TicketCheck => TicketCheckTemplate,
+ _ => base.SelectTemplateCore(item)
+ };
+ }
+ }
+}
diff --git a/CRSim/Services/DialogService.cs b/CRSim/Services/DialogService.cs
index 2fb76e2..19d1eca 100644
--- a/CRSim/Services/DialogService.cs
+++ b/CRSim/Services/DialogService.cs
@@ -1,4 +1,5 @@
-using Windows.Storage;
+using Microsoft.Win32;
+using Windows.Storage;
using Windows.Storage.Pickers;
namespace CRSim.Services
@@ -6,7 +7,7 @@ namespace CRSim.Services
public class DialogService : IDialogService
{
public XamlRoot? XamlRoot { get; set; }
- public async Task GetInputAsync(string title)
+ public async Task GetInputAsync(string title,string placeholder)
{
ContentDialog dialog = new()
{
@@ -16,7 +17,7 @@ namespace CRSim.Services
PrimaryButtonText = "确定",
CloseButtonText = "取消",
DefaultButton = ContentDialogButton.Primary,
- Content = new InputDialog()
+ Content = new InputDialog(placeholder)
};
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
@@ -72,50 +73,25 @@ namespace CRSim.Services
};
await dialog.ShowAsync();
}
- public async Task<(string, List)> GetInputTicketCheckAsync(List waitingAreaNames)
- {
- bool isButtonEnabled = false;
- ContentDialog dialog = new()
- {
- XamlRoot = XamlRoot,
- Style = Application.Current.Resources["DefaultContentDialogStyle"] as Style,
- Title = "新增检票口",
- PrimaryButtonText = "确定",
- CloseButtonText = "取消",
- DefaultButton = ContentDialogButton.Primary,
- IsPrimaryButtonEnabled = false
- };
- var ticketCheckDialog = new TicketCheckDialog(waitingAreaNames, isValid => dialog.IsPrimaryButtonEnabled = isValid);
- dialog.Content = ticketCheckDialog;
- dialog.PrimaryButtonClick += (s, e) =>
- {
- ticketCheckDialog.GenerateTicketChecks();
- };
- var result = await dialog.ShowAsync();
- if (result == ContentDialogResult.Primary)
- {
- var inputDialog = dialog.Content as TicketCheckDialog;
- return (inputDialog.SelectedWaitingArea, inputDialog.GeneratedTicketChecks);
- }
- return (null, null);
- }
- public async Task GetFileAsync(string[] filter)
+ public string? GetFile(string[] extensions)
{
- var openPicker = new FileOpenPicker();
- var window = App.MainWindow;
- var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
- WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);
- openPicker.ViewMode = PickerViewMode.Thumbnail;
- openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
- foreach (var f in filter)
+ var dlg = new OpenFileDialog();
+ dlg.Multiselect = false;
+
+ var filters = extensions
+ .Select(ext =>
+ {
+ var extNoDot = ext.TrimStart('.').ToUpperInvariant();
+ return $"{extNoDot} 文件 (*{ext})|*{ext}";
+ });
+
+ dlg.Filter = string.Join("|", filters);
+
+ bool? result = dlg.ShowDialog();
+ if (result == true)
{
- openPicker.FileTypeFilter.Add(f);
- }
- var file = await openPicker.PickSingleFileAsync();
- if (file != null)
- {
- return file.Path;
+ return dlg.FileName;
}
return null;
}
@@ -134,7 +110,7 @@ namespace CRSim.Services
return null;
}
- public async Task GetInputTrainStopAsync(List ticketChecks, List platforms)
+ public async Task GetInputTrainStopAsync(List waitingAreas, List platforms)
{
bool isButtonEnabled = false;
ContentDialog dialog = new()
@@ -147,7 +123,7 @@ namespace CRSim.Services
DefaultButton = ContentDialogButton.Primary,
IsPrimaryButtonEnabled = false
};
- var platformDialog = new TrainStopDialog(ticketChecks,platforms,isValid => dialog.IsPrimaryButtonEnabled = isValid);
+ var platformDialog = new TrainStopDialog(waitingAreas, platforms,isValid => dialog.IsPrimaryButtonEnabled = isValid);
dialog.Content = platformDialog;
dialog.PrimaryButtonClick += (s, e) =>
{
@@ -162,7 +138,7 @@ namespace CRSim.Services
return null;
}
- public async Task EditInputTrainStopAsync(List ticketChecks, List platforms, TrainStop trainStop)
+ public async Task EditInputTrainStopAsync(List waitingAreas, List platforms, TrainStop trainStop)
{
bool isButtonEnabled = false;
ContentDialog dialog = new()
@@ -175,7 +151,7 @@ namespace CRSim.Services
DefaultButton = ContentDialogButton.Primary,
IsPrimaryButtonEnabled = false
};
- var platformDialog = new TrainStopDialog(ticketChecks, platforms, trainStop, isValid => dialog.IsPrimaryButtonEnabled = isValid);
+ var platformDialog = new TrainStopDialog(waitingAreas, platforms, trainStop, isValid => dialog.IsPrimaryButtonEnabled = isValid);
dialog.Content = platformDialog;
dialog.PrimaryButtonClick += (s, e) =>
{
@@ -190,17 +166,21 @@ namespace CRSim.Services
return null;
}
- public async Task SaveFileAsync(string filter, string f)
+ public string? SaveFile(string extension, string suggestedFileName)
{
- FileSavePicker savePicker = new();
- var window = App.MainWindow;
- var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
- WinRT.Interop.InitializeWithWindow.Initialize(savePicker, hWnd);
- savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
- savePicker.SuggestedFileName = f;
- savePicker.FileTypeChoices.Add("File", [filter]);
- StorageFile file = await savePicker.PickSaveFileAsync();
- return file?.Path;
+ var dlg = new SaveFileDialog
+ {
+ FileName = suggestedFileName
+ };
+ var extNoDot = extension.TrimStart('.').ToUpperInvariant();
+ var filter = $"{extNoDot} Files (*{extension})|*{extension}";
+ dlg.Filter = filter;
+ bool? result = dlg.ShowDialog();
+ if (result == true)
+ {
+ return dlg.FileName;
+ }
+ return null;
}
public async Task?> GetInputPlatformAsync()
diff --git a/CRSim/Services/IDialogService.cs b/CRSim/Services/IDialogService.cs
index 269e513..f7309d1 100644
--- a/CRSim/Services/IDialogService.cs
+++ b/CRSim/Services/IDialogService.cs
@@ -2,17 +2,16 @@
{
public interface IDialogService
{
- Task GetFileAsync(string[] filter);
- Task SaveFileAsync(string filter,string fileName);
- Task GetInputAsync(string title);
+ string? GetFile(string[] filter);
+ string? SaveFile(string filter,string fileName);
+ Task GetInputAsync(string title,string placeholder);
Task GetConfirmAsync(string title);
Task ShowMessageAsync(string title, string message);
Task ShowTextAsync(string title, string message);
TrainStop? GetInputTrainNumberStop(TrainStop? t);
- Task GetInputTrainStopAsync(List ticketChecks, List platforms);
- Task EditInputTrainStopAsync(List ticketChecks, List platforms, TrainStop trainStop);
+ Task GetInputTrainStopAsync(List waitingAreas, List platforms);
+ Task EditInputTrainStopAsync(List waitingAreas, List platforms, TrainStop trainStop);
Task?> GetInputPlatformAsync();
- Task<(string, List)> GetInputTicketCheckAsync(List waitingAreaNames);
XamlRoot? XamlRoot { get; set; }
}
}
diff --git a/CRSim/ViewModels/PluginManagementPageViewModel.cs b/CRSim/ViewModels/PluginManagementPageViewModel.cs
index 7561694..fd3af09 100644
--- a/CRSim/ViewModels/PluginManagementPageViewModel.cs
+++ b/CRSim/ViewModels/PluginManagementPageViewModel.cs
@@ -56,7 +56,7 @@ public partial class PluginManagementPageViewModel : ObservableObject
[RelayCommand]
public async Task InstallPluginLocal()
{
- if (await _dialogService.GetFileAsync([".crsp"]) is string filePath)
+ if (_dialogService.GetFile([".crsp"]) is string filePath)
{
try
{
@@ -85,7 +85,7 @@ public partial class PluginManagementPageViewModel : ObservableObject
public async Task PackPlugin()
{
if (SelectedPlugin == null) return;
- string? filePath = await _dialogService.SaveFileAsync(".crsp", $"{SelectedPlugin.Manifest.Id}");
+ string? filePath = _dialogService.SaveFile(".crsp", $"{SelectedPlugin.Manifest.Id}");
if (filePath == null) return;
try
{
diff --git a/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs b/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs
index bb6a5fd..964172a 100644
--- a/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs
+++ b/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs
@@ -29,7 +29,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable plugin
[ObservableProperty]
public partial bool LocationNeeded { get; set; }
public List StationNames => [.. databaseService.GetAllStations().Select(x => x.Name)];
- public ObservableCollection TicketChecks { get; private set; } = [];
+ public ObservableCollection TicketChecks { get; private set; } = [];
public ObservableCollection Platforms { get; private set; } = [];
public ObservableCollection Locations { get; private set; } = [];
@@ -41,7 +41,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable plugin
public string SelectedStationName = "";
- public string SelectedTicketCheck = "";
+ public TicketCheck? SelectedTicketCheck;
public string SelectedPlatformName = "";
@@ -79,14 +79,18 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable plugin
var station = databaseService.GetStationByName(v);
SelectedStationName = station.Name;
SelectedPlatformName = "";
- SelectedTicketCheck = "";
+ SelectedTicketCheck = null;
SelectedLoaction = 0;
TicketChecks.Clear();
foreach (var waitingArea in station.WaitingAreas)
{
- foreach (string ticketCheck in waitingArea.TicketChecks)
+ foreach (var ticketCheck in waitingArea.TicketChecks)
{
- TicketChecks.Add($"{waitingArea.Name} - {ticketCheck}");//重复检票口名称的临时解决方案
+ TicketChecks.Add(new TicketCheck()
+ {
+ Id = ticketCheck.Id,
+ Name = waitingArea.Name + " - " + ticketCheck.Name,
+ });
}
}
Platforms.Clear();
@@ -101,7 +105,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable plugin
[RelayCommand]
public void SelectTicketCheck(object s)
{
- if (s is string ticketCheck)
+ if (s is TicketCheck ticketCheck)
{
SelectedTicketCheck = ticketCheck;
}
@@ -134,7 +138,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable plugin
[RelayCommand]
public async Task SelectVideo()
{
- string? Path = await dialogService.GetFileAsync([".wmv",".asf",".mp4",".m4v",".mov",".mpg",".mpeg"]);
+ string? Path = dialogService.GetFile([".wmv",".asf",".mp4",".m4v",".mov",".mpg",".mpeg"]);
if (Path == null) return;
Video = Path;
}
@@ -150,7 +154,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable plugin
Text = (TextNeeded && !string.IsNullOrWhiteSpace(Text)) ? Text : null,
Video = (VideoNeeded && !string.IsNullOrWhiteSpace(Video)) ? new Uri(Video) : null,
Station = StationNeeded ? databaseService.GetStationByName(SelectedStationName) : null,
- TicketCheck = TicketCheckNeeded ? SelectedTicketCheck : string.Empty,
+ TicketCheck = TicketCheckNeeded ? SelectedTicketCheck : null,
PlatformName = PlatformNeeded ? SelectedPlatformName : string.Empty,
Loaction = (LocationNeeded && SelectedLoaction != 0) ? SelectedLoaction : 0
};
@@ -161,7 +165,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable plugin
{
IsStartSimulationAvailable = SelectedStyle != null &&
(!StationNeeded || !string.IsNullOrWhiteSpace(SelectedStationName)) &&
- (!TicketCheckNeeded || !string.IsNullOrWhiteSpace(SelectedTicketCheck)) &&
+ (!TicketCheckNeeded || SelectedTicketCheck is not null) &&
(!LocationNeeded || SelectedLoaction != 0) &&
(!PlatformNeeded || !string.IsNullOrWhiteSpace(SelectedPlatformName));
}
diff --git a/CRSim/ViewModels/SettingsPageViewModel.cs b/CRSim/ViewModels/SettingsPageViewModel.cs
index f38cc23..c43928f 100644
--- a/CRSim/ViewModels/SettingsPageViewModel.cs
+++ b/CRSim/ViewModels/SettingsPageViewModel.cs
@@ -113,14 +113,14 @@ namespace CRSim.ViewModels
[RelayCommand]
public async Task ExportData()
{
- string? path = await _dialogService.SaveFileAsync(".json", "data");
+ string? path = _dialogService.SaveFile(".json", "data");
if (string.IsNullOrWhiteSpace(path)) return;
await _databaseService.ExportData(path);
}
[RelayCommand]
public async Task ImportData()
{
- string? path = await _dialogService.GetFileAsync([".json"]);
+ string? path = _dialogService.GetFile([".json"]);
if (string.IsNullOrWhiteSpace(path)) return;
_databaseService.ImportData(path);
await _databaseService.SaveData();
diff --git a/CRSim/ViewModels/StationManagementPageViewModel.cs b/CRSim/ViewModels/StationManagementPageViewModel.cs
index d9a9517..0878a31 100644
--- a/CRSim/ViewModels/StationManagementPageViewModel.cs
+++ b/CRSim/ViewModels/StationManagementPageViewModel.cs
@@ -1,4 +1,4 @@
-using CRSim.Core.Abstractions;
+using System.Text.RegularExpressions;
namespace CRSim.ViewModels;
@@ -18,10 +18,9 @@ public partial class StationManagementPageViewModel : ObservableObject
[ObservableProperty]
public partial Station SelectedStation { get; set; } = new();
- public ObservableCollection WaitingAreaNames { get; private set; } = [];
- public ObservableCollection Platforms { get; private set; } = [];
+ public ObservableCollection WaitingAreas { get; private set; } = [];
- public ObservableCollection TicketChecks { get; private set; } = [];
+ public ObservableCollection Platforms { get; private set; } = [];
public ObservableCollection TrainStops { get; private set; } = [];
@@ -53,13 +52,13 @@ public partial class StationManagementPageViewModel : ObservableObject
{
IconGlyph = "\uECA5",
Title = "候车室数",
- Detail = WaitingAreaNames.Count.ToString()
+ Detail = WaitingAreas.Count.ToString()
});
InfoItems.Add(new InfoItem()
{
IconGlyph = "\uF161",
Title = "检票口数",
- Detail = TicketChecks.Count.ToString()
+ Detail = WaitingAreas.SelectMany(x=>x.TicketChecks).Count().ToString()
});
InfoItems.Add(new InfoItem()
{
@@ -69,7 +68,7 @@ public partial class StationManagementPageViewModel : ObservableObject
});
}
-#region Station
+ #region Station
public void RefreshStations()
{
var stationsList = _databaseService.GetAllStations();
@@ -78,20 +77,15 @@ public partial class StationManagementPageViewModel : ObservableObject
[RelayCommand]
public void StationSelected(object args)
{
- WaitingAreaNames.Clear();
+ WaitingAreas.Clear();
Platforms.Clear();
- TicketChecks.Clear();
TrainStops.Clear();
if (args is SelectionChangedEventArgs selectedStation && selectedStation.AddedItems.Count > 0)
{
SelectedStation = _databaseService.GetStationByName(selectedStation.AddedItems[0].ToString());
foreach (WaitingArea waitingArea in SelectedStation.WaitingAreas)
{
- WaitingAreaNames.Add(waitingArea.Name);
- foreach (string ticketCheck in waitingArea.TicketChecks)
- {
- TicketChecks.Add(new TicketCheck { WaitingAreaName = waitingArea.Name, Name = ticketCheck });
- }
+ WaitingAreas.Add(waitingArea);
}
foreach (TrainStop trainStop in SelectedStation.TrainStops)
{
@@ -113,7 +107,7 @@ public partial class StationManagementPageViewModel : ObservableObject
[RelayCommand]
public async Task AddStation()
{
- string? station = await _dialogService.GetInputAsync("请输入车站名称");
+ string? station = await _dialogService.GetInputAsync("请输入车站名称",string.Empty);
if (station != null)
{
if (StationNames.Contains(station))
@@ -147,29 +141,21 @@ public partial class StationManagementPageViewModel : ObservableObject
await _databaseService.SaveData();
RefreshStations();
}
- public static Station GenerateStation(string stationName, ObservableCollection waitingAreaNames, ObservableCollection ticketChecks, ObservableCollection trainStops, ObservableCollection platforms)
+ public static Station GenerateStation(string stationName, ObservableCollection waitingAreas, ObservableCollection trainStops, ObservableCollection platforms)
{
var station = new Station
{
Name = stationName,
- WaitingAreas = [.. waitingAreaNames.Select(name => new WaitingArea { Name = name })],
+ WaitingAreas = [.. waitingAreas],
TrainStops = [.. trainStops],
Platforms = [.. platforms]
};
-
- // 将 TicketCheck 映射到对应的 WaitingArea
- foreach (var ticketCheck in ticketChecks)
- {
- var waitingArea = station.WaitingAreas.FirstOrDefault(wa => wa.Name == ticketCheck.WaitingAreaName);
- waitingArea?.TicketChecks.Add(ticketCheck.Name);
- }
-
return station;
}
[RelayCommand]
public async Task ImportFrom7D()
{
- var path = await _dialogService.GetFileAsync([".exe"]);
+ var path = _dialogService.GetFile([".exe"]);
if (path == null) return;
try
{
@@ -184,69 +170,144 @@ public partial class StationManagementPageViewModel : ObservableObject
}
#endregion
- #region TicketCheck
- [RelayCommand]
- public async Task AddTicketCheck()
- {
- (string waitingAreaName, List ticketChecks) = await _dialogService.GetInputTicketCheckAsync([.. WaitingAreaNames]);
- if (ticketChecks != null && waitingAreaName != null)
- {
- foreach (string ticketCheck in ticketChecks)
- {
- if (TicketChecks.Where(x => x.WaitingAreaName == waitingAreaName).Select(x => x.Name).Contains(ticketCheck))
- {
- await _dialogService.ShowMessageAsync("添加失败", $"编号 {ticketCheck} 检票口已存在。");
- return;
- }
- TicketChecks.Add(new TicketCheck { WaitingAreaName = waitingAreaName, Name = ticketCheck });
- }
- }
- }
- [RelayCommand]
- public void DeleteTicketCheck(object selectedTicketCheck)
- {
- if (selectedTicketCheck is TicketCheck ticketCheck)
- {
- TicketChecks.Remove(ticketCheck);
- }
- }
- [RelayCommand]
- public async Task DeleteAllTicketCheck()
- {
- if (!await _dialogService.GetConfirmAsync("当前操作会删除全部检票口,是否继续?")) return;
- TicketChecks.Clear();
- }
- #endregion
-
#region WaitingArea
[RelayCommand]
public async Task AddWaitingArea()
{
- string? waitingAreaName = await _dialogService.GetInputAsync("请输入候车室名称");
+ string? waitingAreaName = await _dialogService.GetInputAsync("请输入候车室名称",string.Empty);
if (waitingAreaName != null)
{
- if (WaitingAreaNames.Contains(waitingAreaName))
+ if (WaitingAreas.Any(x=>x.Name==waitingAreaName))
{
await _dialogService.ShowMessageAsync("添加失败", $"名称 {waitingAreaName} 候车室已存在。");
return;
}
- WaitingAreaNames.Add(waitingAreaName);
+ WaitingAreas.Add(new WaitingArea { Name = waitingAreaName });
}
}
[RelayCommand]
public void DeleteWaitingArea(object selectedWaitingArea)
{
- if (selectedWaitingArea is string n)
+ if (selectedWaitingArea is WaitingArea n)
{
- WaitingAreaNames.Remove(n);
+ WaitingAreas.Remove(n);
}
}
[RelayCommand]
- public async Task DeleteAllWaitingArea()
+ public async Task DeleteAllTicketChecks()
{
- if (!await _dialogService.GetConfirmAsync("当前操作会删除全部候车室,是否继续?")) return;
- WaitingAreaNames.Clear();
+ if (!await _dialogService.GetConfirmAsync("当前操作会删除全部候车室和检票口,是否继续?")) return;
+ WaitingAreas.Clear();
}
+
+ [RelayCommand]
+ public async Task AddTicketCheck(object selectedWaitingArea)
+ {
+ if(selectedWaitingArea is WaitingArea waitingArea)
+ {
+ var input = await _dialogService.GetInputAsync("请输入检票口", "试试“1-3”/“1A-5B”");
+ if (input == null) return;
+ var ticketCheckNames = GenerateTicketChecks(input);
+ var duplicatedNames = waitingArea.TicketChecks
+ .Where(x => ticketCheckNames.Contains(x.Name))
+ .Select(x => x.Name);
+ if (duplicatedNames.Any())
+ {
+ string duplicatedNamesStr = string.Join(", ", duplicatedNames);
+ await _dialogService.ShowMessageAsync("添加失败", $"检票口 {duplicatedNamesStr} 已存在。");
+ return;
+ }
+ foreach (var name in ticketCheckNames)
+ {
+ waitingArea.TicketChecks.Add(new TicketCheck { Name = name });
+ }
+ OnPropertyChanged(nameof(WaitingAreas));
+ }
+ else
+ {
+ await _dialogService.ShowMessageAsync("错误", "请先选择候车室");
+ }
+ }
+
+ [RelayCommand]
+ public void DeleteItem(object selected)
+ {
+ if (selected is WaitingArea waitingArea)
+ {
+ WaitingAreas.Remove(waitingArea);
+ }
+ if (selected is TicketCheck ticketCheck)
+ {
+ var area = WaitingAreas.FirstOrDefault(w => w.TicketChecks.Contains(ticketCheck));
+ area?.TicketChecks.Remove(ticketCheck);
+ }
+ }
+
+ public static List GenerateTicketChecks(string input)
+ {
+ if (!input.Contains('-'))
+ {
+ return [input];
+ }
+
+ string[] parts = input.Split(['-'], 2);
+ if (parts.Length != 2)
+ {
+ return [input];
+ }
+
+ var startMatch = MyRegex().Match(parts[0]);
+ var endMatch = MyRegex().Match(parts[1]);
+
+ if (!startMatch.Success || !endMatch.Success)
+ {
+ return [input];
+ }
+
+ int startNum = int.Parse(startMatch.Groups[1].Value);
+ string sLetter = startMatch.Groups[2].Value;
+ int endNum = int.Parse(endMatch.Groups[1].Value);
+ string eLetter = endMatch.Groups[2].Value;
+
+ bool startHasLetter = !string.IsNullOrEmpty(sLetter);
+ bool endHasLetter = !string.IsNullOrEmpty(eLetter);
+
+ if (startHasLetter != endHasLetter)
+ {
+ return [input];
+ }
+
+ int min = Math.Min(startNum, endNum);
+ int max = Math.Max(startNum, endNum);
+ List numbers = [.. Enumerable.Range(min, max - min + 1)];
+
+ List result = [];
+
+ if (startHasLetter)
+ {
+ if (sLetter == eLetter)
+ {
+ numbers.ForEach(n => result.Add($"{n}{sLetter}"));
+ }
+ else
+ {
+ numbers.ForEach(n =>
+ {
+ result.Add($"{n}A");
+ result.Add($"{n}B");
+ });
+ }
+ }
+ else
+ {
+ numbers.ForEach(n => result.Add(n.ToString()));
+ }
+ return result;
+ }
+
+ [GeneratedRegex(@"^(\d+)([AB]?)$")]
+ private static partial Regex MyRegex();
+
#endregion
#region Platform
@@ -308,7 +369,7 @@ public partial class StationManagementPageViewModel : ObservableObject
public async Task ImportFromLulutong()
{
if (!await CheckCanImport()) return;
- var path = await _dialogService.GetFileAsync([".csv"]);
+ var path = _dialogService.GetFile([".csv"]);
if (path == null) return;
try
{
@@ -364,7 +425,7 @@ public partial class StationManagementPageViewModel : ObservableObject
{
if (!await CheckCanImport()) return;
- var path = await _dialogService.GetFileAsync([".pyetgr",".pyetdb",".json"]);
+ var path = _dialogService.GetFile([".pyetgr",".pyetdb",".json"]);
if (path == null) return;
try
{
@@ -450,7 +511,7 @@ public partial class StationManagementPageViewModel : ObservableObject
return;
}
}
- var path = await _dialogService.GetFileAsync([".xlsx"]);
+ var path = _dialogService.GetFile([".xlsx"]);
if (path == null) return;
try
{
@@ -465,9 +526,8 @@ public partial class StationManagementPageViewModel : ObservableObject
worksheet.Cells[row, 2].Text.Trim() == "" ||
worksheet.Cells[row, 5].Text.Trim() == "" ||
worksheet.Cells[row, 6].Text.Trim() == "" ||
- worksheet.Cells[row, 7].Text.Trim() == "" ||
- worksheet.Cells[row, 9].Text.Trim() == "" ||
- worksheet.Cells[row, 10].Text.Trim() == "")
+ worksheet.Cells[row, 8].Text.Trim() == "" ||
+ worksheet.Cells[row, 9].Text.Trim() == "")
{
continue;
}
@@ -478,12 +538,42 @@ public partial class StationManagementPageViewModel : ObservableObject
Length = int.TryParse(worksheet.Cells[row, 2].Text, out int length) ? length : 0,
ArrivalTime = TimeSpan.TryParseExact(worksheet.Cells[row, 3].Text, @"hh\:mm", null, out TimeSpan arrival) ? arrival : null,
DepartureTime = TimeSpan.TryParseExact(worksheet.Cells[row, 4].Text, @"hh\:mm", null, out TimeSpan departure) ? departure : null,
- WaitingArea = worksheet.Cells[row, 5].Text.Trim(),
- TicketChecks = [.. worksheet.Cells[row, 6].Text.Split(' ', StringSplitOptions.RemoveEmptyEntries)],
- Platform = worksheet.Cells[row, 7].Text.Trim(),
- Landmark = worksheet.Cells[row, 8].Text.Trim() == "" ? "无" : worksheet.Cells[row, 8].Text.Trim(),
- Origin = worksheet.Cells[row, 9].Text.Trim(),
- Terminal = worksheet.Cells[row, 10].Text.Trim()
+ TicketCheckIds = [.. worksheet.Cells[row, 5].Text
+ .Split(' ', StringSplitOptions.RemoveEmptyEntries)
+ .Select(entry =>
+ {
+ var parts = entry.Split('|');
+ if (parts.Length < 2)
+ return Guid.Empty;
+ var waitingAreaName = parts[0];
+ var ticketCheckName = parts[1];
+ var waitingArea = WaitingAreas.FirstOrDefault(w => w.Name == waitingAreaName);
+ TicketCheck tc;
+ if (waitingArea == null)
+ {
+ tc = new TicketCheck { Name = ticketCheckName };
+ WaitingAreas.Add(new WaitingArea
+ {
+ Name = waitingAreaName,
+ TicketChecks = [tc]
+ });
+ }
+ else
+ {
+ tc = waitingArea.TicketChecks.FirstOrDefault(c => c.Name == ticketCheckName);
+ if (tc == null)
+ {
+ tc = new TicketCheck { Name = ticketCheckName };
+ waitingArea.TicketChecks.Add(tc);
+ }
+ }
+ return tc.Id;
+ })
+ .Where(id => id != Guid.Empty)],
+ Platform = worksheet.Cells[row, 6].Text.Trim(),
+ Landmark = worksheet.Cells[row, 7].Text.Trim() == "" ? "无" : worksheet.Cells[row, 8].Text.Trim(),
+ Origin = worksheet.Cells[row, 8].Text.Trim(),
+ Terminal = worksheet.Cells[row, 9].Text.Trim()
});
}
}
@@ -495,7 +585,7 @@ public partial class StationManagementPageViewModel : ObservableObject
[RelayCommand]
public async Task ExportToExcel()
{
- var path = await _dialogService.SaveFileAsync(".xlsx", "data");
+ var path = _dialogService.SaveFile(".xlsx", "data");
if (path == null) return;
ExcelPackage.License.SetNonCommercialPersonal("CRSim");
using var package = new ExcelPackage();
@@ -504,31 +594,39 @@ public partial class StationManagementPageViewModel : ObservableObject
worksheet.Cells[1, 2].Value = "长度";
worksheet.Cells[1, 3].Value = "到时";
worksheet.Cells[1, 4].Value = "发时";
- worksheet.Cells[1, 5].Value = "候车区";
- worksheet.Cells[1, 6].Value = "检票口";
- worksheet.Cells[1, 7].Value = "站台";
- worksheet.Cells[1, 8].Value = "地标";
- worksheet.Cells[1, 9].Value = "始发站";
- worksheet.Cells[1, 10].Value = "终到站";
+ worksheet.Cells[1, 5].Value = "检票口";
+ worksheet.Cells[1, 6].Value = "站台";
+ worksheet.Cells[1, 7].Value = "地标";
+ worksheet.Cells[1, 8].Value = "始发站";
+ worksheet.Cells[1, 9].Value = "终到站";
for (int i = 0; i < TrainStops.Count; i++)
{
worksheet.Cells[i + 2, 1].Value = TrainStops[i].Number;
worksheet.Cells[i + 2, 2].Value = TrainStops[i].Length;
worksheet.Cells[i + 2, 3].Value = TrainStops[i].ArrivalTime?.ToString(@"hh\:mm") ?? string.Empty;
worksheet.Cells[i + 2, 4].Value = TrainStops[i].DepartureTime?.ToString(@"hh\:mm") ?? string.Empty;
- worksheet.Cells[i + 2, 5].Value = TrainStops[i].WaitingArea;
- worksheet.Cells[i + 2, 6].Value = TrainStops[i].TicketChecks.Count == 0 ? string.Empty : string.Join(" ", TrainStops[i].TicketChecks);
- worksheet.Cells[i + 2, 7].Value = TrainStops[i].Platform;
- worksheet.Cells[i + 2, 8].Value = TrainStops[i].Landmark;
- worksheet.Cells[i + 2, 9].Value = TrainStops[i].Origin;
- worksheet.Cells[i + 2, 10].Value = TrainStops[i].Terminal;
+ worksheet.Cells[i + 2, 5].Value = TrainStops[i].TicketCheckIds is null ? string.Empty : string.Join(" ", TrainStops[i].TicketCheckIds
+ .Select(id =>
+ {
+ var area = WaitingAreas.FirstOrDefault(a => a.TicketChecks.Any(tc => tc.Id == id));
+ var check = area?.TicketChecks.FirstOrDefault(tc => tc.Id == id);
+ if (area != null && check != null)
+ return $"{area.Name}|{check.Name}";
+ else
+ return null;
+ })
+ .Where(x => x != null));
+ worksheet.Cells[i + 2, 6].Value = TrainStops[i].Platform;
+ worksheet.Cells[i + 2, 7].Value = TrainStops[i].Landmark;
+ worksheet.Cells[i + 2, 8].Value = TrainStops[i].Origin;
+ worksheet.Cells[i + 2, 9].Value = TrainStops[i].Terminal;
}
await package.SaveAsAsync(new FileInfo(path));
}
[RelayCommand]
public async Task AddTrainStop()
{
- var newTrainStop = await _dialogService.GetInputTrainStopAsync([.. TicketChecks.Select(x => $"{x.WaitingAreaName} - {x.Name}")], [.. Platforms.Select(x => x.Name)]);
+ var newTrainStop = await _dialogService.GetInputTrainStopAsync([.. WaitingAreas], [.. Platforms.Select(x => x.Name)]);
if (newTrainStop != null)
{
if (TrainStops.Any(x => x.Number == newTrainStop.Number))
@@ -558,7 +656,7 @@ public partial class StationManagementPageViewModel : ObservableObject
{
if (_selectedTrainStop is TrainStop selectedTrainStop)
{
- var newTrainStop = await _dialogService.EditInputTrainStopAsync([.. TicketChecks.Select(x => $"{x.WaitingAreaName} - {x.Name}")], [.. Platforms.Select(x => x.Name)], selectedTrainStop);
+ var newTrainStop = await _dialogService.EditInputTrainStopAsync([.. WaitingAreas], [.. Platforms.Select(x => x.Name)], selectedTrainStop);
if (newTrainStop != null)
{
if (TrainStops.Where(x => x.Number == newTrainStop.Number).Count() > 1)
@@ -590,7 +688,7 @@ public partial class StationManagementPageViewModel : ObservableObject
}
private async Task CheckCanImport()
{
- if (TicketChecks.Count == 0)
+ if (WaitingAreas.All(x => x.TicketChecks.Count == 0))
{
await _dialogService.ShowMessageAsync("导入失败", "请先添加检票口。");
return false;
@@ -616,9 +714,19 @@ public partial class StationManagementPageViewModel : ObservableObject
t.Platform = Platforms[new Random().Next(Platforms.Count)].Name;
if (t.DepartureTime.HasValue)
{
- t.TicketChecks = [.. TicketChecks.Where(x => x.Name == t.Platform + "A" || x.Name == t.Platform + "B").Select(x => x.Name)];
- if (t.TicketChecks.Count == 0) t.TicketChecks = [TicketChecks[new Random().Next(TicketChecks.Count)].Name];
- t.WaitingArea = TicketChecks.Where(x => x.Name == t.TicketChecks[0]).ToList()[new Random().Next(TicketChecks.Where(x => x.Name == t.TicketChecks[0]).ToList().Count)].WaitingAreaName;
+ //t.TicketCheckIds = [.. WaitingAreas
+ // .FirstOrDefault(x => x.TicketChecks.Any(x => x.Name == t.Platform + "A")
+ // && x.TicketChecks.Any(x => x.Name == t.Platform + "B"))?
+ // .TicketChecks
+ // .Where(x => x.Name == t.Platform + "A" || x.Name == t.Platform + "B")
+ // .Select(x => x.Id)];
+ //根据站台选择检票口
+ if (t.TicketCheckIds is null || t.TicketCheckIds.Count == 0) t.TicketCheckIds = [WaitingAreas
+ .SelectMany(x => x.TicketChecks)
+ .Select(x => x.Id)
+ .OrderBy(_ => new Random().Next())
+ .FirstOrDefault()];
+ //若没有则随机匹配
}
return t;
}
@@ -628,7 +736,7 @@ public partial class StationManagementPageViewModel : ObservableObject
public async Task SaveChanges()
{
if (!await Validate()) return;
- _databaseService.UpdateStation(SelectedStation.Name, GenerateStation(SelectedStation.Name, WaitingAreaNames, TicketChecks, TrainStops, Platforms));
+ _databaseService.UpdateStation(SelectedStation.Name, GenerateStation(SelectedStation.Name, WaitingAreas, TrainStops, Platforms));
await _databaseService.SaveData();
UpdateInfoItems();
}
@@ -636,6 +744,7 @@ public partial class StationManagementPageViewModel : ObservableObject
private async Task Validate()
{
string warningMessage = "";
+ string errorMessage = "";
var platformGroups = TrainStops
.Where(ts => !string.IsNullOrEmpty(ts.Platform) && ts.DepartureTime != null && ts.ArrivalTime != null)
.GroupBy(ts => ts.Platform);
@@ -655,30 +764,17 @@ public partial class StationManagementPageViewModel : ObservableObject
}
}
- string errorMessage = "";
- foreach (var t in TicketChecks)
- {
- if (!WaitingAreaNames.Contains(t.WaitingAreaName))
- {
- errorMessage += $"\n检票口 {t.Name} 所在的候车室 {t.WaitingAreaName} 不存在;";
- }
- }
foreach (var s in TrainStops)
{
if (s.DepartureTime.HasValue)
{
- if (!WaitingAreaNames.Contains(s.WaitingArea))
+ List allTicketChecks = [.. WaitingAreas.SelectMany(x => x.TicketChecks.Select(x=>x.Id))];
+ foreach (var ticketCheckId in s.TicketCheckIds)
{
- errorMessage += $"\n车次 {s.Number} 所分配的候车区 {s.WaitingArea} 不存在;";
- }
- else
- {
- foreach (var t in s.TicketChecks)
+ if (!allTicketChecks.Contains(ticketCheckId))
{
- if (!TicketChecks.Any(x => x.Name == t && x.WaitingAreaName == s.WaitingArea))
- {
- errorMessage += $"\n车次 {s.Number} 所分配的检票口 {t} 在候车区 {s.WaitingArea} 中不存在;";
- }
+ warningMessage += $"\n车次 {s.Number} 所分配的检票口 {ticketCheckId} 不存在,已自动删除;";
+ s.TicketCheckIds.Remove(ticketCheckId);//感觉这个代码放在这个位置不合适,但我也不知放在哪里好QAQ
}
}
}
diff --git a/CRSim/Views/DialogContents/InputDialog.xaml b/CRSim/Views/DialogContents/InputDialog.xaml
index f189073..a298cd9 100644
--- a/CRSim/Views/DialogContents/InputDialog.xaml
+++ b/CRSim/Views/DialogContents/InputDialog.xaml
@@ -8,6 +8,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
-
+
diff --git a/CRSim/Views/DialogContents/InputDialog.xaml.cs b/CRSim/Views/DialogContents/InputDialog.xaml.cs
index f0ec009..d5de69f 100644
--- a/CRSim/Views/DialogContents/InputDialog.xaml.cs
+++ b/CRSim/Views/DialogContents/InputDialog.xaml.cs
@@ -2,8 +2,10 @@ namespace CRSim.Views;
public sealed partial class InputDialog : Page
{
public string InputText { get; set; }
- public InputDialog()
+ public string Placeholder { get; set; }
+ public InputDialog(string placeholder)
{
+ Placeholder = placeholder;
InitializeComponent();
}
}
diff --git a/CRSim/Views/DialogContents/TicketCheckDialog.xaml b/CRSim/Views/DialogContents/TicketCheckDialog.xaml
deleted file mode 100644
index a1f593f..0000000
--- a/CRSim/Views/DialogContents/TicketCheckDialog.xaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
diff --git a/CRSim/Views/DialogContents/TicketCheckDialog.xaml.cs b/CRSim/Views/DialogContents/TicketCheckDialog.xaml.cs
deleted file mode 100644
index f01d422..0000000
--- a/CRSim/Views/DialogContents/TicketCheckDialog.xaml.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using System.Text.RegularExpressions;
-
-namespace CRSim.Views;
-public sealed partial class TicketCheckDialog : Page
-{
- private readonly Action _onValidityChanged;
- public List GeneratedTicketChecks = [];
- public string SelectedWaitingArea => WaitingAreasComboBox.SelectedValue.ToString();
- private List WaitingAreaNames { get; set; } = [];
- private void Validate(object sender, object e)
- {
- bool isValid = !string.IsNullOrWhiteSpace(TicketCheckTextBox.Text) && !string.IsNullOrWhiteSpace(WaitingAreasComboBox.SelectedValue?.ToString());
- _onValidityChanged?.Invoke(isValid);
- }
- public TicketCheckDialog(List waitingAreaNames, Action onValidityChanged)
- {
- _onValidityChanged = onValidityChanged;
- WaitingAreaNames = waitingAreaNames;
- InitializeComponent();
- }
- public void GenerateTicketChecks()
- {
- var input = TicketCheckTextBox.Text.Trim();
- if (!input.Contains('-'))
- {
- GeneratedTicketChecks = [input];
- return;
- }
-
- string[] parts = input.Split(['-'], 2);
- if (parts.Length != 2)
- {
- GeneratedTicketChecks = [input];
- return;
- }
-
- var startMatch = MyRegex().Match(parts[0]);
- var endMatch = MyRegex().Match(parts[1]);
-
- if (!startMatch.Success || !endMatch.Success)
- {
- GeneratedTicketChecks = [input];
- return;
- }
-
- int startNum = int.Parse(startMatch.Groups[1].Value);
- string sLetter = startMatch.Groups[2].Value;
- int endNum = int.Parse(endMatch.Groups[1].Value);
- string eLetter = endMatch.Groups[2].Value;
-
- bool startHasLetter = !string.IsNullOrEmpty(sLetter);
- bool endHasLetter = !string.IsNullOrEmpty(eLetter);
-
- if (startHasLetter != endHasLetter)
- {
- GeneratedTicketChecks = [input];
- }
-
- int min = Math.Min(startNum, endNum);
- int max = Math.Max(startNum, endNum);
- List numbers = [.. Enumerable.Range(min, max - min + 1)];
-
- List result = [];
-
- if (startHasLetter)
- {
- if (sLetter == eLetter)
- {
- numbers.ForEach(n => result.Add($"{n}{sLetter}"));
- }
- else
- {
- numbers.ForEach(n =>
- {
- result.Add($"{n}A");
- result.Add($"{n}B");
- });
- }
- }
- else
- {
- numbers.ForEach(n => result.Add(n.ToString()));
- }
- GeneratedTicketChecks = result;
- return;
- }
-
- [GeneratedRegex(@"^(\d+)([AB]?)$")]
- private static partial Regex MyRegex();
-}
diff --git a/CRSim/Views/DialogContents/TrainStopDialog.xaml b/CRSim/Views/DialogContents/TrainStopDialog.xaml
index 24db57f..c771c82 100644
--- a/CRSim/Views/DialogContents/TrainStopDialog.xaml
+++ b/CRSim/Views/DialogContents/TrainStopDialog.xaml
@@ -6,12 +6,25 @@
xmlns:local="using:CRSim.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:models="using:CRSim.Models"
+ xmlns:coremodels="using:CRSim.Core.Models"
+ xmlns:selectors="using:CRSim.Selectors"
mc:Ignorable="d">
+
+
+
+
+
+
+
+
+
-
+
@@ -57,13 +70,8 @@
-
-
-
-
-
-
-
+
diff --git a/CRSim/Views/DialogContents/TrainStopDialog.xaml.cs b/CRSim/Views/DialogContents/TrainStopDialog.xaml.cs
index d196eea..3a1c330 100644
--- a/CRSim/Views/DialogContents/TrainStopDialog.xaml.cs
+++ b/CRSim/Views/DialogContents/TrainStopDialog.xaml.cs
@@ -1,53 +1,38 @@
-using Microsoft.UI.Xaml.Controls.Primitives;
+using CRSim.Core.Models;
namespace CRSim.Views;
public sealed partial class TrainStopDialog : Page
{
public TrainStop GeneratedTrainStop;
+
public List Landmarks { get; set; } = ["", "ɫ", "ɫ", "ɫ", "ɫ", "ɫ", "ɫ", "ɫ"];
+
public List Platforms { get; set; } = [];
- public ObservableCollection TicketChecksList { get; set; } = [];
+
+ public List WaitingAreas { get; set; }
+
private readonly Action _onValidityChanged;
- public TrainStopDialog(List ticketChecks, List platforms, Action onValidityChanged)
+
+ public TrainStopDialog(List waitingAreas, List platforms, Action onValidityChanged)
{
- InitializeComponent();
- _onValidityChanged = onValidityChanged;
- TicketChecksList.Clear();
- foreach (string s in ticketChecks)
- {
- var checkItem = new CheckListItem()
- {
- Name = s,
- IsSelected = false,
- };
- checkItem.PropertyChanged += Validate;
- TicketChecksList.Add(checkItem);
- }
+ WaitingAreas = waitingAreas;
foreach (string s in platforms)
{
Platforms.Add(s);
}
+ InitializeComponent();
+ _onValidityChanged = onValidityChanged;
Validate(null, null);
}
- public TrainStopDialog(List ticketChecks, List platforms,TrainStop trainStop, Action onValidityChanged)
+ public TrainStopDialog(List waitingAreas, List platforms, TrainStop trainStop, Action onValidityChanged)
{
- InitializeComponent();
- _onValidityChanged = onValidityChanged;
- TicketChecksList.Clear();
- foreach (string s in ticketChecks)
- {
- var checkItem = new CheckListItem()
- {
- Name = s,
- IsSelected = false,
- };
- checkItem.PropertyChanged += Validate;
- TicketChecksList.Add(checkItem);
- }
+ WaitingAreas = waitingAreas;
foreach (string s in platforms)
{
Platforms.Add(s);
}
+ InitializeComponent();
+ _onValidityChanged = onValidityChanged;
NumberTextBox.Text = trainStop.Number;
LengthTextBox.Text = trainStop.Length.ToString();
ArrivalTextBox.Text = trainStop.Terminal;
@@ -76,13 +61,14 @@ public sealed partial class TrainStopDialog : Page
EndMinute.IsEnabled = false;
StationKindPanelRadioButtons.SelectedIndex = 2;
}
- if(trainStop.TicketChecks != null && trainStop.TicketChecks.Count > 0)
+ if (trainStop.TicketCheckIds != null)
{
- foreach (string s in trainStop.TicketChecks)
+ foreach (var id in trainStop.TicketCheckIds)
{
- TicketChecksList.FirstOrDefault(x => x.Name == trainStop.WaitingArea + " - " + s)!.IsSelected = true;
+ //WaitingAreasList.SelectedItems.Add(waitingAreas.SelectMany(x => x.TicketChecks).FirstOrDefault(x => x.Id == id));
}
}
+
Validate(null, null);
}
private static bool ValidateTime(string input, int maxValue)
@@ -101,8 +87,8 @@ public sealed partial class TrainStopDialog : Page
(!EndHour.IsEnabled || ValidateTime(EndHour.Text, 24)) &&
(!EndMinute.IsEnabled || ValidateTime(EndMinute.Text, 60));
bool isValid =
- (!TicketChecksCheckList.IsEnabled ||
- (TicketChecksList.Any(x => x.IsSelected) && TicketChecksList.Where(x => x.IsSelected).Select(x => x.Name.Split(" - ")[0]).Distinct().Count() <= 1)) &&
+ (!WaitingAreasList.IsEnabled ||
+ WaitingAreasList.SelectedItems?.Count != 0) &&
areTextBoxesFilled &&
!string.IsNullOrWhiteSpace(NumberTextBox.Text) &&
!string.IsNullOrWhiteSpace(ArrivalTextBox.Text) &&
@@ -138,8 +124,9 @@ public sealed partial class TrainStopDialog : Page
Origin = DepartureTextBox.Text,
ArrivalTime = StartHour.IsEnabled ? TimeSpan.Parse($"{StartHour.Text}:{StartMinute.Text}") : null,
DepartureTime = EndHour.IsEnabled ? TimeSpan.Parse($"{EndHour.Text}:{EndMinute.Text}") : null,
- WaitingArea = EndHour.IsEnabled ? TicketChecksList.Where(x => x.IsSelected).FirstOrDefault().Name.Split(" - ")[0] : null,
- TicketChecks = EndHour.IsEnabled ? [.. TicketChecksList.Where(x => x.IsSelected).Select(x => x.Name.Split(" - ")[1])] : null,
+ TicketCheckIds = EndHour.IsEnabled ? [.. WaitingAreasList.SelectedItems
+ .OfType()
+ .Select(x => x.Id)] : null,
Platform = (string)PlatformComboBox.SelectedItem,
Length = int.Parse(LengthTextBox.Text),
Landmark = (string)LandmarkComboBox.SelectedItem == "" ? null : (string)LandmarkComboBox.SelectedItem,
@@ -159,21 +146,21 @@ public sealed partial class TrainStopDialog : Page
StartMinute.IsEnabled = false;
EndHour.IsEnabled = true;
EndMinute.IsEnabled = true;
- TicketChecksCheckList.IsEnabled = true;
+ WaitingAreasList.IsEnabled = true;
break;
case "мվ":
StartHour.IsEnabled = true;
StartMinute.IsEnabled = true;
EndHour.IsEnabled = true;
EndMinute.IsEnabled = true;
- TicketChecksCheckList.IsEnabled = true;
+ WaitingAreasList.IsEnabled = true;
break;
case "յվ":
StartHour.IsEnabled = true;
StartMinute.IsEnabled = true;
EndHour.IsEnabled = false;
EndMinute.IsEnabled = false;
- TicketChecksCheckList.IsEnabled = false;
+ WaitingAreasList.IsEnabled = false;
break;
}
Validate(null, null);
diff --git a/CRSim/Views/ScreenSimulatorPage.xaml b/CRSim/Views/ScreenSimulatorPage.xaml
index e5b62a0..9e8caf2 100644
--- a/CRSim/Views/ScreenSimulatorPage.xaml
+++ b/CRSim/Views/ScreenSimulatorPage.xaml
@@ -130,7 +130,7 @@
-
+
diff --git a/CRSim/Views/StartWindow.xaml.cs b/CRSim/Views/StartWindow.xaml.cs
index 7a27a3f..4414cb5 100644
--- a/CRSim/Views/StartWindow.xaml.cs
+++ b/CRSim/Views/StartWindow.xaml.cs
@@ -2,13 +2,9 @@ using System.ComponentModel;
namespace CRSim.Views
{
- // ¼ί
- public delegate void SplashScreenClosedEventHandler(object sender, EventArgs e);
-
public sealed partial class StartWindow : Window, INotifyPropertyChanged
{
// ¼
- public event SplashScreenClosedEventHandler SplashScreenClosed;
public string AppVersion { get; set; } = App.AppVersion;
private string _status = "...";
@@ -24,7 +20,6 @@ namespace CRSim.Views
}
}
}
-
public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(string propertyName)
@@ -60,12 +55,5 @@ namespace CRSim.Views
}
-
- // ɳʼر
- public void CompleteInitialization()
- {
- SplashScreenClosed?.Invoke(this, EventArgs.Empty);
- this.Close();
- }
}
}
diff --git a/CRSim/Views/StationManagementPage.xaml b/CRSim/Views/StationManagementPage.xaml
index 9a77ba0..d5239ff 100644
--- a/CRSim/Views/StationManagementPage.xaml
+++ b/CRSim/Views/StationManagementPage.xaml
@@ -13,12 +13,23 @@
xmlns:viewmodels="using:CRSim.ViewModels"
xmlns:models="using:CRSim.Models"
xmlns:coremodels="using:CRSim.Core.Models"
+ xmlns:selectors="using:CRSim.Selectors"
mc:Ignorable="d"
Loaded="Page_Loaded"
d:DataContext="{d:DesignInstance Type=viewmodels:StationManagementPageViewModel}">
-
+
+
+
+
+
+
+
+
@@ -81,52 +92,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -164,6 +129,17 @@
+
+
+
+
+
+
+
+
+
+
@@ -195,18 +171,16 @@
-
-
-
-
-
-
-
+
+
+
+
+
@@ -222,18 +196,16 @@
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/Directory.Build.props b/Directory.Build.props
index eb6a662..49591e6 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,6 +1,6 @@
- 2.3.107.0
+ 2.3.108.0
电排骨
https://github.com/denglihong2007/CRSim