mirror of
https://github.com/denglihong2007/CRSim
synced 2026-08-11 04:05:36 +08:00
@@ -13,8 +13,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Downloader" Version="4.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.7" />
|
||||
<PackageReference Include="Downloader" Version="4.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,7 @@ namespace CRSim.Core.Models
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter))]
|
||||
public TimeSpan? DepartureTime { get; set; }
|
||||
|
||||
public List<string>? TicketChecks { get; set; }
|
||||
|
||||
public string? WaitingArea { get; set; }
|
||||
public List<Guid>? TicketCheckIds { get; set; }
|
||||
|
||||
public string? Origin { get; set; }
|
||||
|
||||
|
||||
@@ -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<string> TicketChecks { get; set; } = [];
|
||||
public ObservableCollection<TicketCheck> TicketChecks { get; set; } = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>(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,
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
||||
<PackageReference Include="PinYinConverterCore" Version="1.0.2" />
|
||||
<PackageReference Include="PP.Wpf" Version="1.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<StartWindow>();
|
||||
splashScreenWindow.SplashScreenClosed += OnSplashScreenClosed;
|
||||
var splashScreenWindow = AppHost.Services.GetRequiredService<StartWindow>();
|
||||
splashScreenWindow.Activate();
|
||||
_ = PerformInitializationAsync(splashScreenWindow);
|
||||
await PerformInitializationAsync(splashScreenWindow);
|
||||
MainWindow = AppHost.Services.GetRequiredService<MainWindow>();
|
||||
MainWindow.Activate();
|
||||
splashScreenWindow.Close();
|
||||
}
|
||||
|
||||
private static async Task PerformInitializationAsync(StartWindow splashScreen)
|
||||
private static async Task PerformInitializationAsync(StartWindow startWindow)
|
||||
{
|
||||
try
|
||||
{
|
||||
var startWindow = AppHost.Services.GetService<StartWindow>();
|
||||
await Task.Delay(2000);
|
||||
if(!Debugger.IsAttached) await Task.Delay(2000);
|
||||
startWindow.Status = "正在加载设置...";
|
||||
AppHost.Services.GetService<ISettingsService>().LoadSettings();
|
||||
await Task.Delay(500);
|
||||
if (!Debugger.IsAttached) await Task.Delay(500);
|
||||
startWindow.Status = "正在加载数据库...";
|
||||
AppHost.Services.GetService<IDatabaseService>().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>();
|
||||
mainWindow.Activate();
|
||||
MainWindow = mainWindow;
|
||||
}
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Converters" Version="8.2.250402" />
|
||||
<PackageReference Include="EPPlus" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.UI.Xaml" Version="2.8.7" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4654" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
||||
|
||||
@@ -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<string> ticketChecks)
|
||||
{
|
||||
// 使用自定义的 Separator 将字符串连接
|
||||
return string.Join(Separator, ticketChecks);
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
// 通常不需要实现 ConvertBack
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
CRSim/Converters/TicketChecksToStringConverter.cs
Normal file
27
CRSim/Converters/TicketChecksToStringConverter.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace CRSim.Converters
|
||||
{
|
||||
public partial class TicketChecksToStringConverter : IValueConverter
|
||||
{
|
||||
public string Separator { get; set; } = "";
|
||||
public ObservableCollection<WaitingArea> WaitingAreas { get; set; } = [];
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is List<Guid> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
<NavigationView Grid.Row="1" x:Name="nvSample" SelectionChanged="nvSample_SelectionChanged"
|
||||
IsBackButtonVisible="Collapsed" IsBackEnabled="False">
|
||||
<NavigationView.MenuItems>
|
||||
<NavigationViewItem Icon="Home" Content="主页" Tag="DashboardPage" />
|
||||
<NavigationViewItem Icon="Home" Content="主页" Tag="DashboardPage" IsSelected="True"/>
|
||||
<NavigationViewItem Content="插件" Tag="PluginManagementPage">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace CRSim.Models
|
||||
{
|
||||
public partial class CheckListItem : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial bool IsSelected { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
18
CRSim/Selectors/FileName.cs
Normal file
18
CRSim/Selectors/FileName.cs
Normal file
@@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<string?> GetInputAsync(string title)
|
||||
public async Task<string?> 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<string>)> GetInputTicketCheckAsync(List<string> 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<string?> 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<TrainStop?> GetInputTrainStopAsync(List<string> ticketChecks, List<string> platforms)
|
||||
public async Task<TrainStop?> GetInputTrainStopAsync(List<WaitingArea> waitingAreas, List<string> 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<TrainStop?> EditInputTrainStopAsync(List<string> ticketChecks, List<string> platforms, TrainStop trainStop)
|
||||
public async Task<TrainStop?> EditInputTrainStopAsync(List<WaitingArea> waitingAreas, List<string> 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<string?> 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<List<Platform>?> GetInputPlatformAsync()
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
{
|
||||
public interface IDialogService
|
||||
{
|
||||
Task<string?> GetFileAsync(string[] filter);
|
||||
Task<string?> SaveFileAsync(string filter,string fileName);
|
||||
Task<string?> GetInputAsync(string title);
|
||||
string? GetFile(string[] filter);
|
||||
string? SaveFile(string filter,string fileName);
|
||||
Task<string?> GetInputAsync(string title,string placeholder);
|
||||
Task<bool> GetConfirmAsync(string title);
|
||||
Task ShowMessageAsync(string title, string message);
|
||||
Task ShowTextAsync(string title, string message);
|
||||
TrainStop? GetInputTrainNumberStop(TrainStop? t);
|
||||
Task<TrainStop?> GetInputTrainStopAsync(List<string> ticketChecks, List<string> platforms);
|
||||
Task<TrainStop?> EditInputTrainStopAsync(List<string> ticketChecks, List<string> platforms, TrainStop trainStop);
|
||||
Task<TrainStop?> GetInputTrainStopAsync(List<WaitingArea> waitingAreas, List<string> platforms);
|
||||
Task<TrainStop?> EditInputTrainStopAsync(List<WaitingArea> waitingAreas, List<string> platforms, TrainStop trainStop);
|
||||
Task<List<Platform>?> GetInputPlatformAsync();
|
||||
Task<(string, List<string>)> GetInputTicketCheckAsync(List<string> waitingAreaNames);
|
||||
XamlRoot? XamlRoot { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable<PluginBase> plugin
|
||||
[ObservableProperty]
|
||||
public partial bool LocationNeeded { get; set; }
|
||||
public List<string> StationNames => [.. databaseService.GetAllStations().Select(x => x.Name)];
|
||||
public ObservableCollection<string> TicketChecks { get; private set; } = [];
|
||||
public ObservableCollection<TicketCheck> TicketChecks { get; private set; } = [];
|
||||
public ObservableCollection<Platform> Platforms { get; private set; } = [];
|
||||
public ObservableCollection<int> Locations { get; private set; } = [];
|
||||
|
||||
@@ -41,7 +41,7 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable<PluginBase> plugin
|
||||
|
||||
public string SelectedStationName = "";
|
||||
|
||||
public string SelectedTicketCheck = "";
|
||||
public TicketCheck? SelectedTicketCheck;
|
||||
|
||||
public string SelectedPlatformName = "";
|
||||
|
||||
@@ -79,14 +79,18 @@ public partial class ScreenSimulatorPageViewModel(IEnumerable<PluginBase> 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<PluginBase> 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<PluginBase> 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<PluginBase> 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<PluginBase> plugin
|
||||
{
|
||||
IsStartSimulationAvailable = SelectedStyle != null &&
|
||||
(!StationNeeded || !string.IsNullOrWhiteSpace(SelectedStationName)) &&
|
||||
(!TicketCheckNeeded || !string.IsNullOrWhiteSpace(SelectedTicketCheck)) &&
|
||||
(!TicketCheckNeeded || SelectedTicketCheck is not null) &&
|
||||
(!LocationNeeded || SelectedLoaction != 0) &&
|
||||
(!PlatformNeeded || !string.IsNullOrWhiteSpace(SelectedPlatformName));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<string> WaitingAreaNames { get; private set; } = [];
|
||||
public ObservableCollection<Platform> Platforms { get; private set; } = [];
|
||||
public ObservableCollection<WaitingArea> WaitingAreas { get; private set; } = [];
|
||||
|
||||
public ObservableCollection<TicketCheck> TicketChecks { get; private set; } = [];
|
||||
public ObservableCollection<Platform> Platforms { get; private set; } = [];
|
||||
|
||||
public ObservableCollection<TrainStop> 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<string> waitingAreaNames, ObservableCollection<TicketCheck> ticketChecks, ObservableCollection<TrainStop> trainStops, ObservableCollection<Platform> platforms)
|
||||
public static Station GenerateStation(string stationName, ObservableCollection<WaitingArea> waitingAreas, ObservableCollection<TrainStop> trainStops, ObservableCollection<Platform> 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<string> 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<string> 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<int> numbers = [.. Enumerable.Range(min, max - min + 1)];
|
||||
|
||||
List<string> 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<bool> 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<bool> 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<Guid> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<TextBox Text="{x:Bind InputText, Mode=TwoWay}" />
|
||||
<TextBox PlaceholderText="{x:Bind Placeholder}" Text="{x:Bind InputText, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</Page>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Page
|
||||
x:Class="CRSim.Views.TicketCheckDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:CRSim.Views"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<ComboBox ItemsSource="{x:Bind WaitingAreaNames}" Margin="0,0,0,16" x:Name="WaitingAreasComboBox"
|
||||
SelectionChanged="Validate" MinWidth="100" Header="候车室"/>
|
||||
<TextBox PlaceholderText="试试“1-3”/“1A-5B”" x:Name="TicketCheckTextBox" TextChanged="Validate" Header="编号"/>
|
||||
</StackPanel>
|
||||
</Page>
|
||||
@@ -1,90 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace CRSim.Views;
|
||||
public sealed partial class TicketCheckDialog : Page
|
||||
{
|
||||
private readonly Action<bool> _onValidityChanged;
|
||||
public List<string> GeneratedTicketChecks = [];
|
||||
public string SelectedWaitingArea => WaitingAreasComboBox.SelectedValue.ToString();
|
||||
private List<string> 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<string> waitingAreaNames, Action<bool> 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<int> numbers = [.. Enumerable.Range(min, max - min + 1)];
|
||||
|
||||
List<string> 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();
|
||||
}
|
||||
@@ -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">
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="WaitingAreaTemplate" x:DataType="coremodels:WaitingArea">
|
||||
<TreeViewItem Content="{x:Bind Name}" ItemsSource="{x:Bind TicketChecks}" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="TicketCheckTemplate" x:DataType="coremodels:TicketCheck">
|
||||
<TextBlock Text="{x:Bind Name}" />
|
||||
</DataTemplate>
|
||||
<selectors:TreeViewTemplateSelector
|
||||
x:Key="TreeViewTemplateSelector"
|
||||
WaitingAreaTemplate="{StaticResource WaitingAreaTemplate}"
|
||||
TicketCheckTemplate="{StaticResource TicketCheckTemplate}" />
|
||||
</Page.Resources>
|
||||
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Grid ColumnSpacing="24" RowSpacing="16">
|
||||
@@ -57,13 +70,8 @@
|
||||
<TextBlock Text="检票口" Margin="0,0,0,12"/>
|
||||
<Border Style="{StaticResource ListViewBorder}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible" MaxHeight="300">
|
||||
<ListView x:Name="TicketChecksCheckList" ItemsSource="{x:Bind TicketChecksList}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:CheckListItem">
|
||||
<CheckBox Content="{x:Bind Name}" IsChecked="{x:Bind IsSelected, Mode=TwoWay}"/>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<TreeView SelectionMode="Multiple" Name="WaitingAreasList" Width="120" SelectionChanged="Validate"
|
||||
ItemsSource="{x:Bind WaitingAreas, Mode=OneWay}" ItemTemplateSelector="{StaticResource TreeViewTemplateSelector}" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
@@ -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<string> Landmarks { get; set; } = ["无", "红色", "绿色", "褐色", "蓝色", "紫色", "黄色", "橙色"];
|
||||
|
||||
public List<string> Platforms { get; set; } = [];
|
||||
public ObservableCollection<CheckListItem> TicketChecksList { get; set; } = [];
|
||||
|
||||
public List<WaitingArea> WaitingAreas { get; set; }
|
||||
|
||||
private readonly Action<bool> _onValidityChanged;
|
||||
public TrainStopDialog(List<string> ticketChecks, List<string> platforms, Action<bool> onValidityChanged)
|
||||
|
||||
public TrainStopDialog(List<WaitingArea> waitingAreas, List<string> platforms, Action<bool> 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<string> ticketChecks, List<string> platforms,TrainStop trainStop, Action<bool> onValidityChanged)
|
||||
public TrainStopDialog(List<WaitingArea> waitingAreas, List<string> platforms, TrainStop trainStop, Action<bool> 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<TicketCheck>()
|
||||
.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);
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard Header="检票口" Description="仅加载某个检票口的数据" HeaderIcon="{winui:FontIcon Glyph=}"
|
||||
Visibility="{x:Bind ViewModel.TicketCheckNeeded,Converter={StaticResource BoolToVisibilityConverter},Mode=OneWay}">
|
||||
<ComboBox ItemsSource="{x:Bind ViewModel.TicketChecks}" x:Name="TicketChecksList">
|
||||
<ComboBox ItemsSource="{x:Bind ViewModel.TicketChecks}" x:Name="TicketChecksList" DisplayMemberPath="Name">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:EventTriggerBehavior EventName="SelectionChanged">
|
||||
<interactivity:InvokeCommandAction Command="{x:Bind ViewModel.SelectTicketCheckCommand}" CommandParameter="{x:Bind TicketChecksList.SelectedItem,Mode=OneWay}" />
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}">
|
||||
<Page.Resources>
|
||||
<converters:TimeSpanToStringConverter x:Key="TimeSpanToStringConverter" />
|
||||
<converters:ListToStringConverter x:Key="ListToStringConverter" Separator=", " />
|
||||
<converters:TicketChecksToStringConverter x:Key="TicketChecksToStringConverter" Separator=" " WaitingAreas="{x:Bind ViewModel.WaitingAreas}"/>
|
||||
<DataTemplate x:Key="WaitingAreaTemplate" x:DataType="coremodels:WaitingArea">
|
||||
<TreeViewItem Content="{x:Bind Name}" ItemsSource="{x:Bind TicketChecks}" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="TicketCheckTemplate" x:DataType="coremodels:TicketCheck">
|
||||
<TextBlock Text="{x:Bind Name}" />
|
||||
</DataTemplate>
|
||||
<selectors:TreeViewTemplateSelector
|
||||
x:Key="TreeViewTemplateSelector"
|
||||
WaitingAreaTemplate="{StaticResource WaitingAreaTemplate}"
|
||||
TicketCheckTemplate="{StaticResource TicketCheckTemplate}" />
|
||||
</Page.Resources>
|
||||
<Grid x:Name="ContentPagePane" Margin="36,40,0,36">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -81,52 +92,6 @@
|
||||
<controls:WrapLayout Orientation="Horizontal" VerticalSpacing="8" HorizontalSpacing="24"/>
|
||||
</ItemsRepeater.Layout>
|
||||
</ItemsRepeater>
|
||||
<TextBlock Text="候车室" Style="{StaticResource BodyStrongTextBlockStyle}" Margin="0,24,0,0"/>
|
||||
<CommandBar DefaultLabelPosition="Right" HorizontalAlignment="Right" Margin="0,12,0,0">
|
||||
<AppBarButton Icon="Add" Label="添加" Command="{x:Bind ViewModel.AddWaitingAreaCommand}" />
|
||||
<AppBarButton Icon="Clear" Label="删除" Command="{x:Bind ViewModel.DeleteWaitingAreaCommand}" CommandParameter="{x:Bind WaitingAreaList.SelectedItem, Mode=OneWay}"/>
|
||||
<AppBarButton Icon="Delete" Label="清空" Command="{x:Bind ViewModel.DeleteAllWaitingAreaCommand}" />
|
||||
</CommandBar>
|
||||
<Border Style="{StaticResource ListViewBorder}" Margin="0,8,0,0">
|
||||
<ListView x:Name="WaitingAreaList" ItemsSource="{x:Bind ViewModel.WaitingAreaNames}" MaxHeight="300"/>
|
||||
</Border>
|
||||
<TextBlock Text="检票口" Style="{StaticResource BodyStrongTextBlockStyle}" Margin="0,24,0,0"/>
|
||||
<CommandBar DefaultLabelPosition="Right" HorizontalAlignment="Right" Margin="0,12,0,0">
|
||||
<AppBarButton Icon="Add" Label="添加" Command="{x:Bind ViewModel.AddTicketCheckCommand}" />
|
||||
<AppBarButton Icon="Clear" Label="删除" Command="{x:Bind ViewModel.DeleteTicketCheckCommand}" CommandParameter="{x:Bind TicketChecksList.SelectedItem, Mode=OneWay}" />
|
||||
<AppBarButton Icon="Delete" Label="清空" Command="{x:Bind ViewModel.DeleteAllTicketCheckCommand}" />
|
||||
</CommandBar>
|
||||
<Border Style="{StaticResource ListViewBorder}" Margin="0,8,0,0">
|
||||
<ListView x:Name="TicketChecksList" ItemsSource="{x:Bind ViewModel.TicketChecks}" MaxHeight="300">
|
||||
<ListView.Header>
|
||||
<Grid Padding="16,12" ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="编号" />
|
||||
<TextBlock Grid.Column="1" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="候车室" />
|
||||
</Grid>
|
||||
</ListView.Header>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="coremodels:TicketCheck">
|
||||
<Grid ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="{x:Bind Name}" />
|
||||
<TextBlock Grid.Column="1" Text="{x:Bind WaitingAreaName}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style BasedOn="{StaticResource DefaultListViewItemStyle}" TargetType="ListViewItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
</ListView>
|
||||
</Border>
|
||||
<TextBlock Text="站台" Style="{StaticResource BodyStrongTextBlockStyle}" Margin="0,24,0,0"/>
|
||||
<CommandBar DefaultLabelPosition="Right" HorizontalAlignment="Right" Margin="0,12,0,0">
|
||||
<AppBarButton Icon="Add" Label="添加" Command="{x:Bind ViewModel.AddPlatformCommand}" />
|
||||
@@ -164,6 +129,17 @@
|
||||
</ListView.ItemContainerStyle>
|
||||
</ListView>
|
||||
</Border>
|
||||
<TextBlock Text="检票口" Style="{StaticResource BodyStrongTextBlockStyle}" Margin="0,24,0,0"/>
|
||||
<CommandBar DefaultLabelPosition="Right" HorizontalAlignment="Right" Margin="0,12,0,0">
|
||||
<AppBarButton Icon="Add" Label="添加候车区" Command="{x:Bind ViewModel.AddWaitingAreaCommand}" />
|
||||
<AppBarButton Icon="Add" Label="添加检票口" Command="{x:Bind ViewModel.AddTicketCheckCommand}" CommandParameter="{x:Bind WaitingAreasList.SelectedItem, Mode=OneWay}"/>
|
||||
<AppBarButton Icon="Clear" Label="删除" Command="{x:Bind ViewModel.DeleteItemCommand}" CommandParameter="{x:Bind WaitingAreasList.SelectedItem, Mode=OneWay}" />
|
||||
<AppBarButton Icon="Delete" Label="清空" Command="{x:Bind ViewModel.DeleteAllTicketChecksCommand}" />
|
||||
</CommandBar>
|
||||
<Border Style="{StaticResource ListViewBorder}" Margin="0,8,0,0">
|
||||
<TreeView MaxHeight="300" Name="WaitingAreasList"
|
||||
ItemsSource="{x:Bind ViewModel.WaitingAreas, Mode=OneWay}" ItemTemplateSelector="{StaticResource TreeViewTemplateSelector}" />
|
||||
</Border>
|
||||
<TextBlock Text="车次" Style="{StaticResource BodyStrongTextBlockStyle}" Margin="0,24,0,0"/>
|
||||
<CommandBar DefaultLabelPosition="Right" HorizontalAlignment="Right" Margin="0,12,0,0">
|
||||
<AppBarButton Icon="Add" Label="添加" Command="{x:Bind ViewModel.AddTrainStopCommand}" />
|
||||
@@ -195,18 +171,16 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="车次" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="1" Text="长度" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="2" Text="到时" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="3" Text="发时" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="4" Text="候车区" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="5" Text="检票口" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="6" Text="站台" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="7" Text="地标" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="8" Text="始发站" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="9" Text="终到站" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="4" Text="检票口" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}"/>
|
||||
<TextBlock Grid.Column="5" Text="站台" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="6" Text="地标" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="7" Text="始发站" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Grid.Column="8" Text="终到站" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</Grid>
|
||||
</ListView.Header>
|
||||
<ListView.ItemTemplate>
|
||||
@@ -222,18 +196,16 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="{x:Bind Number}" />
|
||||
<TextBlock Grid.Column="1" Text="{x:Bind Length}" />
|
||||
<TextBlock Grid.Column="2" Text="{x:Bind ArrivalTime, Converter={StaticResource TimeSpanToStringConverter}}" />
|
||||
<TextBlock Grid.Column="3" Text="{x:Bind DepartureTime, Converter={StaticResource TimeSpanToStringConverter}}" />
|
||||
<TextBlock Grid.Column="4" Text="{x:Bind WaitingArea}" />
|
||||
<TextBlock Grid.Column="5" Text="{x:Bind TicketChecks, Converter={StaticResource ListToStringConverter}}" />
|
||||
<TextBlock Grid.Column="6" Text="{x:Bind Platform}" />
|
||||
<TextBlock Grid.Column="7" Text="{x:Bind Landmark}" />
|
||||
<TextBlock Grid.Column="8" Text="{x:Bind Origin}" />
|
||||
<TextBlock Grid.Column="9" Text="{x:Bind Terminal}" />
|
||||
<TextBlock Grid.Column="4" Text="{x:Bind TicketCheckIds, Converter={StaticResource TicketChecksToStringConverter}}"/>
|
||||
<TextBlock Grid.Column="5" Text="{x:Bind Platform}" />
|
||||
<TextBlock Grid.Column="6" Text="{x:Bind Landmark}" />
|
||||
<TextBlock Grid.Column="7" Text="{x:Bind Origin}" />
|
||||
<TextBlock Grid.Column="8" Text="{x:Bind Terminal}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>2.3.107.0</Version>
|
||||
<Version>2.3.108.0</Version>
|
||||
<Authors>电排骨</Authors>
|
||||
<RepositoryUrl>https://github.com/denglihong2007/CRSim</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
Reference in New Issue
Block a user