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:
qzl
2026-04-10 18:50:08 +08:00
parent 17ef460391
commit 3f3d613d99
28 changed files with 3481 additions and 651 deletions
@@ -0,0 +1,46 @@
import '../../data/apis/notification_api.dart';
import '../../data/models/notification_item.dart';
import '../../data/models/notification_list_result.dart';
abstract class NotificationRepository {
Future<NotificationListResult> listNotifications({
int limit = 20,
String? cursor,
});
Future<int> getUnreadCount();
Future<NotificationItem> markRead({required String notificationId});
Future<int> markAllRead();
}
class NotificationRepositoryImpl implements NotificationRepository {
NotificationRepositoryImpl({required NotificationApi notificationApi})
: _notificationApi = notificationApi;
final NotificationApi _notificationApi;
@override
Future<NotificationListResult> listNotifications({
int limit = 20,
String? cursor,
}) async {
return _notificationApi.listNotifications(limit: limit, cursor: cursor);
}
@override
Future<int> getUnreadCount() async {
return _notificationApi.getUnreadCount();
}
@override
Future<NotificationItem> markRead({required String notificationId}) async {
return _notificationApi.markRead(notificationId: notificationId);
}
@override
Future<int> markAllRead() async {
return _notificationApi.markAllRead();
}
}