feat(session): 优化工作台会话分页与筛选
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"kefu-cloud/server/internal/model"
|
||||
)
|
||||
|
||||
func setupSessionListTestDB(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(
|
||||
sqlite.Open(fmt.Sprintf("file:kefu_session_list_%d?mode=memory&cache=shared", time.Now().UnixNano())),
|
||||
&gorm.Config{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("打开测试数据库失败: %v", err)
|
||||
}
|
||||
model.DB = db
|
||||
if err := model.Migrate(db); err != nil {
|
||||
t.Fatalf("迁移测试数据库失败: %v", err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func TestListSessionsWorkbenchPaginatesSortsAndExcludesEnded(t *testing.T) {
|
||||
db := setupSessionListTestDB(t)
|
||||
tenant := model.Tenant{Name: "分页测试租户", Status: "normal"}
|
||||
if err := db.Create(&tenant).Error; err != nil {
|
||||
t.Fatalf("创建租户失败: %v", err)
|
||||
}
|
||||
customer := model.Customer{TenantID: tenant.ID, Name: "星河科技"}
|
||||
if err := db.Create(&customer).Error; err != nil {
|
||||
t.Fatalf("创建客户失败: %v", err)
|
||||
}
|
||||
|
||||
now := time.Now().Truncate(time.Second)
|
||||
sessions := []model.Session{
|
||||
{
|
||||
TenantID: tenant.ID, CustomerID: customer.ID, Status: "active", Priority: "urgent",
|
||||
VisitorIP: "10.0.0.1", CreatedAt: now.Add(-4 * time.Hour),
|
||||
},
|
||||
{
|
||||
TenantID: tenant.ID, CustomerID: customer.ID, Status: "waiting", Priority: "normal",
|
||||
VisitorIP: "10.0.0.2", CreatedAt: now.Add(-3 * time.Hour),
|
||||
},
|
||||
{
|
||||
TenantID: tenant.ID, CustomerID: customer.ID, Status: "active", Priority: "normal",
|
||||
VisitorIP: "10.0.0.3", CreatedAt: now.Add(-2 * time.Hour),
|
||||
},
|
||||
{
|
||||
TenantID: tenant.ID, CustomerID: customer.ID, Status: "ended", Priority: "urgent",
|
||||
VisitorIP: "10.0.0.4", CreatedAt: now.Add(-time.Hour),
|
||||
},
|
||||
}
|
||||
if err := db.Create(&sessions).Error; err != nil {
|
||||
t.Fatalf("创建会话失败: %v", err)
|
||||
}
|
||||
messages := []model.Message{
|
||||
{SessionID: sessions[0].ID, SenderType: "visitor", Content: "紧急报价单", Type: "text", Seq: 1, SentAt: now.Add(-10 * time.Minute)},
|
||||
{SessionID: sessions[1].ID, SenderType: "visitor", Content: "等待接入", Type: "text", Seq: 1, SentAt: now.Add(-5 * time.Minute)},
|
||||
{SessionID: sessions[2].ID, SenderType: "visitor", Content: "普通咨询", Type: "text", Seq: 1, SentAt: now.Add(-time.Minute)},
|
||||
{SessionID: sessions[3].ID, SenderType: "visitor", Content: "已结束会话", Type: "text", Seq: 1, SentAt: now},
|
||||
}
|
||||
if err := db.Create(&messages).Error; err != nil {
|
||||
t.Fatalf("创建消息失败: %v", err)
|
||||
}
|
||||
|
||||
allData := Actor{SessionAll: true, HistoryAll: true}
|
||||
firstPage, total, err := ListSessions(allData, tenant.ID, SessionFilter{
|
||||
Scope: "workbench", Page: 1, PageSize: 2,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("查询第一页失败: %v", err)
|
||||
}
|
||||
if total != 3 {
|
||||
t.Fatalf("工作台总数=%d,期望 3(不包含已结束会话)", total)
|
||||
}
|
||||
if len(firstPage) != 2 {
|
||||
t.Fatalf("第一页数量=%d,期望 2", len(firstPage))
|
||||
}
|
||||
if firstPage[0].ID != sessions[0].ID || firstPage[1].ID != sessions[1].ID {
|
||||
t.Fatalf("排序异常: got [%d, %d], want [%d, %d]",
|
||||
firstPage[0].ID, firstPage[1].ID, sessions[0].ID, sessions[1].ID)
|
||||
}
|
||||
if firstPage[0].CustomerName != "星河科技" || firstPage[0].LastMessage != "紧急报价单" {
|
||||
t.Fatalf("会话摘要补全异常: %+v", firstPage[0])
|
||||
}
|
||||
if firstPage[0].UnreadCount != 1 || firstPage[0].MessageCount != 1 {
|
||||
t.Fatalf("未读/消息数异常: unread=%d messages=%d", firstPage[0].UnreadCount, firstPage[0].MessageCount)
|
||||
}
|
||||
|
||||
secondPage, secondTotal, err := ListSessions(allData, tenant.ID, SessionFilter{
|
||||
Scope: "workbench", Page: 2, PageSize: 2,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("查询第二页失败: %v", err)
|
||||
}
|
||||
if secondTotal != 3 || len(secondPage) != 1 || secondPage[0].ID != sessions[2].ID {
|
||||
t.Fatalf("第二页异常: total=%d items=%+v", secondTotal, secondPage)
|
||||
}
|
||||
|
||||
historyItems, historyTotal, err := ListSessions(allData, tenant.ID, SessionFilter{Page: 1, PageSize: 20})
|
||||
if err != nil {
|
||||
t.Fatalf("查询普通会话列表失败: %v", err)
|
||||
}
|
||||
if historyTotal != 4 || len(historyItems) != 4 {
|
||||
t.Fatalf("非工作台查询不应排除已结束会话: total=%d items=%+v", historyTotal, historyItems)
|
||||
}
|
||||
|
||||
agentItems, agentTotal, err := ListSessions(Actor{UserID: 999}, tenant.ID, SessionFilter{
|
||||
Scope: "workbench", Page: 1, PageSize: 20,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("查询普通坐席工作台失败: %v", err)
|
||||
}
|
||||
if agentTotal != 1 || len(agentItems) != 1 || agentItems[0].ID != sessions[1].ID {
|
||||
t.Fatalf("普通坐席只能看到等待中或自己的进行中会话: total=%d items=%+v", agentTotal, agentItems)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListSessionsWorkbenchFiltersSearchAndCustomer(t *testing.T) {
|
||||
db := setupSessionListTestDB(t)
|
||||
tenant := model.Tenant{Name: "筛选测试租户", Status: "normal"}
|
||||
if err := db.Create(&tenant).Error; err != nil {
|
||||
t.Fatalf("创建租户失败: %v", err)
|
||||
}
|
||||
customers := []model.Customer{
|
||||
{TenantID: tenant.ID, Name: "远山贸易"},
|
||||
{TenantID: tenant.ID, Name: "青禾设计"},
|
||||
}
|
||||
if err := db.Create(&customers).Error; err != nil {
|
||||
t.Fatalf("创建客户失败: %v", err)
|
||||
}
|
||||
sessions := []model.Session{
|
||||
{TenantID: tenant.ID, CustomerID: customers[0].ID, Status: "waiting", Priority: "urgent"},
|
||||
{TenantID: tenant.ID, CustomerID: customers[1].ID, Status: "active", Priority: "normal"},
|
||||
}
|
||||
if err := db.Create(&sessions).Error; err != nil {
|
||||
t.Fatalf("创建会话失败: %v", err)
|
||||
}
|
||||
messages := []model.Message{
|
||||
{SessionID: sessions[0].ID, SenderType: "visitor", Content: "需要产品报价", Type: "text", Seq: 1, SentAt: time.Now()},
|
||||
{SessionID: sessions[0].ID, SenderType: "agent", Content: "稍等", Type: "text", Seq: 2, SentAt: time.Now()},
|
||||
{SessionID: sessions[1].ID, SenderType: "visitor", Content: "售后服务", Type: "text", Seq: 1, SentAt: time.Now()},
|
||||
}
|
||||
if err := db.Create(&messages).Error; err != nil {
|
||||
t.Fatalf("创建消息失败: %v", err)
|
||||
}
|
||||
|
||||
allData := Actor{SessionAll: true, HistoryAll: true}
|
||||
cases := []struct {
|
||||
name string
|
||||
filter SessionFilter
|
||||
want uint
|
||||
}{
|
||||
{name: "按客户名搜索", filter: SessionFilter{Scope: "workbench", Search: "远山"}, want: sessions[0].ID},
|
||||
{name: "按最后消息搜索", filter: SessionFilter{Scope: "workbench", Search: "稍等"}, want: sessions[0].ID},
|
||||
{name: "按状态筛选", filter: SessionFilter{Scope: "workbench", Status: "active"}, want: sessions[1].ID},
|
||||
{name: "按优先级筛选", filter: SessionFilter{Scope: "workbench", Priority: "urgent"}, want: sessions[0].ID},
|
||||
{name: "按客户筛选", filter: SessionFilter{Scope: "workbench", CustomerID: fmt.Sprint(customers[1].ID)}, want: sessions[1].ID},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tc.filter.Page = 1
|
||||
tc.filter.PageSize = 20
|
||||
items, total, err := ListSessions(allData, tenant.ID, tc.filter)
|
||||
if err != nil {
|
||||
t.Fatalf("查询失败: %v", err)
|
||||
}
|
||||
if total != 1 || len(items) != 1 || items[0].ID != tc.want {
|
||||
t.Fatalf("筛选结果异常: total=%d items=%+v want=%d", total, items, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user