907 lines
25 KiB
Go
907 lines
25 KiB
Go
|
package controller
|
|||
|
|
|||
|
import (
|
|||
|
"encoding/json"
|
|||
|
"fmt"
|
|||
|
"github.com/gin-gonic/gin"
|
|||
|
"github.com/gorilla/websocket"
|
|||
|
"kefu/common"
|
|||
|
"kefu/lib"
|
|||
|
"kefu/models"
|
|||
|
"kefu/service"
|
|||
|
"kefu/tools"
|
|||
|
"kefu/types"
|
|||
|
"kefu/ws"
|
|||
|
"log"
|
|||
|
"net/url"
|
|||
|
"os"
|
|||
|
"path"
|
|||
|
"strconv"
|
|||
|
"strings"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
type VisitorMessageForm struct {
|
|||
|
ToId string `form:"to_id" json:"to_id" uri:"to_id" xml:"to_id" binding:"required"`
|
|||
|
FromId string `form:"from_id" json:"from_id" uri:"from_id" xml:"from_id" binding:"required"`
|
|||
|
Content string `form:"content" json:"content" uri:"content" xml:"content" binding:"required"`
|
|||
|
IsAutoReply string `form:"is_autoreply" json:"is_autoreply" uri:"is_autoreply" xml:"is_autoreply"`
|
|||
|
}
|
|||
|
|
|||
|
func SendMessageV2(c *gin.Context) {
|
|||
|
var form VisitorMessageForm
|
|||
|
err := c.Bind(&form)
|
|||
|
if err != nil {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.FAILED,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.INVALID),
|
|||
|
"result": err.Error(),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
fromId := form.FromId
|
|||
|
toId := form.ToId
|
|||
|
content := form.Content
|
|||
|
//判断是否离线
|
|||
|
//_, ok := ws.ClientList[fromId]
|
|||
|
//if !ok {
|
|||
|
// c.JSON(200, gin.H{
|
|||
|
// "code": types.ApiCode.VISITOR_OFFLINE,
|
|||
|
// "msg": types.ApiCode.GetMessage(types.ApiCode.VISITOR_OFFLINE),
|
|||
|
// })
|
|||
|
// return
|
|||
|
//}
|
|||
|
//限流
|
|||
|
if models.FindConfig("SystemFreqLimt") != "true" && !tools.LimitFreqSingle("sendmessage:"+c.ClientIP(), 1, 1) {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.FREQ_LIMIT,
|
|||
|
"msg": c.ClientIP() + types.ApiCode.GetMessage(types.ApiCode.FREQ_LIMIT),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
//验证黑名单
|
|||
|
//验证访客黑名单
|
|||
|
if !CheckVisitorBlack(fromId) {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.VISITOR_BAN,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.VISITOR_BAN),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//过滤敏感词
|
|||
|
content, isBlack := ReplaceBlackWords(content)
|
|||
|
|
|||
|
var kefuInfo models.User
|
|||
|
var vistorInfo models.Visitor
|
|||
|
|
|||
|
vistorInfo = models.FindVisitorByVistorId(fromId)
|
|||
|
//提示上班时间
|
|||
|
//查询企业配置项
|
|||
|
entConfigs := models.GetEntConfigsMap(vistorInfo.EntId, "workTimeStatus",
|
|||
|
"workDay", "morningWorkTime", "afternoonWorkTime", "otherWorkTime", "afterWorkMessage", "BaiduFanyiAppId", "BaiduFanyiAppSec", "BaiduFanyiAuto")
|
|||
|
if entConfigs["workTimeStatus"] == "yes" {
|
|||
|
if !tools.IsWorkTime(strings.Split(entConfigs["workDay"], "|"),
|
|||
|
strings.Split(entConfigs["morningWorkTime"], "|"),
|
|||
|
strings.Split(entConfigs["afternoonWorkTime"], "|"),
|
|||
|
strings.Split(entConfigs["otherWorkTime"], "|")) {
|
|||
|
ws.VisitorNotice(vistorInfo.VisitorId, entConfigs["afterWorkMessage"])
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
kefuInfo = models.FindUser(toId)
|
|||
|
|
|||
|
if kefuInfo.ID == 0 || vistorInfo.ID == 0 {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.ACCOUNT_NO_EXIST,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.ACCOUNT_NO_EXIST),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
msgId := models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, content, "visitor", vistorInfo.EntId, "unread")
|
|||
|
|
|||
|
guest, ok := ws.ClientList[vistorInfo.VisitorId]
|
|||
|
if ok && guest != nil {
|
|||
|
guest.UpdateTime = time.Now()
|
|||
|
}
|
|||
|
|
|||
|
wsContent := content
|
|||
|
//是否进行百度翻译
|
|||
|
if entConfigs["BaiduFanyiAppId"] != "" && entConfigs["BaiduFanyiAppSec"] != "" && entConfigs["BaiduFanyiAuto"] == "on" {
|
|||
|
baidu := &lib.BaiduFanyi{
|
|||
|
AppId: entConfigs["BaiduFanyiAppId"],
|
|||
|
AppSec: entConfigs["BaiduFanyiAppSec"],
|
|||
|
}
|
|||
|
res, err := baidu.Translate(content, "auto", "zh")
|
|||
|
if err == nil && res != "" {
|
|||
|
wsContent += "\n" + res
|
|||
|
}
|
|||
|
}
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "message",
|
|||
|
Data: ws.ClientMessage{
|
|||
|
MsgId: msgId,
|
|||
|
Avator: vistorInfo.Avator,
|
|||
|
Id: vistorInfo.VisitorId,
|
|||
|
VisitorId: vistorInfo.VisitorId,
|
|||
|
Name: vistorInfo.Name,
|
|||
|
ToId: kefuInfo.Name,
|
|||
|
Content: wsContent,
|
|||
|
Time: time.Now().Format("2006-01-02 15:04:05"),
|
|||
|
IsKefu: "no",
|
|||
|
},
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
|
|||
|
ws.OneKefuMessage(kefuInfo.Name, str)
|
|||
|
//回调url
|
|||
|
go SendVisitorMessageCallUrl(vistorInfo.EntId, vistorInfo.Name, kefuInfo.Name, vistorInfo.Name, vistorInfo.Avator, content)
|
|||
|
go SendAppGetuiPush(kefuInfo.Name, "[信息]"+vistorInfo.Name, content)
|
|||
|
go SendWechatVisitorMessageTemplate(kefuInfo.Name, vistorInfo.Name, vistorInfo.VisitorId, content, vistorInfo.EntId)
|
|||
|
//go SendWechatKefuNotice(kefuInfo.Name, "[访客]"+vistorInfo.Name+",说:"+content, vistorInfo.EntId)
|
|||
|
kefus, ok := ws.KefuList[kefuInfo.Name]
|
|||
|
go service.SendWorkWechatMesage(vistorInfo.EntId, vistorInfo, kefuInfo, content, c)
|
|||
|
if !ok || len(kefus.Users) == 0 {
|
|||
|
go SendNoticeEmail(vistorInfo.Name, "[留言]"+vistorInfo.Name, vistorInfo.EntId, content)
|
|||
|
}
|
|||
|
//是否机器人回复
|
|||
|
if form.IsAutoReply != "no" {
|
|||
|
go ws.VisitorAutoReply(vistorInfo, kefuInfo, content)
|
|||
|
}
|
|||
|
|
|||
|
go models.ReadMessageByVisitorId(vistorInfo.VisitorId, "kefu")
|
|||
|
go models.UpdateVisitorVisitorId(vistorInfo.VisitorId, vistorInfo.VisitorId)
|
|||
|
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
"result": gin.H{
|
|||
|
"content": content,
|
|||
|
"isBlack": isBlack,
|
|||
|
},
|
|||
|
})
|
|||
|
|
|||
|
}
|
|||
|
func SendSyncMessage(c *gin.Context) {
|
|||
|
visitorId := c.PostForm("visitor_id")
|
|||
|
content := c.PostForm("content")
|
|||
|
//验证访客黑名单
|
|||
|
if !CheckVisitorBlack(visitorId) {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.VISITOR_BAN,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.VISITOR_BAN),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//过滤敏感词
|
|||
|
content, _ = ReplaceBlackWords(content)
|
|||
|
var vistorInfo models.Visitor
|
|||
|
vistorInfo = models.FindVisitorByVistorId(visitorId)
|
|||
|
|
|||
|
kefuInfo := models.FindUser(vistorInfo.ToId)
|
|||
|
if kefuInfo.ID == 0 || vistorInfo.ID == 0 {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.ACCOUNT_NO_EXIST,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.ACCOUNT_NO_EXIST),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
models.CreateMessage(vistorInfo.ToId, vistorInfo.VisitorId, content, "kefu", vistorInfo.EntId, "read")
|
|||
|
go ws.KefuMessage(visitorId, content, kefuInfo)
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.SUCCESS,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
|
|||
|
})
|
|||
|
}
|
|||
|
func SendRobotMessage(c *gin.Context) {
|
|||
|
visitorId := c.PostForm("visitor_id")
|
|||
|
entId := c.PostForm("ent_id")
|
|||
|
content := c.PostForm("content")
|
|||
|
|
|||
|
//限流
|
|||
|
if !tools.LimitFreqSingle("sendmessage:"+c.ClientIP(), 1, 1) {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.FREQ_LIMIT,
|
|||
|
"msg": c.ClientIP() + types.ApiCode.GetMessage(types.ApiCode.FREQ_LIMIT),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
vistorInfo := models.FindVisitorByVistorId(visitorId)
|
|||
|
kefuInfo := models.FindUserByUid(entId)
|
|||
|
if kefuInfo.ID == 0 {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.ACCOUNT_NO_EXIST,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.ACCOUNT_NO_EXIST),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
//查询机器人信息
|
|||
|
configs := models.GetEntConfigsMap(entId, "RobotName", "RobotAvator")
|
|||
|
robotName := configs["RobotName"]
|
|||
|
robotAvator := configs["RobotAvator"]
|
|||
|
|
|||
|
articles := models.FindArticleList(1, 10, "score desc", "ent_id= ? and title like ?", entId, "%"+content+"%")
|
|||
|
|
|||
|
result := ""
|
|||
|
articleLen := len(articles)
|
|||
|
//未匹配,进入学习库
|
|||
|
if articleLen == 0 {
|
|||
|
if len([]rune(content)) > 1 {
|
|||
|
go AddUpdateLearn(entId, content)
|
|||
|
}
|
|||
|
} else if articleLen == 1 {
|
|||
|
result = articles[0].Content
|
|||
|
article := models.Article{
|
|||
|
Score: articles[0].Score + 1,
|
|||
|
}
|
|||
|
go article.SaveArticle("ent_id = ? and id = ?", entId, articles[0].Id)
|
|||
|
} else if articleLen > 1 {
|
|||
|
result = "您是不是想问:"
|
|||
|
for _, article := range articles {
|
|||
|
title := strings.Split(strings.ReplaceAll(article.Title, ",", ","), ",")[0]
|
|||
|
result += fmt.Sprintf("<p><a href='#'>%s</a></p>", title)
|
|||
|
}
|
|||
|
}
|
|||
|
//调用GPT3.5
|
|||
|
if result == "" && models.CheckVisitorRobotReply(vistorInfo.State) {
|
|||
|
result = ws.Gpt3Knowledge(entId, visitorId, kefuInfo, content)
|
|||
|
}
|
|||
|
//调用chatGPT
|
|||
|
//if result == "" {
|
|||
|
// result = ws.Gpt3dot5Message(entId, visitorId, kefuInfo, content)
|
|||
|
//}
|
|||
|
models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, content, "visitor", vistorInfo.EntId, "read")
|
|||
|
if result != "" {
|
|||
|
go models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, result, "kefu", vistorInfo.EntId, "read")
|
|||
|
}
|
|||
|
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.SUCCESS,
|
|||
|
"msg": "ok",
|
|||
|
"result": gin.H{
|
|||
|
"username": tools.Ifelse(robotName != "", robotName, kefuInfo.Nickname),
|
|||
|
"avator": tools.Ifelse(robotAvator != "", robotAvator, kefuInfo.Avator),
|
|||
|
"content": result,
|
|||
|
},
|
|||
|
})
|
|||
|
|
|||
|
}
|
|||
|
func SendKefuMessage(c *gin.Context) {
|
|||
|
entId, _ := c.Get("ent_id")
|
|||
|
fromId, _ := c.Get("kefu_name")
|
|||
|
toId := c.PostForm("to_id")
|
|||
|
content := c.PostForm("content")
|
|||
|
cType := c.PostForm("type")
|
|||
|
if content == "" {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "内容不能为空",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
//过滤敏感词
|
|||
|
content, _ = ReplaceBlackWords(content)
|
|||
|
|
|||
|
var kefuInfo models.User
|
|||
|
var vistorInfo models.Visitor
|
|||
|
kefuInfo = models.FindUser(fromId.(string))
|
|||
|
vistorInfo = models.FindVisitorByVistorId(toId)
|
|||
|
|
|||
|
if kefuInfo.ID == 0 || vistorInfo.ID == 0 {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "用户不存在",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
roleId, _ := c.Get("role_id")
|
|||
|
kefuInfo.RoleId = fmt.Sprintf("%v", roleId)
|
|||
|
var msg ws.TypeMessage
|
|||
|
guest, ok := ws.ClientList[vistorInfo.VisitorId]
|
|||
|
isRead := "unread"
|
|||
|
msgId := models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, content, cType, entId.(string), isRead)
|
|||
|
if guest != nil && ok {
|
|||
|
conn := guest.Conn
|
|||
|
msg = ws.TypeMessage{
|
|||
|
Type: "message",
|
|||
|
Data: ws.ClientMessage{
|
|||
|
MsgId: msgId,
|
|||
|
Name: kefuInfo.Nickname,
|
|||
|
Avator: kefuInfo.Avator,
|
|||
|
Id: kefuInfo.Name,
|
|||
|
Time: time.Now().Format("2006-01-02 15:04:05"),
|
|||
|
ToId: vistorInfo.VisitorId,
|
|||
|
Content: content,
|
|||
|
IsKefu: "no",
|
|||
|
},
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
conn.WriteMessage(websocket.TextMessage, str)
|
|||
|
} else {
|
|||
|
//客服发送给公众号模板消息
|
|||
|
//go SendWechatKefuTemplate(vistorInfo.VisitorId, kefuInfo.Name, kefuInfo.Nickname, content, fmt.Sprintf("%v", entId))
|
|||
|
go SendKefuMessageCallUrl(kefuInfo.Name, vistorInfo.VisitorId, content, vistorInfo.EntId, kefuInfo.Nickname)
|
|||
|
//客服发给小程序订阅模板消息
|
|||
|
go service.SendMiniSubscribe(vistorInfo.VisitorId, content, fmt.Sprintf("%v", entId), kefuInfo.Nickname)
|
|||
|
}
|
|||
|
//客服发送给小程序访客消息
|
|||
|
go SendMiniVisitorMessage(vistorInfo.VisitorId, content, fmt.Sprintf("%v", entId))
|
|||
|
|
|||
|
//客服发送给公众号用户信息
|
|||
|
go SendWechatVisitorMessage(vistorInfo.VisitorId, content, fmt.Sprintf("%v", entId))
|
|||
|
//客服发送给微信客服用户的消息
|
|||
|
go SendWeworkKfVisitorMessage(vistorInfo, content)
|
|||
|
//客服发送到抖音评论
|
|||
|
go SendDouyinCommentMessage(vistorInfo, content)
|
|||
|
//客服发送到抖音评论
|
|||
|
go SendDouyinPrivateMessage(vistorInfo, content)
|
|||
|
msg = ws.TypeMessage{
|
|||
|
Type: "message",
|
|||
|
Data: ws.ClientMessage{
|
|||
|
MsgId: msgId,
|
|||
|
Name: kefuInfo.Nickname,
|
|||
|
Avator: kefuInfo.Avator,
|
|||
|
Id: vistorInfo.VisitorId,
|
|||
|
Time: time.Now().Format("2006-01-02 15:04:05"),
|
|||
|
ToId: vistorInfo.VisitorId,
|
|||
|
Content: content,
|
|||
|
IsKefu: "yes",
|
|||
|
},
|
|||
|
}
|
|||
|
str2, _ := json.Marshal(msg)
|
|||
|
ws.OneKefuMessage(kefuInfo.Name, str2)
|
|||
|
go models.ReadMessageByVisitorId(vistorInfo.VisitorId, "visitor")
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
func SendVisitorNotice(c *gin.Context) {
|
|||
|
notice := c.Query("msg")
|
|||
|
if notice == "" {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "msg不能为空",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "notice",
|
|||
|
Data: notice,
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
for _, visitor := range ws.ClientList {
|
|||
|
visitor.Conn.WriteMessage(websocket.TextMessage, str)
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
func SendCloseMessageV2(c *gin.Context) {
|
|||
|
ent_id, _ := c.Get("ent_id")
|
|||
|
visitorId := c.Query("visitor_id")
|
|||
|
if visitorId == "" {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "visitor_id不能为空",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
config := models.FindEntConfig(ent_id, "CloseVisitorMessage")
|
|||
|
oldUser, ok := ws.ClientList[visitorId]
|
|||
|
if oldUser != nil || ok {
|
|||
|
ws.VisitorOffline(oldUser.ToId, oldUser.Id, oldUser.Name)
|
|||
|
if config.ConfValue != "" {
|
|||
|
kefu := models.FindUserByUid(ent_id)
|
|||
|
ws.VisitorMessage(visitorId, config.ConfValue, kefu)
|
|||
|
}
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "force_close",
|
|||
|
Data: visitorId,
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
err := oldUser.Conn.WriteMessage(websocket.TextMessage, str)
|
|||
|
oldUser.Conn.Close()
|
|||
|
delete(ws.ClientList, visitorId)
|
|||
|
log.Println("close_message", oldUser, err)
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
func UploadImg(c *gin.Context) {
|
|||
|
f, err := c.FormFile("imgfile")
|
|||
|
if err != nil {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "上传失败!",
|
|||
|
})
|
|||
|
return
|
|||
|
} else {
|
|||
|
|
|||
|
fileExt := strings.ToLower(path.Ext(f.Filename))
|
|||
|
if fileExt != ".png" && fileExt != ".jpg" && fileExt != ".gif" && fileExt != ".jpeg" {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "上传失败!只允许png,jpg,gif,jpeg文件",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
fileName := tools.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
|
|||
|
fildDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
|
|||
|
isExist, _ := tools.IsFileExist(fildDir)
|
|||
|
if !isExist {
|
|||
|
os.Mkdir(fildDir, os.ModePerm)
|
|||
|
}
|
|||
|
filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
|
|||
|
c.SaveUploadedFile(f, filepath)
|
|||
|
|
|||
|
path := "/" + filepath
|
|||
|
//上传到阿里云oss
|
|||
|
oss, err := lib.NewOssLib()
|
|||
|
if err == nil {
|
|||
|
dstUrl, err := oss.Upload(filepath, filepath)
|
|||
|
if err == nil {
|
|||
|
path = dstUrl
|
|||
|
} else {
|
|||
|
log.Println(err.Error())
|
|||
|
}
|
|||
|
} else {
|
|||
|
log.Println(err.Error())
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "上传成功!",
|
|||
|
"result": gin.H{
|
|||
|
"path": path,
|
|||
|
},
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
func UploadFile(c *gin.Context) {
|
|||
|
SendAttachment, err := strconv.ParseBool(models.FindConfig("SendAttachment"))
|
|||
|
if !SendAttachment || err != nil {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "禁止上传附件!",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
f, err := c.FormFile("realfile")
|
|||
|
if err != nil {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "上传失败!",
|
|||
|
})
|
|||
|
return
|
|||
|
} else {
|
|||
|
maxSize := 20 * 1024 * 1024
|
|||
|
uploadMaxSize := models.FindConfig("UploadMaxSize")
|
|||
|
if uploadMaxSize != "" {
|
|||
|
uploadMaxSizeInt, _ := strconv.Atoi(uploadMaxSize)
|
|||
|
maxSize = uploadMaxSizeInt * 1024 * 1024
|
|||
|
}
|
|||
|
fileExt := strings.ToLower(path.Ext(f.Filename))
|
|||
|
if f.Size >= int64(maxSize) {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "上传失败,文件大小超限!",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
fileName := tools.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
|
|||
|
fildDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
|
|||
|
isExist, _ := tools.IsFileExist(fildDir)
|
|||
|
if !isExist {
|
|||
|
os.Mkdir(fildDir, os.ModePerm)
|
|||
|
}
|
|||
|
filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
|
|||
|
c.SaveUploadedFile(f, filepath)
|
|||
|
path := "/" + filepath
|
|||
|
//上传到阿里云oss
|
|||
|
oss, err := lib.NewOssLib()
|
|||
|
if err == nil {
|
|||
|
dstUrl, err := oss.Upload(filepath, filepath)
|
|||
|
if err == nil {
|
|||
|
path = dstUrl
|
|||
|
}
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "上传成功!",
|
|||
|
"result": gin.H{
|
|||
|
"path": path,
|
|||
|
},
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
func UploadAudio(c *gin.Context) {
|
|||
|
SendAttachment, err := strconv.ParseBool(models.FindConfig("SendAttachment"))
|
|||
|
if !SendAttachment || err != nil {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "禁止上传附件!",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
f, err := c.FormFile("realfile")
|
|||
|
if err != nil {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "上传失败!",
|
|||
|
})
|
|||
|
return
|
|||
|
} else {
|
|||
|
|
|||
|
fileExt := ".mp3"
|
|||
|
if f.Size >= 20*1024*1024 {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "上传失败!不允许超过20M",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
fileName := tools.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
|
|||
|
fildDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
|
|||
|
isExist, _ := tools.IsFileExist(fildDir)
|
|||
|
if !isExist {
|
|||
|
os.Mkdir(fildDir, os.ModePerm)
|
|||
|
}
|
|||
|
filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
|
|||
|
c.SaveUploadedFile(f, filepath)
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "上传成功!",
|
|||
|
"result": gin.H{
|
|||
|
"path": filepath,
|
|||
|
},
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
func GetMessagesV2(c *gin.Context) {
|
|||
|
visitorId := c.Query("visitor_id")
|
|||
|
messages := models.FindMessageByVisitorId(visitorId)
|
|||
|
//result := make([]map[string]interface{}, 0)
|
|||
|
chatMessages := make([]ChatMessage, 0)
|
|||
|
|
|||
|
for _, message := range messages {
|
|||
|
//item := make(map[string]interface{})
|
|||
|
var chatMessage ChatMessage
|
|||
|
chatMessage.Time = message.CreatedAt.Format("2006-01-02 15:04:05")
|
|||
|
chatMessage.Content = message.Content
|
|||
|
chatMessage.MesType = message.MesType
|
|||
|
if message.MesType == "kefu" {
|
|||
|
chatMessage.Name = message.KefuName
|
|||
|
chatMessage.Avator = message.KefuAvator
|
|||
|
} else {
|
|||
|
chatMessage.Name = message.VisitorName
|
|||
|
chatMessage.Avator = message.VisitorAvator
|
|||
|
}
|
|||
|
chatMessages = append(chatMessages, chatMessage)
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
"result": chatMessages,
|
|||
|
})
|
|||
|
}
|
|||
|
func PostMessagesVisitorRead(c *gin.Context) {
|
|||
|
visitorId := c.PostForm("visitor_id")
|
|||
|
toId := c.PostForm("kefu")
|
|||
|
models.ReadMessageByVisitorId(visitorId, "kefu")
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "read",
|
|||
|
Data: ws.ClientMessage{
|
|||
|
VisitorId: visitorId,
|
|||
|
ToId: toId,
|
|||
|
},
|
|||
|
}
|
|||
|
str2, _ := json.Marshal(msg)
|
|||
|
ws.OneKefuMessage(toId, str2)
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
func PostMessagesKefuRead(c *gin.Context) {
|
|||
|
visitorId := c.PostForm("visitor_id")
|
|||
|
entId, _ := c.Get("ent_id")
|
|||
|
kefuName, _ := c.Get("kefu_name")
|
|||
|
models.ReadMessageByEntIdVisitorId(visitorId, entId.(string), "visitor")
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "read",
|
|||
|
Data: ws.ClientMessage{
|
|||
|
VisitorId: visitorId,
|
|||
|
},
|
|||
|
}
|
|||
|
ws.VisitorCustomMessage(visitorId, msg)
|
|||
|
|
|||
|
unreadNum := models.CountMessage("kefu_id = ? and mes_type='visitor' and status = 'unread'", kefuName)
|
|||
|
msg2 := ws.TypeMessage{
|
|||
|
Type: "unread_num",
|
|||
|
Data: unreadNum,
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg2)
|
|||
|
ws.OneKefuMessage(kefuName.(string), str)
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
func PostMessagesAsk(c *gin.Context) {
|
|||
|
entId := c.PostForm("ent_id")
|
|||
|
content := c.PostForm("content")
|
|||
|
visitorId := c.PostForm("from_id")
|
|||
|
if content == "" {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "内容不能为空",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
entInfo := models.FindUserByUid(entId)
|
|||
|
go models.CreateMessage(entInfo.Name, visitorId, content, "visitor", entId, "unread")
|
|||
|
reply := models.FindReplyItemByUserIdTitle(entInfo.Name, content)
|
|||
|
if reply.Content != "" {
|
|||
|
go models.CreateMessage(entInfo.Name, visitorId, reply.Content, "kefu", entId, "read")
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
"result": gin.H{
|
|||
|
"content": reply.Content,
|
|||
|
"name": entInfo.Nickname,
|
|||
|
"avator": entInfo.Avator,
|
|||
|
"time": time.Now().Format("2006-01-02 15:05:05"),
|
|||
|
},
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 400,
|
|||
|
"msg": "no result!",
|
|||
|
})
|
|||
|
}
|
|||
|
func GetMessagesVisitorUnread(c *gin.Context) {
|
|||
|
visitorId := c.Query("visitor_id")
|
|||
|
messages := models.FindMessageByVisitorIdUnread(visitorId, "kefu")
|
|||
|
chatMessages := make([]ChatMessage, 0)
|
|||
|
|
|||
|
for _, message := range messages {
|
|||
|
//item := make(map[string]interface{})
|
|||
|
var chatMessage ChatMessage
|
|||
|
chatMessage.Time = message.CreatedAt.Format("2006-01-02 15:04:05")
|
|||
|
chatMessage.Content = message.Content
|
|||
|
chatMessage.MesType = message.MesType
|
|||
|
if message.MesType == "kefu" {
|
|||
|
chatMessage.Name = message.KefuName
|
|||
|
chatMessage.Avator = message.KefuAvator
|
|||
|
} else {
|
|||
|
chatMessage.Name = message.VisitorName
|
|||
|
chatMessage.Avator = message.VisitorAvator
|
|||
|
}
|
|||
|
chatMessages = append(chatMessages, chatMessage)
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
"result": chatMessages,
|
|||
|
})
|
|||
|
}
|
|||
|
func GetAllVisitorMessagesByKefu(c *gin.Context) {
|
|||
|
visitorId := c.Query("visitor_id")
|
|||
|
messages := models.FindMessageByVisitorId(visitorId)
|
|||
|
//result := make([]map[string]interface{}, 0)
|
|||
|
chatMessages := make([]ChatMessage, 0)
|
|||
|
|
|||
|
for _, message := range messages {
|
|||
|
//item := make(map[string]interface{})
|
|||
|
var chatMessage ChatMessage
|
|||
|
chatMessage.Time = message.CreatedAt.Format("2006-01-02 15:04:05")
|
|||
|
chatMessage.Content = message.Content
|
|||
|
chatMessage.MesType = message.MesType
|
|||
|
if message.MesType == "kefu" {
|
|||
|
chatMessage.Name = message.KefuName
|
|||
|
chatMessage.Avator = message.KefuAvator
|
|||
|
} else {
|
|||
|
chatMessage.Name = message.VisitorName
|
|||
|
chatMessage.Avator = message.VisitorAvator
|
|||
|
}
|
|||
|
chatMessages = append(chatMessages, chatMessage)
|
|||
|
}
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
"result": chatMessages,
|
|||
|
})
|
|||
|
}
|
|||
|
func GetVisitorListMessagesPage(c *gin.Context) {
|
|||
|
visitorId := c.Query("visitor_id")
|
|||
|
entId := c.Query("ent_id")
|
|||
|
page, _ := strconv.Atoi(c.Query("page"))
|
|||
|
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
|
|||
|
if pagesize == 0 {
|
|||
|
pagesize = int(common.PageSize)
|
|||
|
}
|
|||
|
count := models.CountMessage("message.ent_id= ? and message.visitor_id=?", entId, visitorId)
|
|||
|
chatMessages := CommonMessagesPage(uint(page), uint(pagesize), visitorId, entId)
|
|||
|
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "获取成功",
|
|||
|
"result": gin.H{
|
|||
|
"count": count,
|
|||
|
"page": page,
|
|||
|
"list": chatMessages,
|
|||
|
"pagesize": pagesize,
|
|||
|
},
|
|||
|
})
|
|||
|
}
|
|||
|
func GetVisitorListMessagesPageBykefu(c *gin.Context) {
|
|||
|
visitorId := c.Query("visitor_id")
|
|||
|
entId, _ := c.Get("ent_id")
|
|||
|
page, _ := strconv.Atoi(c.Query("page"))
|
|||
|
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
|
|||
|
if pagesize == 0 {
|
|||
|
pagesize = int(common.PageSize)
|
|||
|
}
|
|||
|
count := models.CountMessage("message.ent_id= ? and message.visitor_id=?", entId.(string), visitorId)
|
|||
|
chatMessages := CommonMessagesPage(uint(page), uint(pagesize), visitorId, entId.(string))
|
|||
|
go func() {
|
|||
|
models.ReadMessageByVisitorId(visitorId, "visitor")
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "read",
|
|||
|
Data: ws.ClientMessage{
|
|||
|
VisitorId: visitorId,
|
|||
|
},
|
|||
|
}
|
|||
|
ws.VisitorCustomMessage(visitorId, msg)
|
|||
|
}()
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "获取成功",
|
|||
|
"result": gin.H{
|
|||
|
"count": count,
|
|||
|
"page": page,
|
|||
|
"list": chatMessages,
|
|||
|
"pagesize": common.PageSize,
|
|||
|
},
|
|||
|
})
|
|||
|
}
|
|||
|
func DeleteMessage(c *gin.Context) {
|
|||
|
entId, _ := c.Get("ent_id")
|
|||
|
visitorId := c.PostForm("visitor_id")
|
|||
|
msgId := c.PostForm("msg_id")
|
|||
|
message := models.FindOneMessageByWhere("id=? and visitor_id=? and ent_id=?", msgId, visitorId, entId)
|
|||
|
|
|||
|
//判断撤回时间限制
|
|||
|
limitTime := tools.Now() - message.CreatedAt.Unix()
|
|||
|
systemLimitTime := models.FindConfig("KefuDeleteMessageLimitTime")
|
|||
|
if systemLimitTime != "" && limitTime > tools.Str2Int64(systemLimitTime) {
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": types.ApiCode.DELETE_MESSAGE_OVERTIME,
|
|||
|
"msg": types.ApiCode.GetMessage(types.ApiCode.DELETE_MESSAGE_OVERTIME),
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
models.DelMessage("id=? and visitor_id=? and ent_id=?", msgId, visitorId, entId)
|
|||
|
msgIdInt, _ := strconv.Atoi(msgId)
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "delete",
|
|||
|
Data: ws.ClientMessage{
|
|||
|
MsgId: uint(msgIdInt),
|
|||
|
VisitorId: visitorId,
|
|||
|
},
|
|||
|
}
|
|||
|
ws.VisitorCustomMessage(visitorId, msg)
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
// 删除访客聊天记录
|
|||
|
func DeleteVisitorMessage(c *gin.Context) {
|
|||
|
entId, _ := c.Get("ent_id")
|
|||
|
visitorId := c.Query("visitor_id")
|
|||
|
models.DelMessage("visitor_id=? and ent_id=?", visitorId, entId)
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
// 一键已读
|
|||
|
func GetClearUnread(c *gin.Context) {
|
|||
|
entId, _ := c.Get("ent_id")
|
|||
|
kefuName, _ := c.Get("kefu_name")
|
|||
|
models.ReadMessageByEntIdKefuName(entId.(string), kefuName.(string))
|
|||
|
msg := ws.TypeMessage{
|
|||
|
Type: "unread_num",
|
|||
|
Data: 0,
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
go ws.OneKefuMessage(kefuName.(string), str)
|
|||
|
c.JSON(200, gin.H{
|
|||
|
"code": 200,
|
|||
|
"msg": "ok",
|
|||
|
})
|
|||
|
}
|
|||
|
func CommonMessagesPage(page, pagesize uint, visitorId, entId string) []ChatMessage {
|
|||
|
|
|||
|
list := models.FindMessageByPage(page, pagesize, "message.ent_id= ? and message.visitor_id=?", entId, visitorId)
|
|||
|
chatMessages := make([]ChatMessage, 0)
|
|||
|
|
|||
|
for _, message := range list {
|
|||
|
//item := make(map[string]interface{})
|
|||
|
var chatMessage ChatMessage
|
|||
|
chatMessage.MsgId = message.ID
|
|||
|
chatMessage.Time = message.CreatedAt.Format("2006-01-02 15:04:05")
|
|||
|
chatMessage.Content = message.Content
|
|||
|
chatMessage.MesType = message.MesType
|
|||
|
chatMessage.ReadStatus = message.Status
|
|||
|
if message.MesType == "kefu" {
|
|||
|
chatMessage.Name = message.KefuName
|
|||
|
chatMessage.Avator = message.KefuAvator
|
|||
|
} else {
|
|||
|
chatMessage.Name = message.VisitorName
|
|||
|
chatMessage.Avator = message.VisitorAvator
|
|||
|
}
|
|||
|
chatMessages = append(chatMessages, chatMessage)
|
|||
|
}
|
|||
|
return chatMessages
|
|||
|
}
|
|||
|
|
|||
|
// 调用回调通知url
|
|||
|
func SendVisitorMessageCallUrl(entId, from, to, nickname, avatar, content string) string {
|
|||
|
api := models.FindConfig("VisitorMessageCallUrl")
|
|||
|
if api == "" {
|
|||
|
api = models.FindEntConfig(entId, "VisitorMessageCallUrl").ConfValue
|
|||
|
}
|
|||
|
if api == "" {
|
|||
|
return ""
|
|||
|
}
|
|||
|
data := url.Values{}
|
|||
|
data.Set("from", from)
|
|||
|
data.Set("to", to)
|
|||
|
data.Set("content", content)
|
|||
|
data.Set("nickname", nickname)
|
|||
|
data.Set("avatar", avatar)
|
|||
|
res, err := tools.PostForm(api, data)
|
|||
|
if err != nil {
|
|||
|
log.Println("访客消息发送回调错误:" + err.Error())
|
|||
|
}
|
|||
|
return res
|
|||
|
}
|
|||
|
|
|||
|
// 客服调用回调通知url
|
|||
|
func SendKefuMessageCallUrl(kefuName, visitorId, content, entId, nickname string) string {
|
|||
|
api := models.FindConfig("KefuMessageCallUrl")
|
|||
|
if api == "" {
|
|||
|
api = models.FindEntConfig(entId, "KefuMessageCallUrl").ConfValue
|
|||
|
}
|
|||
|
if api == "" {
|
|||
|
return ""
|
|||
|
}
|
|||
|
data := url.Values{}
|
|||
|
data.Set("kefu_name", kefuName)
|
|||
|
data.Set("visitor_id", visitorId)
|
|||
|
data.Set("ent_id", entId)
|
|||
|
data.Set("content", content)
|
|||
|
data.Set("nickname", nickname)
|
|||
|
res, err := tools.PostForm(api, data)
|
|||
|
if err != nil {
|
|||
|
log.Println("客服消息发送回调错误:" + err.Error())
|
|||
|
}
|
|||
|
log.Println("客服消息发送回调成功:" + data.Encode())
|
|||
|
return res
|
|||
|
}
|