Files
WCS/Cowain.TestProject/ViewModels/LoginWindowViewModel.cs

321 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Cowain.Base.Abstractions.Navigation;
using Cowain.Base.Attributes;
using Cowain.Base.Helpers;
using Cowain.Base.IServices;
using Cowain.Base.Models.Menu;
using Cowain.Base.ViewModels;
using Ke.Bee.Localization.Localizer.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Semi.Avalonia;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MenuItem = Cowain.Base.Models.Menu.MenuItem;
namespace Cowain.TestProject.ViewModels
{
public partial class LoginWindowViewModel : ViewModelBase
{
private class UserData
{
public string? UserName { get; set; }
public string? Password { get; set; }
public bool IsRemember { get; set; }
}
/// <summary>
/// 登录成功
/// </summary>
[ObservableProperty]
private bool _loginSuccess;
/// <summary>
/// 是否记住用户名
/// </summary>
[ObservableProperty]
private bool _rememberUserName;
/// <summary>
/// 用户名
/// </summary>
[ObservableProperty]
[NotifyDataErrorInfo]
[NotifyCanExecuteChangedFor(nameof(LoginCommand))]
[MinLength(2, "Errors.MinLength")]
private string? _userName;
/// <summary>
/// 密码
/// </summary>
[ObservableProperty]
[NotifyDataErrorInfo]
[NotifyCanExecuteChangedFor(nameof(LoginCommand))]
[MinLength(4, "Errors.MinLength")]
private string? _password;
/// <summary>
/// 错误信息
/// </summary>
[ObservableProperty]
private string? _errorMessage;
/// <summary>
/// 当前页面视图模型
/// </summary>
[ObservableProperty]
private PageViewModelBase? _currentPage;
/// <summary>
/// 设置菜单集合
/// </summary>
[ObservableProperty]
private ObservableCollection<Base.ViewModels.MenuItemViewModel>? _settingMenus;
private readonly ILocalizer _l;
/// <summary>
/// 视图导航器
/// </summary>
private readonly IViewNavigator _viewNavigator;
/// <summary>
/// 菜单数据
/// </summary>
private readonly List<MenuItem> _menuItems;
private ILogger<LoginWindowViewModel> _logger;
private IAccountService _accountService;
private IConfiguration _configuration;
private string userFileName = "userdata.json";
public LoginWindowViewModel(MenuConfigurationContext menuContext, ILocalizer localizer, ILogger<LoginWindowViewModel> logger, IViewNavigator viewNavigator, IAccountService accountService, IConfiguration configuration)
{
_l = localizer;
_logger = logger;
string pdtName = GetProductName();
userFileName= $"{pdtName}_userdata.json";
_menuItems = menuContext.Menus;
_viewNavigator = viewNavigator;
_accountService = accountService;
_configuration = configuration;
LoadSettingMenus();
ReadUserData();
}
/// <summary>
/// MenuItem 到 MenuItemViewModel 的转换器
/// </summary>
private Func<MenuItem, MenuItemViewModel> MenuItemToViewModel => x => new MenuItemViewModel(_l[x.LocaleKey])
{
Key = x.Key,
IsActive = x.IsActive == true,
Icon = string.IsNullOrWhiteSpace(x.Icon) ? null : StreamGeometry.Parse(x.Icon),
CommandParameter = x.CommandParameter,
//PageActions = x.PageActions,
Items = x.Items.Select(MenuItemToViewModel).ToList(),
MenuClickCommand = GetRelayCommand(x.CommandType),
};
/// <summary>
/// 根据命令类型返回中继命令
/// </summary>
/// <param name="commandType"></param>
/// <returns></returns>
private IRelayCommand? GetRelayCommand(string? commandType)
{
if (!Enum.TryParse<MenuClickCommandType>(commandType, out var cmdType))
{
return null;
}
return cmdType switch
{
// 主题切换返回的中继命令
MenuClickCommandType.SwitchTheme => new RelayCommand<MenuItemViewModel>((MenuItemViewModel? menuItem) =>
{
var app = Application.Current;
if (app is not null)
{
ThemeVariant? tv = menuItem?.CommandParameter switch
{
nameof(ThemeVariant.Default) => ThemeVariant.Default,
nameof(ThemeVariant.Dark) => ThemeVariant.Dark,
"Desert" => SemiTheme.Desert,
"Dusk" => SemiTheme.Dusk,
"NightSky" => SemiTheme.NightSky,
_ => ThemeVariant.Default
};
app.RequestedThemeVariant = tv;
// 重载视图
_viewNavigator.ReloadCurrentPage();
}
}),
// 打开链接返回的中继命令
MenuClickCommandType.Link => new RelayCommand<MenuItemViewModel>((MenuItemViewModel? menuItem) =>
{
var url = menuItem?.CommandParameter;
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
}),
// 切换本地化语言
MenuClickCommandType.SwitchLanguage => new RelayCommand<MenuItemViewModel>((MenuItemViewModel? menuItem) =>
{
_l.CurrentCulture = _l.AvailableCultures.FirstOrDefault(f => f.IetfLanguageTag == menuItem?.CommandParameter) ??
Thread.CurrentThread.CurrentCulture;
// 重载视图,触发本地化更新
_viewNavigator.ReloadCurrentPage();
LoadSettingMenus();
var app = Application.Current;
if (app is null) return;
CultureInfo cultureInfo = menuItem?.CommandParameter is string parameter
? new CultureInfo(parameter)
: Thread.CurrentThread.CurrentCulture;
Semi.Avalonia.SemiTheme.OverrideLocaleResources(app, cultureInfo);
Ursa.Themes.Semi.SemiTheme.OverrideLocaleResources(app, cultureInfo);
}),
// 返回 null
_ => null
};
}
/// <summary>
/// 载入设置栏菜单
/// </summary>
private void LoadSettingMenus()
{
var settingMenus = _menuItems.Where(x => x.Group == "Settings").Select(MenuItemToViewModel);
SettingMenus = [.. settingMenus];
}
private void ReadUserData()
{
var path = PathHelper.GetLocalFilePath(userFileName);
if (File.Exists(path))
{
var json = File.ReadAllText(path);
var userData = JsonSerializer.Deserialize<UserData>(json);
if (userData != null)
{
RememberUserName = userData.IsRemember;
if (RememberUserName)
{
UserName = userData.UserName;
if (!string.IsNullOrEmpty(userData.Password))
{
Password = DESHelper.Decrypt(userData.Password, "ZSL12345");
}
}
}
}
}
private bool CanLogin()
{
ValidateAllProperties();
return !HasErrors;
}
[RelayCommand(CanExecute = nameof(CanLogin))]
private async Task LoginAsync(object obj)
{
if (string.IsNullOrEmpty(UserName))
{
ErrorMessage = _l["LoginWindow.UserNameEmpty"];
return;
}
if (string.IsNullOrEmpty(Password))
{
ErrorMessage = _l["LoginWindow.PasseordEmpty"];
return;
}
var loginResult = await _accountService.LoginAsync(UserName, Password);
if (loginResult.IsSuccess)
{
GlobalData.Instance.CurrentUser = loginResult.Data;
//GlobalData.Instance.AddOrUpdate("UserName", UserName);
GlobalData.Instance.AddOrUpdate("CurrentUser", loginResult.Data!.User);
LoginSuccess = true;
if (RememberUserName)
{
var userData = new UserData { UserName = UserName, Password = DESHelper.Encrypt(Password, "ZSL12345"), IsRemember = RememberUserName };
var json = JsonSerializer.Serialize(userData);
var path = PathHelper.GetLocalFilePath(userFileName);
await File.WriteAllTextAsync(path, json);
}
else
{
var path = PathHelper.GetLocalFilePath(userFileName);
if (File.Exists(path))
{
File.Delete(path);
}
}
// 关闭登录窗口,并且 DialogResult返回True
if (obj is Window window)
{
window.Close(true);
}
//WeakReferenceMessenger.Default.Send(new LoginSuccessMessage(new UserItemViewModel { UserName = "Admin", IsActive = true }));
}
else
{
ErrorMessage = _l["LoginWindow.LoginFailed"];
}
}
[RelayCommand]
private void ToggleTheme()
{
var app = Application.Current;
if (app is null) return;
var theme = app.ActualThemeVariant;
app.RequestedThemeVariant = theme == ThemeVariant.Dark ? ThemeVariant.Light : ThemeVariant.Dark;
}
/// <summary>
/// 获取项目文件中<Product>属性的值
/// </summary>
/// <returns>Product属性字符串如"Cowain WCS"</returns>
public string GetProductName()
{
try
{
// 获取当前程序集(如果是其他项目,替换为对应程序集)
Assembly assembly = Assembly.GetExecutingAssembly();
// 获取AssemblyProduct特性
var productAttribute = assembly.GetCustomAttribute<AssemblyProductAttribute>();
// 返回值(为空时返回默认值)
return productAttribute?.Product ?? "未知产品名称";
}
catch (Exception ex)
{
// 异常处理(根据你的日志框架调整)
_logger.LogError(ex, "读取Product属性失败");
return "未知产品名称";
}
}
}
}