拆分大型 Repository 文件职责
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
"hfb_sys/backend/internal/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (r *Repository) ListConversations(ctx context.Context, principal Principal, page, pageSize int) (*PaginatedResult, error) {
|
||||
page, pageSize = normalizePagination(page, pageSize)
|
||||
db := r.db.WithContext(ctx)
|
||||
var total int64
|
||||
countDB := db.Table("chat_conversations AS c").
|
||||
Joins("JOIN chat_participants AS cp ON cp.conversation_id = c.id").
|
||||
Where("cp.participant_type = ? AND cp.participant_id = ?", principal.Type, principal.ID)
|
||||
if err := countDB.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rows []conversationRow
|
||||
offset := (page - 1) * pageSize
|
||||
err := r.conversationQuery(ctx, principal).
|
||||
Order("COALESCE(c.last_message_at, c.created_at) DESC, c.id DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]ConversationDTO, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
items = append(items, row.toDTO(nil))
|
||||
}
|
||||
return &PaginatedResult{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
func (r *Repository) FindConversation(ctx context.Context, principal Principal, id uint64) (*ConversationDTO, error) {
|
||||
db := r.db.WithContext(ctx)
|
||||
// 管理员可以查看任意会话,无需是 participant
|
||||
if principal.Type == "admin" {
|
||||
var conversation model.ChatConversation
|
||||
if err := db.First(&conversation, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrConversationNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
participants, err := r.participants(ctx, conversation.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := ConversationDTO{
|
||||
ID: conversation.ID,
|
||||
OrderID: conversation.OrderID,
|
||||
Type: conversation.Type,
|
||||
Title: conversation.Title,
|
||||
Status: conversation.Status,
|
||||
Role: "admin", // 管理员角色
|
||||
Participants: participants,
|
||||
LastMessageID: conversation.LastMessageID,
|
||||
LastMessagePreview: conversation.LastMessagePreview,
|
||||
LastMessageAt: conversation.LastMessageAt,
|
||||
UnreadCount: 0, // 管理员不计未读
|
||||
CreatedAt: conversation.CreatedAt,
|
||||
UpdatedAt: conversation.UpdatedAt,
|
||||
}
|
||||
return &dto, nil
|
||||
}
|
||||
|
||||
// 普通用户需要是 participant
|
||||
var row conversationRow
|
||||
err := r.conversationQuery(ctx, principal).Where("c.id = ?", id).First(&row).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrConversationNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
participants, err := r.participants(ctx, row.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := row.toDTO(participants)
|
||||
return &dto, nil
|
||||
}
|
||||
func (r *Repository) FindOrderConversation(ctx context.Context, userID uint64, orderID uint64) (*ConversationDTO, error) {
|
||||
var row conversationRow
|
||||
principal := Principal{Type: "user", ID: userID}
|
||||
err := r.conversationQuery(ctx, principal).Where("c.order_id = ?", orderID).First(&row).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrConversationNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
participants, err := r.participants(ctx, row.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := row.toDTO(participants)
|
||||
return &dto, nil
|
||||
}
|
||||
func (r *Repository) EnsureSupportConversation(ctx context.Context, userID uint64) (*ConversationDTO, error) {
|
||||
var conversationID uint64
|
||||
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var existing model.ChatConversation
|
||||
err := tx.Table("chat_conversations AS c").
|
||||
Select("c.*").
|
||||
Joins("JOIN chat_participants AS cp ON cp.conversation_id = c.id").
|
||||
Where("c.type = ? AND cp.participant_type = ? AND cp.participant_id = ?", "general_support", "user", userID).
|
||||
Order("c.id ASC").
|
||||
Limit(1).
|
||||
Find(&existing).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing.ID > 0 {
|
||||
conversationID = existing.ID
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
conversation := model.ChatConversation{
|
||||
Type: "general_support",
|
||||
Title: "平台客服",
|
||||
Status: "active",
|
||||
}
|
||||
if err := tx.Create(&conversation).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
participants := []model.ChatParticipant{
|
||||
{
|
||||
ConversationID: conversation.ID,
|
||||
ParticipantType: "user",
|
||||
ParticipantID: userID,
|
||||
Role: "customer",
|
||||
JoinedAt: now,
|
||||
},
|
||||
}
|
||||
if supportID := defaultSupportAdminID(tx); supportID > 0 {
|
||||
participants = append(participants, model.ChatParticipant{
|
||||
ConversationID: conversation.ID,
|
||||
ParticipantType: "admin",
|
||||
ParticipantID: supportID,
|
||||
Role: "support",
|
||||
JoinedAt: now,
|
||||
})
|
||||
}
|
||||
for _, participant := range participants {
|
||||
if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&participant).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
message := model.ChatMessage{
|
||||
ConversationID: conversation.ID,
|
||||
SenderType: "system",
|
||||
SenderRole: "system",
|
||||
ContentType: "system",
|
||||
Content: "您好,客服会尽快回复,请直接描述您遇到的问题。",
|
||||
AttachmentURLS: emptyJSONList(),
|
||||
}
|
||||
if err := tx.Create(&message).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
conversation.LastMessageID = &message.ID
|
||||
conversation.LastMessagePreview = truncatePreview(message.Content)
|
||||
conversation.LastMessageAt = &message.CreatedAt
|
||||
if err := tx.Save(&conversation).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
conversationID = conversation.ID
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item, err := r.FindConversation(ctx, Principal{Type: "user", ID: userID}, conversationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.NotifyNewConversation(conversationID)
|
||||
return item, nil
|
||||
}
|
||||
Reference in New Issue
Block a user