Files
Atomx/Atomx.Admin/Atomx.Admin.Client/Pages/Login.razor
2025-12-09 19:10:10 +08:00

214 lines
7.6 KiB
Plaintext
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.
@page "/account/login"
@page "/{locale}/account/login"
@layout EmptyLayout
@inject ILogger<Login> Logger
@inject IStringLocalizer<Login> L
<PageTitle>@L["login.title"]</PageTitle>
@if (!dataLoaded)
{
<Spin Spinning="_isLoading" />
}
else
{
<Flex Style="height:100vh" Justify="FlexJustify.Center" Align="FlexAlign.Center" Direction="FlexDirection.Vertical">
<GridRow Justify="RowJustify.Center" Class="">
<GridCol>
<Card>
<Form @ref="form" Model="@login" OnFinish="LoginAsync">
<FluentValidationValidator />
<FormItem>
<AntDesign.Input Placeholder="@L["login.account.placeholder"]" Size="InputSize.Large" @bind-Value="@login.Account">
<Prefix><Icon Type="user" /></Prefix>
</AntDesign.Input>
</FormItem>
<FormItem>
<AntDesign.Input Placeholder="@L["login.password.placeholder"]" Size="InputSize.Large" @bind-Value="@login.Password" Type="InputType.Password">
<Prefix><Icon Type="lock" /></Prefix>
</AntDesign.Input>
</FormItem>
<FormItem>
<a style="float: left;">
@L["login.forgot"]
</a>
<a style="float: right;">
<NavLink href="/register">@L["login.register"]</NavLink>
</a>
</FormItem>
<FormItem>
<Button Type="ButtonType.Primary" HtmlType="submit" Class="submit" Size="ButtonSize.Large" Block>@L["login.submit"]</Button>
</FormItem>
<FormItem>
<a @onclick="setAccount">
@L["login.setdev"]
</a>
</FormItem>
</Form>
</Card>
</GridCol>
</GridRow>
<GridRow Style="padding-top:40px">
<span style="font-size:12px;padding-right:3px;">@L["copyright"]</span>
<span style="font-size:12px">runing as @handler</span>
</GridRow>
<GridRow>
<Atomx.Admin.Client.Components.LangSelector />
</GridRow>
<GridRow Style="padding-top:10px">
<div>
<strong>Quick links:</strong>
<span style="padding-left:10px;"><NavLink href="/counter">Counter</NavLink></span>
<span style="padding-left:10px;"><NavLink href="/weather">Weather</NavLink></span>
</div>
<div>
<strong>zh Quick links:</strong>
<span style="padding-left:10px;"><NavLink href="/zh/counter">Counter</NavLink></span>
<span style="padding-left:10px;"><NavLink href="/zh/weather">Weather</NavLink></span>
</div>
<div>
<strong>en Quick links:</strong>
<span style="padding-left:10px;"><NavLink href="/en/counter">Counter</NavLink></span>
<span style="padding-left:10px;"><NavLink href="/en/weather">Weather</NavLink></span>
</div>
</GridRow>
</Flex>
}
@code {
string handler = "Server";
[Parameter]
public string Locale { get; set; } = string.Empty;
[Parameter]
[SupplyParameterFromQuery(Name = "ReturnUrl")]
public string? ReturnUrl { get; set; }
[SupplyParameterFromForm]
public LoginModel login { get; set; } = new();
private Form<LoginModel> form = null!;
bool dataLoaded = false;
string message { get; set; } = string.Empty;
private bool _isLoading = false;
protected override void OnInitialized()
{
if (OperatingSystem.IsBrowser())
{
handler = "Wasm";
}
else
{
handler = "Server";
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
if (authState.User.Identity != null && authState.User.Identity.IsAuthenticated)
{
Navigation.NavigateTo(ReturnUrl ?? "/");
}
}
if (!dataLoaded)
{
dataLoaded = true;
StateHasChanged();
}
}
private async Task LoginAsync()
{
if (!form.Validate()) return;
_isLoading = true;
StateHasChanged();
try
{
var api = "/api/sign/in";
if (!OperatingSystem.IsBrowser())
{
// Server 模式:使用浏览器发起的 fetch通过 JS并携带 credentials: 'include'
var jsResult = await JS.InvokeAsync<JsonElement>("ajax.Post", api, login);
var result = jsResult.ToJson().FromJson<ApiResult<AuthResponse>>();
if (result != null && result.Success)
{
var auth = result.Data;
await localStorage.SetItemAsync(StorageKeys.AccessToken, auth.Token);
await localStorage.SetItemAsync(StorageKeys.RefreshToken, auth.RefreshToken);
if (AuthStateProvider is PersistentAuthenticationStateProvider provider)
{
provider.UpdateAuthenticationState(auth.Token);
}
Logger.LogInformation($"登录成功server 跳转: {ReturnUrl}");
Navigation.NavigateTo(ReturnUrl ?? "/", forceLoad: true);
}
else
{
ModalService.Error(new ConfirmOptions() { Title = "提示", Content = result.Message });
}
}
else
{
// Wasm 模式:保存 localStorage 并更新 AuthStateProvider
var result = await HttpService.Post<ApiResult<AuthResponse>>(api, login);
if (result.Success && result.Data != null)
{
var auth = result.Data;
await localStorage.SetItemAsync(StorageKeys.AccessToken, auth.Token);
await localStorage.SetItemAsync(StorageKeys.RefreshToken, auth.RefreshToken);
if (AuthStateProvider is PersistentAuthenticationStateProvider provider)
{
provider.UpdateAuthenticationState(auth.Token);
}
Logger.LogInformation("登录成功wasm 跳转: {ReturnUrl}", ReturnUrl);
Navigation.NavigateTo(ReturnUrl ?? "/");
}
else
{
ModalService.Error(new ConfirmOptions() { Title = "提示", Content = result.Message });
}
}
}
catch (Exception ex)
{
Logger.LogError(ex, "登录失败");
ModalService.Error(new ConfirmOptions() { Title = "错误", Content = "登录异常,请稍后重试" });
}
finally
{
_isLoading = false;
StateHasChanged();
}
}
private async Task OnPasswordKeyDown(KeyboardEventArgs value)
{
if (value.Key == "Enter")
{
await LoginAsync();
}
}
void setAccount()
{
login.Account = "admin";
login.Password = "admin888";
}
}