feat: 实现站内通知系统
- 后端: 新增 notifications/user_notifications 表迁移及 ORM 模型
- 后端: 实现 schema/repository/service/router 全套通知 API
- GET /api/v1/notifications (列表+游标分页)
- GET /api/v1/notifications/unread-count
- PATCH /api/v1/notifications/{id}/read (幂等)
- PATCH /api/v1/notifications/mark-all-read (幂等)
- 后端: payload 使用 Pydantic discriminated union (none/open_route/open_url)
- 后端: 19 个单元测试全部通过
- Flutter: 通知 feature 完整实现 (models/apis/repositories/bloc/UI)
- Flutter: Home 页通知按钮接入真实页面,显示未读 badge
- Flutter: 14 个测试全部通过
- 协议文档: notification-inbox-protocol.md 及错误码注册
This commit is contained in:
@@ -15,6 +15,9 @@ import '../features/auth/presentation/screens/login_screen.dart';
|
||||
import '../features/divination/data/apis/divination_api.dart';
|
||||
import '../features/divination/data/models/divination_result.dart';
|
||||
import '../features/home/presentation/screens/home_screen.dart';
|
||||
import '../features/notifications/data/apis/notification_api.dart';
|
||||
import '../features/notifications/data/repositories/notification_repository.dart';
|
||||
import '../features/notifications/presentation/bloc/notification_bloc.dart';
|
||||
import '../features/settings/data/apis/profile_api.dart';
|
||||
import '../features/settings/data/models/profile_settings.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
@@ -35,6 +38,9 @@ class _EryaoAppState extends State<EryaoApp> {
|
||||
late final AuthBloc _authBloc;
|
||||
late final DivinationApi _divinationApi;
|
||||
late final ProfileApi _profileApi;
|
||||
late final NotificationApi _notificationApi;
|
||||
late final NotificationRepository _notificationRepository;
|
||||
late final NotificationBloc _notificationBloc;
|
||||
Locale _locale = const Locale('zh');
|
||||
ProfileSettingsV1 _profileSettings = ProfileSettingsV1.defaultsForLocale(
|
||||
const Locale('zh'),
|
||||
@@ -61,6 +67,11 @@ class _EryaoAppState extends State<EryaoApp> {
|
||||
final authApi = AuthApi(apiClient: apiClient);
|
||||
_divinationApi = DivinationApi(apiClient: apiClient);
|
||||
_profileApi = ProfileApi(apiClient: apiClient);
|
||||
_notificationApi = NotificationApi(apiClient: apiClient);
|
||||
_notificationRepository = NotificationRepositoryImpl(
|
||||
notificationApi: _notificationApi,
|
||||
);
|
||||
_notificationBloc = NotificationBloc(repository: _notificationRepository);
|
||||
final authRepository = AuthRepositoryImpl(
|
||||
authApi: authApi,
|
||||
sessionStore: _sessionStore,
|
||||
@@ -347,6 +358,7 @@ class _EryaoAppState extends State<EryaoApp> {
|
||||
@override
|
||||
void dispose() {
|
||||
_authBloc.dispose();
|
||||
_notificationBloc.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -415,6 +427,7 @@ class _EryaoAppState extends State<EryaoApp> {
|
||||
_ensureCreditsLoaded(state.user!.email);
|
||||
_ensureHistoryLoaded(state.user!.email);
|
||||
_refreshProfile(userEmail: state.user!.email);
|
||||
_notificationBloc.handleEvent(RefreshUnreadCount());
|
||||
return HomeScreen(
|
||||
account: state.user!.email,
|
||||
sessionStore: _sessionStore,
|
||||
@@ -423,6 +436,8 @@ class _EryaoAppState extends State<EryaoApp> {
|
||||
historyRecords: _historyRecords,
|
||||
coinBalance: _creditsBalance,
|
||||
divinationApi: _divinationApi,
|
||||
notificationBloc: _notificationBloc,
|
||||
notificationRepository: _notificationRepository,
|
||||
onLocaleChanged: _handleInterfaceLanguageChanged,
|
||||
onProfileSettingsChanged: _saveProfileSettings,
|
||||
onSaveProfile: _saveProfile,
|
||||
|
||||
Reference in New Issue
Block a user