Files
jiang13-bbs/backend/service/notification.go
freefire 42c395a864 feat: 实时消息与管理端运营能力
新增群聊/私信与公共 WebSocket 总线,站长用户内容档案,并将通知与待审角标改为推送驱动;同步精简管理仪表盘并修复主题换肤 DOM 冲突。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 22:58:16 +08:00

116 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"github.com/freefire/jiang13-bbs/model"
"gorm.io/gorm"
)
// NotificationService 通知服务
type NotificationService struct {
db *gorm.DB
// OnNotifyNew 落库成功后回调(用于 WS 推送红点);可为 nil
OnNotifyNew func(userID uint)
}
func NewNotificationService(db *gorm.DB) *NotificationService {
return &NotificationService{db: db}
}
// Create 创建通知(actorID == userID 时跳过,不通知自己)
func (s *NotificationService) Create(userID, actorID uint, notifType string, postID, commentID uint, content string) {
if userID == 0 || actorID == 0 || userID == actorID {
return
}
// 截断内容预览
if len(content) > 200 {
content = content[:200]
}
n := &model.Notification{
UserID: userID,
ActorID: actorID,
Type: notifType,
PostID: postID,
CommentID: commentID,
Content: content,
IsRead: false,
}
// 通知创建失败不影响主流程,忽略错误
if err := s.db.Create(n).Error; err != nil {
return
}
if s.OnNotifyNew != nil {
s.OnNotifyNew(userID)
}
}
// CreateMention 创建群聊 @ 提醒(PostID=0,用 RoomID/MessageID 关联)。
// 返回创建出的通知 ID(0 表示未创建),供 handler 实时推送。
func (s *NotificationService) CreateMention(userID, actorID, roomID, messageID uint, content string) uint {
if userID == 0 || actorID == 0 || userID == actorID || roomID == 0 {
return 0
}
if runes := []rune(content); len(runes) > 100 {
content = string(runes[:100])
}
n := &model.Notification{
UserID: userID,
ActorID: actorID,
Type: model.NotificationTypeMention,
RoomID: roomID,
MessageID: messageID,
Content: content,
}
if err := s.db.Create(n).Error; err != nil {
return 0
}
if s.OnNotifyNew != nil {
s.OnNotifyNew(userID)
}
return n.ID
}
// List 获取用户通知列表(分页,按时间倒序)
func (s *NotificationService) List(userID uint, page, size int) ([]model.Notification, int64, error) {
if page < 1 {
page = 1
}
if size < 1 || size > 50 {
size = 20
}
query := s.db.Model(&model.Notification{}).Where("user_id = ?", userID)
var total int64
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
var list []model.Notification
offset := (page - 1) * size
if err := query.Order("created_at DESC").Offset(offset).Limit(size).
Preload("Actor").Preload("Post").Preload("Room").Find(&list).Error; err != nil {
return nil, 0, err
}
return list, total, nil
}
// UnreadCount 获取未读通知数
func (s *NotificationService) UnreadCount(userID uint) (int64, error) {
var total int64
err := s.db.Model(&model.Notification{}).Where("user_id = ? AND is_read = ?", userID, false).Count(&total).Error
return total, err
}
// MarkRead 标记单条通知为已读(校验归属)
func (s *NotificationService) MarkRead(id, userID uint) error {
result := s.db.Model(&model.Notification{}).
Where("id = ? AND user_id = ?", id, userID).
Update("is_read", true)
return result.Error
}
// MarkAllRead 标记用户所有通知为已读
func (s *NotificationService) MarkAllRead(userID uint) error {
result := s.db.Model(&model.Notification{}).
Where("user_id = ? AND is_read = ?", userID, false).
Update("is_read", true)
return result.Error
}