二维码自动补发

This commit is contained in:
yml2213
2026-06-19 17:08:57 +08:00
parent 5ff1ea40b0
commit 076ac6098e
7 changed files with 303 additions and 43 deletions
+129 -28
View File
@@ -8,6 +8,7 @@ import (
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/modules/chathub"
)
// QrCodeStatus 二维码状态常量
@@ -83,24 +84,35 @@ type QrCodeOCRConfig struct {
// CreateQrCode 创建二维码
func (r *Repository) CreateQrCode(ctx context.Context, adminID uint64, req CreateQrCodeRequest) (*model.ChatQrCode, error) {
qrcode := model.ChatQrCode{
ImageURL: req.ImageURL,
GroupName: req.GroupName,
Status: QrCodeStatusUnused,
CreatedBy: adminID,
Note: req.Note,
ExpiresAt: req.ExpiresAt,
}
var qrcode model.ChatQrCode
var deliveredMessages []model.ChatMessage
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
qrcode = model.ChatQrCode{
ImageURL: req.ImageURL,
GroupName: req.GroupName,
Status: QrCodeStatusUnused,
CreatedBy: adminID,
Note: req.Note,
ExpiresAt: req.ExpiresAt,
}
// 如果未指定过期时间,默认7天后过期
if qrcode.ExpiresAt == nil {
expires := time.Now().Add(7 * 24 * time.Hour)
qrcode.ExpiresAt = &expires
}
// 如果未指定过期时间,默认7天后过期
if qrcode.ExpiresAt == nil {
expires := time.Now().Add(7 * 24 * time.Hour)
qrcode.ExpiresAt = &expires
}
if err := r.db.WithContext(ctx).Create(&qrcode).Error; err != nil {
if err := tx.Create(&qrcode).Error; err != nil {
return err
}
var err error
deliveredMessages, err = deliverPendingQrCodes(tx)
return err
})
if err != nil {
return nil, err
}
r.notifyDeliveredQrCodeMessages(deliveredMessages)
return &qrcode, nil
}
@@ -108,26 +120,36 @@ func (r *Repository) CreateQrCode(ctx context.Context, adminID uint64, req Creat
// BatchCreateQrCode 批量创建二维码
func (r *Repository) BatchCreateQrCode(ctx context.Context, adminID uint64, req BatchCreateQrCodeRequest) ([]model.ChatQrCode, error) {
var qrcodes []model.ChatQrCode
var deliveredMessages []model.ChatMessage
defaultExpires := time.Now().Add(7 * 24 * time.Hour)
for _, item := range req.Items {
qr := model.ChatQrCode{
ImageURL: item.ImageURL,
GroupName: item.GroupName,
Status: QrCodeStatusUnused,
CreatedBy: adminID,
Note: item.Note,
ExpiresAt: item.ExpiresAt,
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
for _, item := range req.Items {
qr := model.ChatQrCode{
ImageURL: item.ImageURL,
GroupName: item.GroupName,
Status: QrCodeStatusUnused,
CreatedBy: adminID,
Note: item.Note,
ExpiresAt: item.ExpiresAt,
}
if qr.ExpiresAt == nil {
qr.ExpiresAt = &defaultExpires
}
qrcodes = append(qrcodes, qr)
}
if qr.ExpiresAt == nil {
qr.ExpiresAt = &defaultExpires
}
qrcodes = append(qrcodes, qr)
}
if err := r.db.WithContext(ctx).Create(&qrcodes).Error; err != nil {
if err := tx.Create(&qrcodes).Error; err != nil {
return err
}
var err error
deliveredMessages, err = deliverPendingQrCodes(tx)
return err
})
if err != nil {
return nil, err
}
r.notifyDeliveredQrCodeMessages(deliveredMessages)
return qrcodes, nil
}
@@ -342,3 +364,82 @@ func (r *Repository) markQrCodeAsUsed(tx *gorm.DB, qrcodeID uint64, conversation
"used_at": now,
}).Error
}
func deliverPendingQrCodes(tx *gorm.DB) ([]model.ChatMessage, error) {
deliveredMessages := make([]model.ChatMessage, 0)
for {
var task model.ChatQrCodeDeliveryTask
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
Where("status = ?", "pending").
Order("created_at ASC, id ASC").
First(&task).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return deliveredMessages, nil
}
return nil, err
}
qrcode, err := fetchUnusedQrCode(tx)
if err != nil {
return nil, err
}
if qrcode == nil {
return deliveredMessages, nil
}
if err := markQrCodeAsUsed(tx, qrcode.ID, task.ConversationID); err != nil {
return nil, err
}
message, err := sendQrCodeImage(tx, task.ConversationID, qrcode.ImageURL)
if err != nil {
now := time.Now()
if updateErr := tx.Model(&task).Updates(map[string]interface{}{
"status": "failed",
"qrcode_id": qrcode.ID,
"error_message": err.Error(),
"updated_at": now,
}).Error; updateErr != nil {
return nil, updateErr
}
continue
}
deliveredMessages = append(deliveredMessages, *message)
now := time.Now()
if err := tx.Model(&task).Updates(map[string]interface{}{
"status": "sent",
"qrcode_id": qrcode.ID,
"error_message": "",
"sent_at": now,
"updated_at": now,
}).Error; err != nil {
return nil, err
}
}
}
func (r *Repository) notifyDeliveredQrCodeMessages(messages []model.ChatMessage) {
if r.hub == nil {
return
}
for _, msg := range messages {
event := &chathub.ChatEvent{
Type: "new_message",
ConversationID: msg.ConversationID,
Message: &chathub.MessageData{
ID: msg.ID,
ConversationID: msg.ConversationID,
SenderType: msg.SenderType,
SenderID: msg.SenderID,
SenderRole: msg.SenderRole,
SenderName: "系统",
ContentType: msg.ContentType,
Content: msg.Content,
AttachmentURLS: decodeStringList(msg.AttachmentURLS),
CreatedAt: msg.CreatedAt.Format(time.RFC3339),
},
}
r.hub.NotifyConversation(msg.ConversationID, event)
r.hub.NotifyAllAdmins(event)
}
}