fix: 统一商务表格展示并修正筛选和全量排序
This commit is contained in:
@@ -3,6 +3,7 @@ package business
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
@@ -25,7 +26,8 @@ func analyticsPromotes(db *gorm.DB, scope business.AnalyticsScope, f business.An
|
||||
if f.PromoteName == "" {
|
||||
return q
|
||||
}
|
||||
hits := analyticsBasePromotes(db, scope, f, "hit").Select("1").Where("hit.account LIKE ?", "%"+f.PromoteName+"%").Where("hit.source_db=" + alias + ".source_db")
|
||||
keyword := strings.ToLower(strings.TrimSpace(f.PromoteName))
|
||||
hits := analyticsBasePromotes(db, scope, f, "hit").Select("1").Where("INSTR(LOWER(hit.account),?)>0 OR INSTR(LOWER(hit.nickname),?)>0", keyword, keyword).Where("hit.source_db=" + alias + ".source_db")
|
||||
if scope.IncludeSub {
|
||||
root := "CASE WHEN hit.promote_level=1 THEN hit.id WHEN hit.top_promote_id>0 THEN hit.top_promote_id ELSE hit.id END"
|
||||
hits = hits.Where("(" + alias + ".id=(" + root + ") OR " + alias + ".top_promote_id=(" + root + "))")
|
||||
|
||||
@@ -102,6 +102,24 @@ func TestAnalyticsFiltersKeepHierarchyAndSnapshotNames(t *testing.T) {
|
||||
t.Fatal("不能用当前游戏表名替代报表快照过滤")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyticsChannelSearchMatchesNicknameAndKeepsScope(t *testing.T) {
|
||||
db, repo, scope, filter := prepareAnalyticsData(t)
|
||||
if err := db.Exec("UPDATE tab_promote SET nickname='同名推广' WHERE id=100").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
scope.Viewer = business.UserScope{SelfID: 9, OnlySelf: true}
|
||||
filter.PromoteName = "推广"
|
||||
data, err := repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
|
||||
if err != nil || len(data.Rows) != 1 || data.Rows[0].SourceDB != "lx" || data.Rows[0].ID != 100 {
|
||||
t.Fatalf("nickname search must remain scoped: %+v %v", data, err)
|
||||
}
|
||||
filter.PromoteName = "%"
|
||||
data, err = repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
|
||||
if err != nil || len(data.Rows) != 0 {
|
||||
t.Fatal("wildcard keyword must not broaden the query")
|
||||
}
|
||||
}
|
||||
func TestAnalyticsMissingScopeAndTablesDoNotBroaden(t *testing.T) {
|
||||
db, repo, scope, filter := prepareAnalyticsData(t)
|
||||
scope.IncludeSub = false
|
||||
|
||||
@@ -86,7 +86,8 @@ func (r *channelRepo) List(ctx context.Context, scope business.UserScope, filter
|
||||
q = q.Where("p.source_db IN ?", filter.Sources)
|
||||
}
|
||||
if filter.Keyword != "" {
|
||||
q = q.Where("p.account LIKE ?", "%"+filter.Keyword+"%")
|
||||
keyword := strings.ToLower(strings.TrimSpace(filter.Keyword))
|
||||
q = q.Where("INSTR(LOWER(p.account),?)>0 OR INSTR(LOWER(p.nickname),?)>0 OR INSTR(LOWER(p.real_name),?)>0", keyword, keyword, keyword)
|
||||
}
|
||||
for _, field := range []struct {
|
||||
column string
|
||||
|
||||
@@ -43,6 +43,23 @@ func prepareChannels(t *testing.T) (*gorm.DB, business.ChannelRepo) {
|
||||
func channelTestScope() business.UserScope {
|
||||
return business.UserScope{SelfID: 8, IncludeSelf: true, DescendantPath: "0,7,8"}
|
||||
}
|
||||
|
||||
func TestChannelKeywordMatchesNameAndContactWithinScope(t *testing.T) {
|
||||
db, repo := prepareChannels(t)
|
||||
if err := db.Exec("UPDATE tab_promote SET nickname='同名公会', real_name='负责人甲' WHERE id=100").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, keyword := range []string{"公会", "负责人甲"} {
|
||||
page, err := repo.List(context.Background(), business.UserScope{SelfID: 9, OnlySelf: true}, business.ChannelFilter{Keyword: keyword})
|
||||
if err != nil || page.Total != 1 || len(page.Rows) != 1 || page.Rows[0].SourceDB != "lx" {
|
||||
t.Fatalf("keyword must not escape the business scope: %q %+v %v", keyword, page, err)
|
||||
}
|
||||
}
|
||||
page, err := repo.List(context.Background(), channelTestScope(), business.ChannelFilter{Keyword: "%"})
|
||||
if err != nil || page.Total != 0 {
|
||||
t.Fatal("keyword wildcards must be treated literally")
|
||||
}
|
||||
}
|
||||
func TestChannelListMatchesBindingsAndLiteralBusinessKeyword(t *testing.T) {
|
||||
db, repo := prepareChannels(t)
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -287,6 +287,8 @@ func (r *ledgerRepo) Spends(ctx context.Context, scope business.LedgerScope, fil
|
||||
order := "r.pay_time"
|
||||
if filter.SortField == "payAmount" {
|
||||
order = "r.pay_amount"
|
||||
} else if filter.SortField == "id" {
|
||||
order = "r.id"
|
||||
}
|
||||
if filter.Ascending {
|
||||
order += " ASC"
|
||||
|
||||
@@ -147,3 +147,24 @@ func TestLedgerChannelNicknameAndLiteralFuzzyFilter(t *testing.T) {
|
||||
t.Fatal("模糊搜索不得扩大商务范围")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpendIDSortIsGlobalAndStableAcrossPages(t *testing.T) {
|
||||
db, repo, scope, filter := prepareLedgerData(t)
|
||||
if err := db.Exec("UPDATE tab_spend SET pay_time=1999 WHERE id=901").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
filter.SortField, filter.Ascending = "id", true
|
||||
first, err := repo.Spends(context.Background(), scope, filter, business.LedgerListOptions{Limit: 2})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
second, err := repo.Spends(context.Background(), scope, filter, business.LedgerListOptions{Offset: 2, Limit: 2})
|
||||
if err != nil || len(first.Rows) != 2 || len(second.Rows) != 2 || first.Rows[1].ID >= second.Rows[0].ID {
|
||||
t.Fatal("ascending sort must be applied before pagination")
|
||||
}
|
||||
filter.Ascending = false
|
||||
last, err := repo.Spends(context.Background(), scope, filter, business.LedgerListOptions{Limit: 2})
|
||||
if err != nil || last.Rows[0].ID != 909 || last.Rows[1].ID != 904 {
|
||||
t.Fatalf("ID ordering must not fall back to timestamps: %+v %v", last, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user