Compare commits
	
		
			No commits in common. "17e3b6513f5d80c12b8f50ff7892f94c2823d3a8" and "ac5fe7a2669a029f0a7a1c2b818acd3cf2178449" have entirely different histories.
		
	
	
		
			17e3b6513f
			...
			ac5fe7a266
		
	
		
| @ -194,8 +194,8 @@ func (o *ChatRoom) Register(c *Client) (sessionId string) { | ||||
| // message: 消息内容
 | ||||
| func (o *ChatRoom) SendSessionMessage(sender *accountFiee.ChatUserData, sessionId string, msgType WsType, message any) (userIdInSession []int64, err error) { | ||||
| 	fmt.Println("ChatRoom.SendSessionMessage ------------------1") | ||||
| 	o.clientsRwLocker.Lock() | ||||
| 	defer o.clientsRwLocker.Unlock() | ||||
| 	//o.clientsRwLocker.Lock()
 | ||||
| 	//defer o.clientsRwLocker.Unlock()
 | ||||
| 	var msg = WsSessionInfo{ | ||||
| 		Type:    msgType, | ||||
| 		Content: message, | ||||
| @ -209,26 +209,18 @@ func (o *ChatRoom) SendSessionMessage(sender *accountFiee.ChatUserData, sessionI | ||||
| 	fmt.Println("ChatRoom.SendSessionMessage ------------------3") | ||||
| 	usableClients := []*Client{} | ||||
| 	fmt.Printf("sessionId:[%s],客户端数量%d\n", sessionId, len(o.Session[sessionId])) | ||||
| 	pushed := false | ||||
| 	for i, client := range o.Session[sessionId] { | ||||
| 		if client != nil { | ||||
| 			_, exist := o.clients[client.UserId][client.ClientId] | ||||
| 			if exist { | ||||
| 				usableClients = append(usableClients, o.Session[sessionId][i]) | ||||
| 				if !pushed { | ||||
| 					go o.pushEvent(EventChatMessage, EventProgressBefore, sender, o.Session[sessionId][i], message) | ||||
| 					pushed = true | ||||
| 				} | ||||
| 				go o.pushEvent(EventChatMessage, EventProgressBefore, sender, o.Session[sessionId][i], message) | ||||
| 			} | ||||
| 		} | ||||
| 		fmt.Printf("client:%+v\n", client) | ||||
| 		pushed = false | ||||
| 		if client != nil && (client.UserId != sender.ID || sender.Role == 3) { | ||||
| 			client.Send <- msgBytes | ||||
| 			if !pushed { | ||||
| 				go o.pushEvent(EventChatMessage, EventProgressAfter, sender, o.Session[sessionId][i], message) | ||||
| 				pushed = true | ||||
| 			} | ||||
| 			go o.pushEvent(EventChatMessage, EventProgressAfter, sender, o.Session[sessionId][i], message) | ||||
| 			userIdInSession = append(userIdInSession, client.UserId) | ||||
| 		} | ||||
| 		//client.Send <- msgBytes
 | ||||
|  | ||||
| @ -40,42 +40,39 @@ func AuthorizationVerify(sourceData []byte) (userInfo *accountFiee.ChatUserData, | ||||
| 	var ctx = context.Background() | ||||
| 	var accountInfo accountFiee.ChatUserData | ||||
| 	//fiee token校验
 | ||||
| 	switch msg.Content.Domain { | ||||
| 	case "app": | ||||
| 		var fieeJwtInfo *jwt.Claims | ||||
| 		fieeJwtInfo, err = jwt.ParseToken(msg.Content.Auth, m.JWTSecret) | ||||
| 	var fieeJwtInfo *jwt.Claims | ||||
| 	fieeJwtInfo, err = jwt.ParseToken(msg.Content.Auth, m.JWTSecret) | ||||
| 	if err != nil { | ||||
| 		check = false | ||||
| 		fmt.Printf("fiee token parse err:%v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("fieeJwtInfo :%#v\n", fieeJwtInfo) | ||||
| 		accountInfo.Origin = config.AppConfig.System.Domain | ||||
| 		//accountInfo.OriginId = int64(fieeJwtInfo.ID)
 | ||||
| 		accountInfo.Account = fieeJwtInfo.Account | ||||
| 		accountInfo.NickName = fieeJwtInfo.NickName | ||||
| 		infoReq := &accountFiee.UserByTelRequest{ | ||||
| 			Tel:    fieeJwtInfo.Phone, | ||||
| 			Domain: config.AppConfig.System.Domain, | ||||
| 		} | ||||
| 		var accInfo *accountFiee.UserInfoResponse | ||||
| 		accInfo, err = service.AccountFieeProvider.UserByTel(ctx, infoReq) | ||||
| 		if err != nil { | ||||
| 			check = false | ||||
| 			fmt.Printf("fiee token parse err:%v\n", err) | ||||
| 		} else { | ||||
| 			fmt.Printf("fieeJwtInfo :%#v\n", fieeJwtInfo) | ||||
| 			accountInfo.Origin = config.AppConfig.System.Domain | ||||
| 			//accountInfo.OriginId = int64(fieeJwtInfo.ID)
 | ||||
| 			accountInfo.Account = fieeJwtInfo.Account | ||||
| 			accountInfo.NickName = fieeJwtInfo.NickName | ||||
| 			infoReq := &accountFiee.UserByTelRequest{ | ||||
| 				Tel:    fieeJwtInfo.Phone, | ||||
| 				Domain: config.AppConfig.System.Domain, | ||||
| 			} | ||||
| 			var accInfo *accountFiee.UserInfoResponse | ||||
| 			accInfo, err = service.AccountFieeProvider.UserByTel(ctx, infoReq) | ||||
| 			if err != nil { | ||||
| 				check = false | ||||
| 				fmt.Printf("err:%#v\n", err) | ||||
| 			} else if accInfo != nil { | ||||
| 				fmt.Printf("fiee accInfo :%#v\n", accInfo) | ||||
| 				accountInfo.OriginId = int64(accInfo.Id) | ||||
| 				accountInfo.Account = accInfo.TelNum | ||||
| 				accountInfo.Avatar = accInfo.GroupPhoto | ||||
| 				if accInfo.Name != "" { | ||||
| 					accountInfo.NickName = accInfo.Name | ||||
| 				} | ||||
| 			fmt.Printf("err:%#v\n", err) | ||||
| 		} else if accInfo != nil { | ||||
| 			fmt.Printf("fiee accInfo :%#v\n", accInfo) | ||||
| 			accountInfo.OriginId = int64(accInfo.Id) | ||||
| 			accountInfo.Account = accInfo.TelNum | ||||
| 			accountInfo.Avatar = accInfo.GroupPhoto | ||||
| 			if accInfo.Name != "" { | ||||
| 				accountInfo.NickName = accInfo.Name | ||||
| 			} | ||||
| 		} | ||||
| 	case "fontree": | ||||
| 	} | ||||
| 	if !check { | ||||
| 		msg.Content.Auth, err = secret.GetJwtFromStr(msg.Content.Auth) | ||||
| 		if err != nil { | ||||
| 			fmt.Println("token解析失败:", err.Error()) | ||||
| 			check = false | ||||
| 		} else { | ||||
| 			var fontreeJwtInfo *account.DecryptJwtResponse | ||||
|  | ||||
| @ -111,7 +111,7 @@ func (a *ChatAutoReplyRulerHandler) GetChatAutoReplyRulerList(c *gin.Context) { | ||||
| 	var protoReq = accountFiee.GetChatAutoReplyRulerListRequest{Query: &accountFiee.ChatAutoReplyRulerData{}} | ||||
| 	utils.RequestDataConvert(&req, &protoReq) | ||||
| 	if req.RuleType != "" { | ||||
| 		protoReq.Where = fmt.Sprintf("ruler LIKE '%%%s\":{\"enable\":true%%'", req.RuleType) | ||||
| 		protoReq.Where = fmt.Sprintf("ruler LIKE '%%\"%s\":{\"enable\":true}%%'", req.RuleType) | ||||
| 	} | ||||
| 	resp, err := service.AccountFieeProvider.GetChatAutoReplyRulerList(c, &protoReq) | ||||
| 	if err != nil { | ||||
|  | ||||
| @ -99,7 +99,7 @@ func (cr ChatCache) GetChatRecord(sessionId string) (data []*accountFiee.ChatRec | ||||
| 		//log.Print("获取聊天记录失败", zap.Error(err))
 | ||||
| 		return | ||||
| 	} | ||||
| 	//fmt.Printf("cache data: %+v", string(messages))
 | ||||
| 	fmt.Printf("cache data: %+v", string(messages)) | ||||
| 	if len(messages) > 0 { | ||||
| 		_ = json.Unmarshal(messages, &data) | ||||
| 	} | ||||
| @ -144,36 +144,29 @@ func (cr ChatCache) IncreaseNewMessageTotal(ownerId int64, sessionId string) (er | ||||
| 
 | ||||
| // 重置新消息数量
 | ||||
| func (cr ChatCache) ResetNewMessageTotal(ownerId int64, sessionId string, total ...int64) error { | ||||
| 	fmt.Printf("ResetNewMessageTotal: %d ,sessionId:%s ,total:%v\n", ownerId, sessionId, total) | ||||
| 	chatCacheLocker.Lock() | ||||
| 	defer chatCacheLocker.Unlock() | ||||
| 	var tl int64 | ||||
| 	if len(total) > 0 { | ||||
| 		tl = total[0] | ||||
| 	} | ||||
| 	fmt.Println("ResetNewMessageTotal tl:", tl) | ||||
| 	ctx := context.Background() | ||||
| 	data := cr.GetNewMessageStat(ctx, ownerId) | ||||
| 	fmt.Printf("ResetNewMessageTotal data:%+v\n", data) | ||||
| 	found := false | ||||
| 	for i, v := range data { | ||||
| 		if v.SessionId == sessionId { | ||||
| 			found = true | ||||
| 			data[i].Total = tl | ||||
| 			fmt.Println("ResetNewMessageTotal found!") | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if !found { | ||||
| 		fmt.Println("ResetNewMessageTotal not found!") | ||||
| 		data = append(data, dto.UserMsgStatic{ | ||||
| 			SessionId: sessionId, | ||||
| 			Total:     tl, | ||||
| 		}) | ||||
| 	} | ||||
| 	err := cr.coverOwnerNewMessageStat(ctx, ownerId, data) | ||||
| 	fmt.Println("ResetNewMessageTotal result:", err) | ||||
| 	return err | ||||
| 	return cr.coverOwnerNewMessageStat(ctx, ownerId, data) | ||||
| } | ||||
| 
 | ||||
| func (cr ChatCache) RecountNewMessageTotal(ownerId int64) { | ||||
| @ -201,8 +194,7 @@ func (cr ChatCache) RecountNewMessageTotal(ownerId int64) { | ||||
| 		if len(messages) > 0 { | ||||
| 			_ = json.Unmarshal(messages, &data) | ||||
| 		} | ||||
| 		lastIndex := strings.Count(key, ":") | ||||
| 		var sessionId = strings.Split(key, ":")[lastIndex] | ||||
| 		var sessionId = strings.Split(key, ":")[1] | ||||
| 		countMap[sessionId] = 0 | ||||
| 		for _, v := range data { | ||||
| 			if v.WaiterRead == 2 { //统计未读消息数量
 | ||||
|  | ||||
| @ -31,10 +31,8 @@ type MessageMedia struct { | ||||
| // 客户端发送消息请求,使用api发送消息
 | ||||
| type NewMessageRequest struct { | ||||
| 	Waiter    bool   `json:"waiter"` //是否是客服发送,客服没有userId
 | ||||
| 	Robot     bool   `json:"-"`      //是否机器人发送
 | ||||
| 	SessionId string `json:"sessionId"` | ||||
| 	Message | ||||
| 	AtUserId int64 `json:"atUserId"` //指定发送给sessionId中的某一个用户
 | ||||
| } | ||||
| 
 | ||||
| // 服务端接收到消息后,使用websocket发送给userId关联的客户端,通知客户端有新消息,然后调用接口获取消息
 | ||||
|  | ||||
| @ -230,9 +230,9 @@ func (cr ChatHandler) MessageList(c *gin.Context) { | ||||
| 		service.Error(c, err) | ||||
| 		return | ||||
| 	} | ||||
| 	//domain := c.GetHeader("domain")
 | ||||
| 	//fmt.Println("MessageList domain:", domain)
 | ||||
| 	if (request.Direction == 0 && !request.Recent) || (request.Direction > 0 && request.Recent) { | ||||
| 	domain := c.GetHeader("domain") | ||||
| 	fmt.Println("MessageList domain:", domain) | ||||
| 	if (request.Direction == 0 && request.Recent == false) || (request.Direction > 0 && request.Recent == true) { | ||||
| 		service.Error(c, errors.New("组合条件校验失败")) | ||||
| 		return | ||||
| 	} | ||||
| @ -249,7 +249,7 @@ func (cr ChatHandler) MessageList(c *gin.Context) { | ||||
| 		service.Success(c, resp) | ||||
| 		return | ||||
| 	} | ||||
| 	accessUser, code := jwt.ParseToChatUser(c) | ||||
| 	chatUser, code := jwt.ParseToChatUser(c) | ||||
| 	if code != 0 { | ||||
| 		service.ErrWithCode(c, code) | ||||
| 		return | ||||
| @ -261,16 +261,16 @@ func (cr ChatHandler) MessageList(c *gin.Context) { | ||||
| 	//		return
 | ||||
| 	//	}
 | ||||
| 	//}
 | ||||
| 	messages := cr.cache.GetChatRecord(request.SessionId) | ||||
| 	//messages := []*accountFiee.ChatRecordData{}
 | ||||
| 	//messages := cr.cache.GetChatRecord(request.SessionId)
 | ||||
| 	messages := []*accountFiee.ChatRecordData{} | ||||
| 	var returnDataIdList = make([]int64, 0) | ||||
| 	defer func() { | ||||
| 		//获取最新数据时,重置新消息数量统计
 | ||||
| 		if request.Direction == 2 || request.Recent { | ||||
| 			cr.cache.ResetNewMessageTotal(accessUser.ID, request.SessionId) | ||||
| 			cr.cache.ResetNewMessageTotal(chatUser.ID, request.SessionId) | ||||
| 		} | ||||
| 		//设置消息已被客服阅读,当客服重新通过通过websocket连接时,这些消息将不被纳入新消息数量统计
 | ||||
| 		if len(returnDataIdList) > 0 && accessUser.Role == 2 { | ||||
| 		if len(returnDataIdList) > 0 && domain == "fontree" { | ||||
| 			for _, hasReadId := range returnDataIdList { | ||||
| 				for i, message := range messages { | ||||
| 					if message.ID == hasReadId { | ||||
| @ -368,8 +368,6 @@ func (cr ChatHandler) MessageList(c *gin.Context) { | ||||
| 			resp[i].Message.Media = []dto.MessageMedia{} | ||||
| 		} | ||||
| 	} | ||||
| 	if accessUser.Role == 1 { | ||||
| 	} | ||||
| 	service.Success(c, resp) | ||||
| } | ||||
| 
 | ||||
| @ -503,21 +501,10 @@ func (cr ChatHandler) UserMessageStat(c *gin.Context) { | ||||
| 			} | ||||
| 		} | ||||
| 		if result[i].Name == "" { | ||||
| 			result[i].Name = beautifulZeroNameWithPhone(result[i].Name, result[i].UserId) | ||||
| 			result[i].Name = beautifulZeroName(result[i].Name, result[i].UserId) | ||||
| 		} | ||||
| 	} | ||||
| 	reverse(result) | ||||
| 	if chatUser.Role == 1 { | ||||
| 		userSessionId := fmt.Sprintf("%d", chatUser.ID) | ||||
| 		newResp := []dto.UserMsgStatic{} | ||||
| 		for _, v := range result { | ||||
| 			if v.SessionId == userSessionId { | ||||
| 				newResp = append(newResp, v) | ||||
| 				service.Success(c, newResp) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	service.Success(c, result) | ||||
| } | ||||
| func reverse(slice []dto.UserMsgStatic) { | ||||
| @ -576,10 +563,6 @@ func (cr ChatHandler) UserDetail(c *gin.Context) { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	//fmt.Printf("chatUser:%#v\n", chatUser)
 | ||||
| 	//if chatUser.Origin == "fiee" {
 | ||||
| 	//	chatUser.Origin = "app"
 | ||||
| 	//}
 | ||||
| 	resp, err := service.AccountFieeProvider.Info(c, &accountFiee.InfoRequest{ID: uint64(chatUser.OriginId), Domain: chatUser.Origin}) | ||||
| 	if err != nil { | ||||
| 		service.Error(c, err) | ||||
| @ -605,31 +588,3 @@ func (cr ChatHandler) UserDetail(c *gin.Context) { | ||||
| func beautifulZeroName(name string, userId int64) string { | ||||
| 	return utils.IfGec(name == "", fmt.Sprintf("未实名用户:%d", userId), name) | ||||
| } | ||||
| 
 | ||||
| var userIdMapPhone = make(map[int64]string) | ||||
| 
 | ||||
| func beautifulZeroNameWithPhone(name string, userId int64) string { | ||||
| 	var ctx = context.Background() | ||||
| 	if name == "" { | ||||
| 		telNum, ok := userIdMapPhone[userId] | ||||
| 		if ok { | ||||
| 			return telNum | ||||
| 		} | ||||
| 		chatUserRes, err := service.AccountFieeProvider.GetChatUserDetail(ctx, &accountFiee.GetChatUserByIdRequest{Id: userId}) | ||||
| 		if err != nil { | ||||
| 			return fmt.Sprintf("未实名用户:%d", userId) | ||||
| 		} else { | ||||
| 			if userRes, errs := service.AccountFieeProvider.Info(ctx, &accountFiee.InfoRequest{ | ||||
| 				Domain: chatUserRes.Origin, | ||||
| 				ID:     uint64(chatUserRes.OriginId), | ||||
| 				Scene:  "", | ||||
| 			}); errs != nil { | ||||
| 				return fmt.Sprintf("未实名用户:%d", userId) | ||||
| 			} else { | ||||
| 				userIdMapPhone[userId] = userRes.TelNum | ||||
| 				return userRes.TelNum | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| @ -24,8 +24,8 @@ import ( | ||||
| //}
 | ||||
| 
 | ||||
| type AutoReply struct { | ||||
| 	Response string                `json:"response"` | ||||
| 	Rules    map[string]IRobotTask `json:"rules"` | ||||
| 	Response string           `json:"response"` | ||||
| 	Rules    map[string]IRule `json:"rules"` | ||||
| } | ||||
| type AutoReplyRule struct { | ||||
| 	Enable       bool     `json:"enable"` | ||||
|  | ||||
| @ -26,6 +26,3 @@ web端和后端交互式时,增删改查的规则配置是存放在rules对象 | ||||
| - keywords :关键字回复 | ||||
| - joinSession:用户打开聊天窗口后 | ||||
| - noReplyAfter:客服指定时间没有回复后 | ||||
| 
 | ||||
| ## 注意 | ||||
| - 目前不支持用户多端登录,会导致用户收到重复消息 | ||||
| @ -7,20 +7,26 @@ | ||||
| package robot | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fonchain-fiee/api/accountFiee" | ||||
| 	"fonchain-fiee/pkg/common/ws" | ||||
| 	"fonchain-fiee/pkg/service" | ||||
| 	"fonchain-fiee/pkg/service/asChat/chatCache" | ||||
| 	"fonchain-fiee/pkg/service/asChat/dto" | ||||
| 	"fonchain-fiee/pkg/service/asChat/logic" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // 回复规则
 | ||||
| type Reply struct { | ||||
| 	Title    string | ||||
| 	Response string | ||||
| 	Rules    []IRobotTask | ||||
| 	Rules    []IRule | ||||
| } | ||||
| 
 | ||||
| func (r *Reply) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, rule IRobotTask) { | ||||
| 	for _, rule = range r.Rules { | ||||
| 		hit = rule.Hit(event, robotInfo) | ||||
| func (r *Reply) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) { | ||||
| 	for _, rule := range r.Rules { | ||||
| 		hit, task = rule.Hit(event, robotInfo) | ||||
| 		if hit { | ||||
| 			return | ||||
| 		} | ||||
| @ -28,219 +34,226 @@ func (r *Reply) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserDat | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| //// 规则接口
 | ||||
| //type IRule interface {
 | ||||
| //	Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask)
 | ||||
| //}
 | ||||
| //
 | ||||
| //// KeywordsRuleChecker 关键字回复
 | ||||
| //type ReplyWhenHitKeywords struct {
 | ||||
| //	Keywords []string `json:"keywords"`
 | ||||
| //}
 | ||||
| //
 | ||||
| //func NewReplyWhenHitKeywords(keywords []string) IRule {
 | ||||
| //	return &ReplyWhenHitKeywords{Keywords: keywords}
 | ||||
| //}
 | ||||
| //func (k ReplyWhenHitKeywords) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) {
 | ||||
| //	if event.EventType != ws.EventChatMessage || event.Msg == "" || event.Client == nil || event.ChatUser == nil {
 | ||||
| //		return
 | ||||
| //	}
 | ||||
| //	if event.ChatUser.Role != 1 {
 | ||||
| //		return
 | ||||
| //	}
 | ||||
| //	for _, v := range k.Keywords {
 | ||||
| //		if strings.Contains(event.Msg, v) {
 | ||||
| //			hit = true
 | ||||
| //			break
 | ||||
| //		}
 | ||||
| //	}
 | ||||
| //	atUserId := event.Client.UserId
 | ||||
| //	task = RobotTask{
 | ||||
| //		ChatUser: event.ChatUser,
 | ||||
| //		Run: func(msg string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error {
 | ||||
| //			return logic.NewMessage(context.Background(), cache, Sender, dto.NewMessageRequest{
 | ||||
| //				Waiter:    true,
 | ||||
| //				Robot:     true,
 | ||||
| //				AtUserId:  atUserId,
 | ||||
| //				SessionId: event.Client.SessionId,
 | ||||
| //				Message: dto.Message{
 | ||||
| //					MsgType:    1,
 | ||||
| //					Text:       msg,
 | ||||
| //					LocalStamp: time.Now().Unix(),
 | ||||
| //				},
 | ||||
| //			})
 | ||||
| //		},
 | ||||
| //	}
 | ||||
| //	return
 | ||||
| //}
 | ||||
| //
 | ||||
| //// 用户打开聊天会话直接发送
 | ||||
| //type ReplyWhenUserJoinSession struct {
 | ||||
| //}
 | ||||
| //
 | ||||
| //func NewReplyWhenUserJoinSession() IRule {
 | ||||
| //	return &ReplyWhenUserJoinSession{}
 | ||||
| //}
 | ||||
| //
 | ||||
| //func (k ReplyWhenUserJoinSession) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) {
 | ||||
| //	if event.EventType != ws.EventUserJoin {
 | ||||
| //		return
 | ||||
| //	}
 | ||||
| //	if event.Client == nil {
 | ||||
| //		return
 | ||||
| //	}
 | ||||
| //	clientSessionId := event.Client.SessionId
 | ||||
| //	atUserId := event.Client.UserId
 | ||||
| //	ctx := context.Background()
 | ||||
| //	queryRes, err := service.AccountFieeProvider.GetChatRecordList(ctx, &accountFiee.GetChatRecordListRequest{
 | ||||
| //		Query: &accountFiee.ChatRecordData{
 | ||||
| //			SessionId: event.Client.SessionId,
 | ||||
| //		},
 | ||||
| //		Page:     1,
 | ||||
| //		PageSize: 1,
 | ||||
| //		Order:    "created_at desc",
 | ||||
| //	})
 | ||||
| //	if err != nil {
 | ||||
| //		return
 | ||||
| //	}
 | ||||
| //	//如果最近一次的消息也是机器人发送的,就不再发送了
 | ||||
| //	for i, v := range queryRes.List {
 | ||||
| //		if i == 0 {
 | ||||
| //			if v.UserId == robotInfo.ID {
 | ||||
| //				return
 | ||||
| //			} else {
 | ||||
| //				break
 | ||||
| //			}
 | ||||
| //		}
 | ||||
| //	}
 | ||||
| //	hit = true
 | ||||
| //	if event.ChatUser == nil {
 | ||||
| //		event.ChatUser, err = service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: event.Client.UserId})
 | ||||
| //		if err != nil {
 | ||||
| //			return
 | ||||
| //		}
 | ||||
| //	}
 | ||||
| //	task = RobotTask{
 | ||||
| //		ChatUser: event.ChatUser,
 | ||||
| //		Run: func(msg string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error {
 | ||||
| //			return logic.NewMessage(ctx, cache, Sender, dto.NewMessageRequest{
 | ||||
| //				Waiter:    true,
 | ||||
| //				Robot:     true,
 | ||||
| //				AtUserId:  atUserId,
 | ||||
| //				SessionId: clientSessionId,
 | ||||
| //				Message: dto.Message{
 | ||||
| //					MsgType:    1,
 | ||||
| //					Text:       msg,
 | ||||
| //					LocalStamp: time.Now().Unix(),
 | ||||
| //				},
 | ||||
| //			})
 | ||||
| //		},
 | ||||
| //	}
 | ||||
| //	//logicFunc = func(msg string, cache *chatCache.ChatCache, chatUser *accountFiee.ChatUserData) error {
 | ||||
| //	//	//var notice = dto.MessageListType{}
 | ||||
| //	//	//newRecord := &accountFiee.ChatRecordData{
 | ||||
| //	//	//	SessionId: wsClient.SessionId,
 | ||||
| //	//	//	UserId:    wsClient.UserId,
 | ||||
| //	//	//	Name:      wsClient.SessionId,
 | ||||
| //	//	//	Avatar:    robotInfo.Avatar,
 | ||||
| //	//	//	MsgType:   1,
 | ||||
| //	//	//	Content:   msg,
 | ||||
| //	//	//}
 | ||||
| //	//	//notice.BuildMessage(newRecord)
 | ||||
| //	//	//_, err = consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
 | ||||
| //	//	err = logic.NewMessage(ctx, cache, chatUser, dto.NewMessageRequest{
 | ||||
| //	//		Waiter:    true,
 | ||||
| //	//		SessionId: wsClient.SessionId,
 | ||||
| //	//		Message: dto.Message{
 | ||||
| //	//			MsgType:    1,
 | ||||
| //	//			Text:       msg,
 | ||||
| //	//			LocalStamp: time.Now().Unix(),
 | ||||
| //	//		},
 | ||||
| //	//	})
 | ||||
| //	//	return err
 | ||||
| //	//}
 | ||||
| //	return
 | ||||
| //}
 | ||||
| //
 | ||||
| //// 客服指定时间不回复则自动回复
 | ||||
| //
 | ||||
| //type ReplyWhenWaiterNoAction struct {
 | ||||
| //	DelaySecond time.Duration
 | ||||
| //}
 | ||||
| //
 | ||||
| ////func NewReplyWhenWaiterNoAction(delaySecond time.Duration) *ReplyWhenWaiterNoAction {
 | ||||
| ////	return &ReplyWhenWaiterNoAction{
 | ||||
| ////		DelaySecond: delaySecond,
 | ||||
| ////	}
 | ||||
| ////}
 | ||||
| //
 | ||||
| //func (k *ReplyWhenWaiterNoAction) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool, task RobotTask) {
 | ||||
| //	if event.Client == nil || event.EventType != ws.EventChatMessage {
 | ||||
| //		return
 | ||||
| //	}
 | ||||
| //	//客服和机器人的的消息不需要处理
 | ||||
| //	if event.ChatUser.Role != 1 {
 | ||||
| //		return
 | ||||
| //	}
 | ||||
| //	hit = true // 立即保存SessionId的值
 | ||||
| //
 | ||||
| //	clientSessionId := event.Client.SessionId
 | ||||
| //	atUserId := event.Client.UserId
 | ||||
| //	fmt.Printf("闭包前: clientSessionId=%s\n", clientSessionId)
 | ||||
| //	task = RobotTask{
 | ||||
| //		RunTime: time.Now().Add(k.DelaySecond * time.Second),
 | ||||
| //		Run: func(content string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error {
 | ||||
| //			// 记录闭包执行时的Client状态
 | ||||
| //			fmt.Printf("闭包执行: clientSessionId=%s\n", clientSessionId)
 | ||||
| //
 | ||||
| //			//如果客服已经回复则不发送消息
 | ||||
| //			chatRecordListRes, err := service.AccountFieeProvider.GetChatRecordList(context.Background(), &accountFiee.GetChatRecordListRequest{
 | ||||
| //				Query: &accountFiee.ChatRecordData{
 | ||||
| //					SessionId: event.Client.SessionId,
 | ||||
| //				},
 | ||||
| //				Page:     1,
 | ||||
| //				PageSize: 1,
 | ||||
| //				Order:    "created_at desc",
 | ||||
| //			})
 | ||||
| //			if err != nil || chatRecordListRes.Total == 0 {
 | ||||
| //				return err
 | ||||
| //			}
 | ||||
| //			checkUserId := chatRecordListRes.List[0].UserId
 | ||||
| //			checkChatUser, err := service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: checkUserId})
 | ||||
| //			if err != nil || checkChatUser.Role != 1 {
 | ||||
| //				return err
 | ||||
| //			}
 | ||||
| //
 | ||||
| //			//var notice = dto.MessageListType{}
 | ||||
| //			//newRecord := &accountFiee.ChatRecordData{
 | ||||
| //			//	SessionId: wsClient.SessionId,
 | ||||
| //			//	UserId:    wsClient.UserId,
 | ||||
| //			//	Name:      chatUser.NickName,
 | ||||
| //			//	Avatar:    robotInfo.Avatar,
 | ||||
| //			//	MsgType:   1,
 | ||||
| //			//	Content:   content,
 | ||||
| //			//}
 | ||||
| //			//notice.BuildMessage(newRecord)
 | ||||
| //			//_, err = consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
 | ||||
| //			//return err
 | ||||
| //			fmt.Println("延时回复 sessionID:", clientSessionId)
 | ||||
| //			err = logic.NewMessage(context.Background(), cache, sender, dto.NewMessageRequest{
 | ||||
| //				Waiter:    true,
 | ||||
| //				Robot:     true,
 | ||||
| //				AtUserId:  atUserId,
 | ||||
| //				SessionId: clientSessionId,
 | ||||
| //				Message: dto.Message{
 | ||||
| //					MsgType:    1,
 | ||||
| //					Text:       content,
 | ||||
| //					LocalStamp: time.Now().Unix(),
 | ||||
| //				},
 | ||||
| //			})
 | ||||
| //			return err
 | ||||
| //		},
 | ||||
| //		Response: "",
 | ||||
| //		ChatUser: event.ChatUser,
 | ||||
| //	}
 | ||||
| //	return
 | ||||
| //
 | ||||
| //}
 | ||||
| // 规则接口
 | ||||
| type IRule interface { | ||||
| 	Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) | ||||
| } | ||||
| 
 | ||||
| // KeywordsRuleChecker 关键字回复
 | ||||
| type ReplyWhenHitKeywords struct { | ||||
| 	Keywords []string `json:"keywords"` | ||||
| } | ||||
| 
 | ||||
| func NewReplyWhenHitKeywords(keywords []string) IRule { | ||||
| 	return &ReplyWhenHitKeywords{Keywords: keywords} | ||||
| } | ||||
| func (k ReplyWhenHitKeywords) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) { | ||||
| 	if event.EventType != ws.EventChatMessage || event.Msg == "" || event.Client == nil || event.ChatUser == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	//客服的消息不需要处理
 | ||||
| 	if event.ChatUser.Role == 2 { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, v := range k.Keywords { | ||||
| 		if strings.Contains(event.Msg, v) { | ||||
| 			hit = true | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	task = RobotTask{ | ||||
| 		ChatUser: event.ChatUser, | ||||
| 		Run: func(msg string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error { | ||||
| 			return logic.NewMessage(context.Background(), cache, Sender, dto.NewMessageRequest{ | ||||
| 				Waiter:    true, | ||||
| 				SessionId: event.Client.SessionId, | ||||
| 				Message: dto.Message{ | ||||
| 					MsgType:    1, | ||||
| 					Text:       msg, | ||||
| 					LocalStamp: time.Now().Unix(), | ||||
| 				}, | ||||
| 			}) | ||||
| 		}, | ||||
| 	} | ||||
| 	//logicFunc = func(content string, cache *chatCache.ChatCache, chatUser *accountFiee.ChatUserData) error {
 | ||||
| 	//	//var notice = dto.MessageListType{}
 | ||||
| 	//	//newRecord := &accountFiee.ChatRecordData{
 | ||||
| 	//	//	SessionId: wsClient.SessionId,
 | ||||
| 	//	//	UserId:    wsClient.UserId,
 | ||||
| 	//	//	Name:      chatUser.NickName,
 | ||||
| 	//	//	Avatar:    robotInfo.Avatar,
 | ||||
| 	//	//	MsgType:   1,
 | ||||
| 	//	//	Content:   content,
 | ||||
| 	//	//}
 | ||||
| 	//	//notice.BuildMessage(newRecord)
 | ||||
| 	//	//_, err := consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
 | ||||
| 	//	//return err
 | ||||
| 	//	err := logic.NewMessage(context.Background(), cache, chatUser, dto.NewMessageRequest{
 | ||||
| 	//		Waiter:    true,
 | ||||
| 	//		SessionId: wsClient.SessionId,
 | ||||
| 	//		Message: dto.Message{
 | ||||
| 	//			MsgType:    1,
 | ||||
| 	//			Text:       msg,
 | ||||
| 	//			LocalStamp: time.Now().Unix(),
 | ||||
| 	//		},
 | ||||
| 	//	})
 | ||||
| 	//	return err
 | ||||
| 	//}
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // 用户打开聊天会话直接发送
 | ||||
| type ReplyWhenUserJoinSession struct { | ||||
| } | ||||
| 
 | ||||
| func NewReplyWhenUserJoinSession() IRule { | ||||
| 	return &ReplyWhenUserJoinSession{} | ||||
| } | ||||
| 
 | ||||
| func (k ReplyWhenUserJoinSession) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) { | ||||
| 	if event.EventType != ws.EventUserJoin { | ||||
| 		return | ||||
| 	} | ||||
| 	if event.Client == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	ctx := context.Background() | ||||
| 	queryRes, err := service.AccountFieeProvider.GetChatRecordList(ctx, &accountFiee.GetChatRecordListRequest{ | ||||
| 		Query: &accountFiee.ChatRecordData{ | ||||
| 			SessionId: event.Client.SessionId, | ||||
| 		}, | ||||
| 		Page:     1, | ||||
| 		PageSize: 1, | ||||
| 		Order:    "created_at desc", | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	//如果最近一次的消息也是机器人发送的,就不再发送了
 | ||||
| 	for i, v := range queryRes.List { | ||||
| 		if i == 0 { | ||||
| 			if v.UserId == robotInfo.ID { | ||||
| 				return | ||||
| 			} else { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	hit = true | ||||
| 	if event.ChatUser == nil { | ||||
| 		event.ChatUser, err = service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: event.Client.UserId}) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	task = RobotTask{ | ||||
| 		ChatUser: event.ChatUser, | ||||
| 		Run: func(msg string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error { | ||||
| 			return logic.NewMessage(ctx, cache, Sender, dto.NewMessageRequest{ | ||||
| 				Waiter:    true, | ||||
| 				SessionId: event.Client.SessionId, | ||||
| 				Message: dto.Message{ | ||||
| 					MsgType:    1, | ||||
| 					Text:       msg, | ||||
| 					LocalStamp: time.Now().Unix(), | ||||
| 				}, | ||||
| 			}) | ||||
| 		}, | ||||
| 	} | ||||
| 	//logicFunc = func(msg string, cache *chatCache.ChatCache, chatUser *accountFiee.ChatUserData) error {
 | ||||
| 	//	//var notice = dto.MessageListType{}
 | ||||
| 	//	//newRecord := &accountFiee.ChatRecordData{
 | ||||
| 	//	//	SessionId: wsClient.SessionId,
 | ||||
| 	//	//	UserId:    wsClient.UserId,
 | ||||
| 	//	//	Name:      wsClient.SessionId,
 | ||||
| 	//	//	Avatar:    robotInfo.Avatar,
 | ||||
| 	//	//	MsgType:   1,
 | ||||
| 	//	//	Content:   msg,
 | ||||
| 	//	//}
 | ||||
| 	//	//notice.BuildMessage(newRecord)
 | ||||
| 	//	//_, err = consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
 | ||||
| 	//	err = logic.NewMessage(ctx, cache, chatUser, dto.NewMessageRequest{
 | ||||
| 	//		Waiter:    true,
 | ||||
| 	//		SessionId: wsClient.SessionId,
 | ||||
| 	//		Message: dto.Message{
 | ||||
| 	//			MsgType:    1,
 | ||||
| 	//			Text:       msg,
 | ||||
| 	//			LocalStamp: time.Now().Unix(),
 | ||||
| 	//		},
 | ||||
| 	//	})
 | ||||
| 	//	return err
 | ||||
| 	//}
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // 客服指定时间不回复则自动回复
 | ||||
| 
 | ||||
| type ReplyWhenWaiterNoAction struct { | ||||
| 	DelaySecond time.Duration | ||||
| } | ||||
| 
 | ||||
| func NewReplyWhenWaiterNoAction(delaySecond time.Duration) *ReplyWhenWaiterNoAction { | ||||
| 	return &ReplyWhenWaiterNoAction{ | ||||
| 		DelaySecond: delaySecond, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (k *ReplyWhenWaiterNoAction) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool, task RobotTask) { | ||||
| 	if event.Client == nil || event.EventType != ws.EventChatMessage { | ||||
| 		return | ||||
| 	} | ||||
| 	//客服的消息不需要处理
 | ||||
| 	if event.ChatUser.Role == 2 { | ||||
| 		return | ||||
| 	} | ||||
| 	hit = true | ||||
| 	task = RobotTask{ | ||||
| 		RunTime: time.Now().Add(k.DelaySecond * time.Second), | ||||
| 		Run: func(content string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error { | ||||
| 			//如果客服已经回复则不发送消息
 | ||||
| 			chatRecordListRes, err := service.AccountFieeProvider.GetChatRecordList(context.Background(), &accountFiee.GetChatRecordListRequest{ | ||||
| 				Query: &accountFiee.ChatRecordData{ | ||||
| 					SessionId: event.Client.SessionId, | ||||
| 				}, | ||||
| 				Page:     1, | ||||
| 				PageSize: 1, | ||||
| 				Order:    "created_at desc", | ||||
| 			}) | ||||
| 			if err != nil || chatRecordListRes.Total == 0 { | ||||
| 				return err | ||||
| 			} | ||||
| 			checkUserId := chatRecordListRes.List[0].UserId | ||||
| 			checkChatUser, err := service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: checkUserId}) | ||||
| 			if err != nil || checkChatUser.Role != 1 { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			//var notice = dto.MessageListType{}
 | ||||
| 			//newRecord := &accountFiee.ChatRecordData{
 | ||||
| 			//	SessionId: wsClient.SessionId,
 | ||||
| 			//	UserId:    wsClient.UserId,
 | ||||
| 			//	Name:      chatUser.NickName,
 | ||||
| 			//	Avatar:    robotInfo.Avatar,
 | ||||
| 			//	MsgType:   1,
 | ||||
| 			//	Content:   content,
 | ||||
| 			//}
 | ||||
| 			//notice.BuildMessage(newRecord)
 | ||||
| 			//_, err = consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
 | ||||
| 			//return err
 | ||||
| 			err = logic.NewMessage(context.Background(), cache, sender, dto.NewMessageRequest{ | ||||
| 				Waiter:    true, | ||||
| 				SessionId: event.Client.SessionId, | ||||
| 				Message: dto.Message{ | ||||
| 					MsgType:    1, | ||||
| 					Text:       content, | ||||
| 					LocalStamp: time.Now().Unix(), | ||||
| 				}, | ||||
| 			}) | ||||
| 			return err | ||||
| 		}, | ||||
| 		Response: "", | ||||
| 		ChatUser: event.ChatUser, | ||||
| 	} | ||||
| 	return | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -57,7 +57,7 @@ func NewRobot(cache *chatCache.ChatCache) *Robot { | ||||
| 		cache: cache, | ||||
| 	} | ||||
| 	err = r.ReloadRules(ctx) | ||||
| 	fmt.Println("机器人规则加载完成,结果:", err) | ||||
| 	fmt.Println("机器人规则加载失败") | ||||
| 	consts.ChatRoom.RegisterEventListener(r.EventListener) | ||||
| 	go r.Run() | ||||
| 	return r | ||||
| @ -66,7 +66,7 @@ func NewRobot(cache *chatCache.ChatCache) *Robot { | ||||
| type Robot struct { | ||||
| 	Info      *accountFiee.ChatUserData //机器人信息
 | ||||
| 	Rules     []Reply                   //回复规则
 | ||||
| 	DelayTask []IRobotTask              //演示任务
 | ||||
| 	DelayTask []RobotTask               //演示任务
 | ||||
| 	ticker    *time.Ticker              //定时器
 | ||||
| 	stopChan  chan struct{}             //停止管道
 | ||||
| 	isRunning bool                      //运行状态
 | ||||
| @ -140,12 +140,12 @@ func (r *Robot) Run() { | ||||
| 				//return // 没有任务时退出
 | ||||
| 			} | ||||
| 			now := time.Now() | ||||
| 			var remainingTasks []IRobotTask | ||||
| 			var remainingTasks []RobotTask | ||||
| 			for _, task := range r.DelayTask { | ||||
| 				if now.After(task.RunTime()) { | ||||
| 				if now.After(task.RunTime) { | ||||
| 					// 执行任务
 | ||||
| 					go func() { | ||||
| 						err := task.Run(r.cache) | ||||
| 						err := task.Run(task.Response, r.cache, task.ChatUser) | ||||
| 						if err != nil { | ||||
| 							log.Printf("聊天机器人[%d]延时回复消息失败:%v", r.Info.ID, err) | ||||
| 						} else { | ||||
| @ -163,26 +163,23 @@ func (r *Robot) Run() { | ||||
| 			return | ||||
| 		case event := <-r.EventListener.Chan: | ||||
| 			fmt.Printf("robot listen event:%#v\n", event) | ||||
| 			r.mu.Lock() | ||||
| 			for _, ruleResponse := range r.Rules { | ||||
| 				hit, task := ruleResponse.Hit(event, r.Info) | ||||
| 				if hit { | ||||
| 					fmt.Println("命中规则:", ruleResponse.Title) | ||||
| 					if task.RunTime().IsZero() { | ||||
| 						task.SetResponse(ruleResponse.Response) | ||||
| 						err := task.Run(r.cache) | ||||
| 					if task.RunTime.IsZero() { | ||||
| 						err := task.Run(ruleResponse.Response, r.cache, r.Info) | ||||
| 						if err != nil { | ||||
| 							log.Printf("robot 执行任务失败:%v\n", err) | ||||
| 						} | ||||
| 					} else { | ||||
| 						ruleResponse := ruleResponse | ||||
| 						task.SetResponse(ruleResponse.Response) | ||||
| 						task.Response = ruleResponse.Response | ||||
| 						r.RegisterDelayTask(task) | ||||
| 
 | ||||
| 					} | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			r.mu.Unlock() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -195,7 +192,9 @@ func (r *Robot) Stop() { | ||||
| 	} | ||||
| 	r.mu.Unlock() | ||||
| } | ||||
| func (r *Robot) RegisterDelayTask(task IRobotTask) { | ||||
| func (r *Robot) RegisterDelayTask(task RobotTask) { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if task.Run == nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @ -7,7 +7,6 @@ | ||||
| package robot | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"fonchain-fiee/pkg/service/asChat/dto" | ||||
| 	"strings" | ||||
| ) | ||||
| @ -15,7 +14,6 @@ import ( | ||||
| // 自动回复规则结构转换
 | ||||
| func ParseReplyRule(data *dto.ChatAutoReplyData) (r Reply) { | ||||
| 	r.Response = data.Response | ||||
| 	r.Title = data.Title | ||||
| 	for ruleName, v := range data.Rules { | ||||
| 		if !v.Enable { | ||||
| 			continue | ||||
| @ -28,7 +26,6 @@ func ParseReplyRule(data *dto.ChatAutoReplyData) (r Reply) { | ||||
| 			} else { | ||||
| 				keywords = strings.Split(v.Content, ",") | ||||
| 			} | ||||
| 			fmt.Println("ParseReplyRule 解析keywords:", keywords) | ||||
| 			r.Rules = append(r.Rules, NewReplyWhenHitKeywords(keywords)) | ||||
| 		case "joinSession": //加入聊天后回复
 | ||||
| 			r.Rules = append(r.Rules, NewReplyWhenUserJoinSession()) | ||||
|  | ||||
| @ -1,98 +0,0 @@ | ||||
| // Package robot -----------------------------
 | ||||
| // @file      : ruler_ReplyWhenWaiterNoAction.go
 | ||||
| // @author    : JJXu
 | ||||
| // @contact   : wavingbear@163.com
 | ||||
| // @time      : 2025/6/13 18:02
 | ||||
| // -------------------------------------------
 | ||||
| package robot | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"fonchain-fiee/api/accountFiee" | ||||
| 	"fonchain-fiee/pkg/common/ws" | ||||
| 	"fonchain-fiee/pkg/service" | ||||
| 	"fonchain-fiee/pkg/service/asChat/chatCache" | ||||
| 	"fonchain-fiee/pkg/service/asChat/dto" | ||||
| 	"fonchain-fiee/pkg/service/asChat/logic" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type IRobotTask interface { | ||||
| 	Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool) | ||||
| 	Run(cache *chatCache.ChatCache) error | ||||
| 	RunTime() time.Time | ||||
| 	SetResponse(response string) | ||||
| } | ||||
| 
 | ||||
| // 客服指定时间不回复则自动回复
 | ||||
| func NewReplyWhenWaiterNoAction(delaySecond time.Duration) IRobotTask { | ||||
| 	return &RobotTaskReplyWhenWaiterNoAction{ | ||||
| 		delaySecond: delaySecond, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type RobotTaskReplyWhenWaiterNoAction struct { | ||||
| 	runTime     time.Time | ||||
| 	Response    string | ||||
| 	Receiver    *accountFiee.ChatUserData | ||||
| 	Sender      *accountFiee.ChatUserData | ||||
| 	Msg         string | ||||
| 	Resp        string | ||||
| 	delaySecond time.Duration | ||||
| } | ||||
| 
 | ||||
| func (r *RobotTaskReplyWhenWaiterNoAction) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool) { | ||||
| 	if event.Client == nil || event.EventType != ws.EventChatMessage { | ||||
| 		return | ||||
| 	} | ||||
| 	//客服和机器人的的消息不需要处理
 | ||||
| 	if event.ChatUser.Role != 1 { | ||||
| 		return | ||||
| 	} | ||||
| 	hit = true // 立即保存SessionId的值
 | ||||
| 	r.Sender = sender | ||||
| 	r.Receiver = event.ChatUser | ||||
| 	r.runTime = time.Now().Add(r.delaySecond * time.Second) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (r *RobotTaskReplyWhenWaiterNoAction) Run(cache *chatCache.ChatCache) error { | ||||
| 	clientSessionId := fmt.Sprintf("%d", r.Receiver.ID) | ||||
| 	fmt.Println("延时回复 sessionID:", clientSessionId) | ||||
| 	//如果客服已经回复则不发送消息
 | ||||
| 	chatRecordListRes, err := service.AccountFieeProvider.GetChatRecordList(context.Background(), &accountFiee.GetChatRecordListRequest{ | ||||
| 		Query: &accountFiee.ChatRecordData{ | ||||
| 			SessionId: clientSessionId, | ||||
| 		}, | ||||
| 		Page:     1, | ||||
| 		PageSize: 1, | ||||
| 		Order:    "created_at desc", | ||||
| 	}) | ||||
| 	if err != nil || chatRecordListRes.Total == 0 { | ||||
| 		return err | ||||
| 	} | ||||
| 	checkUserId := chatRecordListRes.List[0].UserId | ||||
| 	checkChatUser, err := service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: checkUserId}) | ||||
| 	if err != nil || checkChatUser.Role != 1 { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = logic.NewMessage(context.Background(), cache, r.Sender, dto.NewMessageRequest{ | ||||
| 		Waiter:    true, | ||||
| 		Robot:     true, | ||||
| 		AtUserId:  r.Receiver.ID, | ||||
| 		SessionId: clientSessionId, | ||||
| 		Message: dto.Message{ | ||||
| 			MsgType:    1, | ||||
| 			Text:       r.Resp, | ||||
| 			LocalStamp: time.Now().Unix(), | ||||
| 		}, | ||||
| 	}) | ||||
| 	return err | ||||
| } | ||||
| func (r *RobotTaskReplyWhenWaiterNoAction) RunTime() time.Time { | ||||
| 	return r.runTime | ||||
| } | ||||
| func (r *RobotTaskReplyWhenWaiterNoAction) SetResponse(response string) { | ||||
| 	r.Resp = response | ||||
| } | ||||
| @ -1,69 +0,0 @@ | ||||
| package robot | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"fonchain-fiee/api/accountFiee" | ||||
| 	"fonchain-fiee/pkg/common/ws" | ||||
| 	"fonchain-fiee/pkg/service/asChat/chatCache" | ||||
| 	"fonchain-fiee/pkg/service/asChat/dto" | ||||
| 	"fonchain-fiee/pkg/service/asChat/logic" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type RobotTaskWithKeyworkds struct { | ||||
| 	runTime  time.Time | ||||
| 	Response string | ||||
| 	Receiver *accountFiee.ChatUserData | ||||
| 	Sender   *accountFiee.ChatUserData | ||||
| 	Msg      string | ||||
| 	Resp     string | ||||
| 	keywords []string | ||||
| } | ||||
| 
 | ||||
| func NewReplyWhenHitKeywords(keywords []string) IRobotTask { | ||||
| 	return &RobotTaskWithKeyworkds{keywords: keywords} | ||||
| } | ||||
| func (r *RobotTaskWithKeyworkds) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool) { | ||||
| 	if event.EventType != ws.EventChatMessage || event.Msg == "" || event.Client == nil || event.ChatUser == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if event.ChatUser.Role != 1 { | ||||
| 		return | ||||
| 	} | ||||
| 	r.Sender = sender | ||||
| 	r.Receiver = event.ChatUser | ||||
| 	for _, v := range r.keywords { | ||||
| 		if strings.Contains(event.Msg, v) { | ||||
| 			fmt.Printf("关键词比对:%s ----- %s : true", event.Msg, v) | ||||
| 			hit = true | ||||
| 			break | ||||
| 		} | ||||
| 		fmt.Printf("关键词比对:%s ----- %s: false", event.Msg, v) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (r *RobotTaskWithKeyworkds) Run(cache *chatCache.ChatCache) (err error) { | ||||
| 	err = logic.NewMessage(context.Background(), cache, r.Sender, dto.NewMessageRequest{ | ||||
| 		Waiter:    true, | ||||
| 		Robot:     true, | ||||
| 		AtUserId:  r.Receiver.ID, | ||||
| 		SessionId: fmt.Sprintf("%d", r.Receiver.ID), | ||||
| 		Message: dto.Message{ | ||||
| 			MsgType:    1, | ||||
| 			Text:       r.Resp, | ||||
| 			LocalStamp: time.Now().Unix(), | ||||
| 		}, | ||||
| 	}) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (r *RobotTaskWithKeyworkds) RunTime() time.Time { | ||||
| 	return time.Time{} | ||||
| } | ||||
| 
 | ||||
| func (r *RobotTaskWithKeyworkds) SetResponse(response string) { | ||||
| 	r.Resp = response | ||||
| } | ||||
| @ -1,85 +0,0 @@ | ||||
| package robot | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fonchain-fiee/api/accountFiee" | ||||
| 	"fonchain-fiee/pkg/common/ws" | ||||
| 	"fonchain-fiee/pkg/service" | ||||
| 	"fonchain-fiee/pkg/service/asChat/chatCache" | ||||
| 	"fonchain-fiee/pkg/service/asChat/dto" | ||||
| 	"fonchain-fiee/pkg/service/asChat/logic" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| func NewReplyWhenUserJoinSession() IRobotTask { | ||||
| 	return &ReplyWhenUserJoinSession{} | ||||
| } | ||||
| 
 | ||||
| type ReplyWhenUserJoinSession struct { | ||||
| 	Response  string | ||||
| 	Sender    *accountFiee.ChatUserData | ||||
| 	Msg       string | ||||
| 	Resp      string | ||||
| 	sessionId string | ||||
| 	atUserId  int | ||||
| } | ||||
| 
 | ||||
| func (r *ReplyWhenUserJoinSession) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool) { | ||||
| 	if event.EventType != ws.EventUserJoin { | ||||
| 		return | ||||
| 	} | ||||
| 	if event.Client == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	ctx := context.Background() | ||||
| 	queryRes, err := service.AccountFieeProvider.GetChatRecordList(ctx, &accountFiee.GetChatRecordListRequest{ | ||||
| 		Query: &accountFiee.ChatRecordData{ | ||||
| 			SessionId: event.Client.SessionId, | ||||
| 		}, | ||||
| 		Page:     1, | ||||
| 		PageSize: 1, | ||||
| 		Order:    "created_at desc", | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	//如果最近一次的消息也是机器人发送的,就不再发送了
 | ||||
| 	for i, v := range queryRes.List { | ||||
| 		if i == 0 { | ||||
| 			if v.UserId == sender.ID { | ||||
| 				return | ||||
| 			} else { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	hit = true | ||||
| 	r.Sender = sender | ||||
| 	r.sessionId = event.Client.SessionId | ||||
| 	r.atUserId, _ = strconv.Atoi(event.Client.SessionId) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (r *ReplyWhenUserJoinSession) Run(cache *chatCache.ChatCache) (err error) { | ||||
| 	err = logic.NewMessage(context.Background(), cache, r.Sender, dto.NewMessageRequest{ | ||||
| 		Waiter:    true, | ||||
| 		Robot:     true, | ||||
| 		AtUserId:  int64(r.atUserId), | ||||
| 		SessionId: r.sessionId, | ||||
| 		Message: dto.Message{ | ||||
| 			MsgType:    1, | ||||
| 			Text:       r.Resp, | ||||
| 			LocalStamp: time.Now().Unix(), | ||||
| 		}, | ||||
| 	}) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (r *ReplyWhenUserJoinSession) RunTime() time.Time { | ||||
| 	return time.Time{} | ||||
| } | ||||
| 
 | ||||
| func (r *ReplyWhenUserJoinSession) SetResponse(response string) { | ||||
| 	r.Resp = response | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user