feat(app): 实现认证模块 — F2 Auth BLoC + 登录/注册/角色选择/班级码加入
新增文件 (10): - data/models/user.dart — 用户+角色模型 (匹配后端 UserResp/RoleResp) - data/models/auth_token.dart — 认证令牌模型 (匹配后端 LoginResp) - data/repositories/auth_repository.dart — 认证仓库 (JWT 安全持久化 + PIPL 合规) - features/auth/bloc/auth_bloc.dart — 认证 BLoC (8 种事件, 6 种状态) - features/auth/bloc/auth_event.dart — 认证事件 (sealed class 穷尽匹配) - features/auth/bloc/auth_state.dart — 认证状态 (Authenticated 含角色/班级码流程) - features/auth/views/login_page.dart — 登录/注册页面 (重写占位页面) - features/auth/views/role_selection_page.dart — 角色选择页 (4 种角色卡片) - features/auth/views/class_code_join_page.dart — 班级码加入页 (6 位输入) 修改文件 (5): - pubspec.yaml — 添加 flutter_secure_storage 依赖 - app.dart — 注入 AuthBloc + RepositoryProvider - main.dart — 简化入口 (认证恢复在 BLoC 中处理) - core/routing/app_router.dart — 添加认证路由守卫 + 2 新路由 - erp-diary/service/class_service.rs — 移除未使用的 PaginatorTrait import 验证: flutter analyze (0 error) + cargo check 通过
This commit is contained in:
76
app/lib/features/auth/bloc/auth_state.dart
Normal file
76
app/lib/features/auth/bloc/auth_state.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
// 认证状态 — AuthBloc 输出的 UI 状态
|
||||
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
/// 认证状态基类 — 使用 sealed class 实现穷尽匹配
|
||||
sealed class AuthState {
|
||||
const AuthState();
|
||||
}
|
||||
|
||||
/// 初始状态 — App 刚启动
|
||||
final class AuthInitial extends AuthState {
|
||||
const AuthInitial();
|
||||
}
|
||||
|
||||
/// 加载中 — 正在检查本地存储的认证状态
|
||||
final class AuthLoading extends AuthState {
|
||||
const AuthLoading();
|
||||
}
|
||||
|
||||
/// 未认证 — 需要登录
|
||||
final class Unauthenticated extends AuthState {
|
||||
const Unauthenticated();
|
||||
}
|
||||
|
||||
/// 认证中 — 正在登录或注册
|
||||
final class Authenticating extends AuthState {
|
||||
/// 是否为注册模式(显示不同的 UI 提示)
|
||||
final bool isRegister;
|
||||
|
||||
const Authenticating({this.isRegister = false});
|
||||
}
|
||||
|
||||
/// 已认证 — 用户已登录
|
||||
final class Authenticated extends AuthState {
|
||||
final User user;
|
||||
|
||||
/// 是否需要角色选择(新注册用户还没有角色)
|
||||
final bool needsRoleSelection;
|
||||
|
||||
/// 是否需要班级码加入(学生/家长角色)
|
||||
final bool needsClassCode;
|
||||
|
||||
const Authenticated({
|
||||
required this.user,
|
||||
this.needsRoleSelection = false,
|
||||
this.needsClassCode = false,
|
||||
});
|
||||
|
||||
Authenticated copyWith({
|
||||
User? user,
|
||||
bool? needsRoleSelection,
|
||||
bool? needsClassCode,
|
||||
}) =>
|
||||
Authenticated(
|
||||
user: user ?? this.user,
|
||||
needsRoleSelection: needsRoleSelection ?? this.needsRoleSelection,
|
||||
needsClassCode: needsClassCode ?? this.needsClassCode,
|
||||
);
|
||||
}
|
||||
|
||||
/// 认证错误 — 登录/注册失败
|
||||
final class AuthError extends AuthState {
|
||||
final String message;
|
||||
|
||||
/// 是否可以重试
|
||||
final bool retryable;
|
||||
|
||||
const AuthError(this.message, {this.retryable = true});
|
||||
}
|
||||
|
||||
/// 需要家长授权 — 未满 14 岁用户需要家长确认
|
||||
final class ParentAuthRequired extends AuthState {
|
||||
final User user;
|
||||
|
||||
const ParentAuthRequired(this.user);
|
||||
}
|
||||
Reference in New Issue
Block a user