321 lines
12 KiB
C#
321 lines
12 KiB
C#
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 "未知产品名称";
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|