优化站内信模块
This commit is contained in:
@@ -0,0 +1,399 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
"server/models"
|
||||
)
|
||||
|
||||
// GetSiteReminderConfig 获取站内信配置(只读首条记录,不存在则初始化默认值)
|
||||
func GetSiteReminderConfig() (models.SystemSiteReminder, error) {
|
||||
var row models.SystemSiteReminder
|
||||
err := models.Orm.QueryTable(new(models.SystemSiteReminder)).OrderBy("id").Limit(1).One(&row)
|
||||
if err == orm.ErrNoRows {
|
||||
// 默认配置
|
||||
now := time.Now()
|
||||
row = models.SystemSiteReminder{
|
||||
RetentionDays: 30,
|
||||
AutoRead: 0,
|
||||
CreateTime: &now,
|
||||
UpdateTime: &now,
|
||||
}
|
||||
_, err = models.Orm.Insert(&row)
|
||||
if err != nil {
|
||||
return row, err
|
||||
}
|
||||
return row, nil
|
||||
}
|
||||
return row, err
|
||||
}
|
||||
|
||||
// SaveSiteReminderConfig 保存/更新配置
|
||||
func SaveSiteReminderConfig(retentionDays int, autoRead int8) error {
|
||||
if retentionDays <= 0 {
|
||||
retentionDays = 30
|
||||
}
|
||||
cfg, err := GetSiteReminderConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
now := time.Now()
|
||||
cfg.RetentionDays = retentionDays
|
||||
cfg.AutoRead = autoRead
|
||||
cfg.UpdateTime = &now
|
||||
|
||||
_, err = models.Orm.Update(&cfg, "RetentionDays", "AutoRead", "UpdateTime")
|
||||
return err
|
||||
}
|
||||
|
||||
// SendSiteReminder 发送站内信
|
||||
// targetType: platform (平台端), tenant_all (管理端所有用户), role (平台角色), tenant (特定租户)
|
||||
func SendSiteReminder(title, content string, senderID uint64, senderType string, targetType string, targetRoleID uint64, targetTenantID uint64) error {
|
||||
var receiverIDs []uint64
|
||||
var receiverType string
|
||||
|
||||
switch targetType {
|
||||
case "platform":
|
||||
receiverType = "platform"
|
||||
var list []models.AdminUser
|
||||
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询平台用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
case "tenant_all":
|
||||
receiverType = "tenant"
|
||||
var list []models.SystemTenantUser
|
||||
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询租户用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
case "role":
|
||||
receiverType = "platform"
|
||||
var list []models.AdminUser
|
||||
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("role_id", targetRoleID).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("根据角色查询用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
case "tenant":
|
||||
receiverType = "tenant"
|
||||
var list []models.SystemTenantUser
|
||||
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("tid", targetTenantID).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("根据租户查询用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("未知的发送目标类型: %s", targetType)
|
||||
}
|
||||
|
||||
if len(receiverIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
batchID := fmt.Sprintf("%d_%d", now.UnixNano(), senderID)
|
||||
var reminders []models.SystemReminderList
|
||||
for _, rid := range receiverIDs {
|
||||
reminders = append(reminders, models.SystemReminderList{
|
||||
Title: title,
|
||||
Content: content,
|
||||
SenderID: senderID,
|
||||
SenderType: senderType,
|
||||
ReceiverID: rid,
|
||||
ReceiverType: receiverType,
|
||||
IsRead: 0,
|
||||
CreateTime: &now,
|
||||
BatchID: batchID,
|
||||
TargetType: targetType,
|
||||
TargetRoleID: targetRoleID,
|
||||
TargetTenantID: targetTenantID,
|
||||
})
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
_, err := models.Orm.InsertMulti(100, reminders)
|
||||
return err
|
||||
}
|
||||
|
||||
// ListReminders 列表查询
|
||||
func ListReminders(receiverID uint64, receiverType string, page, pageSize int, isRead *int8) ([]models.SystemReminderList, int64, error) {
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
var list []models.SystemReminderList
|
||||
qs := models.Orm.QueryTable(new(models.SystemReminderList)).
|
||||
Filter("receiver_id", receiverID).
|
||||
Filter("receiver_type", receiverType).
|
||||
Filter("delete_time__isnull", true)
|
||||
|
||||
if isRead != nil {
|
||||
qs = qs.Filter("is_read", *isRead)
|
||||
}
|
||||
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
_, err = qs.OrderBy("-create_time", "-id").Limit(pageSize, offset).All(&list)
|
||||
return list, total, err
|
||||
}
|
||||
|
||||
// MarkReminderRead 标记单条已读
|
||||
func MarkReminderRead(id uint64, receiverID uint64, receiverType string) error {
|
||||
now := time.Now()
|
||||
_, err := models.Orm.QueryTable(new(models.SystemReminderList)).
|
||||
Filter("id", id).
|
||||
Filter("receiver_id", receiverID).
|
||||
Filter("receiver_type", receiverType).
|
||||
Update(map[string]interface{}{
|
||||
"is_read": 1,
|
||||
"read_time": &now,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// MarkAllRemindersRead 一键全部已读
|
||||
func MarkAllRemindersRead(receiverID uint64, receiverType string) error {
|
||||
now := time.Now()
|
||||
_, err := models.Orm.QueryTable(new(models.SystemReminderList)).
|
||||
Filter("receiver_id", receiverID).
|
||||
Filter("receiver_type", receiverType).
|
||||
Filter("is_read", 0).
|
||||
Update(map[string]interface{}{
|
||||
"is_read": 1,
|
||||
"read_time": &now,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteReminder 删除消息
|
||||
func DeleteReminder(id uint64, receiverID uint64, receiverType string) error {
|
||||
now := time.Now()
|
||||
_, err := models.Orm.QueryTable(new(models.SystemReminderList)).
|
||||
Filter("id", id).
|
||||
Filter("receiver_id", receiverID).
|
||||
Filter("receiver_type", receiverType).
|
||||
Update(map[string]interface{}{
|
||||
"delete_time": &now,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// AutoCleanExpiredReminders 自动清理过期站内信
|
||||
func AutoCleanExpiredReminders() error {
|
||||
cfg, err := GetSiteReminderConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cfg.RetentionDays <= 0 {
|
||||
return nil
|
||||
}
|
||||
expireTime := time.Now().AddDate(0, 0, -cfg.RetentionDays)
|
||||
_, err = models.Orm.QueryTable(new(models.SystemReminderList)).
|
||||
Filter("create_time__lt", expireTime).
|
||||
Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
// ListSentReminders 获取已发送的消息列表(按 batch_id 分组)
|
||||
func ListSentReminders(senderID uint64, page, pageSize int) ([]models.SystemReminderList, int64, error) {
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
var total int64
|
||||
err := models.Orm.Raw("SELECT COUNT(DISTINCT batch_id) FROM yz_system_reminderlist WHERE sender_id = ? AND delete_time IS NULL", senderID).QueryRow(&total)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var list []models.SystemReminderList
|
||||
_, err = models.Orm.Raw("SELECT * FROM yz_system_reminderlist WHERE id IN (SELECT MIN(id) FROM yz_system_reminderlist WHERE sender_id = ? AND delete_time IS NULL GROUP BY batch_id) ORDER BY id DESC LIMIT ? OFFSET ?", senderID, pageSize, offset).QueryRows(&list)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
// UpdateSentReminder 更新已发出的消息(更新该批次下所有接收者的消息,支持修改目标接收群体)
|
||||
func UpdateSentReminder(batchID string, title, content, targetType string, targetRoleID, targetTenantID uint64) error {
|
||||
// 1. 获取当前发送者ID (从该批次中任意一条记录中获取)
|
||||
var firstRecord models.SystemReminderList
|
||||
err := models.Orm.QueryTable(new(models.SystemReminderList)).Filter("batch_id", batchID).Limit(1).One(&firstRecord)
|
||||
if err != nil {
|
||||
return fmt.Errorf("找不到该批次的站内信记录: %w", err)
|
||||
}
|
||||
senderID := firstRecord.SenderID
|
||||
senderType := firstRecord.SenderType
|
||||
|
||||
// 2. 根据新的目标接收群体获取接收人列表
|
||||
var receiverIDs []uint64
|
||||
var receiverType string
|
||||
|
||||
switch targetType {
|
||||
case "platform":
|
||||
receiverType = "platform"
|
||||
var list []models.AdminUser
|
||||
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询平台用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
case "tenant_all":
|
||||
receiverType = "tenant"
|
||||
var list []models.SystemTenantUser
|
||||
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询租户用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
case "role":
|
||||
receiverType = "platform"
|
||||
var list []models.AdminUser
|
||||
_, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("status", 1).Filter("role_id", targetRoleID).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("根据角色查询用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
case "tenant":
|
||||
receiverType = "tenant"
|
||||
var list []models.SystemTenantUser
|
||||
_, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("status", 1).Filter("tid", targetTenantID).Filter("delete_time__isnull", true).All(&list, "id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("根据租户查询用户失败: %w", err)
|
||||
}
|
||||
for _, u := range list {
|
||||
receiverIDs = append(receiverIDs, u.ID)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("未知的发送目标类型: %s", targetType)
|
||||
}
|
||||
|
||||
// 3. 获取该批次中现有的所有记录 (包括已删除的)
|
||||
var existingRecords []models.SystemReminderList
|
||||
_, err = models.Orm.QueryTable(new(models.SystemReminderList)).Filter("batch_id", batchID).All(&existingRecords)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取现有记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 建立 map 快速查找,Key 为 "receiverType_receiverID"
|
||||
existingMap := make(map[string]*models.SystemReminderList)
|
||||
for i := range existingRecords {
|
||||
key := fmt.Sprintf("%s_%d", existingRecords[i].ReceiverType, existingRecords[i].ReceiverID)
|
||||
existingMap[key] = &existingRecords[i]
|
||||
}
|
||||
|
||||
newReceiverMap := make(map[string]bool)
|
||||
for _, rid := range receiverIDs {
|
||||
key := fmt.Sprintf("%s_%d", receiverType, rid)
|
||||
newReceiverMap[key] = true
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
// 事务处理
|
||||
err = models.Orm.DoTx(func(c context.Context, txOrm orm.TxOrmer) error {
|
||||
// A. 对于已经不在新接收者列表中的用户,软删除
|
||||
for key, rec := range existingMap {
|
||||
if !newReceiverMap[key] {
|
||||
if rec.DeleteTime == nil {
|
||||
rec.DeleteTime = &now
|
||||
if _, e := txOrm.Update(rec, "DeleteTime"); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// B. 对于仍然在新接收者列表中的用户,更新标题、内容、以及 target 信息;如果原来被删除了,清除 delete_time
|
||||
var newInserts []models.SystemReminderList
|
||||
for _, rid := range receiverIDs {
|
||||
key := fmt.Sprintf("%s_%d", receiverType, rid)
|
||||
if rec, exists := existingMap[key]; exists {
|
||||
rec.Title = title
|
||||
rec.Content = content
|
||||
rec.TargetType = targetType
|
||||
rec.TargetRoleID = targetRoleID
|
||||
rec.TargetTenantID = targetTenantID
|
||||
|
||||
cols := []string{"Title", "Content", "TargetType", "TargetRoleID", "TargetTenantID"}
|
||||
if rec.DeleteTime != nil {
|
||||
rec.DeleteTime = nil
|
||||
rec.IsRead = 0
|
||||
rec.ReadTime = nil
|
||||
cols = append(cols, "DeleteTime", "IsRead", "ReadTime")
|
||||
}
|
||||
if _, e := txOrm.Update(rec, cols...); e != nil {
|
||||
return e
|
||||
}
|
||||
} else {
|
||||
// C. 对于新增加的接收者,插入新记录
|
||||
newInserts = append(newInserts, models.SystemReminderList{
|
||||
Title: title,
|
||||
Content: content,
|
||||
SenderID: senderID,
|
||||
SenderType: senderType,
|
||||
ReceiverID: rid,
|
||||
ReceiverType: receiverType,
|
||||
IsRead: 0,
|
||||
CreateTime: &now,
|
||||
BatchID: batchID,
|
||||
TargetType: targetType,
|
||||
TargetRoleID: targetRoleID,
|
||||
TargetTenantID: targetTenantID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(newInserts) > 0 {
|
||||
if _, e := txOrm.InsertMulti(100, newInserts); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteSentReminderBatch 删除已发送消息(删除该批次下所有记录)
|
||||
func DeleteSentReminderBatch(batchID string) error {
|
||||
now := time.Now()
|
||||
_, err := models.Orm.QueryTable(new(models.SystemReminderList)).
|
||||
Filter("batch_id", batchID).
|
||||
Update(map[string]interface{}{
|
||||
"delete_time": &now,
|
||||
})
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user