diff --git a/AuroraDesk.Infrastructure/AuroraDesk.Infrastructure.csproj b/AuroraDesk.Infrastructure/AuroraDesk.Infrastructure.csproj index 5985e48..8a42f99 100644 --- a/AuroraDesk.Infrastructure/AuroraDesk.Infrastructure.csproj +++ b/AuroraDesk.Infrastructure/AuroraDesk.Infrastructure.csproj @@ -11,11 +11,16 @@ - - - + + + + + + + + diff --git a/AuroraDesk.Infrastructure/Extensions/HostBuilderExtensions.cs b/AuroraDesk.Infrastructure/Extensions/HostBuilderExtensions.cs new file mode 100644 index 0000000..d81a5c3 --- /dev/null +++ b/AuroraDesk.Infrastructure/Extensions/HostBuilderExtensions.cs @@ -0,0 +1,75 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Serilog; +using Serilog.Events; +using System; +using System.IO; + +namespace AuroraDesk.Infrastructure.Extensions; + +/// +/// HostBuilder 扩展方法(基础设施层) +/// 用于配置日志记录功能 +/// +public static class HostBuilderExtensions +{ + /// + /// 配置文件日志记录 + /// + /// HostBuilder + /// HostBuilder + /// + /// 配置优先级说明: + /// 1. 代码中的配置(WriteTo.Console、WriteTo.File)优先级最高,会覆盖配置文件中的相同配置 + /// 2. serilog.json 文件中的 "Serilog" 节点配置次之,会被 ReadFrom.Configuration 读取 + /// + /// 注意:Serilog 配置已提取到独立的 serilog.json 文件中,便于管理和维护 + /// + public static IHostBuilder ConfigureFileLogging(this IHostBuilder hostBuilder) + { + return hostBuilder.UseSerilog((context, services, configuration) => + { + var environment = context.HostingEnvironment; + + // 配置日志目录 + var logDirectory = Path.Combine( + Directory.GetCurrentDirectory(), + "logs" + ); + + // 确保日志目录存在 + if (!Directory.Exists(logDirectory)) + { + Directory.CreateDirectory(logDirectory); + } + + // 配置 Serilog + // 注意:ReadFrom.Configuration 会读取 serilog.json 文件中的 "Serilog" 节点 + // 然后代码中的配置会在此基础上添加或覆盖 + configuration + .ReadFrom.Configuration(context.Configuration) // 读取 serilog.json 中的 "Serilog" 节点 + .ReadFrom.Services(services) + .Enrich.FromLogContext() + .Enrich.WithProperty("Environment", environment.EnvironmentName) + // 以下代码配置会覆盖配置文件中相同类型的配置(如果存在) + .WriteTo.Console( + outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] {Message:lj}{NewLine}{Exception}", + restrictedToMinimumLevel: LogEventLevel.Information + ) + .WriteTo.File( + path: Path.Combine(logDirectory, "auroradesk-.log"), + rollingInterval: RollingInterval.Day, + retainedFileCountLimit: 30, + outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}", + restrictedToMinimumLevel: LogEventLevel.Debug + ) + .WriteTo.File( + path: Path.Combine(logDirectory, "auroradesk-error-.log"), + rollingInterval: RollingInterval.Day, + retainedFileCountLimit: 60, + outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}", + restrictedToMinimumLevel: LogEventLevel.Error + ); + }); + } +} diff --git a/AuroraDesk.Presentation/ViewModels/CloseConfirmViewModel.cs b/AuroraDesk.Presentation/ViewModels/CloseConfirmViewModel.cs new file mode 100644 index 0000000..2b384d0 --- /dev/null +++ b/AuroraDesk.Presentation/ViewModels/CloseConfirmViewModel.cs @@ -0,0 +1,82 @@ +using Avalonia.Media; +using HeroIconsAvalonia.Enums; +using ReactiveUI; + +namespace AuroraDesk.Presentation.ViewModels; + +/// +/// 关闭确认对话框的 ViewModel +/// +public class CloseConfirmViewModel : ReactiveObject +{ + private string _title = "确认关闭"; + private string _message = "确定要退出程序吗?"; + private IconType _icon = IconType.QuestionMarkCircle; + private IBrush _accentBrush = new SolidColorBrush(Color.FromRgb(59, 130, 246)); + private string _primaryButtonText = "确认"; + private string _secondaryButtonText = "取消"; + + /// + /// 对话框标题 + /// + public string Title + { + get => _title; + set => this.RaiseAndSetIfChanged(ref _title, value); + } + + /// + /// 对话框消息 + /// + public string Message + { + get => _message; + set => this.RaiseAndSetIfChanged(ref _message, value); + } + + /// + /// 对话框图标 + /// + public IconType Icon + { + get => _icon; + set => this.RaiseAndSetIfChanged(ref _icon, value); + } + + /// + /// 对话框强调色 + /// + public IBrush AccentBrush + { + get => _accentBrush; + set => this.RaiseAndSetIfChanged(ref _accentBrush, value); + } + + /// + /// 主操作按钮文本 + /// + public string PrimaryButtonText + { + get => _primaryButtonText; + set => this.RaiseAndSetIfChanged(ref _primaryButtonText, value); + } + + /// + /// 次操作按钮文本 + /// + public string SecondaryButtonText + { + get => _secondaryButtonText; + set + { + this.RaiseAndSetIfChanged(ref _secondaryButtonText, value); + this.RaisePropertyChanged(nameof(HasSecondaryButton)); + } + } + + /// + /// 是否显示次操作按钮 + /// + public bool HasSecondaryButton => !string.IsNullOrWhiteSpace(_secondaryButtonText); +} + diff --git a/AuroraDesk.Presentation/ViewModels/MainWindowViewModel.cs b/AuroraDesk.Presentation/ViewModels/MainWindowViewModel.cs index 4140528..56c75e6 100644 --- a/AuroraDesk.Presentation/ViewModels/MainWindowViewModel.cs +++ b/AuroraDesk.Presentation/ViewModels/MainWindowViewModel.cs @@ -91,6 +91,20 @@ public class MainWindowViewModel : ReactiveObject public ReactiveCommand CloseTabCommand { get; } public ReactiveCommand SelectTabCommand { get; } + // 关闭确认对话框 Interaction + public Interaction CloseConfirmInteraction { get; } + + /// + /// 请求关闭确认 + /// + public async System.Threading.Tasks.Task RequestCloseConfirmAsync() + { + var viewModel = new CloseConfirmViewModel(); + var result = await CloseConfirmInteraction.Handle(viewModel); + _logger?.LogInformation("用户选择: {Result}", result ? "确认关闭" : "取消关闭"); + return result; + } + public MainWindowViewModel( IScreen screen, INavigationService navigationService, @@ -121,6 +135,9 @@ public class MainWindowViewModel : ReactiveObject // 创建选择标签页命令(委托给 TabManagementService) SelectTabCommand = ReactiveCommand.Create(tab => SelectTab(tab)); + // 创建关闭确认对话框 Interaction + CloseConfirmInteraction = new Interaction(); + // 监听导航项选择变化 this.WhenAnyValue(x => x.SelectedNavigationItem) .Where(item => item != null) @@ -358,6 +375,7 @@ public class MainWindowViewModel : ReactiveObject _logger?.LogInformation("关闭标签页: {Title}", tab.Title); } + /// /// 释放资源 /// diff --git a/AuroraDesk.Presentation/Views/Dialogs/CloseConfirmDialog.axaml b/AuroraDesk.Presentation/Views/Dialogs/CloseConfirmDialog.axaml new file mode 100644 index 0000000..122b6a7 --- /dev/null +++ b/AuroraDesk.Presentation/Views/Dialogs/CloseConfirmDialog.axaml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + +