feat(session): 优化工作台会话分页与筛选
This commit is contained in:
@@ -84,15 +84,17 @@ func (h *SessionHandler) SendMessage(c *gin.Context) {
|
||||
func (h *SessionHandler) List(c *gin.Context) {
|
||||
page, pageSize := middleware.GetPageParams(c)
|
||||
f := service.SessionFilter{
|
||||
Status: c.Query("status"),
|
||||
Priority: c.Query("priority"),
|
||||
AgentID: c.Query("agent_id"),
|
||||
ChannelID: c.Query("channel_id"),
|
||||
Search: strings.TrimSpace(c.Query("search")),
|
||||
From: c.Query("from"),
|
||||
To: c.Query("to"),
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Scope: c.Query("scope"),
|
||||
Status: c.Query("status"),
|
||||
Priority: c.Query("priority"),
|
||||
AgentID: c.Query("agent_id"),
|
||||
ChannelID: c.Query("channel_id"),
|
||||
CustomerID: c.Query("customer_id"),
|
||||
Search: strings.TrimSpace(c.Query("search")),
|
||||
From: c.Query("from"),
|
||||
To: c.Query("to"),
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}
|
||||
items, total, err := service.ListSessions(sessionActor(c), middleware.GetTenantID(c), f)
|
||||
if err != nil {
|
||||
|
||||
@@ -98,10 +98,10 @@ type BlacklistEntry struct {
|
||||
|
||||
type Session struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
TenantID uint `gorm:"index;index:idx_session_tenant_status,priority:1;index:idx_session_tenant_agent_status,priority:1;not null" json:"tenant_id"`
|
||||
ChannelID uint `json:"channel_id"`
|
||||
CustomerID uint `gorm:"index" json:"customer_id"`
|
||||
AgentID *uint `gorm:"index" json:"agent_id"`
|
||||
AgentID *uint `gorm:"index;index:idx_session_tenant_agent_status,priority:2" json:"agent_id"`
|
||||
VisitorTokenHash string `gorm:"size:64;index" json:"-"`
|
||||
VisitorIP string `gorm:"size:64" json:"visitor_ip"`
|
||||
VisitorRegion string `gorm:"size:100" json:"visitor_region"`
|
||||
@@ -128,7 +128,7 @@ type Session struct {
|
||||
DraftText string `gorm:"type:text" json:"draft_text"`
|
||||
DraftUpdatedAt *time.Time `json:"draft_updated_at"`
|
||||
LastReadSeq int `gorm:"default:0" json:"last_read_seq"`
|
||||
Status string `gorm:"size:20;default:waiting" json:"status"`
|
||||
Status string `gorm:"size:20;default:waiting;index:idx_session_tenant_status,priority:2;index:idx_session_tenant_agent_status,priority:3" json:"status"`
|
||||
Priority string `gorm:"size:20;default:normal" json:"priority"`
|
||||
SatisfactionScore *int `json:"satisfaction_score"`
|
||||
SatisfactionText string `gorm:"size:500" json:"satisfaction_text"`
|
||||
|
||||
@@ -41,15 +41,17 @@ type AgentItem struct {
|
||||
|
||||
// SessionFilter 会话列表筛选。
|
||||
type SessionFilter struct {
|
||||
Status string
|
||||
Priority string
|
||||
AgentID string
|
||||
ChannelID string
|
||||
Search string
|
||||
From string
|
||||
To string
|
||||
Page int
|
||||
PageSize int
|
||||
Scope string
|
||||
Status string
|
||||
Priority string
|
||||
AgentID string
|
||||
ChannelID string
|
||||
CustomerID string
|
||||
Search string
|
||||
From string
|
||||
To string
|
||||
Page int
|
||||
PageSize int
|
||||
}
|
||||
|
||||
// LoadTenantSession 加载本租户会话;跨租户访问返回 403。
|
||||
@@ -120,21 +122,30 @@ func assignableRoleCodes(tenantID uint) []string {
|
||||
return append(codes, customCodes...)
|
||||
}
|
||||
|
||||
func unreadCount(session model.Session) int {
|
||||
var count int64
|
||||
model.DB.Model(&model.Message{}).
|
||||
Where("session_id = ? AND sender_type = ? AND seq > ?", session.ID, "visitor", session.LastReadSeq).
|
||||
Count(&count)
|
||||
return int(count)
|
||||
}
|
||||
|
||||
// ListSessions 会话列表:筛选、分页并批量补全客户/坐席/渠道/消息数。
|
||||
// ListSessions 会话列表:筛选、分页并批量补全客户/坐席/渠道/消息摘要。
|
||||
func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListItem, int64, error) {
|
||||
var sessions []model.Session
|
||||
var total int64
|
||||
|
||||
page := f.Page
|
||||
pageSize := f.PageSize
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 {
|
||||
pageSize = 20
|
||||
}
|
||||
if pageSize > 100 {
|
||||
pageSize = 100
|
||||
}
|
||||
|
||||
query := model.DB.Model(&model.Session{}).Where("sessions.tenant_id = ?", tenantID)
|
||||
if !actor.SessionAll || !actor.HistoryAll {
|
||||
if f.Scope == "workbench" {
|
||||
query = query.Where("sessions.status IN ?", []string{"waiting", "active"})
|
||||
if !actor.SessionAll {
|
||||
query = query.Where("sessions.agent_id = ? OR sessions.status = ?", actor.UserID, "waiting")
|
||||
}
|
||||
} else if !actor.SessionAll || !actor.HistoryAll {
|
||||
query = query.Where("sessions.agent_id = ? OR sessions.status = ?", actor.UserID, "waiting")
|
||||
}
|
||||
if f.Status != "" {
|
||||
@@ -149,6 +160,9 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
|
||||
if f.ChannelID != "" {
|
||||
query = query.Where("sessions.channel_id = ?", f.ChannelID)
|
||||
}
|
||||
if f.CustomerID != "" {
|
||||
query = query.Where("sessions.customer_id = ?", f.CustomerID)
|
||||
}
|
||||
if f.From != "" {
|
||||
if t, err := time.ParseInLocation("2006-01-02", f.From, time.Local); err == nil {
|
||||
query = query.Where("sessions.created_at >= ?", t)
|
||||
@@ -161,16 +175,52 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
|
||||
}
|
||||
if f.Search != "" {
|
||||
like := "%" + f.Search + "%"
|
||||
query = query.Joins("LEFT JOIN customers ON customers.id = sessions.customer_id").
|
||||
Where("customers.name LIKE ? OR CAST(sessions.id AS TEXT) LIKE ? OR COALESCE(sessions.end_reason, '') LIKE ?", like, like, like)
|
||||
query = query.Where(
|
||||
`EXISTS (
|
||||
SELECT 1 FROM customers AS search_customers
|
||||
WHERE search_customers.id = sessions.customer_id
|
||||
AND search_customers.name LIKE ?
|
||||
) OR CAST(sessions.id AS TEXT) LIKE ? OR EXISTS (
|
||||
SELECT 1 FROM messages AS search_messages
|
||||
WHERE search_messages.session_id = sessions.id
|
||||
AND search_messages.seq = (
|
||||
SELECT MAX(latest_message.seq)
|
||||
FROM messages AS latest_message
|
||||
WHERE latest_message.session_id = sessions.id
|
||||
)
|
||||
AND search_messages.content LIKE ?
|
||||
)`,
|
||||
like, like, like,
|
||||
)
|
||||
}
|
||||
|
||||
query.Count(&total)
|
||||
if err := query.Order("sessions.created_at desc").Offset((f.Page - 1) * f.PageSize).Limit(f.PageSize).Find(&sessions).Error; err != nil {
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, Internal("统计会话失败")
|
||||
}
|
||||
if f.Scope == "workbench" {
|
||||
query = query.
|
||||
Order(`CASE
|
||||
WHEN sessions.priority = 'urgent' THEN 0
|
||||
WHEN sessions.status = 'waiting' THEN 1
|
||||
ELSE 2
|
||||
END ASC`).
|
||||
Order(`COALESCE(
|
||||
(SELECT order_messages.sent_at
|
||||
FROM messages AS order_messages
|
||||
WHERE order_messages.session_id = sessions.id
|
||||
ORDER BY order_messages.seq DESC
|
||||
LIMIT 1),
|
||||
sessions.created_at
|
||||
) DESC`).
|
||||
Order("sessions.id DESC")
|
||||
} else {
|
||||
query = query.Order("sessions.created_at DESC").Order("sessions.id DESC")
|
||||
}
|
||||
if err := query.Offset((page - 1) * pageSize).Limit(pageSize).Find(&sessions).Error; err != nil {
|
||||
return nil, 0, Internal("查询会话失败")
|
||||
}
|
||||
|
||||
// 批量补全客户 / 客服 / 渠道 / 消息数
|
||||
// 批量补全客户 / 客服 / 渠道 / 消息摘要,避免按会话逐条查询。
|
||||
customerIDs := make([]uint, 0)
|
||||
agentIDs := make([]uint, 0)
|
||||
channelIDs := make([]uint, 0)
|
||||
@@ -186,7 +236,9 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
|
||||
customerMap := map[uint]model.Customer{}
|
||||
if len(customerIDs) > 0 {
|
||||
var customers []model.Customer
|
||||
model.DB.Where("id IN ?", UniqueUint(customerIDs)).Find(&customers)
|
||||
if err := model.DB.Where("id IN ?", UniqueUint(customerIDs)).Find(&customers).Error; err != nil {
|
||||
return nil, 0, Internal("查询会话客户失败")
|
||||
}
|
||||
for _, cu := range customers {
|
||||
customerMap[cu.ID] = cu
|
||||
}
|
||||
@@ -194,7 +246,9 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
|
||||
agentMap := map[uint]model.User{}
|
||||
if len(agentIDs) > 0 {
|
||||
var users []model.User
|
||||
model.DB.Where("id IN ?", UniqueUint(agentIDs)).Find(&users)
|
||||
if err := model.DB.Where("id IN ?", UniqueUint(agentIDs)).Find(&users).Error; err != nil {
|
||||
return nil, 0, Internal("查询会话坐席失败")
|
||||
}
|
||||
for _, u := range users {
|
||||
agentMap[u.ID] = u
|
||||
}
|
||||
@@ -202,35 +256,74 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
|
||||
channelMap := map[uint]model.Channel{}
|
||||
if len(channelIDs) > 0 {
|
||||
var channels []model.Channel
|
||||
model.DB.Unscoped().Where("id IN ?", UniqueUint(channelIDs)).Find(&channels)
|
||||
if err := model.DB.Unscoped().Where("id IN ?", UniqueUint(channelIDs)).Find(&channels).Error; err != nil {
|
||||
return nil, 0, Internal("查询会话渠道失败")
|
||||
}
|
||||
for _, ch := range channels {
|
||||
channelMap[ch.ID] = ch
|
||||
}
|
||||
}
|
||||
msgCountMap := map[uint]int{}
|
||||
lastMessageMap := map[uint]model.Message{}
|
||||
unreadMap := map[uint]int{}
|
||||
if len(sessionIDs) > 0 {
|
||||
type row struct {
|
||||
SessionID uint
|
||||
Cnt int
|
||||
Cnt int `gorm:"column:cnt"`
|
||||
}
|
||||
var rows []row
|
||||
model.DB.Model(&model.Message{}).
|
||||
if err := model.DB.Model(&model.Message{}).
|
||||
Select("session_id, COUNT(*) as cnt").
|
||||
Where("session_id IN ?", sessionIDs).
|
||||
Group("session_id").
|
||||
Scan(&rows)
|
||||
Scan(&rows).Error; err != nil {
|
||||
return nil, 0, Internal("统计会话消息失败")
|
||||
}
|
||||
for _, r := range rows {
|
||||
msgCountMap[r.SessionID] = r.Cnt
|
||||
}
|
||||
|
||||
var lastMessages []model.Message
|
||||
if err := model.DB.Where(
|
||||
`session_id IN ? AND seq = (
|
||||
SELECT MAX(latest.seq)
|
||||
FROM messages AS latest
|
||||
WHERE latest.session_id = messages.session_id
|
||||
)`,
|
||||
sessionIDs,
|
||||
).Find(&lastMessages).Error; err != nil {
|
||||
return nil, 0, Internal("查询会话最后消息失败")
|
||||
}
|
||||
for _, msg := range lastMessages {
|
||||
lastMessageMap[msg.SessionID] = msg
|
||||
}
|
||||
|
||||
var unreadRows []row
|
||||
if err := model.DB.Table("messages").
|
||||
Select("messages.session_id, COUNT(*) AS cnt").
|
||||
Joins("JOIN sessions AS unread_sessions ON unread_sessions.id = messages.session_id").
|
||||
Where(
|
||||
"messages.session_id IN ? AND messages.sender_type = ? AND messages.seq > unread_sessions.last_read_seq",
|
||||
sessionIDs,
|
||||
"visitor",
|
||||
).
|
||||
Group("messages.session_id").
|
||||
Scan(&unreadRows).Error; err != nil {
|
||||
return nil, 0, Internal("统计会话未读数失败")
|
||||
}
|
||||
for _, r := range unreadRows {
|
||||
unreadMap[r.SessionID] = r.Cnt
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]SessionListItem, 0, len(sessions))
|
||||
for _, session := range sessions {
|
||||
item := SessionListItem{Session: session, MessageCount: msgCountMap[session.ID]}
|
||||
item.VisitorOnline = VisitorIsOnline(&session, time.Now())
|
||||
if !actor.SessionAll && session.AgentID != nil && *session.AgentID == actor.UserID {
|
||||
item.UnreadCount = unreadCount(session)
|
||||
item := SessionListItem{
|
||||
Session: session,
|
||||
MessageCount: msgCountMap[session.ID],
|
||||
UnreadCount: unreadMap[session.ID],
|
||||
}
|
||||
item.VisitorOnline = VisitorIsOnline(&session, time.Now())
|
||||
if cu, ok := customerMap[session.CustomerID]; ok {
|
||||
item.CustomerName = cu.Name
|
||||
}
|
||||
@@ -244,8 +337,7 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
|
||||
item.ChannelType = ch.Type
|
||||
item.ChannelDomain = ch.SiteDomain
|
||||
}
|
||||
var lastMsg model.Message
|
||||
if err := model.DB.Where("session_id = ?", session.ID).Order("seq desc").First(&lastMsg).Error; err == nil {
|
||||
if lastMsg, ok := lastMessageMap[session.ID]; ok {
|
||||
if lastMsg.Type == "image" {
|
||||
item.LastMessage = "[图片]"
|
||||
} else {
|
||||
|
||||
@@ -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