refactor: update Conversation model to include CustomerName, adjust related logic and queries

This commit is contained in:
mlogclub
2026-04-27 19:27:24 +08:00
parent 3a9bc4914a
commit d713bd5158
7 changed files with 108 additions and 45 deletions
+1 -11
View File
@@ -19,7 +19,7 @@ func BuildConversation(item *models.Conversation) response.ConversationResponse
AIAgentID: item.AIAgentID, AIAgentID: item.AIAgentID,
ChannelID: item.ChannelID, ChannelID: item.ChannelID,
CustomerID: item.CustomerID, CustomerID: item.CustomerID,
CustomerName: buildConversationCustomerName(item.CustomerID), CustomerName: item.CustomerName,
Status: item.Status, Status: item.Status,
ServiceMode: item.ServiceMode, ServiceMode: item.ServiceMode,
Priority: item.Priority, Priority: item.Priority,
@@ -62,16 +62,6 @@ func BuildConversation(item *models.Conversation) response.ConversationResponse
return ret return ret
} }
func buildConversationCustomerName(customerID int64) string {
if customerID <= 0 {
return ""
}
if customer := services.CustomerService.Get(customerID); customer != nil {
return strings.TrimSpace(customer.Name)
}
return ""
}
func BuildParticipantResponses(conversationID int64) []response.ConversationParticipantResponse { func BuildParticipantResponses(conversationID int64) []response.ConversationParticipantResponse {
list := services.ConversationParticipantService.Find(sqls.NewCnd().Eq("conversation_id", conversationID).Asc("id")) list := services.ConversationParticipantService.Find(sqls.NewCnd().Eq("conversation_id", conversationID).Asc("id"))
if len(list) == 0 { if len(list) == 0 {
@@ -36,7 +36,7 @@ func (c *ConversationController) AnyList() *web.JsonResult {
if keyword, _ := params.Get(c.Ctx, "keyword"); strs.IsNotBlank(keyword) { if keyword, _ := params.Get(c.Ctx, "keyword"); strs.IsNotBlank(keyword) {
keywordLike := "%" + strings.TrimSpace(keyword) + "%" keywordLike := "%" + strings.TrimSpace(keyword) + "%"
cnd.Where("last_message_summary LIKE ? OR customer_id IN (SELECT id FROM t_customer WHERE name LIKE ?)", keywordLike, keywordLike) cnd.Where("customer_name LIKE ? OR last_message_summary LIKE ?", keywordLike, keywordLike)
} }
// 标签搜索 // 标签搜索
@@ -0,0 +1,24 @@
package migration
import (
"cs-agent/internal/models"
"github.com/mlogclub/simple/sqls"
)
func init() {
register(6, "backfill conversation customer name", func() error {
db := sqls.DB()
if !db.Migrator().HasColumn(&models.Conversation{}, "customer_name") {
return nil
}
return db.Exec(`
UPDATE t_conversation
SET customer_name = (
SELECT name FROM t_customer WHERE t_customer.id = t_conversation.customer_id
)
WHERE customer_id > 0
AND (customer_name = '' OR customer_name IS NULL)
`).Error
})
}
+1
View File
@@ -327,6 +327,7 @@ type Conversation struct {
AIAgentID int64 `gorm:"type:bigint;not null;default:0;index"` // AIAgentID 为当前会话绑定的 AI Agent ID。 AIAgentID int64 `gorm:"type:bigint;not null;default:0;index"` // AIAgentID 为当前会话绑定的 AI Agent ID。
ChannelID int64 `gorm:"type:bigint;not null;default:0;index"` // ChannelID 为该会话来源接入渠道ID。 ChannelID int64 `gorm:"type:bigint;not null;default:0;index"` // ChannelID 为该会话来源接入渠道ID。
CustomerID int64 `gorm:"type:bigint;not null;default:0;index"` // CustomerID 为会话所属客户 ID。 CustomerID int64 `gorm:"type:bigint;not null;default:0;index"` // CustomerID 为会话所属客户 ID。
CustomerName string `gorm:"type:varchar(100);not null;default:'';index"` // CustomerName 为客户名称冗余字段,用于列表展示和搜索。
Status enums.IMConversationStatus `gorm:"type:int;not null;default:1;index"` // Status 为会话状态,如待接入、处理中、已关闭。 Status enums.IMConversationStatus `gorm:"type:int;not null;default:1;index"` // Status 为会话状态,如待接入、处理中、已关闭。
ServiceMode enums.IMConversationServiceMode `gorm:"type:int;not null;default:3;index"` // ServiceMode 为服务模式,如仅AI、仅人工、AI优先人工接管。 ServiceMode enums.IMConversationServiceMode `gorm:"type:int;not null;default:3;index"` // ServiceMode 为服务模式,如仅AI、仅人工、AI优先人工接管。
Priority int `gorm:"type:int;not null;default:0;index"` // Priority 为会话优先级。 Priority int `gorm:"type:int;not null;default:0;index"` // Priority 为会话优先级。
@@ -91,6 +91,11 @@ func (r *conversationRepository) Updates(db *gorm.DB, id int64, columns map[stri
return return
} }
func (r *conversationRepository) UpdatesByCustomerID(db *gorm.DB, customerID int64, columns map[string]interface{}) (err error) {
err = db.Model(&models.Conversation{}).Where("customer_id = ?", customerID).Updates(columns).Error
return
}
func (r *conversationRepository) UpdateColumn(db *gorm.DB, id int64, name string, value interface{}) (err error) { func (r *conversationRepository) UpdateColumn(db *gorm.DB, id int64, name string, value interface{}) (err error) {
err = db.Model(&models.Conversation{}).Where("id = ?", id).UpdateColumn(name, value).Error err = db.Model(&models.Conversation{}).Where("id = ?", id).UpdateColumn(name, value).Error
return return
+21 -2
View File
@@ -59,7 +59,7 @@ func (s *conversationService) ListConversations(userID int64, filter request.Age
if strs.IsNotBlank(keyword) { if strs.IsNotBlank(keyword) {
keyword = strings.TrimSpace(keyword) keyword = strings.TrimSpace(keyword)
keywordLike := "%" + keyword + "%" keywordLike := "%" + keyword + "%"
cnd.Where("last_message_summary LIKE ? OR customer_id IN (SELECT id FROM t_customer WHERE name LIKE ?)", keywordLike, keywordLike) cnd.Where("customer_name LIKE ? OR last_message_summary LIKE ?", keywordLike, keywordLike)
} }
switch filter { switch filter {
@@ -113,8 +113,18 @@ func (s *conversationService) Create(externalInfo openidentity.ExternalInfo, cha
if err != nil { if err != nil {
return err return err
} }
customerName := s.getCustomerName(ctx.Tx, customerID)
if existing := s.getLatestNotFinishedByCustomerID(ctx.Tx, customerID); existing != nil { if existing := s.getLatestNotFinishedByCustomerID(ctx.Tx, customerID); existing != nil {
conversation = existing conversation = existing
if customerName != "" && existing.CustomerName != customerName {
if err := repositories.ConversationRepository.Updates(ctx.Tx, existing.ID, map[string]any{
"customer_name": customerName,
"updated_at": time.Now(),
}); err != nil {
return err
}
conversation.CustomerName = customerName
}
return nil return nil
} }
created = true created = true
@@ -123,6 +133,7 @@ func (s *conversationService) Create(externalInfo openidentity.ExternalInfo, cha
AIAgentID: aiAgentID, AIAgentID: aiAgentID,
ChannelID: channelID, ChannelID: channelID,
CustomerID: customerID, CustomerID: customerID,
CustomerName: customerName,
Status: s.resolveInitialStatus(aiAgent.ServiceMode), Status: s.resolveInitialStatus(aiAgent.ServiceMode),
ServiceMode: aiAgent.ServiceMode, ServiceMode: aiAgent.ServiceMode,
Priority: 0, Priority: 0,
@@ -662,7 +673,14 @@ func (s *conversationService) BuildConversationSummary(conversation *models.Conv
if strings.TrimSpace(conversation.LastMessageSummary) != "" { if strings.TrimSpace(conversation.LastMessageSummary) != "" {
return conversation.LastMessageSummary return conversation.LastMessageSummary
} }
if customer := CustomerService.Get(conversation.CustomerID); customer != nil { return strings.TrimSpace(conversation.CustomerName)
}
func (s *conversationService) getCustomerName(db *gorm.DB, customerID int64) string {
if customerID <= 0 {
return ""
}
if customer := repositories.CustomerRepository.Get(db, customerID); customer != nil {
return strings.TrimSpace(customer.Name) return strings.TrimSpace(customer.Name)
} }
return "" return ""
@@ -739,6 +757,7 @@ func (s *conversationService) LinkConversationCustomer(conversationID, customerI
now := time.Now() now := time.Now()
return repositories.ConversationRepository.Updates(ctx.Tx, conversationID, map[string]any{ return repositories.ConversationRepository.Updates(ctx.Tx, conversationID, map[string]any{
"customer_id": customerID, "customer_id": customerID,
"customer_name": strings.TrimSpace(cust.Name),
"update_user_id": operator.UserID, "update_user_id": operator.UserID,
"update_user_name": operator.Username, "update_user_name": operator.Username,
"updated_at": now, "updated_at": now,
+26 -2
View File
@@ -218,7 +218,9 @@ func (s *customerService) UpdateCustomer(req request.UpdateCustomerRequest, oper
} }
} }
return repositories.CustomerRepository.Updates(sqls.DB(), req.ID, map[string]any{ return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
now := time.Now()
if err := repositories.CustomerRepository.Updates(ctx.Tx, req.ID, map[string]any{
"name": name, "name": name,
"gender": req.Gender, "gender": req.Gender,
"company_id": req.CompanyID, "company_id": req.CompanyID,
@@ -227,7 +229,11 @@ func (s *customerService) UpdateCustomer(req request.UpdateCustomerRequest, oper
"remark": strings.TrimSpace(req.Remark), "remark": strings.TrimSpace(req.Remark),
"update_user_id": operator.UserID, "update_user_id": operator.UserID,
"update_user_name": operator.Username, "update_user_name": operator.Username,
"updated_at": time.Now(), "updated_at": now,
}); err != nil {
return err
}
return s.syncConversationCustomerName(ctx.Tx, req.ID, name, operator, now)
}) })
} }
@@ -244,6 +250,21 @@ func (s *customerService) DeleteCustomer(id int64, operator dto.AuthPrincipal) e
}) })
} }
func (s *customerService) syncConversationCustomerName(db *gorm.DB, customerID int64, name string, operator *dto.AuthPrincipal, now time.Time) error {
if customerID <= 0 {
return nil
}
updates := map[string]any{
"customer_name": strings.TrimSpace(name),
"updated_at": now,
}
if operator != nil {
updates["update_user_id"] = operator.UserID
updates["update_user_name"] = operator.Username
}
return repositories.ConversationRepository.UpdatesByCustomerID(db, customerID, updates)
}
func (s *customerService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error { func (s *customerService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error {
if operator == nil { if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期") return errorsx.Unauthorized("未登录或登录已过期")
@@ -316,6 +337,9 @@ func (s *customerService) SaveCustomerProfile(req request.SaveCustomerProfileReq
}); err != nil { }); err != nil {
return err return err
} }
if err := s.syncConversationCustomerName(ctx.Tx, customerID, name, operator, now); err != nil {
return err
}
out = repositories.CustomerRepository.Get(ctx.Tx, customerID) out = repositories.CustomerRepository.Get(ctx.Tx, customerID)
} }
return CustomerContactService.ReplaceAllForCustomerInTx(ctx, customerID, req.Contacts, operator) return CustomerContactService.ReplaceAllForCustomerInTx(ctx, customerID, req.Contacts, operator)