| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- package repository
- import (
- "errors"
- "time"
- "github.com/2930134478/AI-CS/backend/models"
- "gorm.io/gorm"
- )
- // ConversationRepository 封装与会话相关的数据库操作。
- type ConversationRepository struct {
- db *gorm.DB
- }
- // NewConversationRepository 创建会话仓库实例。
- func NewConversationRepository(db *gorm.DB) *ConversationRepository {
- return &ConversationRepository{db: db}
- }
- // FindOpenByVisitorID 查询访客当前未关闭的会话(仅 visitor 类型)。
- func (r *ConversationRepository) FindOpenByVisitorID(visitorID uint) (*models.Conversation, error) {
- var conv models.Conversation
- err := r.db.Where("conversation_type = ? AND visitor_id = ? AND status != ?", "visitor", visitorID, "closed").
- Order("created_at desc").
- First(&conv).Error
- if err != nil {
- return nil, err
- }
- return &conv, nil
- }
- // ListActiveInternalByAgentID 返回某客服的全部未关闭内部对话(知识库测试用)。
- func (r *ConversationRepository) ListActiveInternalByAgentID(agentID uint) ([]models.Conversation, error) {
- var list []models.Conversation
- err := r.db.Where("conversation_type = ? AND agent_id = ? AND status != ?", "internal", agentID, "closed").
- Order("updated_at desc").
- Find(&list).Error
- if err != nil {
- return nil, err
- }
- return list, nil
- }
- // Create 创建新的会话记录。
- func (r *ConversationRepository) Create(conv *models.Conversation) error {
- return r.db.Create(conv).Error
- }
- // UpdateFields 更新会话的指定字段。
- func (r *ConversationRepository) UpdateFields(id uint, values map[string]interface{}) error {
- if len(values) == 0 {
- return nil
- }
- return r.db.Model(&models.Conversation{}).Where("id = ?", id).Updates(values).Error
- }
- // GetByID 根据主键查询会话。
- func (r *ConversationRepository) GetByID(id uint) (*models.Conversation, error) {
- var conv models.Conversation
- if err := r.db.First(&conv, id).Error; err != nil {
- return nil, err
- }
- return &conv, nil
- }
- // ListActive 返回所有未关闭的访客会话(不含 internal)。
- func (r *ConversationRepository) ListActive() ([]models.Conversation, error) {
- var conversations []models.Conversation
- if err := r.db.Where("conversation_type = ? AND status != ?", "visitor", "closed").
- Order("updated_at desc").
- Find(&conversations).Error; err != nil {
- return nil, err
- }
- return conversations, nil
- }
- // ListByTypeAndStatus 返回指定类型的会话列表(支持 open/closed/all)。
- func (r *ConversationRepository) ListByTypeAndStatus(conversationType string, status string) ([]models.Conversation, error) {
- var conversations []models.Conversation
- q := r.db.Where("conversation_type = ?", conversationType)
- switch status {
- case "open":
- q = q.Where("status = ?", "open")
- case "closed":
- q = q.Where("status = ?", "closed")
- case "", "all":
- // no-op
- default:
- return nil, errors.New("invalid status")
- }
- if err := q.Order("updated_at desc").Find(&conversations).Error; err != nil {
- return nil, err
- }
- return conversations, nil
- }
- // ListInternalByAgentIDAndStatus 返回某客服的内部对话(支持 open/closed/all)。
- func (r *ConversationRepository) ListInternalByAgentIDAndStatus(agentID uint, status string) ([]models.Conversation, error) {
- var conversations []models.Conversation
- q := r.db.Where("conversation_type = ? AND agent_id = ?", "internal", agentID)
- switch status {
- case "open":
- q = q.Where("status = ?", "open")
- case "closed":
- q = q.Where("status = ?", "closed")
- case "", "all":
- // no-op
- default:
- return nil, errors.New("invalid status")
- }
- if err := q.Order("updated_at desc").Find(&conversations).Error; err != nil {
- return nil, err
- }
- return conversations, nil
- }
- // ListByIDs 根据多个 ID 批量查询会话。
- func (r *ConversationRepository) ListByIDs(ids []uint) ([]models.Conversation, error) {
- if len(ids) == 0 {
- return []models.Conversation{}, nil
- }
- var conversations []models.Conversation
- if err := r.db.Where("id IN ? AND status != ?", ids, "closed").
- Order("updated_at desc").
- Find(&conversations).Error; err != nil {
- return nil, err
- }
- return conversations, nil
- }
- // SearchByIDOrVisitorLike 根据会话 ID 或访客 ID 进行模糊搜索。
- func (r *ConversationRepository) SearchByIDOrVisitorLike(pattern string) ([]models.Conversation, error) {
- var conversations []models.Conversation
- if err := r.db.Where("CAST(id AS CHAR) LIKE ? OR CAST(visitor_id AS CHAR) LIKE ?", pattern, pattern).
- Find(&conversations).Error; err != nil {
- return nil, err
- }
- return conversations, nil
- }
- // CloseStaleOpenVisitorConversations 关闭长期未更新的 open 访客会话。
- func (r *ConversationRepository) CloseStaleOpenVisitorConversations(olderThan time.Time) (int64, error) {
- result := r.db.Model(&models.Conversation{}).
- Where("conversation_type = ? AND status = ? AND updated_at < ?", "visitor", "open", olderThan).
- Update("status", "closed")
- return result.RowsAffected, result.Error
- }
- // ListVisitorForAgentList 分页查询客服列表可见的访客会话(排除 AI 模式,且需有访客侧消息)。
- func (r *ConversationRepository) ListVisitorForAgentList(status string, offset, limit int) ([]models.Conversation, int64, error) {
- q := r.db.Model(&models.Conversation{}).
- Where("conversation_type = ? AND chat_mode != ?", "visitor", "ai").
- Where("EXISTS (SELECT 1 FROM messages WHERE messages.conversation_id = conversations.id AND messages.sender_is_agent = ?)", false)
- switch status {
- case "open":
- q = q.Where("status = ?", "open")
- case "closed":
- q = q.Where("status = ?", "closed")
- case "", "all":
- default:
- return nil, 0, errors.New("invalid status")
- }
- var total int64
- if err := q.Count(&total).Error; err != nil {
- return nil, 0, err
- }
- var conversations []models.Conversation
- if err := q.Order("updated_at desc").Offset(offset).Limit(limit).Find(&conversations).Error; err != nil {
- return nil, 0, err
- }
- return conversations, total, nil
- }
- func (r *ConversationRepository) AssignAgent(conversationID uint, agentID uint) error {
- result := r.db.Model(&models.Conversation{}).
- Where("id = ?", conversationID).
- Updates(map[string]interface{}{
- "agent_id": agentID,
- })
- if result.Error != nil {
- return result.Error
- }
- if result.RowsAffected == 0 {
- return gorm.ErrRecordNotFound
- }
- return nil
- }
- // UpdateStatus 更新会话状态。
- func (r *ConversationRepository) UpdateStatus(conversationID uint, status string) error {
- if status == "" {
- return errors.New("status cannot be empty")
- }
- return r.db.Model(&models.Conversation{}).
- Where("id = ?", conversationID).
- Update("status", status).Error
- }
|