暂时更改一部分Skill
This commit is contained in:
1 parent
84b28f9672
commit
6d4629e4ac
53 files changed
+5293
-10
No files matched your search
@@ -7,3 +7,65 @@ public interface IPriority
|
||||
/// </summary>
|
||||
int Priority { get; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 优先级
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
public static class IntPriority
|
||||
{
|
||||
/// <summary>
|
||||
/// 最高优先级 (5000)
|
||||
/// </summary>
|
||||
public const int Highest = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// 非常高优先级 (4000)
|
||||
/// </summary>
|
||||
public const int VeryHigh = 4000;
|
||||
|
||||
/// <summary>
|
||||
/// 较高优先级 (3000)
|
||||
/// </summary>
|
||||
public const int Higher = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// 高优先级 (2000)
|
||||
/// </summary>
|
||||
public const int High = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// 高于正常优先级 (1000)
|
||||
/// </summary>
|
||||
public const int AboveNormal = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 正常优先级 (0)
|
||||
/// </summary>
|
||||
public const int Normal = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 低于正常优先级 (-1000)
|
||||
/// </summary>
|
||||
public const int BelowNormal = -1000;
|
||||
|
||||
/// <summary>
|
||||
/// 低优先级 (-2000)
|
||||
/// </summary>
|
||||
public const int Low = -2000;
|
||||
|
||||
/// <summary>
|
||||
/// 较低优先级 (-3000)
|
||||
/// </summary>
|
||||
public const int Lower = -3000;
|
||||
|
||||
/// <summary>
|
||||
/// 非常低优先级 (-4000)
|
||||
/// </summary>
|
||||
public const int VeryLow = -4000;
|
||||
|
||||
/// <summary>
|
||||
/// 最低优先级 (-5000)
|
||||
/// </summary>
|
||||
public const int Lowest = -5000;
|
||||
}
|
||||
@@ -88,8 +88,8 @@ public class AutofacContainerExtension : IContainerExtension<IContainer>, IConta
|
||||
item.Register(Builder);
|
||||
}
|
||||
|
||||
IEnumerable<IPreRegisterTypes> PreRegisterTypes = ReflectionHelper.GetInstancesByInterface<IPreRegisterTypes>(assemblies);
|
||||
foreach (IPreRegisterTypes item in PreRegisterTypes)
|
||||
IEnumerable<IPrismRegisterTypes> PreRegisterTypes = ReflectionHelper.GetInstancesByInterface<IPrismRegisterTypes>(assemblies);
|
||||
foreach (IPrismRegisterTypes item in PreRegisterTypes)
|
||||
{
|
||||
item.RegisterTypes(this);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace MAX.Framework.Prism.Autofac;
|
||||
|
||||
public interface IPreRegisterTypes
|
||||
public interface IPrismRegisterTypes
|
||||
{
|
||||
void RegisterTypes(IContainerRegistry containerRegistry);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
using Autofac;
|
||||
using MAX.Core;
|
||||
using MAX.Framework.Interfaces;
|
||||
|
||||
namespace Store.Admin
|
||||
{
|
||||
public class Startup : IStartup
|
||||
{
|
||||
public int Priority => IntPriority.Normal;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Register(ContainerBuilder builder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Store.Management.Framework\Store.Management.Framework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,35 @@
|
||||
using Autofac;
|
||||
using MAX.Core;
|
||||
using MAX.Framework.Interfaces;
|
||||
using MAX.Framework.Prism.Autofac;
|
||||
using Prism.Ioc;
|
||||
|
||||
namespace Store.ListingProduct
|
||||
{
|
||||
public class Startup : IStartup, IPrismRegisterTypes
|
||||
{
|
||||
public int Priority => IntPriority.Normal;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Register(ContainerBuilder builder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void RegisterTypes(IContainerRegistry containerRegistry)
|
||||
{
|
||||
//containerRegistry.RegisterForNavigation<OnceBrakeDetailView, OnceBrakeDetailViewModel>(NavigationTokens.OnceBrakeDetailContext);
|
||||
//containerRegistry.RegisterForNavigation<SummaryView, SummaryViewModel>(NavigationTokens.SummaryViewContext);
|
||||
|
||||
//containerRegistry.RegisterDialog<SummaryColumnDialog, SummaryColumnDialogViewModel>(nameof(SummaryColumnDialog));
|
||||
//containerRegistry.RegisterDialog<SummaryLogDialog, SummaryLogDialogViewModel>(nameof(SummaryLogDialog));
|
||||
|
||||
//containerRegistry.RegisterDialog<ArchiveDialog, ArchiveDialogViewModel>(nameof(ArchiveDialog));
|
||||
//containerRegistry.RegisterDialog<UnArchiveDialog, UnArchiveDialogViewModel>(nameof(UnArchiveDialog));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Store.Management.Framework\Store.Management.Framework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -5,4 +5,4 @@
|
||||
[assembly: XmlnsDefinition("Store.Management.Framework", "Store.Management.Framework.Controls")]
|
||||
[assembly: XmlnsDefinition("Store.Management.Framework", "Store.Management.Framework.Controls.Attach")]
|
||||
|
||||
[assembly: XmlnsPrefix("Store.Management.Framework", "mf")]
|
||||
[assembly: XmlnsPrefix("Store.Management.Framework", "f")]
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace Store.Management.Framework.Configs;
|
||||
|
||||
/// <summary>
|
||||
/// 应用级常量配置:代码标识与显示名称分离。
|
||||
/// </summary>
|
||||
public static class AppConfig
|
||||
{
|
||||
/// <summary>代码用软件名称(程序集/目录/Mutex 等标识)。</summary>
|
||||
public const string AppName = "Store.Management";
|
||||
|
||||
/// <summary>显示与输出用软件名称(启动页、对话框标题、安装器显示名等)。</summary>
|
||||
public const string AppDisplayName = "Store.Management";
|
||||
|
||||
/// <summary>是否是发布版本。</summary>
|
||||
public static bool IsRelease
|
||||
{
|
||||
get
|
||||
{
|
||||
#if RELEASE
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>当前构建模式显示名(Release / Debug)。</summary>
|
||||
public static string BuildMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return IsRelease ? "Release" : "Debug";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public sealed class FolderConfig : IFolderConfig
|
||||
string IFolderConfig.LoggingFolder => LoggingFolder;
|
||||
string IFolderConfig.CacheFolder => CacheFolder;
|
||||
|
||||
public const string AppName = "Store.Management";
|
||||
public const string AppName = "StoreManagement";
|
||||
|
||||
/// <summary>安装目录,用于读取随程序分发的资源。</summary>
|
||||
public static string ExeFolder => AppContext.BaseDirectory;
|
||||
|
||||
@@ -36,7 +36,10 @@ public partial class DialogWindow : WindowBase, IDialogWindow
|
||||
public DialogWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Owner = Application.Current.MainWindow;
|
||||
if (Application.Current.MainWindow is Window owner && !ReferenceEquals(owner, this))
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
isConstructorSuccessful = true;
|
||||
dialogWindowStyle = (Style)TryFindResource("DialogWindowStyle");
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Store.Management.Framework.Interfaces
|
||||
{
|
||||
|
||||
public interface IMessageBoxService
|
||||
{
|
||||
|
||||
//MessageResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageIcon icon, MessageResult defaultResult);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HandyControl" Version="3.6.2.1" />
|
||||
<PackageReference Include="MAX.Common.WPF" Version="1.4.23" />
|
||||
<ProjectReference Include="..\Core\MAX.Core\MAX.Core.csproj" />
|
||||
<ProjectReference Include="..\Core\MAX.Framework\MAX.Framework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using Prism.Mvvm;
|
||||
|
||||
namespace Store.Management.Framework.ViewModels;
|
||||
|
||||
/// <summary>异步操作的加载消息与错误状态。</summary>
|
||||
public sealed class LoadingStatus : BindableBase
|
||||
{
|
||||
private bool _isLoading;
|
||||
private string _message = "";
|
||||
private string _errorMessage = "";
|
||||
|
||||
public bool IsLoading { get => _isLoading; private set => SetProperty(ref _isLoading, value); }
|
||||
public string Message { get => _message; private set => SetProperty(ref _message, value); }
|
||||
public string ErrorMessage { get => _errorMessage; private set => SetProperty(ref _errorMessage, value); }
|
||||
|
||||
public void Initialize(string message)
|
||||
{
|
||||
ErrorMessage = "";
|
||||
Message = message;
|
||||
IsLoading = true;
|
||||
}
|
||||
|
||||
public void Done()
|
||||
{
|
||||
IsLoading = false;
|
||||
Message = "";
|
||||
}
|
||||
|
||||
public void Error(string message)
|
||||
{
|
||||
Done();
|
||||
ErrorMessage = message;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Prism.Ioc;
|
||||
using Prism.Services.Dialogs;
|
||||
using MAX.Notification;
|
||||
using Store.Management.Notifications;
|
||||
using Store.Management.Framework;
|
||||
@@ -6,12 +7,47 @@ using Store.Management.Services;
|
||||
using Store.Management.ViewModels;
|
||||
using Store.Management.Views;
|
||||
using System.Windows;
|
||||
using Store.Management.Api;
|
||||
namespace Store.Management;
|
||||
public partial class App : FrameworkApplication
|
||||
{
|
||||
protected override Window CreateShell() => Container.Resolve<MainWindow>();
|
||||
private readonly StoreApiClient? _apiClient;
|
||||
|
||||
public App() { }
|
||||
|
||||
public App(StoreApiClient apiClient) => _apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
|
||||
|
||||
private StoreApiClient CreateApiClient() => _apiClient ?? new(new ApiClientOptions
|
||||
{
|
||||
BaseUrl = new Uri("http://localhost:14312/api/")
|
||||
});
|
||||
|
||||
protected override Window CreateShell() => null!;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
// 登录弹窗关闭与主窗口创建之间不触发 WPF 的最后窗口退出。
|
||||
ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
||||
Container.Resolve<IDialogService>().ShowDialog(
|
||||
nameof(LoginWindow), new DialogParameters(), result =>
|
||||
{
|
||||
if (result.Result != ButtonResult.OK)
|
||||
{
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
MainWindow = Container.Resolve<MainWindow>();
|
||||
ShutdownMode = ShutdownMode.OnMainWindowClose;
|
||||
MainWindow.Show();
|
||||
});
|
||||
}
|
||||
|
||||
protected override void RegisterTypes(IContainerRegistry registry)
|
||||
{
|
||||
registry.RegisterInstance(CreateApiClient());
|
||||
registry.Register<LoginViewModel>(provider => new LoginViewModel(provider.Resolve<StoreApiClient>().Auth));
|
||||
registry.RegisterSingleton<SingletonProbe>();
|
||||
registry.Register<TransientProbe>();
|
||||
registry.RegisterSingleton<NotificationExampleState>();
|
||||
@@ -24,6 +60,13 @@ public partial class App : FrameworkApplication
|
||||
new ProductCacheHandler(provider.Resolve<NotificationExampleState>()),
|
||||
new ProductAuditHandler(provider.Resolve<NotificationExampleState>())
|
||||
});
|
||||
registry.RegisterDialog<LoginWindow, LoginViewModel>();
|
||||
registry.RegisterDialog<FrameworkTestDialog, FrameworkTestDialogViewModel>();
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
try { Container?.Resolve<StoreApiClient>().Dispose(); }
|
||||
finally { base.OnExit(e); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Prism.Commands;
|
||||
using MAX.Framework.Controls;
|
||||
using Prism.Services.Dialogs;
|
||||
using System.Windows.Input;
|
||||
using Store.Management.Api.Authentication;
|
||||
using Store.Management.Api.Transport;
|
||||
using Store.Management.Framework.ViewModels;
|
||||
|
||||
namespace Store.Management.ViewModels;
|
||||
|
||||
/// <summary>登录校验、认证请求和窗口生命周期内的请求取消。</summary>
|
||||
public sealed class LoginViewModel(IAuthApi auth) : ConfirmDialogViewModel, IDisposable
|
||||
{
|
||||
private readonly IAuthApi _auth = auth ?? throw new ArgumentNullException(nameof(auth));
|
||||
private readonly CancellationTokenSource _lifetime = new();
|
||||
private string _userName = "";
|
||||
private string _passwordHash = "";
|
||||
private bool _disposed;
|
||||
private bool _authenticated;
|
||||
|
||||
public const int InputMaxLength = 250;
|
||||
public LoadingStatus LoadingStatus { get; } = new();
|
||||
public string UserName { get => _userName; set => SetProperty(ref _userName, value); }
|
||||
public bool CanEdit => !LoadingStatus.IsLoading && !_disposed && !_authenticated;
|
||||
public string LoginButtonText => LoadingStatus.IsLoading ? "正在登录…" : "登录";
|
||||
|
||||
public event EventHandler? ClearPasswordRequested;
|
||||
|
||||
/// <summary>仅由密码控件桥接调用,不保存明文密码。</summary>
|
||||
public void UpdatePassword(string password)
|
||||
{
|
||||
if (!CanEdit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 服务端要求 UTF-8 密码的 32 位大写 MD5,保留首尾空格。
|
||||
_passwordHash = string.IsNullOrEmpty(password)
|
||||
? "" : Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(password)));
|
||||
}
|
||||
|
||||
public override ICommand ConfirmCommand => LoginCommand;
|
||||
|
||||
public override void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
Title = "门店管理 · 登录";
|
||||
}
|
||||
|
||||
public override void OnDialogClosed() => Dispose();
|
||||
|
||||
public AsyncDelegateCommand LoginCommand => field ??= new AsyncDelegateCommand(LoginAsync, () => CanEdit);
|
||||
|
||||
private async Task LoginAsync()
|
||||
{
|
||||
if (!CanEdit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(UserName))
|
||||
{
|
||||
LoadingStatus.Error("请输入用户名。");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(_passwordHash))
|
||||
{
|
||||
LoadingStatus.Error("请输入密码。");
|
||||
return;
|
||||
}
|
||||
|
||||
LoadingStatus.Initialize("正在验证账号,请稍候…");
|
||||
NotifyStateChanged();
|
||||
try
|
||||
{
|
||||
await _auth.LoginAsync(new LoginRequest
|
||||
{
|
||||
UserName = UserName.Trim(),
|
||||
Password = _passwordHash
|
||||
}, _lifetime.Token);
|
||||
if (!_disposed)
|
||||
{
|
||||
_authenticated = true;
|
||||
OnRequestClose(new DialogResult(ButtonResult.OK));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (_disposed)
|
||||
{
|
||||
// 关闭窗口产生的取消无需提示。
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
LoadingStatus.Error(ex.Message);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
LoadingStatus.Error("登录已取消,请重试。");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
LoadingStatus.Error("登录失败,请稍后重试。");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_passwordHash = "";
|
||||
if (!_disposed)
|
||||
{
|
||||
LoadingStatus.Done();
|
||||
ClearPasswordRequested?.Invoke(this, EventArgs.Empty);
|
||||
NotifyStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void NotifyStateChanged()
|
||||
{
|
||||
RaisePropertyChanged(nameof(CanEdit));
|
||||
RaisePropertyChanged(nameof(LoginButtonText));
|
||||
LoginCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_disposed = true;
|
||||
_passwordHash = "";
|
||||
_lifetime.Cancel();
|
||||
_lifetime.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<UserControl
|
||||
x:Class="Store.Management.Views.LoginWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Store.Management.ViewModels"
|
||||
Width="520"
|
||||
Height="620"
|
||||
MinWidth="440"
|
||||
MinHeight="540"
|
||||
d:DataContext="{d:DesignInstance Type=vm:LoginViewModel}"
|
||||
Background="{DynamicResource BackgroundBrush}"
|
||||
Foreground="{DynamicResource PrimaryTextBrush}"
|
||||
Loaded="OnLoaded"
|
||||
Unloaded="OnUnloaded"
|
||||
mc:Ignorable="d">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<Grid Margin="32" VerticalAlignment="Center">
|
||||
<StackPanel MaxWidth="360">
|
||||
<!-- 系统标识与登录说明 -->
|
||||
<TextBlock
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource PrimaryBrush}"
|
||||
Text="STORE MANAGEMENT" />
|
||||
<TextBlock
|
||||
Margin="0,12,0,0"
|
||||
FontSize="28"
|
||||
FontWeight="SemiBold"
|
||||
Text="登录门店管理" />
|
||||
<TextBlock
|
||||
Margin="0,8,0,28"
|
||||
Foreground="{DynamicResource SecondaryTextBrush}"
|
||||
Text="请输入您的用户名和密码"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!-- 登录表单:密码只保留在 PasswordBox 中 -->
|
||||
<Border
|
||||
Padding="24"
|
||||
Background="{DynamicResource RegionBrush}"
|
||||
BorderBrush="{DynamicResource BorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<StackPanel>
|
||||
<Label
|
||||
Padding="0,0,0,8"
|
||||
Content="用户名"
|
||||
Target="{Binding ElementName=UserNameBox, Mode=OneWay}" />
|
||||
<TextBox
|
||||
x:Name="UserNameBox"
|
||||
Height="40"
|
||||
VerticalContentAlignment="Center"
|
||||
AutomationProperties.Name="用户名"
|
||||
IsEnabled="{Binding CanEdit, Mode=OneWay}"
|
||||
MaxLength="{x:Static vm:LoginViewModel.InputMaxLength}"
|
||||
Text="{Binding UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Label
|
||||
Padding="0,20,0,8"
|
||||
Content="密码"
|
||||
Target="{Binding ElementName=PasswordBox, Mode=OneWay}" />
|
||||
<PasswordBox
|
||||
x:Name="PasswordBox"
|
||||
PasswordChanged="OnPasswordChanged"
|
||||
Height="40"
|
||||
VerticalContentAlignment="Center"
|
||||
AutomationProperties.Name="密码"
|
||||
IsEnabled="{Binding CanEdit, Mode=OneWay}"
|
||||
MaxLength="{x:Static vm:LoginViewModel.InputMaxLength}"
|
||||
/>
|
||||
|
||||
<TextBlock
|
||||
Margin="0,12,0,0"
|
||||
AutomationProperties.LiveSetting="Polite"
|
||||
Foreground="{DynamicResource SecondaryTextBrush}"
|
||||
Text="{Binding LoadingStatus.Message, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<!-- 保留错误提示空间,避免登录失败时表单跳动 -->
|
||||
<TextBlock
|
||||
x:Name="ErrorText"
|
||||
MinHeight="42"
|
||||
Margin="0,12,0,8"
|
||||
AutomationProperties.LiveSetting="Polite"
|
||||
Foreground="{DynamicResource DangerBrush}"
|
||||
Text="{Binding LoadingStatus.ErrorMessage, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="LoginButton"
|
||||
Height="40"
|
||||
Command="{Binding LoginCommand, Mode=OneWay}"
|
||||
Content="{Binding LoginButtonText, Mode=OneWay}"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource ButtonPrimary}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<TextBlock
|
||||
Margin="0,20,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="{DynamicResource SecondaryTextBrush}"
|
||||
Text="请使用管理员分配的账号登录"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,42 @@
|
||||
using Store.Management.ViewModels;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Store.Management.Views;
|
||||
|
||||
public partial class LoginWindow : UserControl
|
||||
{
|
||||
public LoginWindow() => InitializeComponent();
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is LoginViewModel viewModel)
|
||||
{
|
||||
viewModel.ClearPasswordRequested += OnClearPasswordRequested;
|
||||
}
|
||||
UserNameBox.Focus();
|
||||
}
|
||||
|
||||
private void OnPasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is LoginViewModel viewModel)
|
||||
{
|
||||
viewModel.UpdatePassword(PasswordBox.Password);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClearPasswordRequested(object? sender, EventArgs e)
|
||||
{
|
||||
PasswordBox.Clear();
|
||||
PasswordBox.Focus();
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is LoginViewModel viewModel)
|
||||
{
|
||||
viewModel.ClearPasswordRequested -= OnClearPasswordRequested;
|
||||
}
|
||||
PasswordBox.Clear();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user