kefu/controller/visitor.go

955 lines
28 KiB
Go
Raw Permalink Normal View History

2024-12-10 02:50:12 +00:00
package controller
import (
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
"kefu/common"
"kefu/models"
v2 "kefu/models/v2"
"kefu/tools"
"kefu/types"
"kefu/ws"
"log"
"math/rand"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
type VisitorLoginForm struct {
VisitorId string `form:"visitor_id" json:"visitor_id" uri:"visitor_id" xml:"visitor_id"`
Refer string `form:"refer" json:"refer" uri:"refer" xml:"refer"`
ReferUrl string `form:"refer_url" json:"refer" uri:"refer" xml:"refer"`
Title string `form:"title" json:"title" uri:"title" xml:"title"`
Url string `form:"url" json:"url" uri:"url" xml:"url"`
ToId string `form:"to_id" json:"to_id" uri:"to_id" xml:"to_id"`
EntId string `form:"ent_id" json:"ent_id" uri:"ent_id" xml:"ent_id" binding:"required"`
Avator string `form:"avator" json:"avator" uri:"avator" xml:"avator"`
UserAgent string `form:"user_agent" json:"user_agent" uri:"user_agent" xml:"user_agent"`
Extra string `form:"extra" json:"extra" uri:"extra" xml:"extra"`
ClientIp string `form:"client_ip" json:"client_ip" uri:"client_ip" xml:"client_ip"`
CityAddress string `form:"city_address" json:"city_address" uri:"city_address" xml:"city_address"`
VisitorName string `form:"visitor_name" json:"visitor_name" uri:"visitor_name" xml:"visitor_name"`
Language string `form:"language" json:"language" uri:"language" xml:"language"`
}
func PostVisitorLogin(c *gin.Context) {
var form VisitorLoginForm
err := c.Bind(&form)
if err != nil {
HandleError(c, types.ApiCode.FAILED, types.ApiCode.GetMessage(types.ApiCode.INVALID), err)
return
}
//限流
if models.FindConfig("SystemFreqLimt") != "true" && !tools.LimitFreqSingle("visitor_login:"+c.ClientIP(), 1, 2) {
HandleError(c, types.ApiCode.FREQ_LIMIT, types.ApiCode.GetMessage(types.ApiCode.FREQ_LIMIT), errors.New("访问接口频率限制"))
return
}
isWechat := false
originVisitorId := ""
// 如果访客ID为空
if form.VisitorId == "" {
// 判断访客ID的生成规则
idRule := models.FindConfig("VisitorIdRule")
if idRule == "ip" {
// 使用IP生成访客ID的MD5哈希值
form.VisitorId = tools.Md5(c.ClientIP())
} else {
// 使用UUID生成访客ID
form.VisitorId = tools.Uuid()
}
form.VisitorId = fmt.Sprintf("%s|%s", form.EntId, form.VisitorId)
} else {
originVisitorId = form.VisitorId
// 验证访客是否在黑名单中
if !CheckVisitorBlack(form.VisitorId) {
HandleError(c, types.ApiCode.VISITOR_BAN, types.ApiCode.GetMessage(types.ApiCode.VISITOR_BAN), errors.New("访客在黑名单中"))
return
}
visitorIds := strings.Split(form.VisitorId, "|")
if len(visitorIds) > 1 {
if visitorIds[0] != "wx" && visitorIds[0] != "mini" {
// 如果不是微信或小程序则重新构造访客ID
form.VisitorId = strings.Join(visitorIds[1:], "|")
form.VisitorId = fmt.Sprintf("%s|%s", form.EntId, form.VisitorId)
} else {
isWechat = true
}
} else {
form.VisitorId = fmt.Sprintf("%s|%s", form.EntId, form.VisitorId)
}
}
// 获取请求的User-Agent信息
form.UserAgent = c.GetHeader("User-Agent")
// 如果Avator为空且不是微信登录
if form.Avator == "" && !isWechat {
// 根据User-Agent判断是移动设备还是桌面设备并设置默认头像
if tools.IsMobile(form.UserAgent) {
form.Avator = "/static/images/phone.png"
} else {
form.Avator = "/static/images/computer.png"
}
} else {
// 解码Avator中的URL转义字符
form.Avator, _ = url.QueryUnescape(form.Avator)
}
// 解析IP地址获取城市信息
ipCity, _ := tools.ParseIpNew(c.ClientIP())
if ipCity != nil {
form.CityAddress = ipCity.CountryName + ipCity.RegionName + ipCity.CityName + ipCity.AreaName
} else {
form.CityAddress = "Unknown Area"
}
// 如果VisitorName为空且不是微信登录
if form.VisitorName == "" && !isWechat {
// 如果IP所在国家是中国则使用省市区作为访客名称否则使用完整城市地址
if ipCity.CountryName == "中国" {
form.VisitorName = ipCity.RegionName + ipCity.CityName + ipCity.AreaName
} else {
form.VisitorName = form.CityAddress
}
} else {
// 解码VisitorName中的URL转义字符
form.VisitorName, _ = url.QueryUnescape(form.VisitorName)
}
form.ClientIp = c.ClientIP()
//验证ip黑名单
ipblack := models.FindIp(form.ClientIp)
if ipblack.IP != "" && ipblack.EntId == form.EntId {
HandleError(c, types.ApiCode.IP_BAN, types.ApiCode.GetMessage(types.ApiCode.IP_BAN), errors.New("IP在黑名单中"))
return
}
makeVisitorLoginForm(&form)
allOffline := true
//查询企业信息
entKefuInfo := models.FindUserRoleById(form.EntId)
if entKefuInfo.ID == 0 || entKefuInfo.RoleId == tools.Int2Str(types.Constant.AgentRoleId) {
HandleError(c, types.ApiCode.ENT_ERROR, types.ApiCode.GetMessage(types.ApiCode.ENT_ERROR), errors.New("商户ID不存在"))
return
}
kefuCommonGin := gin.H{
"username": entKefuInfo.Nickname,
"avatar": entKefuInfo.Avator,
"intro_pic": entKefuInfo.CompanyPic,
}
//查询企业配置项
configs := models.GetEntConfigsMap(form.EntId, "KefuIntroduce",
"RobotStatus", "TurnToMan", "RobotNoAnswer", "RobotName", "RobotAvator", "RobotCard",
"VisitorNotice", "AutoWelcome", "VisitorCookie", "VisitorMaxNum", "VisitorMaxNumNotice", "ScanWechatQrcode",
"VisitorAuthApi", "CloseNotice", "QdrantAIStatus")
//访客Cookie有效期
if configs["VisitorCookie"] == "" {
configs["VisitorCookie"] = fmt.Sprintf("%d", 24*3600*365*100)
}
//机器人信息
RobotCommonGin := gin.H{
"RobotStatus": configs["RobotStatus"],
"TurnToMan": configs["TurnToMan"],
"RobotNoAnswer": configs["RobotNoAnswer"],
"RobotName": configs["RobotName"],
"RobotAvator": configs["RobotAvator"],
"RobotCard": configs["RobotCard"],
"RobotSwitch": tools.Ifelse(configs["RobotStatus"] == "2", "true", "false"),
}
//查看过期时间
nowSecond := time.Now().Unix()
expireSecond := entKefuInfo.ExpiredAt.Unix()
if models.FindConfig("KefuExpired") == "on" && expireSecond < nowSecond {
c.JSON(200, gin.H{
"code": types.ApiCode.ACCOUNT_EXPIRED,
"msg": types.ApiCode.GetMessage(types.ApiCode.ACCOUNT_EXPIRED),
"kefu": kefuCommonGin,
})
return
}
//查看状态
if entKefuInfo.Status == 1 {
c.JSON(200, gin.H{
"code": types.ApiCode.ACCOUNT_FORBIDDEN,
"msg": types.ApiCode.GetMessage(types.ApiCode.ACCOUNT_FORBIDDEN),
"kefu": kefuCommonGin,
})
return
}
//访客认证回调
if configs["VisitorAuthApi"] != "" {
api := configs["VisitorAuthApi"] + "?visitor_id=" + originVisitorId +
"&sign=" + tools.Md5(originVisitorId+"VisitorAuthApi")
res := tools.Get(api)
avatar := gjson.Get(res, "avatar").String()
name := gjson.Get(res, "name").String()
if res == "" || name == "" || avatar == "" {
log.Println("访客认证回调失败:", api, res)
c.JSON(200, gin.H{
"code": types.ApiCode.VISITOR_FORBIDDEN,
"msg": types.ApiCode.GetMessage(types.ApiCode.VISITOR_FORBIDDEN),
"kefu": kefuCommonGin,
})
return
}
form.Avator = avatar
form.VisitorName = name
}
dstKefu := entKefuInfo
if form.ToId != "" && form.ToId != entKefuInfo.Name {
tmpInfo := models.FindUser(form.ToId)
if tmpInfo.Name != "" && (int64(tmpInfo.ID) == tools.Str2Int64(form.EntId) || int64(tmpInfo.Pid) == tools.Str2Int64(form.EntId)) {
dstKefu = tmpInfo
}
}
//判断是否在线,判断指定客服是否在线
_, ok := ws.KefuList[dstKefu.Name]
if dstKefu.OnlineStatus == 1 && ok {
allOffline = false
} else {
//查找在线的子账号
kefus := models.FindUsersWhere("pid = ? and online_status=1", form.EntId)
//kefus := models.FindUsersByPid(form.EntId)
if len(kefus) == 0 {
allOffline = true
} else {
//随机化
rand.Seed(time.Now().Unix())
sort.Sort(models.ByRecNumRand(kefus))
for _, kefu := range kefus {
if _, ok := ws.KefuList[kefu.Name]; ok {
form.ToId = kefu.Name
allOffline = false
dstKefu = kefu
break
}
}
}
}
//如果子账号全都不在线,并且主账号未设置离线,分给主账号
if allOffline == true && form.ToId != entKefuInfo.Name && entKefuInfo.OnlineStatus == 1 {
form.ToId = entKefuInfo.Name
dstKefu = entKefuInfo
_, ok := ws.KefuList[dstKefu.Name]
if ok {
allOffline = false
}
}
//判断是否开启AI自动回复
if configs["QdrantAIStatus"] == "true" {
allOffline = false
}
kefuCommonGin["staffNickname"] = dstKefu.Nickname
kefuCommonGin["staffAvatar"] = dstKefu.Avator
//判断是否绑定手机
if models.FindConfig("KefuBindTel") == "true" && dstKefu.Tel == "" {
c.JSON(200, gin.H{
"code": types.ApiCode.BIND_TEL_FAILD,
"msg": types.ApiCode.GetMessage(types.ApiCode.BIND_TEL_FAILD),
"kefu": kefuCommonGin,
})
return
}
//同时接待人数
visitorMaxNum := int(dstKefu.RecNum)
visitorMaxNumConfig, _ := strconv.Atoi(configs["VisitorMaxNum"])
if visitorMaxNumConfig == 0 {
visitorMaxNumConfig = 100000
}
if visitorMaxNum >= visitorMaxNumConfig {
c.JSON(200, gin.H{
"code": types.ApiCode.VISITOR_MAX_FORBIDDEN,
"msg": types.ApiCode.GetMessage(types.ApiCode.VISITOR_MAX_FORBIDDEN),
"visitorMaxNum": visitorMaxNum,
"robotNoAnswer": configs["RobotNoAnswer"],
"turnToMan": configs["TurnToMan"],
"visitorMaxNumNotice": configs["VisitorMaxNumNotice"],
"result": gin.H{
"avator": form.Avator,
"name": form.VisitorName,
},
"kefu": kefuCommonGin,
})
return
}
visitor := models.FindVisitorByVistorId(form.VisitorId)
visitor.ToId = dstKefu.Name
visitNum := visitor.VisitNum + 1
if visitor.ID != 0 {
if form.Avator == "" && isWechat {
form.Avator = visitor.Avator
}
if form.VisitorName == "" && isWechat {
form.VisitorName = visitor.Name
}
if visitor.RealName != "" {
form.VisitorName = visitor.RealName
}
//更新状态上线
models.UpdateVisitor(form.EntId, form.VisitorName, form.Avator, form.VisitorId, dstKefu.Name, visitor.Status, c.ClientIP(), c.ClientIP(),
form.Refer,
form.Extra,
form.CityAddress,
visitNum,
)
} else {
visitor = *models.CreateVisitor(form.VisitorName, form.Avator, c.ClientIP(), dstKefu.Name, form.VisitorId, form.Refer, form.CityAddress, form.ClientIp, form.EntId, form.Extra)
}
if form.VisitorName != "" {
visitor.Name = form.VisitorName
}
go models.AddVisitorExt(visitor.VisitorId, form.Refer, form.UserAgent, form.Url, form.ReferUrl, form.Title, form.ClientIp, form.CityAddress, form.EntId, form.Language)
//如果没有开启机器人才发送通知
if configs["RobotStatus"] != "2" {
noticeContent := fmt.Sprintf("%s访问%d次", visitor.Name, visitNum)
go SendVisitorLoginNotice(form.ToId, visitor.Name, visitor.Avator, noticeContent, visitor.VisitorId)
//go SendWechatVisitorTemplate(form.ToId, visitor.Name, noticeContent, visitor.EntId)
//go SendWechatKefuNotice(form.ToId, "[访客]"+visitor.Name+",访问:"+form.Refer, visitor.EntId)
go SendNoticeEmail(visitor.Name, "[访客]"+visitor.Name, form.EntId, noticeContent)
go SendAppGetuiPush(dstKefu.Name, "[访客]"+visitor.Name, noticeContent)
} else {
//开启仅机器人接待时,不显示离线状态
allOffline = false
}
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"alloffline": allOffline,
"entIntroduce": configs["KefuIntroduce"],
"robotSwitch": tools.Ifelse(configs["RobotStatus"] == "2", "true", "false"),
"turnToMan": configs["TurnToMan"],
"robotNoAnswer": configs["RobotNoAnswer"],
"visitorNotice": configs["VisitorNotice"],
"autoWelcome": configs["AutoWelcome"],
"visitorCookie": configs["VisitorCookie"],
"scanWechatQrcode": configs["ScanWechatQrcode"],
"closeNotice": configs["CloseNotice"],
"result": visitor,
"kefu": kefuCommonGin,
"robot": RobotCommonGin,
})
}
// 组合扩展信息
func makeVisitorLoginForm(form *VisitorLoginForm) {
//扩展信息
extraJson := tools.Base64Decode(form.Extra)
if extraJson != "" {
var extraObj VisitorExtra
err := json.Unmarshal([]byte(extraJson), &extraObj)
if err == nil {
if extraObj.VisitorName != "" {
form.VisitorName = extraObj.VisitorName
}
if extraObj.VisitorAvatar != "" {
form.Avator = extraObj.VisitorAvatar
}
if extraObj.VisitorId != "" {
form.VisitorId = extraObj.VisitorId
}
}
}
}
func GetVisitor(c *gin.Context) {
visitorId := c.Query("visitorId")
entId, _ := c.Get("ent_id")
vistor := models.FindVisitorByVistorId(visitorId)
exts := models.FindVisitorExtByVistorId(visitorId, 1, 1)
sameIPCount := models.CountVisitorsByEntid(fmt.Sprintf("%v", entId), " and client_ip = ? ", vistor.ClientIp)
osVersion := ""
browser := ""
ua := ""
if len(exts) != 0 {
ext := exts[0]
ua = ext.Ua
uaParser := tools.NewUaParser(ua)
osVersion = uaParser.OsVersion
browser = uaParser.Browser
}
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"create_time": vistor.CreatedAt.Format("2006-01-02 15:04:05"),
"last_time": vistor.UpdatedAt.Format("2006-01-02 15:04:05"),
"os_version": osVersion,
"browser": browser,
"ua": ua,
"same_ip": sameIPCount,
"result": vistor,
})
}
/*
*
获取访客访问动态
*/
func GetVisitorExt(c *gin.Context) {
visitorId := c.Query("visitor_id")
page, pagesize := HandlePagePageSize(c)
list := make([]VisitorExtend, 0)
count := models.CountVisitorExtByVistorId(visitorId)
exts := models.FindVisitorExtByVistorId(visitorId, page, pagesize)
for _, ext := range exts {
uaParser := tools.NewUaParser(ext.Ua)
item := VisitorExtend{
CreatedAt: ext.CreatedAt.Format("2006-01-02 15:04:05"),
ID: ext.ID,
VisitorId: ext.VisitorId,
Url: ext.Url,
Ua: ext.Ua,
Title: ext.Title,
ClientIp: ext.ClientIp,
OsVersion: uaParser.OsVersion,
Browser: uaParser.Browser,
Refer: ext.Refer,
City: ext.City,
ReferUrl: ext.ReferUrl,
Language: ext.Language,
}
list = append(list, item)
}
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": gin.H{
"list": list,
"count": count,
"pagesize": pagesize,
},
})
}
/*
*
获取访客访问动态列表
*/
func GetVisitorExtList(c *gin.Context) {
entId, _ := c.Get("ent_id")
roleId, _ := c.Get("role_id")
query := "1=1 "
var arg = []interface{}{}
if roleId.(float64) != 1 {
query += "and ent_id = ? "
arg = append(arg, entId)
}
title := tools.UrlDecode(c.Query("title"))
referTitle := tools.UrlDecode(c.Query("refer_title"))
if title != "" {
query += "and title like ? "
arg = append(arg, title+"%")
}
if referTitle != "" {
query += "and refer_title like ? "
arg = append(arg, referTitle+"%")
}
page, pagesize := HandlePagePageSize(c)
count := models.CountVisitorExtByWhere(query, arg...)
exts := models.FindVisitorExtByWhere(page, pagesize, query, arg...)
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": gin.H{
"list": exts,
"count": count,
"pagesize": pagesize,
"page": page,
},
})
}
/*
*
获取访客访问动态列表
*/
func GetRateList(c *gin.Context) {
entId, _ := c.Get("ent_id")
roleId, _ := c.Get("role_id")
query := "1=1 "
var arg = []interface{}{}
if roleId.(float64) != 1 {
query += "and ent_id = ? "
arg = append(arg, entId)
}
page, pagesize := HandlePagePageSize(c)
count := models.CountRateWhere(query, arg...)
exts := models.FindRateByWhere(page, pagesize, query, arg...)
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": gin.H{
"list": exts,
"count": count,
"pagesize": pagesize,
"page": page,
},
})
}
// @Summary 获取访客列表接口
// @Produce json
// @Accept multipart/form-data
// @Param page query string true "分页"
// @Param token header string true "认证token"
// @Success 200 {object} controller.Response
// @Failure 200 {object} controller.Response
// @Router /visitors [get]
func GetVisitors(c *gin.Context) {
page, _ := strconv.Atoi(c.Query("page"))
var pagesize uint
myPagesize, _ := strconv.Atoi(c.Query("pagesize"))
if myPagesize != 0 {
pagesize = uint(myPagesize)
} else {
pagesize = common.VisitorPageSize
}
kefuId, _ := c.Get("kefu_name")
vistors := models.FindVisitorsByKefuId(uint(page), pagesize, kefuId.(string))
visitorIds := make([]string, 0)
for _, visitor := range vistors {
visitorIds = append(visitorIds, visitor.VisitorId)
}
messagesMap := models.FindLastMessageMap(visitorIds)
unreadMap := models.FindUnreadMessageNumByVisitorIds(visitorIds, "visitor")
//log.Println(unreadMap)
users := make([]VisitorOnline, 0)
for _, visitor := range vistors {
var unreadNum uint32
if num, ok := unreadMap[visitor.VisitorId]; ok {
unreadNum = num
}
user := VisitorOnline{
Id: visitor.ID,
VisitorId: visitor.VisitorId,
Avator: visitor.Avator,
Ip: visitor.SourceIp,
Username: fmt.Sprintf("#%d %s", visitor.ID, visitor.Name),
LastMessage: messagesMap[visitor.VisitorId],
UpdatedAt: visitor.UpdatedAt,
UnreadNum: unreadNum,
Status: visitor.Status,
}
users = append(users, user)
}
count := models.CountVisitorsByKefuId(kefuId.(string))
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": gin.H{
"list": users,
"count": count,
"pagesize": pagesize,
},
})
}
func GetVisitorsList(c *gin.Context) {
page, _ := strconv.Atoi(c.Query("page"))
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
entId, _ := c.Get("ent_id")
search := ""
args := []interface{}{}
//通过访客名搜索
visitorName := c.Query("visitorName")
if tools.IsIP(visitorName) {
search += " and client_ip = ? "
args = append(args, visitorName)
} else if visitorName != "" {
search += " and (name like ? or visitor_id like ?)"
args = append(args, "%"+visitorName+"%")
args = append(args, "%"+visitorName+"%")
}
//通过客服名搜索
kefuName := c.Query("kefuName")
if kefuName != "" {
search += " and to_id = ? "
args = append(args, kefuName)
}
//根据创建时间
createTime := c.Query("createTime")
if createTime != "" {
timeArr := strings.Split(createTime, "~")
search += " and created_at>= ? and created_at <= ? "
args = append(args, timeArr[0], timeArr[1])
}
//根据活跃时间
updateTime := c.Query("updateTime")
if updateTime != "" {
timeArr := strings.Split(updateTime, "~")
search += " and updated_at>= ? and updated_at <= ? "
args = append(args, timeArr[0], timeArr[1])
}
//根据tag找出visitor
visitorTag := c.Query("visitorTag")
var visitorIdsArr []string
if visitorTag != "" {
visitorTags := v2.GetVisitorTags("tag_id = ? ", visitorTag)
for _, visitorTag := range visitorTags {
visitorIdsArr = append(visitorIdsArr, visitorTag.VisitorId)
}
if len(visitorIdsArr) != 0 {
search += " and visitor_id in (?) "
args = append(args, visitorIdsArr)
}
}
//根据内容找出visitor
visitorMessage := c.Query("visitorMessage")
if visitorMessage != "" {
visitors := models.FindMessageByQuery("ent_id = ? and content like ?", entId, "%"+visitorMessage+"%")
for _, visitor := range visitors {
visitorIdsArr = append(visitorIdsArr, visitor.VisitorId)
}
if len(visitorIdsArr) != 0 {
search += " and visitor_id in (?) "
args = append(args, visitorIdsArr)
}
}
//根据已读未读找出visitor
//根据内容找出visitor
readType := c.Query("readType")
if readType != "" {
visitors := models.FindMessageByQuery("ent_id = ? and mes_type='visitor' and status = ?", entId, readType)
visitorIdsArr = []string{}
for _, visitor := range visitors {
visitorIdsArr = append(visitorIdsArr, visitor.VisitorId)
}
if len(visitorIdsArr) != 0 {
search += " and visitor_id in (?) "
args = append(args, visitorIdsArr)
}
}
//排序参数
orderBy := c.Query("orderBy")
if orderBy == "" {
orderBy = "updated_at desc"
} else {
orderBy = orderBy + " desc"
}
vistors := models.FindVisitorsByEntId(uint(page), uint(pagesize), fmt.Sprintf("%v", entId), orderBy, search, args...)
count := models.CountVisitorsByEntid(fmt.Sprintf("%v", entId), search, args...)
//获取最后一条消息内容
visitorIds := make([]string, 0)
for _, visitor := range vistors {
visitorIds = append(visitorIds, visitor.VisitorId)
}
messagesMap := models.FindLastMessageMap(visitorIds)
//获取访客未读数
unreadMap := models.FindUnreadMessageNumByVisitorIds(visitorIds, "visitor")
//log.Println(unreadMap)
users := make([]VisitorOnline, 0)
for _, visitor := range vistors {
var unreadNum uint32
if num, ok := unreadMap[visitor.VisitorId]; ok {
unreadNum = num
}
username := fmt.Sprintf("#%d %s", visitor.ID, visitor.Name)
if visitor.RealName != "" {
username = visitor.RealName
}
user := VisitorOnline{
Id: visitor.ID,
VisitorId: visitor.VisitorId,
City: visitor.City,
Avator: visitor.Avator,
Ip: visitor.SourceIp,
Username: username,
LastMessage: messagesMap[visitor.VisitorId],
UpdatedAt: visitor.UpdatedAt,
CreatedAt: visitor.CreatedAt,
UnreadNum: unreadNum,
Status: visitor.Status,
}
users = append(users, user)
}
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": gin.H{
"list": users,
"count": count,
"pagesize": uint(pagesize),
"page": page,
},
})
}
func GetVisitorMessageByKefu(c *gin.Context) {
entId, _ := c.Get("ent_id")
visitorId := c.Query("visitor_id")
log.Println(entId, visitorId)
messages := models.FindMessageByWhere("message.visitor_id=? and message.ent_id=?", visitorId, entId)
chatMessages := make([]ChatMessage, 0)
for _, message := range messages {
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)
}
models.ReadMessageByVisitorId(visitorId, "visitor")
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": chatMessages,
})
}
// @Summary 获取在线访客列表接口
// @Produce json
// @Success 200 {object} controller.Response
// @Failure 200 {object} controller.Response
// @Router /visitors_online [get]
func GetVisitorOnlines(c *gin.Context) {
users := make([]map[string]string, 0)
visitorIds := make([]string, 0)
for uid, visitor := range ws.ClientList {
userInfo := make(map[string]string)
userInfo["uid"] = uid
userInfo["name"] = visitor.Name
userInfo["avator"] = visitor.Avatar
users = append(users, userInfo)
visitorIds = append(visitorIds, visitor.Id)
}
//查询最新消息
messages := models.FindLastMessage(visitorIds)
temp := make(map[string]string, 0)
for _, mes := range messages {
temp[mes.VisitorId] = mes.Content
}
for _, user := range users {
user["last_message"] = temp[user["uid"]]
}
tcps := make([]string, 0)
for ip, _ := range clientTcpList {
tcps = append(tcps, ip)
}
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": gin.H{
"ws": users,
"tcp": tcps,
},
})
}
/*
*
设置访客属性
*/
func PostVisitorAttrs(c *gin.Context) {
entId, _ := c.Get("ent_id")
entIdStr := ""
if entId == nil {
entIdStr = c.Query("ent_id")
} else {
entIdStr = entId.(string)
}
if entIdStr == "" {
c.JSON(200, gin.H{
"code": 400,
"msg": "ent_id 不能为空",
})
return
}
var param VisitorAttrParams
if err := c.BindJSON(&param); err != nil {
c.String(200, err.Error())
}
saveVisitorAttr(entIdStr, param)
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
})
}
func saveVisitorAttr(entId string, param VisitorAttrParams) {
attrInfo := models.GetVisitorAttrByVisitorId(param.VisitorId, fmt.Sprintf("%v", entId))
if attrInfo.ID == 0 {
models.CreateVisitorAttr(
fmt.Sprintf("%v", entId),
param.VisitorId,
param.VisitorAttr.RealName,
param.VisitorAttr.Tel,
param.VisitorAttr.Email,
param.VisitorAttr.QQ,
param.VisitorAttr.Wechat,
param.VisitorAttr.Comment)
} else {
var attr = &models.Visitor_attr{
RealName: param.VisitorAttr.RealName,
Tel: param.VisitorAttr.Tel,
Email: param.VisitorAttr.Email,
QQ: param.VisitorAttr.QQ,
Wechat: param.VisitorAttr.Wechat,
Comment: param.VisitorAttr.Comment,
}
models.SaveVisitorAttrByVisitorId(attr, param.VisitorId, fmt.Sprintf("%v", entId))
}
if param.VisitorAttr.RealName != "" {
models.UpdateVisitorRealName(param.VisitorAttr.RealName,
fmt.Sprintf("%v", entId),
param.VisitorId)
go ws.UpdateVisitorName(param.VisitorId, param.VisitorAttr.RealName)
}
}
/*
*
设置访客属性
*/
func GetVisitorAttr(c *gin.Context) {
entId, _ := c.Get("ent_id")
visitorId := c.Query("visitor_id")
attrInfo := models.GetVisitorAttrByVisitorId(visitorId, fmt.Sprintf("%v", entId))
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": attrInfo,
})
}
/*
*
设置访客ID
*/
func PostChangeVisitorId(c *gin.Context) {
entId := c.PostForm("ent_id")
visitorId := c.PostForm("visitor_id")
newId := c.PostForm("new_id")
if entId == "" || visitorId == "" || newId == "" {
c.JSON(200, gin.H{
"code": types.ApiCode.INVALID,
"msg": types.ApiCode.GetMessage(types.ApiCode.INVALID),
})
}
go models.UpdateVisitorVisitorId(visitorId, newId)
go models.UpdateMessageVisitorId(visitorId, newId)
go ws.VisitorChangeId(visitorId, newId)
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
})
}
// @Summary 获取客服的在线访客列表接口
// @Produce json
// @Success 200 {object} controller.Response
// @Failure 200 {object} controller.Response
// @Router /visitors_kefu_online [get]
func GetKefusVisitorOnlines(c *gin.Context) {
kefuName, _ := c.Get("kefu_name")
entId, _ := c.Get("ent_id")
kefuInfo := models.FindUserByUid(entId)
if kefuInfo.Status != 0 && kefuInfo.Status == 1 {
c.JSON(200, gin.H{
"code": 400,
"msg": "账户禁用",
})
return
}
users := make([]*VisitorOnline, 0)
visitorIds := make([]string, 0)
clientList := sortMapToSlice(ws.ClientList)
for _, visitor := range clientList {
if visitor.ToId != kefuName {
continue
}
userInfo := new(VisitorOnline)
userInfo.UpdatedAt = visitor.UpdateTime
userInfo.VisitorId = visitor.Id
userInfo.Username = visitor.Name
userInfo.Avator = visitor.Avatar
users = append(users, userInfo)
visitorIds = append(visitorIds, visitor.Id)
}
//查询最新消息
messages := models.FindLastMessageMap(visitorIds)
//查未读数
unreadMap := models.FindUnreadMessageNumByVisitorIds(visitorIds, "visitor")
for _, user := range users {
user.LastMessage = messages[user.VisitorId]
if user.LastMessage == "" {
user.LastMessage = "new visitor"
}
var unreadNum uint32
if num, ok := unreadMap[user.VisitorId]; ok {
unreadNum = num
}
user.UnreadNum = unreadNum
user.LastTime = user.UpdatedAt.Format("2006-01-02 15:04:05")
}
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": users,
})
}
func DelVisitor(c *gin.Context) {
visitorId := c.Query("visitor_id")
entIdStr, _ := c.Get("ent_id")
entId, _ := strconv.Atoi(entIdStr.(string))
models.DelVisitor("ent_id = ? and visitor_id = ?", entId, visitorId)
models.DelMessage("ent_id = ? and visitor_id = ?", entId, visitorId)
models.DelVisitorAttr("ent_id = ? and visitor_id = ?", entId, visitorId)
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
})
}
func sortMapToSlice(youMap map[string]*ws.VisitorConnection) []*ws.VisitorConnection {
keys := make([]string, 0)
for k, _ := range youMap {
keys = append(keys, k)
}
myMap := make([]*ws.VisitorConnection, 0)
sort.Strings(keys)
for _, k := range keys {
myMap = append(myMap, youMap[k])
}
return myMap
}