feat: 实时消息与管理端运营能力

新增群聊/私信与公共 WebSocket 总线,站长用户内容档案,并将通知与待审角标改为推送驱动;同步精简管理仪表盘并修复主题换肤 DOM 冲突。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-15 22:58:16 +08:00
parent 29db9ae9b5
commit 42c395a864
55 changed files with 7607 additions and 346 deletions

View File

@@ -8,6 +8,8 @@ import (
// NotificationService 通知服务
type NotificationService struct {
db *gorm.DB
// OnNotifyNew 落库成功后回调(用于 WS 推送红点);可为 nil
OnNotifyNew func(userID uint)
}
func NewNotificationService(db *gorm.DB) *NotificationService {
@@ -33,7 +35,38 @@ func (s *NotificationService) Create(userID, actorID uint, notifType string, pos
IsRead: false,
}
// 通知创建失败不影响主流程,忽略错误
_ = s.db.Create(n).Error
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 获取用户通知列表(分页,按时间倒序)
@@ -52,7 +85,7 @@ func (s *NotificationService) List(userID uint, page, size int) ([]model.Notific
var list []model.Notification
offset := (page - 1) * size
if err := query.Order("created_at DESC").Offset(offset).Limit(size).
Preload("Actor").Preload("Post").Find(&list).Error; err != nil {
Preload("Actor").Preload("Post").Preload("Room").Find(&list).Error; err != nil {
return nil, 0, err
}
return list, total, nil