辛集市网站建设_网站建设公司_建站流程_seo优化
2025/12/21 22:18:01 网站建设 项目流程

用 .NET MAUI 10 + VS Copilot 从 0 开发一个签到 App(六)

一、本文背景

在前一篇中,我们已经完成了用户注册,解决了一个核心问题:

用户从哪里来?

但一个系统只有注册,没有登录,是无法真正使用的。

因此在真实项目推进中,下一步几乎是必然的:

登录页面 + 登录态建立

这一篇依然遵循同一个原则:

👉 先跑通真实业务流程,再考虑架构与抽象

需要再次强调的是:

本文中的登录页面(XAML + Code-behind)同样是由 Visual Studio Copilot 生成并整理的实现思路,对应的是一个可直接运行的工程页面。


二、登录页在这个 App 中承担的职责

在这个签到 App 中,登录页并不只是“校验用户名密码”,它实际上承担了多项职责:

  1. 选择当前租户(Tenant)
  2. 恢复上一次登录上下文(租户 / 用户名)
  3. 首次启动时触发引导流程
  4. 成功登录后,进入真实业务页面

这已经明显不是一个简单 Demo 登录页了。


三、Copilot 生成的登录页面(XAML)

下面是登录页的 UI 布局代码:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="SignInMauiApp.LoginPage"><VerticalStackLayout Padding="30,60" Spacing="20"><Label Text="签到系统登录" FontSize="24" HorizontalOptions="Center" /><Image HeightRequest="100" WidthRequest="100" Source="logo.jpg" HorizontalOptions="Center" /><Picker x:Name="TenantPicker" Title="选择租户" MaximumWidthRequest="600" /><Entry x:Name="UsernameEntry" Placeholder="用户名" MaximumWidthRequest="600" /><Entry x:Name="PasswordEntry" Placeholder="密码" IsPassword="True" MaximumWidthRequest="600" /><Button Text="登录" Clicked="OnLoginClicked" MaximumWidthRequest="600" /><Button Text="注册新用户" Clicked="OnRegisterClicked" MaximumWidthRequest="600" /><Label x:Name="ErrorLabel" TextColor="Red" IsVisible="False" MaximumWidthRequest="600" /></VerticalStackLayout>
</ContentPage>

这个 UI 有几个明显的工程化特征:

  • 租户选择是登录的前置条件
  • 登录 / 注册入口并列存在
  • 所有控件宽度做了限制,适配桌面与移动端

它并不“炫”,但非常实用。


四、Copilot 生成的登录逻辑(Code-behind)

对应的页面逻辑如下:

public partial class LoginPage : ContentPage
{private readonly IFreeSql? _fsql;private List<Tenant> _tenants = new();public LoginPage(){InitializeComponent();_fsql = IPlatformApplication.Current?.Services.GetService<IFreeSql>();CheckAndShowOnboardingAsync();LoadTenants();}protected override void OnAppearing(){base.OnAppearing();LoadTenants();}private async void CheckAndShowOnboardingAsync(){var onboardingDone = Preferences.Get("OnboardingDone", false);if (!onboardingDone){await Navigation.PushModalAsync(new OnboardingPage(_fsql));}}private void LoadTenants(){_tenants = _fsql!.Select<Tenant>().ToList();TenantPicker.ItemsSource = _tenants.Select(t => t.Name).ToList();int lastTenantId = Preferences.Get("LastTenantId", -1);int idx = 0;if (_tenants.Count > 0){if (lastTenantId > 0){idx = _tenants.FindIndex(t => t.Id == lastTenantId);if (idx < 0) idx = 0;}TenantPicker.SelectedIndex = idx;}UsernameEntry.Text = Preferences.Get("LastUsername", "");}private async void OnLoginClicked(object sender, EventArgs e){ErrorLabel.IsVisible = false;var username = UsernameEntry.Text?.Trim();var password = PasswordEntry.Text;var tenantIdx = TenantPicker.SelectedIndex;if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || tenantIdx < 0){ErrorLabel.Text = "请填写完整信息";ErrorLabel.IsVisible = true;return;}var tenantId = _tenants[tenantIdx].Id;var user = _fsql!.Select<User>().Where(u => u.Username == username && u.Password == password && u.TenantId == tenantId).First();if (user == null){ErrorLabel.Text = "用户名或密码错误";ErrorLabel.IsVisible = true;return;}Preferences.Set("LastTenantId", tenantId);Preferences.Set("LastUsername", username);await Navigation.PushAsync(new SignInPage(user, _tenants[tenantIdx]));}private async void OnRegisterClicked(object sender, EventArgs e){await Navigation.PushAsync(new RegisterPage());}
}

五、几个非常“真实工程”的细节

1️⃣ 登录不是全局的,而是租户内的

.Where(u => u.Username == username && u.Password == password && u.TenantId == tenantId)

这一行明确体现了:

同一个用户名,在不同租户中是完全独立的身份


2️⃣ 登录体验被认真对待

  • 记住上一次租户
  • 自动填充用户名

这些并不是必须功能,但它们让 App 更像“真的会被每天使用”。


3️⃣ 引导页不是写在文档里的,而是写在代码里的

CheckAndShowOnboardingAsync();

通过本地标记控制首次引导流程,这是一个非常典型的业务 App 设计。


六、Copilot 在“登录态”问题上的边界

需要特别说明的是:

  • Copilot 能写出登录页面
  • 但它并不会自动帮你设计完整的登录态生命周期

例如:

  • 登录后是否清空返回栈
  • 退出登录如何回到初始状态
  • 多页面共享用户上下文如何处理

这些问题,已经开始进入应用结构层面


七、为什么现在依然没有引入认证框架?

和注册页一样,这里依然没有引入:

  • Identity
  • Token
  • Session

原因很简单:

在当前阶段,这个 App 的复杂度还不值得引入这些重量级组件。

而 Copilot 在“简单明确”的业务逻辑下,产出质量反而更高。


八、下一步:初始化数据与租户管理

现在,这个签到 App 已经具备:

  • 注册
  • 登录
  • 多租户隔离
  • 基础业务页面

下一步不可避免地会遇到:

系统第一次启动时怎么办?

也就是:

  • 初始化租户
  • 默认管理员
  • 数据兜底策略

九、下一篇预告

下一篇将进入:

第 7 篇:初始化数据与租户管理 —— Copilot 能写 CRUD,但系统规则必须由你决定

从这一篇开始,这个项目将正式进入“可长期维护”的阶段。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询