fix(app): 家长同意验证流程 — PIPL 第28条合规
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled

- 新增 ParentalConsentPage: 显示隐私政策要点 + 双重确认复选框
- 角色选择流程: 学生 → 家长同意确认 → 班级码输入
- Authenticated 状态: 添加 needsParentalConsent/parentalConsentAt/selectedRole
- ParentalConsentAccepted 事件: 记录同意时间戳
- 路由守卫: 注册 /parental-consent 路径和重定向逻辑
- 非学生角色(老师/家长/独立用户)不需要经过同意流程

审计 ID: S-03
This commit is contained in:
iven
2026-06-03 10:25:23 +08:00
parent a34c9fd176
commit 99db8e5cb0
5 changed files with 318 additions and 4 deletions

View File

@@ -34,6 +34,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
on<LoginRequested>(_onLoginRequested);
on<RegisterRequested>(_onRegisterRequested);
on<RoleSelected>(_onRoleSelected);
on<ParentalConsentAccepted>(_onParentalConsentAccepted);
on<ClassCodeSubmitted>(_onClassCodeSubmitted);
on<LogoutRequested>(_onLogoutRequested);
on<TokenRefreshed>(_onTokenRefreshed);
@@ -124,16 +125,38 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
final currentState = state;
if (currentState is! Authenticated) return;
// 学生角色需要先经过家长同意确认PIPL 第28条
final needsParentalConsent = event.role == UserRoleType.student;
// 根据角色决定下一步
final needsClassCode =
event.role == UserRoleType.student || event.role == UserRoleType.parent;
emit(currentState.copyWith(
needsRoleSelection: false,
needsClassCode: needsClassCode,
needsParentalConsent: needsParentalConsent,
needsClassCode: needsClassCode && !needsParentalConsent,
selectedRole: event.role,
));
_logger.i('角色选择: ${event.role.name}, 需要班级码: $needsClassCode');
_logger.i('角色选择: ${event.role.name}, 需要家长同意: $needsParentalConsent');
}
/// 家长/监护人同意信息收集PIPL 合规)
Future<void> _onParentalConsentAccepted(
ParentalConsentAccepted event,
Emitter<AuthState> emit,
) async {
final currentState = state;
if (currentState is! Authenticated) return;
_logger.i('家长同意已确认: ${event.consentAt}');
emit(currentState.copyWith(
needsParentalConsent: false,
needsClassCode: true,
parentalConsentAt: event.consentAt,
));
}
/// 班级码加入