Init
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/utils"
|
||||
"cs-agent/internal/services"
|
||||
)
|
||||
|
||||
func BuildAgentProfileList(items []models.AgentProfile) []response.AgentProfileResponse {
|
||||
if len(items) == 0 {
|
||||
return []response.AgentProfileResponse{}
|
||||
}
|
||||
|
||||
userIDs := make([]int64, 0, len(items))
|
||||
teamIDs := make([]int64, 0, len(items))
|
||||
for _, item := range items {
|
||||
if item.UserID > 0 {
|
||||
userIDs = append(userIDs, item.UserID)
|
||||
}
|
||||
if item.TeamID > 0 {
|
||||
teamIDs = append(teamIDs, item.TeamID)
|
||||
}
|
||||
}
|
||||
|
||||
users := services.UserService.FindByIds(userIDs)
|
||||
teams := services.AgentTeamService.FindByIds(teamIDs)
|
||||
|
||||
userMap := make(map[int64]*models.User, len(users))
|
||||
for i := range users {
|
||||
userMap[users[i].ID] = &users[i]
|
||||
}
|
||||
|
||||
teamMap := make(map[int64]*models.AgentTeam, len(teams))
|
||||
for i := range teams {
|
||||
teamMap[teams[i].ID] = &teams[i]
|
||||
}
|
||||
|
||||
results := make([]response.AgentProfileResponse, 0, len(items))
|
||||
for _, item := range items {
|
||||
if result := doBuildAgentProfileResponse(&item, userMap[item.UserID], teamMap[item.TeamID]); result != nil {
|
||||
results = append(results, *result)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildAgentProfileResponse(item *models.AgentProfile) *response.AgentProfileResponse {
|
||||
user := services.UserService.Get(item.UserID)
|
||||
team := services.AgentTeamService.Get(item.TeamID)
|
||||
return doBuildAgentProfileResponse(item, user, team)
|
||||
}
|
||||
|
||||
func doBuildAgentProfileResponse(item *models.AgentProfile, user *models.User, team *models.AgentTeam) *response.AgentProfileResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
ret := &response.AgentProfileResponse{
|
||||
ID: item.ID,
|
||||
UserID: item.UserID,
|
||||
TeamID: item.TeamID,
|
||||
AgentCode: item.AgentCode,
|
||||
DisplayName: item.DisplayName,
|
||||
Avatar: item.Avatar,
|
||||
ServiceStatus: item.ServiceStatus,
|
||||
MaxConcurrentCount: item.MaxConcurrentCount,
|
||||
PriorityLevel: item.PriorityLevel,
|
||||
AutoAssignEnabled: item.AutoAssignEnabled,
|
||||
ReceiveOfflineMessage: item.ReceiveOfflineMessage,
|
||||
LastOnlineAt: utils.FormatTimePtr(item.LastOnlineAt),
|
||||
LastStatusAt: utils.FormatTimePtr(item.LastStatusAt),
|
||||
Remark: item.Remark,
|
||||
}
|
||||
if user != nil {
|
||||
ret.Username = user.Username
|
||||
ret.Nickname = user.Nickname
|
||||
}
|
||||
if team != nil {
|
||||
ret.TeamName = team.Name
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
)
|
||||
|
||||
func BuildAgentRunLog(item *models.AgentRunLog) response.AgentRunLogResponse {
|
||||
if item == nil {
|
||||
return response.AgentRunLogResponse{}
|
||||
}
|
||||
return response.AgentRunLogResponse{
|
||||
ID: item.ID,
|
||||
ConversationID: item.ConversationID,
|
||||
MessageID: item.MessageID,
|
||||
AIAgentID: item.AIAgentID,
|
||||
AIConfigID: item.AIConfigID,
|
||||
UserMessage: item.UserMessage,
|
||||
PlannedAction: item.PlannedAction,
|
||||
PlannedSkillCode: item.PlannedSkillCode,
|
||||
PlannedToolCode: item.PlannedToolCode,
|
||||
PlanReason: item.PlanReason,
|
||||
FinalAction: item.FinalAction,
|
||||
ReplyText: item.ReplyText,
|
||||
ErrorMessage: item.ErrorMessage,
|
||||
LatencyMs: item.LatencyMs,
|
||||
TraceData: item.TraceData,
|
||||
CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
)
|
||||
|
||||
func BuildAsset(item *models.Asset) response.AssetResponse {
|
||||
ret := response.AssetResponse{
|
||||
ID: item.ID,
|
||||
AssetID: item.AssetID,
|
||||
Provider: item.Provider,
|
||||
Filename: item.Filename,
|
||||
FileSize: item.FileSize,
|
||||
MimeType: item.MimeType,
|
||||
URL: item.URL,
|
||||
StorageKey: item.StorageKey,
|
||||
Status: item.Status,
|
||||
CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: item.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
CreateUserID: item.CreateUserID,
|
||||
CreateUserName: item.CreateUserName,
|
||||
UpdateUserID: item.UpdateUserID,
|
||||
UpdateUserName: item.UpdateUserName,
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BuildCompany(item *models.Company) *response.CompanyResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
return &response.CompanyResponse{
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
Code: item.Code,
|
||||
Status: item.Status,
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt.Format(time.DateTime),
|
||||
UpdatedAt: item.UpdatedAt.Format(time.DateTime),
|
||||
}
|
||||
}
|
||||
|
||||
func BuildCompanyList(list []models.Company) []response.CompanyResponse {
|
||||
results := make([]response.CompanyResponse, 0, len(list))
|
||||
for _, item := range list {
|
||||
if company := BuildCompany(&item); company != nil {
|
||||
results = append(results, *company)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/enums"
|
||||
"cs-agent/internal/pkg/utils"
|
||||
"cs-agent/internal/services"
|
||||
|
||||
"github.com/mlogclub/simple/sqls"
|
||||
)
|
||||
|
||||
func BuildConversation(item *models.Conversation) response.ConversationResponse {
|
||||
agentReadState, customerReadState := services.ConversationReadStateService.GetConversationReadStates(item.ID)
|
||||
ret := response.ConversationResponse{
|
||||
ID: item.ID,
|
||||
AIAgentID: item.AIAgentID,
|
||||
CustomerID: item.CustomerID,
|
||||
ExternalSource: item.ExternalSource,
|
||||
ExternalID: item.ExternalID,
|
||||
Subject: item.Subject,
|
||||
Status: item.Status,
|
||||
ServiceMode: item.ServiceMode,
|
||||
Priority: item.Priority,
|
||||
CurrentAssigneeID: item.CurrentAssigneeID,
|
||||
LastMessageID: item.LastMessageID,
|
||||
LastMessageAt: utils.FormatTime(item.LastMessageAt),
|
||||
LastActiveAt: utils.FormatTime(item.LastActiveAt),
|
||||
LastMessageSummary: item.LastMessageSummary,
|
||||
CustomerUnreadCount: item.CustomerUnreadCount,
|
||||
AgentUnreadCount: item.AgentUnreadCount,
|
||||
CustomerLastReadMessageID: readStateMessageID(customerReadState),
|
||||
CustomerLastReadSeqNo: readStateSeqNo(customerReadState),
|
||||
CustomerLastReadAt: readStateAt(customerReadState),
|
||||
AgentLastReadMessageID: readStateMessageID(agentReadState),
|
||||
AgentLastReadSeqNo: readStateSeqNo(agentReadState),
|
||||
AgentLastReadAt: readStateAt(agentReadState),
|
||||
ClosedAt: utils.FormatTimePtr(item.ClosedAt),
|
||||
ClosedBy: item.ClosedBy,
|
||||
CloseReason: item.CloseReason,
|
||||
}
|
||||
if item.CurrentAssigneeID > 0 {
|
||||
if user := services.UserService.Get(item.CurrentAssigneeID); user != nil {
|
||||
ret.CurrentAssigneeName = user.Nickname
|
||||
if ret.CurrentAssigneeName == "" {
|
||||
ret.CurrentAssigneeName = user.Username
|
||||
}
|
||||
}
|
||||
}
|
||||
if item.ClosedBy > 0 {
|
||||
if user := services.UserService.Get(item.ClosedBy); user != nil {
|
||||
ret.ClosedByName = user.Nickname
|
||||
if ret.ClosedByName == "" {
|
||||
ret.ClosedByName = user.Username
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildParticipantResponses(conversationID int64) []response.ConversationParticipantResponse {
|
||||
list := services.ConversationParticipantService.Find(sqls.NewCnd().Eq("conversation_id", conversationID).Asc("id"))
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
ret := make([]response.ConversationParticipantResponse, 0, len(list))
|
||||
for _, item := range list {
|
||||
ret = append(ret, response.ConversationParticipantResponse{
|
||||
ID: item.ID,
|
||||
ParticipantType: item.ParticipantType,
|
||||
ParticipantID: item.ParticipantID,
|
||||
ExternalParticipantID: item.ExternalParticipantID,
|
||||
JoinedAt: utils.FormatTimePtr(item.JoinedAt),
|
||||
LeftAt: utils.FormatTimePtr(item.LeftAt),
|
||||
Status: item.Status,
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildMessages(list []models.Message) []response.MessageResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
agentReadState, customerReadState := services.ConversationReadStateService.GetConversationReadStates(list[0].ConversationID)
|
||||
aiSenderNames, userSenderNames := collectMessageSenderNameMaps(list)
|
||||
agentProfiles := collectAgentProfilesByMessages(list)
|
||||
ret := make([]response.MessageResponse, 0, len(list))
|
||||
for i := range list {
|
||||
ret = append(ret, BuildMessageWithReadStates(&list[i], agentReadState, customerReadState, aiSenderNames, userSenderNames, agentProfiles))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildMessage(item *models.Message) response.MessageResponse {
|
||||
agentReadState, customerReadState := services.ConversationReadStateService.GetConversationReadStates(item.ConversationID)
|
||||
return BuildMessageWithReadStates(item, agentReadState, customerReadState, nil, nil, nil)
|
||||
}
|
||||
|
||||
func BuildMessageWithReadStates(item *models.Message, agentReadState, customerReadState *models.ConversationReadState, aiSenderNames, userSenderNames map[int64]string, agentProfiles map[int64]*models.AgentProfile) response.MessageResponse {
|
||||
content, payload := buildMessageResponseContent(item)
|
||||
ret := response.MessageResponse{
|
||||
ID: item.ID,
|
||||
ConversationID: item.ConversationID,
|
||||
ClientMsgID: item.ClientMsgID,
|
||||
SenderType: item.SenderType,
|
||||
SenderID: item.SenderID,
|
||||
MessageType: item.MessageType,
|
||||
Content: content,
|
||||
Payload: payload,
|
||||
SeqNo: item.SeqNo,
|
||||
SendStatus: item.SendStatus,
|
||||
SentAt: utils.FormatTimePtr(item.SentAt),
|
||||
DeliveredAt: utils.FormatTimePtr(item.DeliveredAt),
|
||||
ReadAt: utils.FormatTimePtr(item.ReadAt),
|
||||
CustomerRead: isMessageRead(item, customerReadState),
|
||||
CustomerReadAt: readMessageAt(item, customerReadState),
|
||||
AgentRead: isMessageRead(item, agentReadState),
|
||||
AgentReadAt: readMessageAt(item, agentReadState),
|
||||
RecalledAt: utils.FormatTimePtr(item.RecalledAt),
|
||||
QuotedMessageID: item.QuotedMessageID,
|
||||
}
|
||||
if item.SenderID > 0 {
|
||||
if item.SenderType == enums.IMSenderTypeAI {
|
||||
if aiSenderNames != nil {
|
||||
ret.SenderName = aiSenderNames[item.SenderID]
|
||||
} else if aiAgent := services.AIAgentService.Get(item.SenderID); aiAgent != nil {
|
||||
ret.SenderName = aiAgent.Name
|
||||
}
|
||||
} else if item.SenderType == enums.IMSenderTypeAgent {
|
||||
profile := agentProfiles[item.SenderID]
|
||||
if profile != nil {
|
||||
if dn := strings.TrimSpace(profile.DisplayName); dn != "" {
|
||||
ret.SenderName = dn
|
||||
}
|
||||
if av := strings.TrimSpace(profile.Avatar); av != "" {
|
||||
ret.SenderAvatar = av
|
||||
}
|
||||
}
|
||||
if ret.SenderName == "" {
|
||||
if userSenderNames != nil {
|
||||
ret.SenderName = userSenderNames[item.SenderID]
|
||||
} else if user := services.UserService.Get(item.SenderID); user != nil {
|
||||
ret.SenderName = user.Nickname
|
||||
if ret.SenderName == "" {
|
||||
ret.SenderName = user.Username
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if userSenderNames != nil {
|
||||
ret.SenderName = userSenderNames[item.SenderID]
|
||||
} else if user := services.UserService.Get(item.SenderID); user != nil {
|
||||
ret.SenderName = user.Nickname
|
||||
if ret.SenderName == "" {
|
||||
ret.SenderName = user.Username
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func buildMessageResponseContent(item *models.Message) (content, payload string) {
|
||||
if item == nil {
|
||||
return "", ""
|
||||
}
|
||||
if item.RecalledAt != nil || item.SendStatus == int(enums.IMMessageStatusRecalled) {
|
||||
return "该消息已撤回", ""
|
||||
}
|
||||
return item.Content, item.Payload
|
||||
}
|
||||
|
||||
func collectAgentProfilesByMessages(list []models.Message) map[int64]*models.AgentProfile {
|
||||
var agentUserIDs []int64
|
||||
seen := make(map[int64]struct{})
|
||||
for i := range list {
|
||||
m := &list[i]
|
||||
if m.SenderType != enums.IMSenderTypeAgent || m.SenderID <= 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[m.SenderID]; ok {
|
||||
continue
|
||||
}
|
||||
seen[m.SenderID] = struct{}{}
|
||||
agentUserIDs = append(agentUserIDs, m.SenderID)
|
||||
}
|
||||
if len(agentUserIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
profiles := services.AgentProfileService.Find(sqls.NewCnd().In("user_id", agentUserIDs))
|
||||
out := make(map[int64]*models.AgentProfile, len(profiles))
|
||||
for i := range profiles {
|
||||
out[profiles[i].UserID] = &profiles[i]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func collectMessageSenderNameMaps(list []models.Message) (aiNames map[int64]string, userNames map[int64]string) {
|
||||
aiNames = make(map[int64]string)
|
||||
userNames = make(map[int64]string)
|
||||
var aiIDs, userIDs []int64
|
||||
seenAI := make(map[int64]struct{})
|
||||
seenUser := make(map[int64]struct{})
|
||||
for i := range list {
|
||||
m := &list[i]
|
||||
if m.SenderID <= 0 {
|
||||
continue
|
||||
}
|
||||
if m.SenderType == enums.IMSenderTypeAI {
|
||||
if _, ok := seenAI[m.SenderID]; ok {
|
||||
continue
|
||||
}
|
||||
seenAI[m.SenderID] = struct{}{}
|
||||
aiIDs = append(aiIDs, m.SenderID)
|
||||
continue
|
||||
}
|
||||
if _, ok := seenUser[m.SenderID]; ok {
|
||||
continue
|
||||
}
|
||||
seenUser[m.SenderID] = struct{}{}
|
||||
userIDs = append(userIDs, m.SenderID)
|
||||
}
|
||||
for _, a := range services.AIAgentService.FindByIds(aiIDs) {
|
||||
aiNames[a.ID] = a.Name
|
||||
}
|
||||
for _, u := range services.UserService.FindByIds(userIDs) {
|
||||
name := u.Nickname
|
||||
if name == "" {
|
||||
name = u.Username
|
||||
}
|
||||
userNames[u.ID] = name
|
||||
}
|
||||
return aiNames, userNames
|
||||
}
|
||||
|
||||
func isMessageRead(item *models.Message, state *models.ConversationReadState) bool {
|
||||
return item != nil && state != nil && state.LastReadSeqNo >= item.SeqNo
|
||||
}
|
||||
|
||||
func readMessageAt(item *models.Message, state *models.ConversationReadState) string {
|
||||
if !isMessageRead(item, state) {
|
||||
return ""
|
||||
}
|
||||
return utils.FormatTimePtr(state.LastReadAt)
|
||||
}
|
||||
|
||||
func readStateMessageID(state *models.ConversationReadState) int64 {
|
||||
if state == nil {
|
||||
return 0
|
||||
}
|
||||
return state.LastReadMessageID
|
||||
}
|
||||
|
||||
func readStateSeqNo(state *models.ConversationReadState) int64 {
|
||||
if state == nil {
|
||||
return 0
|
||||
}
|
||||
return state.LastReadSeqNo
|
||||
}
|
||||
|
||||
func readStateAt(state *models.ConversationReadState) string {
|
||||
if state == nil {
|
||||
return ""
|
||||
}
|
||||
return utils.FormatTimePtr(state.LastReadAt)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/utils"
|
||||
"cs-agent/internal/services"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BuildCustomer(item *models.Customer) *response.CustomerResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
return &response.CustomerResponse{
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
Gender: item.Gender,
|
||||
CompanyID: item.CompanyID,
|
||||
Company: BuildCompany(services.CompanyService.Get(item.CompanyID)),
|
||||
LastActiveAt: utils.FormatTimePtr(item.LastActiveAt),
|
||||
PrimaryMobile: item.PrimaryMobile,
|
||||
PrimaryEmail: item.PrimaryEmail,
|
||||
Status: item.Status,
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt.Format(time.DateTime),
|
||||
UpdatedAt: item.UpdatedAt.Format(time.DateTime),
|
||||
}
|
||||
}
|
||||
|
||||
func BuildCustomerList(list []models.Customer) []response.CustomerResponse {
|
||||
results := make([]response.CustomerResponse, 0, len(list))
|
||||
for _, item := range list {
|
||||
if customer := BuildCustomer(&item); customer != nil {
|
||||
results = append(results, *customer)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BuildCustomerContactResponse(item *models.CustomerContact) response.CustomerContactResponse {
|
||||
if item == nil {
|
||||
return response.CustomerContactResponse{}
|
||||
}
|
||||
return response.CustomerContactResponse{
|
||||
ID: item.ID,
|
||||
CustomerID: item.CustomerID,
|
||||
ContactType: item.ContactType,
|
||||
ContactValue: item.ContactValue,
|
||||
IsPrimary: item.IsPrimary,
|
||||
IsVerified: item.IsVerified,
|
||||
VerifiedAt: utils.FormatTimePtr(item.VerifiedAt),
|
||||
Source: item.Source,
|
||||
Status: item.Status,
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt.Format(time.DateTime),
|
||||
UpdatedAt: item.UpdatedAt.Format(time.DateTime),
|
||||
}
|
||||
}
|
||||
|
||||
func BuildCustomerContactList(list []models.CustomerContact) []response.CustomerContactResponse {
|
||||
results := make([]response.CustomerContactResponse, 0, len(list))
|
||||
for i := range list {
|
||||
results = append(results, BuildCustomerContactResponse(&list[i]))
|
||||
}
|
||||
return results
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/enums"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func BuildKnowledgeBase(item *models.KnowledgeBase) response.KnowledgeBaseResponse {
|
||||
return response.KnowledgeBaseResponse{
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
Description: item.Description,
|
||||
KnowledgeType: item.KnowledgeType,
|
||||
KnowledgeTypeName: enums.GetKnowledgeBaseTypeLabel(enums.KnowledgeBaseType(item.KnowledgeType)),
|
||||
Status: item.Status,
|
||||
StatusName: enums.GetStatusLabel(item.Status),
|
||||
DefaultTopK: item.DefaultTopK,
|
||||
DefaultScoreThreshold: item.DefaultScoreThreshold,
|
||||
DefaultRerankLimit: item.DefaultRerankLimit,
|
||||
ChunkProvider: item.ChunkProvider,
|
||||
ChunkTargetTokens: item.ChunkTargetTokens,
|
||||
ChunkMaxTokens: item.ChunkMaxTokens,
|
||||
ChunkOverlapTokens: item.ChunkOverlapTokens,
|
||||
AnswerMode: item.AnswerMode,
|
||||
AnswerModeName: enums.GetKnowledgeAnswerModeLabel(enums.KnowledgeAnswerMode(item.AnswerMode)),
|
||||
FallbackMode: item.FallbackMode,
|
||||
FallbackModeName: enums.GetKnowledgeFallbackModeLabel(enums.KnowledgeFallbackMode(item.FallbackMode)),
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
CreateUserName: item.CreateUserName,
|
||||
UpdateUserName: item.UpdateUserName,
|
||||
}
|
||||
}
|
||||
|
||||
func BuildKnowledgeDocument(item *models.KnowledgeDocument) response.KnowledgeDocumentResponse {
|
||||
return response.KnowledgeDocumentResponse{
|
||||
ID: item.ID,
|
||||
KnowledgeBaseID: item.KnowledgeBaseID,
|
||||
Title: item.Title,
|
||||
Status: item.Status,
|
||||
StatusName: enums.GetStatusLabel(item.Status),
|
||||
IndexStatus: item.IndexStatus,
|
||||
IndexStatusName: enums.GetKnowledgeDocumentIndexStatusLabel(item.IndexStatus),
|
||||
IndexedAt: item.IndexedAt,
|
||||
IndexError: item.IndexError,
|
||||
ContentHash: item.ContentHash,
|
||||
ContentType: item.ContentType,
|
||||
Content: item.Content,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
CreateUserName: item.CreateUserName,
|
||||
UpdateUserName: item.UpdateUserName,
|
||||
}
|
||||
}
|
||||
|
||||
func BuildKnowledgeFAQ(item *models.KnowledgeFAQ) response.KnowledgeFAQResponse {
|
||||
return response.KnowledgeFAQResponse{
|
||||
ID: item.ID,
|
||||
KnowledgeBaseID: item.KnowledgeBaseID,
|
||||
Question: item.Question,
|
||||
Answer: item.Answer,
|
||||
SimilarQuestions: parseSimilarQuestions(item.SimilarQuestions),
|
||||
Status: item.Status,
|
||||
StatusName: enums.GetStatusLabel(item.Status),
|
||||
IndexStatus: item.IndexStatus,
|
||||
IndexStatusName: enums.GetKnowledgeDocumentIndexStatusLabel(item.IndexStatus),
|
||||
IndexedAt: item.IndexedAt,
|
||||
IndexError: item.IndexError,
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
CreateUserName: item.CreateUserName,
|
||||
UpdateUserName: item.UpdateUserName,
|
||||
}
|
||||
}
|
||||
|
||||
func BuildKnowledgeRetrieveLog(item *models.KnowledgeRetrieveLog) response.KnowledgeRetrieveLogResponse {
|
||||
return response.KnowledgeRetrieveLogResponse{
|
||||
ID: item.ID,
|
||||
KnowledgeBaseID: item.KnowledgeBaseID,
|
||||
Channel: item.Channel,
|
||||
ChannelName: enums.GetKnowledgeRetrieveChannelLabel(enums.KnowledgeRetrieveChannel(item.Channel)),
|
||||
Scene: item.Scene,
|
||||
SceneName: enums.GetKnowledgeRetrieveSceneLabel(enums.KnowledgeRetrieveScene(item.Scene)),
|
||||
SessionID: item.SessionID,
|
||||
ConversationID: item.ConversationID,
|
||||
RequestID: item.RequestID,
|
||||
Question: item.Question,
|
||||
RewriteQuestion: item.RewriteQuestion,
|
||||
Answer: item.Answer,
|
||||
AnswerStatus: item.AnswerStatus,
|
||||
AnswerStatusName: enums.GetKnowledgeAnswerStatusLabel(enums.KnowledgeAnswerStatus(item.AnswerStatus)),
|
||||
HitCount: item.HitCount,
|
||||
TopScore: item.TopScore,
|
||||
ChunkProvider: item.ChunkProvider,
|
||||
ChunkTargetTokens: item.ChunkTargetTokens,
|
||||
ChunkMaxTokens: item.ChunkMaxTokens,
|
||||
ChunkOverlapTokens: item.ChunkOverlapTokens,
|
||||
RerankEnabled: item.RerankEnabled,
|
||||
RerankLimit: item.RerankLimit,
|
||||
CitationCount: item.CitationCount,
|
||||
UsedChunkCount: item.UsedChunkCount,
|
||||
LatencyMs: item.LatencyMs,
|
||||
RetrieveMs: item.RetrieveMs,
|
||||
GenerateMs: item.GenerateMs,
|
||||
PromptTokens: item.PromptTokens,
|
||||
CompletionTokens: item.CompletionTokens,
|
||||
ModelName: item.ModelName,
|
||||
TraceData: item.TraceData,
|
||||
CreatedAt: item.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func BuildKnowledgeRetrieveHitResponse(item *models.KnowledgeRetrieveHit) response.KnowledgeRetrieveHitResponse {
|
||||
return response.KnowledgeRetrieveHitResponse{
|
||||
ID: item.ID,
|
||||
RetrieveLogID: item.RetrieveLogID,
|
||||
KnowledgeBaseID: item.KnowledgeBaseID,
|
||||
ChunkID: item.ChunkID,
|
||||
DocumentID: item.DocumentID,
|
||||
DocumentTitle: item.DocumentTitle,
|
||||
FaqID: item.FaqID,
|
||||
FaqQuestion: item.FaqQuestion,
|
||||
ChunkNo: item.ChunkNo,
|
||||
Title: item.Title,
|
||||
SectionPath: item.SectionPath,
|
||||
ChunkType: item.ChunkType,
|
||||
ChunkTypeName: enums.GetKnowledgeChunkTypeLabel(enums.KnowledgeChunkType(item.ChunkType)),
|
||||
Provider: item.Provider,
|
||||
RankNo: item.RankNo,
|
||||
Score: item.Score,
|
||||
RerankScore: item.RerankScore,
|
||||
UsedInAnswer: item.UsedInAnswer,
|
||||
IsCitation: item.IsCitation,
|
||||
Snippet: item.Snippet,
|
||||
CreatedAt: item.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func parseSimilarQuestions(raw string) []string {
|
||||
if raw == "" {
|
||||
return []string{}
|
||||
}
|
||||
var items []string
|
||||
if err := json.Unmarshal([]byte(raw), &items); err != nil {
|
||||
return []string{}
|
||||
}
|
||||
return items
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/enums"
|
||||
)
|
||||
|
||||
func BuildSkillDefinitionResponse(item *models.SkillDefinition) response.SkillDefinitionResponse {
|
||||
return response.SkillDefinitionResponse{
|
||||
ID: item.ID,
|
||||
Code: item.Code,
|
||||
Name: item.Name,
|
||||
Description: item.Description,
|
||||
Prompt: item.Prompt,
|
||||
ExecutionMode: string(item.ExecutionMode),
|
||||
ExecutionModeName: enums.GetSkillExecutionModeLabel(item.ExecutionMode),
|
||||
ExecutionConfig: item.ExecutionConfig,
|
||||
Priority: item.Priority,
|
||||
Status: int(item.Status),
|
||||
StatusName: getSkillStatusName(item.Status),
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
CreateUserName: item.CreateUserName,
|
||||
UpdateUserName: item.UpdateUserName,
|
||||
}
|
||||
}
|
||||
|
||||
func getSkillStatusName(status enums.Status) string {
|
||||
if label := enums.GetStatusLabel(status); label != "" {
|
||||
return label
|
||||
}
|
||||
return "未知"
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BuildTagResponse(item *models.Tag) response.TagResponse {
|
||||
if item == nil {
|
||||
return response.TagResponse{}
|
||||
}
|
||||
return response.TagResponse{
|
||||
ID: item.ID,
|
||||
ParentID: item.ParentID,
|
||||
Name: item.Name,
|
||||
Remark: item.Remark,
|
||||
SortNo: item.SortNo,
|
||||
Status: item.Status,
|
||||
CreatedAt: item.CreatedAt.Format(time.DateTime),
|
||||
UpdatedAt: item.UpdatedAt.Format(time.DateTime),
|
||||
}
|
||||
}
|
||||
|
||||
func BuildTagResponses(list []models.Tag) []response.TagResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TagResponse, 0, len(list))
|
||||
for i := range list {
|
||||
results = append(results, BuildTagResponse(&list[i]))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTagTreeResponses(list []models.Tag) []*response.TagTreeResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodeMap := make(map[int64]*response.TagTreeResponse, len(list))
|
||||
roots := make([]*response.TagTreeResponse, 0)
|
||||
|
||||
for i := range list {
|
||||
item := &list[i]
|
||||
nodeMap[item.ID] = &response.TagTreeResponse{
|
||||
ID: item.ID,
|
||||
ParentID: item.ParentID,
|
||||
Name: item.Name,
|
||||
Remark: item.Remark,
|
||||
SortNo: item.SortNo,
|
||||
Status: item.Status,
|
||||
CreatedAt: item.CreatedAt.Format(time.DateTime),
|
||||
UpdatedAt: item.UpdatedAt.Format(time.DateTime),
|
||||
Children: make([]*response.TagTreeResponse, 0),
|
||||
}
|
||||
}
|
||||
|
||||
for i := range list {
|
||||
item := &list[i]
|
||||
node := nodeMap[item.ID]
|
||||
if item.ParentID == 0 {
|
||||
roots = append(roots, node)
|
||||
continue
|
||||
}
|
||||
parent, ok := nodeMap[item.ParentID]
|
||||
if !ok {
|
||||
roots = append(roots, node)
|
||||
continue
|
||||
}
|
||||
parent.Children = append(parent.Children, node)
|
||||
}
|
||||
|
||||
return roots
|
||||
}
|
||||
@@ -0,0 +1,567 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/enums"
|
||||
"cs-agent/internal/pkg/utils"
|
||||
"cs-agent/internal/services"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/mlogclub/simple/sqls"
|
||||
)
|
||||
|
||||
type TicketBuildContext struct {
|
||||
TagsByTicketID map[int64][]models.Tag
|
||||
Priorities map[int64]*models.TicketPriorityConfig
|
||||
ResolutionCodes map[string]*models.TicketResolutionCode
|
||||
Users map[int64]*models.User
|
||||
Teams map[int64]*models.AgentTeam
|
||||
Customers map[int64]*models.Customer
|
||||
SLAByTicketID map[int64][]models.TicketSLARecord
|
||||
WatchedTicketIDs map[int64]struct{}
|
||||
}
|
||||
|
||||
type TicketDetailBuildContext struct {
|
||||
Users map[int64]*models.User
|
||||
Teams map[int64]*models.AgentTeam
|
||||
AgentProfiles map[int64]*models.AgentProfile
|
||||
RelatedTickets map[int64]*models.Ticket
|
||||
Customers map[int64]*models.Customer
|
||||
AIAgents map[int64]*models.AIAgent
|
||||
}
|
||||
|
||||
func BuildTicket(item *models.Ticket) *response.TicketResponse {
|
||||
return BuildTicketWithContext(item, nil)
|
||||
}
|
||||
|
||||
func BuildTicketWithContext(item *models.Ticket, ctx *TicketBuildContext) *response.TicketResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
ret := &response.TicketResponse{
|
||||
ID: item.ID,
|
||||
TicketNo: item.TicketNo,
|
||||
Title: item.Title,
|
||||
Description: item.Description,
|
||||
Source: item.Source,
|
||||
Channel: item.Channel,
|
||||
CustomerID: item.CustomerID,
|
||||
ConversationID: item.ConversationID,
|
||||
Type: item.Type,
|
||||
Priority: item.Priority,
|
||||
Severity: item.Severity,
|
||||
Status: item.Status,
|
||||
CurrentTeamID: item.CurrentTeamID,
|
||||
CurrentAssigneeID: item.CurrentAssigneeID,
|
||||
PendingReason: item.PendingReason,
|
||||
CloseReason: item.CloseReason,
|
||||
ResolutionCode: item.ResolutionCode,
|
||||
ResolutionSummary: item.ResolutionSummary,
|
||||
FirstResponseAt: utils.FormatTimePtr(item.FirstResponseAt),
|
||||
ResolvedAt: utils.FormatTimePtr(item.ResolvedAt),
|
||||
ClosedAt: utils.FormatTimePtr(item.ClosedAt),
|
||||
DueAt: utils.FormatTimePtr(item.DueAt),
|
||||
NextReplyDeadlineAt: utils.FormatTimePtr(item.NextReplyDeadlineAt),
|
||||
ResolveDeadlineAt: utils.FormatTimePtr(item.ResolveDeadlineAt),
|
||||
ReopenedCount: item.ReopenedCount,
|
||||
CreatedAt: utils.FormatTime(item.CreatedAt),
|
||||
UpdatedAt: utils.FormatTime(item.UpdatedAt),
|
||||
}
|
||||
if ctx != nil {
|
||||
if _, ok := ctx.WatchedTicketIDs[item.ID]; ok {
|
||||
ret.WatchedByMe = true
|
||||
}
|
||||
}
|
||||
if ctx != nil && ctx.TagsByTicketID != nil {
|
||||
ret.Tags = BuildTagResponses(ctx.TagsByTicketID[item.ID])
|
||||
} else {
|
||||
ret.Tags = BuildTagResponses(services.TicketService.GetTags(item.ID))
|
||||
}
|
||||
if item.Priority > 0 && ctx != nil && ctx.Priorities != nil {
|
||||
if priority := ctx.Priorities[item.Priority]; priority != nil {
|
||||
ret.PriorityName = priority.Name
|
||||
}
|
||||
} else if item.Priority > 0 {
|
||||
if priority := services.TicketPriorityConfigService.Get(item.Priority); priority != nil {
|
||||
ret.PriorityName = priority.Name
|
||||
}
|
||||
}
|
||||
if item.ResolutionCode != "" && ctx != nil && ctx.ResolutionCodes != nil {
|
||||
if code := ctx.ResolutionCodes[item.ResolutionCode]; code != nil {
|
||||
ret.ResolutionCodeName = code.Name
|
||||
}
|
||||
} else if item.ResolutionCode != "" {
|
||||
if code := services.TicketResolutionCodeService.Take("code = ? AND status <> ?", item.ResolutionCode, enums.StatusDeleted); code != nil {
|
||||
ret.ResolutionCodeName = code.Name
|
||||
}
|
||||
}
|
||||
if item.CurrentAssigneeID > 0 && ctx != nil && ctx.Users != nil {
|
||||
if user := ctx.Users[item.CurrentAssigneeID]; user != nil {
|
||||
ret.CurrentAssigneeName = user.Nickname
|
||||
if ret.CurrentAssigneeName == "" {
|
||||
ret.CurrentAssigneeName = user.Username
|
||||
}
|
||||
}
|
||||
} else if item.CurrentAssigneeID > 0 {
|
||||
if user := services.UserService.Get(item.CurrentAssigneeID); user != nil {
|
||||
ret.CurrentAssigneeName = user.Nickname
|
||||
if ret.CurrentAssigneeName == "" {
|
||||
ret.CurrentAssigneeName = user.Username
|
||||
}
|
||||
}
|
||||
}
|
||||
if item.CurrentTeamID > 0 && ctx != nil && ctx.Teams != nil {
|
||||
if team := ctx.Teams[item.CurrentTeamID]; team != nil {
|
||||
ret.CurrentTeamName = team.Name
|
||||
}
|
||||
} else if item.CurrentTeamID > 0 {
|
||||
if team := services.AgentTeamService.Get(item.CurrentTeamID); team != nil {
|
||||
ret.CurrentTeamName = team.Name
|
||||
}
|
||||
}
|
||||
if item.CustomerID > 0 && ctx != nil && ctx.Customers != nil {
|
||||
ret.Customer = BuildCustomer(ctx.Customers[item.CustomerID])
|
||||
} else if item.CustomerID > 0 {
|
||||
ret.Customer = BuildCustomer(services.CustomerService.Get(item.CustomerID))
|
||||
}
|
||||
if ctx != nil && ctx.SLAByTicketID != nil {
|
||||
ret.SLA = BuildTicketSLAList(ctx.SLAByTicketID[item.ID])
|
||||
} else {
|
||||
ret.SLA = BuildTicketSLAList(
|
||||
services.TicketSLARecordService.Find(
|
||||
sqls.NewCnd().Eq("ticket_id", item.ID).Asc("id"),
|
||||
),
|
||||
)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildTicketList(list []models.Ticket) []response.TicketResponse {
|
||||
return BuildTicketListWithContext(list, nil)
|
||||
}
|
||||
|
||||
func BuildTicketListWithContext(list []models.Ticket, ctx *TicketBuildContext) []response.TicketResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketResponse, 0, len(list))
|
||||
for i := range list {
|
||||
if item := BuildTicketWithContext(&list[i], ctx); item != nil {
|
||||
results = append(results, *item)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTicketComment(item *models.TicketComment) *response.TicketCommentResponse {
|
||||
return BuildTicketCommentWithContext(item, nil)
|
||||
}
|
||||
|
||||
func BuildTicketCommentWithContext(item *models.TicketComment, ctx *TicketDetailBuildContext) *response.TicketCommentResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
ret := &response.TicketCommentResponse{
|
||||
ID: item.ID,
|
||||
TicketID: item.TicketID,
|
||||
CommentType: item.CommentType,
|
||||
AuthorType: item.AuthorType,
|
||||
AuthorID: item.AuthorID,
|
||||
ContentType: item.ContentType,
|
||||
Content: item.Content,
|
||||
Payload: item.Payload,
|
||||
CreatedAt: utils.FormatTime(item.CreatedAt),
|
||||
}
|
||||
ret.AuthorName = buildTicketOperatorName(item.AuthorType, item.AuthorID, ctx)
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildTicketCommentList(list []models.TicketComment) []response.TicketCommentResponse {
|
||||
return BuildTicketCommentListWithContext(list, nil)
|
||||
}
|
||||
|
||||
func BuildTicketCommentListWithContext(list []models.TicketComment, ctx *TicketDetailBuildContext) []response.TicketCommentResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketCommentResponse, 0, len(list))
|
||||
for i := range list {
|
||||
if item := BuildTicketCommentWithContext(&list[i], ctx); item != nil {
|
||||
results = append(results, *item)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTicketEventLog(item *models.TicketEventLog) *response.TicketEventLogResponse {
|
||||
return BuildTicketEventLogWithContext(item, nil)
|
||||
}
|
||||
|
||||
func BuildTicketEventLogWithContext(item *models.TicketEventLog, ctx *TicketDetailBuildContext) *response.TicketEventLogResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
return &response.TicketEventLogResponse{
|
||||
ID: item.ID,
|
||||
TicketID: item.TicketID,
|
||||
EventType: item.EventType,
|
||||
OperatorType: item.OperatorType,
|
||||
OperatorID: item.OperatorID,
|
||||
OperatorName: buildTicketOperatorName(item.OperatorType, item.OperatorID, ctx),
|
||||
OldValue: item.OldValue,
|
||||
NewValue: item.NewValue,
|
||||
Content: item.Content,
|
||||
Payload: item.Payload,
|
||||
CreatedAt: utils.FormatTime(item.CreatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
func BuildTicketEventLogList(list []models.TicketEventLog) []response.TicketEventLogResponse {
|
||||
return BuildTicketEventLogListWithContext(list, nil)
|
||||
}
|
||||
|
||||
func BuildTicketEventLogListWithContext(list []models.TicketEventLog, ctx *TicketDetailBuildContext) []response.TicketEventLogResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketEventLogResponse, 0, len(list))
|
||||
for i := range list {
|
||||
if item := BuildTicketEventLogWithContext(&list[i], ctx); item != nil {
|
||||
results = append(results, *item)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTicketSLAList(list []models.TicketSLARecord) []response.TicketSLAResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketSLAResponse, 0, len(list))
|
||||
for i := range list {
|
||||
item := &list[i]
|
||||
results = append(results, response.TicketSLAResponse{
|
||||
SLAType: item.SLAType,
|
||||
TargetMinutes: item.TargetMinutes,
|
||||
Status: item.Status,
|
||||
StartedAt: utils.FormatTimePtr(item.StartedAt),
|
||||
PausedAt: utils.FormatTimePtr(item.PausedAt),
|
||||
StoppedAt: utils.FormatTimePtr(item.StoppedAt),
|
||||
BreachedAt: utils.FormatTimePtr(item.BreachedAt),
|
||||
ElapsedMin: item.ElapsedMin,
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTicketDetail(aggregate *services.TicketDetailAggregate) *response.TicketDetailResponse {
|
||||
return BuildTicketDetailWithContext(aggregate, nil)
|
||||
}
|
||||
|
||||
func BuildTicketDetailWithContext(aggregate *services.TicketDetailAggregate, ctx *TicketDetailBuildContext) *response.TicketDetailResponse {
|
||||
if aggregate == nil || aggregate.Ticket == nil {
|
||||
return nil
|
||||
}
|
||||
if ctx == nil {
|
||||
users := make(map[int64]*models.User, len(aggregate.Users)+len(aggregate.OperatorUsers))
|
||||
for id, item := range aggregate.Users {
|
||||
users[id] = item
|
||||
}
|
||||
for id, item := range aggregate.OperatorUsers {
|
||||
users[id] = item
|
||||
}
|
||||
ctx = &TicketDetailBuildContext{
|
||||
Users: users,
|
||||
Teams: aggregate.Teams,
|
||||
AgentProfiles: aggregate.AgentProfiles,
|
||||
RelatedTickets: aggregate.RelatedMap,
|
||||
Customers: aggregate.OperatorCustomers,
|
||||
AIAgents: aggregate.OperatorAIAgents,
|
||||
}
|
||||
}
|
||||
ret := &response.TicketDetailResponse{
|
||||
Ticket: *BuildTicket(aggregate.Ticket),
|
||||
Watchers: BuildTicketWatcherListWithContext(aggregate.Watchers, ctx),
|
||||
Collaborators: BuildTicketCollaboratorListWithContext(aggregate.Collaborators, ctx),
|
||||
RelatedTickets: BuildTicketRelationListWithContext(aggregate.RelatedTickets, ctx),
|
||||
}
|
||||
if len(aggregate.Comments) > 0 {
|
||||
ret.Comments = make([]response.TicketCommentResponse, 0, len(aggregate.Comments))
|
||||
for i := range aggregate.Comments {
|
||||
if item := BuildTicketCommentWithContext(&aggregate.Comments[i], ctx); item != nil {
|
||||
ret.Comments = append(ret.Comments, *item)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(aggregate.Events) > 0 {
|
||||
ret.Events = make([]response.TicketEventLogResponse, 0, len(aggregate.Events))
|
||||
for i := range aggregate.Events {
|
||||
if item := BuildTicketEventLogWithContext(&aggregate.Events[i], ctx); item != nil {
|
||||
ret.Events = append(ret.Events, *item)
|
||||
}
|
||||
}
|
||||
}
|
||||
if aggregate.Customer != nil {
|
||||
ret.Ticket.Customer = BuildCustomer(aggregate.Customer)
|
||||
}
|
||||
ret.Ticket.Tags = BuildTagResponses(aggregate.Tags)
|
||||
ret.Ticket.SLA = BuildTicketSLAList(aggregate.SLAs)
|
||||
for i := range ret.Comments {
|
||||
if ret.Comments[i].AuthorName == "" {
|
||||
ret.Comments[i].AuthorName = buildTicketOperatorName(ret.Comments[i].AuthorType, ret.Comments[i].AuthorID, ctx)
|
||||
}
|
||||
}
|
||||
for i := range ret.Events {
|
||||
if ret.Events[i].OperatorName == "" {
|
||||
ret.Events[i].OperatorName = buildTicketOperatorName(ret.Events[i].OperatorType, ret.Events[i].OperatorID, ctx)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildTicketRelation(item *models.TicketRelation) *response.TicketRelationResponse {
|
||||
return BuildTicketRelationWithContext(item, nil)
|
||||
}
|
||||
|
||||
func BuildTicketRelationWithContext(item *models.TicketRelation, ctx *TicketDetailBuildContext) *response.TicketRelationResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
ret := &response.TicketRelationResponse{
|
||||
ID: item.ID,
|
||||
TicketID: item.TicketID,
|
||||
RelatedTicketID: item.RelatedTicketID,
|
||||
RelationType: item.RelationType,
|
||||
}
|
||||
related := (*models.Ticket)(nil)
|
||||
if ctx != nil && ctx.RelatedTickets != nil {
|
||||
related = ctx.RelatedTickets[item.RelatedTicketID]
|
||||
}
|
||||
if related == nil {
|
||||
related = services.TicketService.Get(item.RelatedTicketID)
|
||||
}
|
||||
if related != nil {
|
||||
ret.RelatedTicketNo = related.TicketNo
|
||||
ret.RelatedTicketTitle = related.Title
|
||||
ret.RelatedTicketStatus = related.Status
|
||||
ret.UpdatedAt = utils.FormatTime(related.UpdatedAt)
|
||||
if related.CurrentTeamID > 0 && ctx != nil && ctx.Teams != nil {
|
||||
if team := ctx.Teams[related.CurrentTeamID]; team != nil {
|
||||
ret.CurrentTeamName = team.Name
|
||||
}
|
||||
} else if related.CurrentTeamID > 0 {
|
||||
if team := services.AgentTeamService.Get(related.CurrentTeamID); team != nil {
|
||||
ret.CurrentTeamName = team.Name
|
||||
}
|
||||
}
|
||||
if related.CurrentAssigneeID > 0 && ctx != nil && ctx.Users != nil {
|
||||
ret.CurrentAssigneeName = buildTicketUserDisplayName(ctx.Users[related.CurrentAssigneeID])
|
||||
} else if related.CurrentAssigneeID > 0 {
|
||||
if user := services.UserService.Get(related.CurrentAssigneeID); user != nil {
|
||||
ret.CurrentAssigneeName = user.Nickname
|
||||
if ret.CurrentAssigneeName == "" {
|
||||
ret.CurrentAssigneeName = user.Username
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildTicketRelationList(list []models.TicketRelation) []response.TicketRelationResponse {
|
||||
return BuildTicketRelationListWithContext(list, nil)
|
||||
}
|
||||
|
||||
func BuildTicketRelationListWithContext(list []models.TicketRelation, ctx *TicketDetailBuildContext) []response.TicketRelationResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketRelationResponse, 0, len(list))
|
||||
for i := range list {
|
||||
if item := BuildTicketRelationWithContext(&list[i], ctx); item != nil {
|
||||
results = append(results, *item)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTicketSummary(summary *services.TicketSummaryAggregate) *response.TicketSummaryResponse {
|
||||
if summary == nil {
|
||||
return nil
|
||||
}
|
||||
return &response.TicketSummaryResponse{
|
||||
All: summary.All,
|
||||
Mine: summary.Mine,
|
||||
Watching: summary.Watching,
|
||||
Collaboration: summary.Collaboration,
|
||||
Participating: summary.Participating,
|
||||
Mentioned: summary.Mentioned,
|
||||
Unassigned: summary.Unassigned,
|
||||
PendingCustomer: summary.PendingCustomer,
|
||||
PendingInternal: summary.PendingInternal,
|
||||
Overdue: summary.Overdue,
|
||||
}
|
||||
}
|
||||
|
||||
func BuildTicketRiskOverview(overview *services.TicketRiskOverviewAggregate) *response.TicketRiskOverviewResponse {
|
||||
if overview == nil {
|
||||
return nil
|
||||
}
|
||||
ret := &response.TicketRiskOverviewResponse{
|
||||
Overdue: overview.Overdue,
|
||||
HighRisk: overview.HighRisk,
|
||||
Unassigned: overview.Unassigned,
|
||||
PendingInternal: overview.PendingInternal,
|
||||
PendingCustomer: overview.PendingCustomer,
|
||||
RiskWindowMins: overview.RiskWindowMins,
|
||||
}
|
||||
if len(overview.Reasons) > 0 {
|
||||
ret.Reasons = make([]response.TicketRiskReasonResponse, 0, len(overview.Reasons))
|
||||
for _, item := range overview.Reasons {
|
||||
ret.Reasons = append(ret.Reasons, response.TicketRiskReasonResponse{
|
||||
Code: item.Code,
|
||||
Title: item.Title,
|
||||
Description: item.Description,
|
||||
Count: item.Count,
|
||||
})
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildTicketWatcherList(list []models.TicketWatcher) []response.TicketWatcherResponse {
|
||||
return BuildTicketWatcherListWithContext(list, nil)
|
||||
}
|
||||
|
||||
func BuildTicketWatcherListWithContext(list []models.TicketWatcher, ctx *TicketDetailBuildContext) []response.TicketWatcherResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketWatcherResponse, 0, len(list))
|
||||
for i := range list {
|
||||
item := &list[i]
|
||||
out := response.TicketWatcherResponse{
|
||||
ID: item.ID,
|
||||
UserID: item.UserID,
|
||||
}
|
||||
if ctx != nil && ctx.Users != nil {
|
||||
out.UserName = buildTicketUserDisplayName(ctx.Users[item.UserID])
|
||||
} else if user := services.UserService.Get(item.UserID); user != nil {
|
||||
out.UserName = buildTicketUserDisplayName(user)
|
||||
}
|
||||
results = append(results, out)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTicketCollaboratorList(list []models.TicketCollaborator) []response.TicketCollaboratorResponse {
|
||||
return BuildTicketCollaboratorListWithContext(list, nil)
|
||||
}
|
||||
|
||||
func BuildTicketCollaboratorListWithContext(list []models.TicketCollaborator, ctx *TicketDetailBuildContext) []response.TicketCollaboratorResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketCollaboratorResponse, 0, len(list))
|
||||
for i := range list {
|
||||
item := &list[i]
|
||||
out := response.TicketCollaboratorResponse{
|
||||
ID: item.ID,
|
||||
UserID: item.UserID,
|
||||
}
|
||||
if ctx != nil && ctx.Users != nil {
|
||||
out.UserName = buildTicketUserDisplayName(ctx.Users[item.UserID])
|
||||
} else if user := services.UserService.Get(item.UserID); user != nil {
|
||||
out.UserName = buildTicketUserDisplayName(user)
|
||||
}
|
||||
if ctx != nil && ctx.AgentProfiles != nil {
|
||||
if profile := ctx.AgentProfiles[item.UserID]; profile != nil && profile.TeamID > 0 {
|
||||
if team := ctx.Teams[profile.TeamID]; team != nil {
|
||||
out.TeamName = team.Name
|
||||
}
|
||||
}
|
||||
} else if profile := services.AgentProfileService.GetByUserID(item.UserID); profile != nil && profile.TeamID > 0 {
|
||||
if team := services.AgentTeamService.Get(profile.TeamID); team != nil {
|
||||
out.TeamName = team.Name
|
||||
}
|
||||
}
|
||||
results = append(results, out)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildTicketView(item *models.TicketView) *response.TicketViewResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
ret := &response.TicketViewResponse{
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
SortNo: item.SortNo,
|
||||
}
|
||||
if strings.TrimSpace(item.FiltersJSON) != "" {
|
||||
_ = json.Unmarshal([]byte(item.FiltersJSON), &ret.Filters)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildTicketViewList(list []models.TicketView) []response.TicketViewResponse {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
results := make([]response.TicketViewResponse, 0, len(list))
|
||||
for i := range list {
|
||||
if item := BuildTicketView(&list[i]); item != nil {
|
||||
results = append(results, *item)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func buildTicketUserDisplayName(user *models.User) string {
|
||||
if user == nil {
|
||||
return ""
|
||||
}
|
||||
if user.Nickname != "" {
|
||||
return user.Nickname
|
||||
}
|
||||
return user.Username
|
||||
}
|
||||
|
||||
func buildTicketOperatorName(senderType enums.IMSenderType, senderID int64, ctx *TicketDetailBuildContext) string {
|
||||
if senderID <= 0 {
|
||||
return ""
|
||||
}
|
||||
switch senderType {
|
||||
case enums.IMSenderTypeAgent:
|
||||
if ctx != nil && ctx.Users != nil {
|
||||
if user := ctx.Users[senderID]; user != nil {
|
||||
return buildTicketUserDisplayName(user)
|
||||
}
|
||||
}
|
||||
if user := services.UserService.Get(senderID); user != nil {
|
||||
return buildTicketUserDisplayName(user)
|
||||
}
|
||||
case enums.IMSenderTypeCustomer:
|
||||
if ctx != nil && ctx.Customers != nil {
|
||||
if customer := ctx.Customers[senderID]; customer != nil {
|
||||
return customer.Name
|
||||
}
|
||||
}
|
||||
if customer := services.CustomerService.Get(senderID); customer != nil {
|
||||
return customer.Name
|
||||
}
|
||||
case enums.IMSenderTypeAI:
|
||||
if ctx != nil && ctx.AIAgents != nil {
|
||||
if ai := ctx.AIAgents[senderID]; ai != nil {
|
||||
return ai.Name
|
||||
}
|
||||
}
|
||||
if ai := services.AIAgentService.Get(senderID); ai != nil {
|
||||
return ai.Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
)
|
||||
|
||||
func BuildTicketResolutionCode(item *models.TicketResolutionCode) *response.TicketResolutionCodeResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
return &response.TicketResolutionCodeResponse{
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
Code: item.Code,
|
||||
SortNo: item.SortNo,
|
||||
Status: item.Status,
|
||||
Remark: item.Remark,
|
||||
}
|
||||
}
|
||||
|
||||
func BuildTicketResolutionCodeList(list []models.TicketResolutionCode) []response.TicketResolutionCodeResponse {
|
||||
if len(list) == 0 {
|
||||
return make([]response.TicketResolutionCodeResponse, 0)
|
||||
}
|
||||
ret := make([]response.TicketResolutionCodeResponse, 0, len(list))
|
||||
for i := range list {
|
||||
if item := BuildTicketResolutionCode(&list[i]); item != nil {
|
||||
ret = append(ret, *item)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildTicketPriorityConfig(item *models.TicketPriorityConfig) *response.TicketPriorityConfigResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
return &response.TicketPriorityConfigResponse{
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
SortNo: item.SortNo,
|
||||
FirstResponseMinutes: item.FirstResponseMinutes,
|
||||
ResolutionMinutes: item.ResolutionMinutes,
|
||||
Status: item.Status,
|
||||
Remark: item.Remark,
|
||||
}
|
||||
}
|
||||
|
||||
func BuildTicketPriorityConfigList(list []models.TicketPriorityConfig) []response.TicketPriorityConfigResponse {
|
||||
if len(list) == 0 {
|
||||
return make([]response.TicketPriorityConfigResponse, 0)
|
||||
}
|
||||
ret := make([]response.TicketPriorityConfigResponse, 0, len(list))
|
||||
for i := range list {
|
||||
if item := BuildTicketPriorityConfig(&list[i]); item != nil {
|
||||
ret = append(ret, *item)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/dto/response"
|
||||
"cs-agent/internal/pkg/utils"
|
||||
"cs-agent/internal/services"
|
||||
)
|
||||
|
||||
type UserBuildOptions struct {
|
||||
Roles bool
|
||||
Permissions bool
|
||||
}
|
||||
|
||||
func BuildUserList(items []models.User, options UserBuildOptions) []response.UserResponse {
|
||||
results := make([]response.UserResponse, 0, len(items))
|
||||
for _, item := range items {
|
||||
results = append(results, *BuildUserResponse(&item, options))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func BuildUserResponse(item *models.User, options UserBuildOptions) *response.UserResponse {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
ret := &response.UserResponse{
|
||||
ID: item.ID,
|
||||
Username: item.Username,
|
||||
Nickname: item.Nickname,
|
||||
Avatar: item.Avatar,
|
||||
Status: item.Status,
|
||||
LastLoginAt: utils.FormatTimePtr(item.LastLoginAt),
|
||||
LastLoginIP: item.LastLoginIP,
|
||||
}
|
||||
|
||||
if item.Mobile != nil {
|
||||
ret.Mobile = *item.Mobile
|
||||
}
|
||||
if item.Email != nil {
|
||||
ret.Email = *item.Email
|
||||
}
|
||||
|
||||
if options.Roles {
|
||||
ret.Roles = buildAssignedRoles(item.ID)
|
||||
}
|
||||
if options.Permissions {
|
||||
permissionCodes, _ := services.AuthService.GetUserPermissions(item.ID)
|
||||
ret.Permissions = permissionCodes
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func buildAssignedRoles(userID int64) []response.RoleResponse {
|
||||
roles, _ := services.AuthService.GetUserRoles(userID)
|
||||
results := make([]response.RoleResponse, 0, len(roles))
|
||||
for _, role := range roles {
|
||||
results = append(results, response.RoleResponse{
|
||||
ID: role.ID,
|
||||
Name: role.Name,
|
||||
Code: role.Code,
|
||||
Status: role.Status,
|
||||
IsSystem: role.IsSystem,
|
||||
SortNo: role.SortNo,
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
Reference in New Issue
Block a user