- 新增 project-health.md — 项目评分/技术债全景/风险矩阵/改进路线图 - 更新 index.md — 代码量分布表/新发现技术债统计/新增症状条目 - 更新 architecture.md — Feature Flag 未实现状态/超大文件发现 - 更新 frontend.md — 状态管理不统一/SSE 端口/测试缺失等 11 项问题 - 更新 erp-diary.md — 代码量分布参考/班级码硬编码问题 基于 4 代理并行深度分析: 后端 Rust 51,459 行 + 前端 Flutter 18,398 行
130 lines
5.2 KiB
Markdown
130 lines
5.2 KiB
Markdown
---
|
||
title: Flutter 前端
|
||
updated: 2026-06-01
|
||
status: active
|
||
tags: [flutter, bloc, design-system, responsive]
|
||
---
|
||
|
||
# Flutter 前端
|
||
|
||
> 从 [[index]] 导航。关联: [[handwriting-engine]] [[data-layer]]
|
||
|
||
## 1. 设计决策
|
||
|
||
### Q: 为什么 BLoC 不是 Provider/Riverpod?
|
||
|
||
编辑器(strokes + elements + undo/redo + autoSave)、同步引擎(pending queue + network status)、日历(date range + mood filter)等复杂交互需要 Event/State 显式建模。BLoC 的单向数据流比 Provider 的 notifyListeners() 更可控。
|
||
|
||
### Q: 为什么 go_router?
|
||
|
||
声明式路由 + 深链接支持 + 路由守卫(auth guard 重定向未登录用户)。比 Navigator 2.0 更简洁。
|
||
|
||
### Q: 设计系统 7 色双模主题?
|
||
|
||
暖记定位"温暖治愈",浅色模式奶油白(#FFF8F0) + 珊瑚色(#E07A5F) + 鼠尾草绿(#81B29A);深色模式自动映射为暖色调暗色。面向小学生,所有颜色避免冷硬感。
|
||
|
||
### Q: 为什么手写模型不用 freezed?
|
||
|
||
Stroke/StrokePoint 是热路径高频创建对象,freezed 生成的代码有额外开销。手写实现 copyWith + toJson/fromJson 更轻量。
|
||
|
||
## 2. 关键文件 + 数据流
|
||
|
||
### 16 个功能模块
|
||
|
||
| 模块 | BLoC | 职责 |
|
||
|------|------|------|
|
||
| editor | EditorBloc | 手写 + 元素 + 撤销重做 + 自动保存 |
|
||
| auth | AuthBloc | 登录/注册/角色选择/班级码加入 |
|
||
| home | HomeBloc | 首页日记列表 + 搜索 |
|
||
| calendar | CalendarBloc | 日历视图 + 日期过滤 |
|
||
| mood | MoodBloc | 心情统计 + 趋势图 |
|
||
| class_ | ClassBloc | 班级管理 + 成员列表 |
|
||
| achievement | AchievementBloc | 成就徽章系统 |
|
||
| stickers | StickerBloc | 贴纸库浏览 + 选择 |
|
||
| templates | TemplateBloc | 模板画廊 |
|
||
| profile | SettingsBloc | 主题切换 + 个人设置 |
|
||
| search | — | 日记搜索 (Isar FTS 待实现) |
|
||
| teacher | — | 老师主题发布 + 批改 |
|
||
| parent | — | 家长监护 + 数据管理 |
|
||
| settings | — | 设置页面 UI |
|
||
|
||
### 注入链 (app.dart)
|
||
|
||
```
|
||
MultiRepositoryProvider
|
||
├─ ApiClient
|
||
├─ AuthRepository
|
||
├─ JournalRepository (= IsarJournalRepository, 离线优先)
|
||
├─ RemoteJournalRepository (供 SyncEngine)
|
||
├─ SyncEngine
|
||
├─ ClassRepository
|
||
└─ SettingsBloc (ChangeNotifier)
|
||
└─ BlocProvider<AuthBloc>
|
||
└─ MaterialApp.router (ListenableBuilder 监听主题)
|
||
```
|
||
|
||
### 路由表
|
||
|
||
`app_router.dart` (269 行) 定义完整路由:
|
||
- `/` → 首页(auth guard 重定向)
|
||
- `/login`, `/role-selection`, `/class-code-join`
|
||
- `/editor/:id?` → 编辑器
|
||
- `/calendar`, `/mood`, `/class`, `/achievements`
|
||
- `/stickers`, `/templates`, `/search`
|
||
- `/teacher/*`, `/parent/*`
|
||
- `/settings`, `/profile`
|
||
|
||
## 3. 代码逻辑
|
||
|
||
### 不变量
|
||
|
||
⚡ **响应式断点** — 手机 <600px 底部 TabBar 单列 / 平板 600-1024px 侧边双栏 / 桌面 >1024px 三栏
|
||
|
||
⚡ **触摸目标 ≥ 44px** — 面向小学生,所有可交互元素不小于 44px
|
||
|
||
⚡ **设计 Token 统一管理** — `core/constants/design_tokens.dart` 定义间距/圆角/阴影
|
||
|
||
⚡ **SettingsBloc 用 ChangeNotifier** — 不用 BLoC 因为设置是全局状态,ChangeNotifier + ListenableBuilder 更轻量
|
||
|
||
### 主题系统
|
||
|
||
```
|
||
AppTheme.light() / AppTheme.dark()
|
||
├─ 7 色 × 2 模式 (bg/accent/secondary/tertiary/fg/surface/rose)
|
||
├─ 3 套字体 (Noto Sans SC / Caveat / JetBrains Mono)
|
||
├─ 4 级圆角 (10/16/22/28/pill)
|
||
└─ 动画曲线 cubic-bezier(0.34, 1.56, 0.64, 1) — 弹性过冲
|
||
```
|
||
|
||
## 4. 活跃问题 + 陷阱
|
||
|
||
| 问题 | 级别 | 状态 | 说明 |
|
||
|------|------|------|------|
|
||
| 编辑器不加载已有数据 | HIGH | 待做 | journalId 非空时需从 Isar 读取 |
|
||
| SSE 端口不一致 | HIGH | 待修 | SSE 用 8080,API 用 3000,推送必然失败 |
|
||
| API base URL 硬编码 | HIGH | 待修 | localhost:3000 硬编码,生产环境需配置化 |
|
||
| 前端测试为零 | HIGH | 待做 | 70 个 Dart 文件无任何测试覆盖 |
|
||
| 状态管理不统一 | MEDIUM | 待规划 | 5 模块用 BLoC,5 模块用 ChangeNotifier |
|
||
| freezed 声明未使用 | MEDIUM | 待清理 | pubspec 声明了但全部手写不可变类 |
|
||
| SyncEngine 缺少网络监听 | MEDIUM | 待做 | 只有 trySync() 方法,无自动触发 |
|
||
| 搜索功能空壳 | MEDIUM | 待做 | Isar FTS 未实现 |
|
||
| 家长/教师页面占位 | LOW | 持续 | 多处 onTap 为 SnackBar 提示 |
|
||
| core/utils/ 空目录 | LOW | 待填充 | 缺少日期格式化、颜色解析等通用工具 |
|
||
| 深色模式细节 | LOW | 持续 | 部分组件深色适配需检查 |
|
||
|
||
### 历史教训
|
||
|
||
- F11 深色模式修复需要 bloat bloc 测试套件同步更新 (05317d5)
|
||
- NuanjiApp 是 StatelessWidget,build() 可被调用多次 → 全局依赖应在 build() 中创建单例
|
||
- 25 处通用 catch(e) 静默吞异常,排查问题时需注意
|
||
- 班级码在 teacher 模块硬编码为 'a1b2c3',需接入后端 API
|
||
|
||
## 5. 变更记录
|
||
|
||
| 日期 | 变更 |
|
||
|------|------|
|
||
| 2026-06-01 | 补充状态管理不统一、SSE 端口问题、测试缺失等新发现 |
|
||
| 2026-06-01 | IsarJournalRepository 注入为主 JournalRepository (2481c8f) |
|
||
| 2026-06-01 | 设置页 UI + Mood/成就/贴纸 BLoC (8331db6) |
|
||
| 2026-06-01 | 初始创建 — 16 模块地图、注入链、设计系统 |
|