实现Widget访客端API:初始化会话、发送消息、消息轮询,前端Widget对接真实API
This commit is contained in:
@@ -13,6 +13,7 @@ func SetupRoutes(r *gin.Engine) {
|
||||
stats := NewStatisticsHandler()
|
||||
admin := NewAdminHandler()
|
||||
ws := NewWsHandler()
|
||||
widget := NewWidgetHandler()
|
||||
|
||||
api := r.Group("/api")
|
||||
|
||||
@@ -20,10 +21,12 @@ func SetupRoutes(r *gin.Engine) {
|
||||
api.POST("/login", auth.Login)
|
||||
api.POST("/register", auth.Register)
|
||||
|
||||
// widget 接口(通过 channel_id 鉴权,简化处理)
|
||||
widget := api.Group("/widget")
|
||||
widget.POST("/init", func(c *gin.Context) { c.JSON(200, gin.H{"code": 0, "data": gin.H{"session_id": 1}}) })
|
||||
widget.POST("/message", func(c *gin.Context) { c.JSON(200, gin.H{"code": 0}) })
|
||||
// widget 接口
|
||||
widgetApi := api.Group("/widget")
|
||||
widgetApi.POST("/init", widget.Init)
|
||||
widgetApi.GET("/init", widget.Init)
|
||||
widgetApi.POST("/message", widget.SendMessage)
|
||||
widgetApi.GET("/messages", widget.GetMessages)
|
||||
|
||||
// 需要认证的接口
|
||||
authRequired := api.Group("")
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"kefu-sys/server/internal/model"
|
||||
)
|
||||
|
||||
type WidgetHandler struct{}
|
||||
|
||||
func NewWidgetHandler() *WidgetHandler { return &WidgetHandler{} }
|
||||
|
||||
type WidgetInitReq struct {
|
||||
ChannelKey string `json:"channel_key" form:"channel_key"`
|
||||
VisitorName string `json:"visitor_name"`
|
||||
}
|
||||
|
||||
type WidgetMessageReq struct {
|
||||
SessionID uint `json:"session_id" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (h *WidgetHandler) Init(c *gin.Context) {
|
||||
var req WidgetInitReq
|
||||
if err := c.ShouldBindQuery(&req); err != nil && c.ShouldBindJSON(&req) != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "参数错误"})
|
||||
return
|
||||
}
|
||||
if req.ChannelKey == "" {
|
||||
req.ChannelKey = c.Query("channel_key")
|
||||
}
|
||||
|
||||
var channel model.Channel
|
||||
if err := model.DB.Where("script_code LIKE ?", "%"+req.ChannelKey+"%").Or("script_code LIKE ?", "%"+req.ChannelKey+"%").First(&channel).Error; err != nil {
|
||||
// 如果没有匹配的渠道,使用第一个启用的渠道
|
||||
if err := model.DB.Where("type = ? AND status = ?", "web", "enabled").First(&channel).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"code": 404, "message": "渠道不存在"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
name := req.VisitorName
|
||||
if name == "" {
|
||||
name = "访客"
|
||||
}
|
||||
|
||||
// 创建或查找客户
|
||||
var customer model.Customer
|
||||
model.DB.Where("tenant_id = ? AND name = ? AND phone = ''", channel.TenantID, name).First(&customer)
|
||||
if customer.ID == 0 {
|
||||
customer = model.Customer{
|
||||
TenantID: channel.TenantID,
|
||||
Name: name,
|
||||
Source: "网页",
|
||||
Status: "online",
|
||||
}
|
||||
model.DB.Create(&customer)
|
||||
}
|
||||
|
||||
// 创建会话
|
||||
session := model.Session{
|
||||
TenantID: channel.TenantID,
|
||||
ChannelID: channel.ID,
|
||||
CustomerID: customer.ID,
|
||||
Status: "waiting",
|
||||
Priority: "normal",
|
||||
}
|
||||
model.DB.Create(&session)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"data": gin.H{
|
||||
"session_id": session.ID,
|
||||
"customer_id": customer.ID,
|
||||
"channel_id": channel.ID,
|
||||
"tenant_id": channel.TenantID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (h *WidgetHandler) SendMessage(c *gin.Context) {
|
||||
var req WidgetMessageReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "参数错误"})
|
||||
return
|
||||
}
|
||||
if req.Type == "" {
|
||||
req.Type = "text"
|
||||
}
|
||||
|
||||
var session model.Session
|
||||
if err := model.DB.First(&session, req.SessionID).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"code": 404, "message": "会话不存在"})
|
||||
return
|
||||
}
|
||||
|
||||
// 如果是等待中的会话,更新为活跃
|
||||
if session.Status == "waiting" {
|
||||
model.DB.Model(&session).Update("status", "active")
|
||||
}
|
||||
|
||||
var maxSeq int
|
||||
model.DB.Model(&model.Message{}).Where("session_id = ?", session.ID).Select("COALESCE(MAX(seq), 0)").Scan(&maxSeq)
|
||||
|
||||
custID := session.CustomerID
|
||||
msg := model.Message{
|
||||
SessionID: session.ID,
|
||||
SenderType: "visitor",
|
||||
SenderID: &custID,
|
||||
Content: req.Content,
|
||||
Type: req.Type,
|
||||
Seq: maxSeq + 1,
|
||||
SentAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := model.DB.Create(&msg).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "发送失败"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "data": msg})
|
||||
}
|
||||
|
||||
func (h *WidgetHandler) GetMessages(c *gin.Context) {
|
||||
sessionID := c.Query("session_id")
|
||||
|
||||
var messages []model.Message
|
||||
model.DB.Where("session_id = ?", sessionID).Order("seq asc").Find(&messages)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "data": messages})
|
||||
}
|
||||
Reference in New Issue
Block a user