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

@@ -28,6 +28,7 @@ import '../../features/profile/views/profile_page.dart';
import '../../features/editor/views/editor_page.dart';
import '../../features/auth/views/login_page.dart';
import '../../features/auth/views/role_selection_page.dart';
import '../../features/auth/views/parental_consent_page.dart';
import '../../features/auth/views/class_code_join_page.dart';
import '../../features/onboarding/views/splash_page.dart';
import '../../features/onboarding/views/onboarding_page.dart';
@@ -49,7 +50,7 @@ final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();
/// 不需要认证的白名单路径
const _publicPaths = ['/splash', '/onboarding', '/login', '/role-selection', '/class-code'];
const _publicPaths = ['/splash', '/onboarding', '/login', '/role-selection', '/parental-consent', '/class-code'];
/// 创建路由配置 — 需要注入 AuthBloc
GoRouter createAppRouter(AuthBloc authBloc) {
@@ -74,6 +75,7 @@ GoRouter createAppRouter(AuthBloc authBloc) {
// 已认证 + 访问公开页面 → 根据状态重定向
if (isAuthenticated && isPublicPath) {
if (authState.needsRoleSelection) return '/role-selection';
if (authState.needsParentalConsent) return '/parental-consent';
if (authState.needsClassCode) return '/class-code';
return '/home';
}
@@ -83,9 +85,14 @@ GoRouter createAppRouter(AuthBloc authBloc) {
if (authState.needsRoleSelection && currentPath != '/role-selection') {
return '/role-selection';
}
if (authState.needsParentalConsent &&
currentPath != '/parental-consent') {
return '/parental-consent';
}
if (authState.needsClassCode &&
currentPath != '/class-code' &&
currentPath != '/role-selection') {
currentPath != '/role-selection' &&
currentPath != '/parental-consent') {
return '/class-code';
}
return null;
@@ -125,6 +132,11 @@ GoRouter createAppRouter(AuthBloc authBloc) {
name: 'roleSelection',
builder: (context, state) => const RoleSelectionPage(),
),
GoRoute(
path: '/parental-consent',
name: 'parentalConsent',
builder: (context, state) => const ParentalConsentPage(),
),
GoRoute(
path: '/class-code',
name: 'classCode',