添加消息发送API、丰富种子对话数据、Dashboard支持真实消息发送和客户名显示

This commit is contained in:
yml2213
2026-07-14 11:45:57 +08:00
parent caf14e8e52
commit 616b1bcaa2
4 changed files with 198 additions and 96 deletions
+25 -4
View File
@@ -95,11 +95,32 @@ func seed() {
}
model.DB.Create(&sessions)
// Messages
// Messages - 模拟真实对话
messages := []model.Message{
{SessionID: sessions[0].ID, SenderType: "visitor", SenderID: &customers[0].ID, Content: "你好,我的订单怎么还没发货?", Type: "text", Seq: 1, SentAt: now},
{SessionID: sessions[0].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "好,请提供一下您的订单号,我帮您查看", Type: "text", Seq: 2, SentAt: now},
{SessionID: sessions[0].ID, SenderType: "visitor", SenderID: &customers[0].ID, Content: "订单号 AB20260714001", Type: "text", Seq: 3, SentAt: now},
// Session 1: 张三 - 订单物流咨询 (urgent)
{SessionID: sessions[0].ID, SenderType: "visitor", Content: "好,我的订单怎么还没发货?已经3天了", Type: "text", Seq: 1, SentAt: now.Add(-10 * time.Minute)},
{SessionID: sessions[0].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "您好,请提供一下您的订单号,我帮您查询", Type: "text", Seq: 2, SentAt: now.Add(-9 * time.Minute)},
{SessionID: sessions[0].ID, SenderType: "visitor", Content: "订单号 AB20260714001", Type: "text", Seq: 3, SentAt: now.Add(-8 * time.Minute)},
{SessionID: sessions[0].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "稍等,正在为您查询物流信息...", Type: "text", Seq: 4, SentAt: now.Add(-7 * time.Minute)},
{SessionID: sessions[0].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "您好,您的包裹已到达北京分拨中心,预计明天下午送达。给您带来不便敬请谅解", Type: "text", Seq: 5, SentAt: now.Add(-6 * time.Minute)},
// Session 2: 李四 - 退换货咨询 (active)
{SessionID: sessions[1].ID, SenderType: "visitor", Content: "你好,我买的商品有质量问题,想退货", Type: "text", Seq: 1, SentAt: now.Add(-5 * time.Minute)},
{SessionID: sessions[1].ID, SenderType: "agent", SenderID: &agent2.ID, Content: "非常抱歉给您带来不便。请拍照上传问题商品图片,我们核实后会为您办理退货", Type: "text", Seq: 2, SentAt: now.Add(-4 * time.Minute)},
{SessionID: sessions[1].ID, SenderType: "visitor", Content: "好的,我拍照上传", Type: "text", Seq: 3, SentAt: now.Add(-3 * time.Minute)},
// Session 3: 王五 - 等待分配 (waiting)
{SessionID: sessions[2].ID, SenderType: "visitor", Content: "您好,请问企业版是否有优惠?我们公司需要50个坐席", Type: "text", Seq: 1, SentAt: now.Add(-2 * time.Minute)},
// Session 4: 赵六科技 - 已结束
{SessionID: sessions[3].ID, SenderType: "visitor", Content: "产品使用手册在哪里下载?", Type: "text", Seq: 1, SentAt: now.Add(-2 * time.Hour)},
{SessionID: sessions[3].ID, SenderType: "agent", SenderID: &agent3.ID, Content: "您好,请在官网帮助中心→文档下载中获取,也可直接访问 docs.example.com", Type: "text", Seq: 2, SentAt: now.Add(-1 * time.Hour + 55*time.Minute)},
{SessionID: sessions[3].ID, SenderType: "visitor", Content: "找到了,谢谢!", Type: "text", Seq: 3, SentAt: now.Add(-1 * time.Hour + 50*time.Minute)},
// Session 5: 钱七 - 已结束
{SessionID: sessions[4].ID, SenderType: "visitor", Content: "退款什么时候到账?已经3天了", Type: "text", Seq: 1, SentAt: now.Add(-3 * time.Hour)},
{SessionID: sessions[4].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "您好,退款一般在3-5个工作日到账,我帮您催一下财务", Type: "text", Seq: 2, SentAt: now.Add(-2 * time.Hour + 55*time.Minute)},
{SessionID: sessions[4].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "已为您加急处理,预计明天到账,请注意查收", Type: "text", Seq: 3, SentAt: now.Add(-2 * time.Hour + 50*time.Minute)},
}
model.DB.Create(&messages)
+1
View File
@@ -41,6 +41,7 @@ func SetupRoutes(r *gin.Engine) {
sessions.POST("/:id/transfer", session.Transfer)
sessions.POST("/:id/end", session.End)
sessions.PUT("/:id/priority", session.UpdatePriority)
sessions.POST("/:id/messages", session.SendMessage)
// 客户管理
customers := authRequired.Group("/customers")
+47 -1
View File
@@ -2,6 +2,7 @@ package handler
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"kefu-sys/server/internal/middleware"
@@ -12,6 +13,52 @@ type SessionHandler struct{}
func NewSessionHandler() *SessionHandler { return &SessionHandler{} }
type SendMessageReq struct {
Content string `json:"content" binding:"required"`
Type string `json:"type"`
}
func (h *SessionHandler) SendMessage(c *gin.Context) {
tenantID := middleware.GetTenantID(c)
userID := middleware.GetUserID(c)
id := c.Param("id")
var req SendMessageReq
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.Where("id = ? AND tenant_id = ?", id, tenantID).First(&session).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "message": "会话不存在"})
return
}
var maxSeq int
model.DB.Model(&model.Message{}).Where("session_id = ?", session.ID).Select("COALESCE(MAX(seq), 0)").Scan(&maxSeq)
msg := model.Message{
SessionID: session.ID,
SenderType: "agent",
SenderID: &userID,
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
}
middleware.JSON(c, msg)
}
type CreateSessionReq struct {
ChannelID uint `json:"channel_id"`
CustomerID uint `json:"customer_id"`
@@ -170,7 +217,6 @@ func (h *SessionHandler) UpdatePriority(c *gin.Context) {
func parseID(s string) uint {
var id uint
// Simple atoi for uint
for _, c := range s {
if c >= '0' && c <= '9' {
id = id*10 + uint(c-'0')