kefu/controller/visitor.go

955 lines
28 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}