架构治理: - Feature Flag 落地: Cargo.toml [features] default=["diary"] + main.rs cfg 条件编译 - 环境配置统一: AppConfig 类 + --dart-define 注入 + SSE 端口 8080→3000 修复 搜索替代方案 (无 FTS): - SearchBloc + 标签/心情筛选接入后端 API - JournalRepository 扩展 mood/tag 筛选参数 - 搜索页 UI 接入实际数据(替换占位文本) 家长中心最小集 (PIPL 合规): - 后端: parent_service (绑定/查看/导出/删除/解绑) + parent_handler (6 个 API 端点) - 前端: ParentBloc + ParentPage 功能完整实现 - 绑定孩子、只读查看日记、导出数据、删除数据、解绑 Docker 部署: - verify.sh 健康检查脚本 (Axum/PG/Redis/OpenAPI 四项检查) 测试修复: - home_bloc_test / calendar_bloc_test 适配 JournalRepository 新参数 验证: flutter test 84/84 pass, cargo test 76/76 pass, cargo check pass
80 lines
2.0 KiB
Dart
80 lines
2.0 KiB
Dart
// 搜索 BLoC — 标签+心情筛选日记
|
|
//
|
|
// 状态机: SearchInitial → SearchLoading → SearchLoaded/SearchError
|
|
// Phase 1 使用简单的标签+心情筛选,后续可扩展全文搜索。
|
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import '../../../data/models/journal_entry.dart';
|
|
import '../../../data/repositories/journal_repository.dart';
|
|
|
|
part 'search_event.dart';
|
|
part 'search_state.dart';
|
|
|
|
/// 搜索 BLoC — 处理标签和心情筛选日记的状态转换
|
|
class SearchBloc extends Bloc<SearchEvent, SearchState> {
|
|
final JournalRepository _journalRepo;
|
|
|
|
SearchBloc({required JournalRepository journalRepository})
|
|
: _journalRepo = journalRepository,
|
|
super(const SearchInitial()) {
|
|
on<SearchByMood>(_onSearchByMood);
|
|
on<SearchByTag>(_onSearchByTag);
|
|
on<SearchClear>(_onSearchClear);
|
|
}
|
|
|
|
/// 按心情筛选日记
|
|
Future<void> _onSearchByMood(
|
|
SearchByMood event,
|
|
Emitter<SearchState> emit,
|
|
) async {
|
|
emit(const SearchLoading());
|
|
try {
|
|
if (event.mood == null) {
|
|
emit(const SearchLoaded());
|
|
return;
|
|
}
|
|
final results = await _journalRepo.getJournals(
|
|
mood: event.mood!.value,
|
|
page: 1,
|
|
pageSize: 50,
|
|
);
|
|
emit(SearchLoaded(
|
|
results: results,
|
|
activeMood: event.mood!.value,
|
|
));
|
|
} catch (e) {
|
|
emit(const SearchError('搜索失败,请重试'));
|
|
}
|
|
}
|
|
|
|
/// 按标签筛选日记
|
|
Future<void> _onSearchByTag(
|
|
SearchByTag event,
|
|
Emitter<SearchState> emit,
|
|
) async {
|
|
emit(const SearchLoading());
|
|
try {
|
|
final results = await _journalRepo.getJournals(
|
|
tag: event.tag,
|
|
page: 1,
|
|
pageSize: 50,
|
|
);
|
|
emit(SearchLoaded(
|
|
results: results,
|
|
activeTag: event.tag,
|
|
));
|
|
} catch (e) {
|
|
emit(const SearchError('搜索失败,请重试'));
|
|
}
|
|
}
|
|
|
|
/// 清除搜索结果
|
|
void _onSearchClear(
|
|
SearchClear event,
|
|
Emitter<SearchState> emit,
|
|
) {
|
|
emit(const SearchLoaded());
|
|
}
|
|
}
|