feat(app): 班级码验证前后端联调 — AuthBloc接入API + 错误计数锁定UI
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
// ↕
|
||||
// Authenticating → Authenticated/AuthError
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
@@ -11,6 +12,7 @@ import '../../../data/models/auth_token.dart';
|
||||
import '../../../data/models/user.dart';
|
||||
import '../../../data/remote/api_client.dart';
|
||||
import '../../../data/repositories/auth_repository.dart';
|
||||
import '../../../data/repositories/class_repository.dart';
|
||||
|
||||
part 'auth_event.dart';
|
||||
part 'auth_state.dart';
|
||||
@@ -18,10 +20,14 @@ part 'auth_state.dart';
|
||||
/// 认证 BLoC — 处理所有认证相关的状态转换
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final AuthRepository _authRepository;
|
||||
final ClassRepository? _classRepository;
|
||||
final Logger _logger = Logger(printer: PrettyPrinter(methodCount: 0));
|
||||
|
||||
AuthBloc({required AuthRepository authRepository})
|
||||
: _authRepository = authRepository,
|
||||
AuthBloc({
|
||||
required AuthRepository authRepository,
|
||||
ClassRepository? classRepository,
|
||||
}) : _authRepository = authRepository,
|
||||
_classRepository = classRepository,
|
||||
super(const AuthInitial()) {
|
||||
// 注册事件处理器
|
||||
on<AppStarted>(_onAppStarted);
|
||||
@@ -138,13 +144,64 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final currentState = state;
|
||||
if (currentState is! Authenticated) return;
|
||||
|
||||
// TODO: 调用后端 API 验证班级码并加入班级
|
||||
// 当前先标记为已完成,班级码验证在 F8 阶段完善
|
||||
emit(currentState.copyWith(
|
||||
needsClassCode: false,
|
||||
));
|
||||
// 如果没有 ClassRepository(离线模式),直接跳过
|
||||
final classRepo = _classRepository;
|
||||
if (classRepo == null) {
|
||||
_logger.w('ClassRepository 不可用,跳过班级码验证');
|
||||
emit(currentState.copyWith(needsClassCode: false));
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.i('班级码加入: ${event.classCode}');
|
||||
emit(currentState.copyWith(isLoading: true));
|
||||
|
||||
try {
|
||||
// 调用后端 API 验证班级码并加入班级
|
||||
await classRepo.joinClass(
|
||||
event.classCode,
|
||||
nickname: currentState.user.displayName,
|
||||
);
|
||||
|
||||
// 成功 — 清除班级码需求
|
||||
emit(currentState.copyWith(
|
||||
needsClassCode: false,
|
||||
isLoading: false,
|
||||
));
|
||||
|
||||
_logger.i('班级码加入成功: ${event.classCode}');
|
||||
} on DioException catch (e) {
|
||||
final statusCode = e.response?.statusCode;
|
||||
String errorMessage = '加入班级失败,请重试';
|
||||
|
||||
if (statusCode == 400) {
|
||||
// 班级码无效或已过期
|
||||
final body = e.response?.data;
|
||||
if (body is Map && body['message'] is String) {
|
||||
errorMessage = body['message'] as String;
|
||||
} else {
|
||||
errorMessage = '班级码无效,请检查后重新输入';
|
||||
}
|
||||
} else if (statusCode == 429) {
|
||||
// 尝试次数过多 — 锁定
|
||||
errorMessage = '尝试次数过多,请等待 30 分钟后再试';
|
||||
}
|
||||
|
||||
_logger.w('班级码验证失败 ($statusCode): $errorMessage');
|
||||
emit(currentState.copyWith(
|
||||
isLoading: false,
|
||||
classCodeError: errorMessage,
|
||||
));
|
||||
} on OfflineException {
|
||||
emit(currentState.copyWith(
|
||||
isLoading: false,
|
||||
classCodeError: '网络不可用,请检查网络后重试',
|
||||
));
|
||||
} catch (e) {
|
||||
_logger.e('班级码验证异常: $e');
|
||||
emit(currentState.copyWith(
|
||||
isLoading: false,
|
||||
classCodeError: '加入班级失败,请稍后重试',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 用户登出
|
||||
|
||||
@@ -40,21 +40,33 @@ final class Authenticated extends AuthState {
|
||||
/// 是否需要班级码加入(学生/家长角色)
|
||||
final bool needsClassCode;
|
||||
|
||||
/// 是否正在加载(班级码验证中)
|
||||
final bool isLoading;
|
||||
|
||||
/// 班级码验证错误信息
|
||||
final String? classCodeError;
|
||||
|
||||
const Authenticated({
|
||||
required this.user,
|
||||
this.needsRoleSelection = false,
|
||||
this.needsClassCode = false,
|
||||
this.isLoading = false,
|
||||
this.classCodeError,
|
||||
});
|
||||
|
||||
Authenticated copyWith({
|
||||
User? user,
|
||||
bool? needsRoleSelection,
|
||||
bool? needsClassCode,
|
||||
bool? isLoading,
|
||||
String? classCodeError,
|
||||
}) =>
|
||||
Authenticated(
|
||||
user: user ?? this.user,
|
||||
needsRoleSelection: needsRoleSelection ?? this.needsRoleSelection,
|
||||
needsClassCode: needsClassCode ?? this.needsClassCode,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
classCodeError: classCodeError,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user