From 56874b33daef96dbc3384eb5b24123768962cf3f Mon Sep 17 00:00:00 2001 From: Yvan <8574526@qq,com> Date: Thu, 5 Nov 2026 14:51:51 +0800 Subject: [PATCH] fix: remove unused channel activity filters --- internal/biz/business/analytics.go | 1 - internal/data/business/analytics.go | 35 ++----------------- internal/data/business/analytics_test.go | 33 +++-------------- internal/service/business/analytics.go | 2 +- internal/service/business/date_range_test.go | 9 +++-- internal/service/dto/analytics.go | 2 -- .../view/sw/components/ReportAnalytics.vue | 4 +-- 7 files changed, 14 insertions(+), 72 deletions(-) diff --git a/internal/biz/business/analytics.go b/internal/biz/business/analytics.go index ff56ca1..7f989b3 100644 --- a/internal/biz/business/analytics.go +++ b/internal/biz/business/analytics.go @@ -30,7 +30,6 @@ type AnalyticsFilter struct { Sources, GameNames []string PromoteName string PromoteType *int - HasRegister, HasPay *bool StartDate, EndDate *time.Time Begin, End, SortField string Ascending bool diff --git a/internal/data/business/analytics.go b/internal/data/business/analytics.go index 317b799..12cab1e 100644 --- a/internal/data/business/analytics.go +++ b/internal/data/business/analytics.go @@ -2,7 +2,6 @@ package business import ( "context" - "math/big" "sort" "strings" "time" @@ -172,7 +171,6 @@ func (r *analyticsRepo) Aggregate(ctx context.Context, kind business.AnalyticsKi var global []portraitCountPO globalPay := "0" withGlobal := kind == business.ChannelAnalytics && scope.Viewer.All - metricFiltered := kind == business.ChannelAnalytics && (f.HasRegister != nil || f.HasPay != nil) group, queryContext := errgroup.WithContext(ctx) // 每个请求最多两个并行查询,复用同一存储客户端;结果读取完后再组装 DO。 group.SetLimit(2) @@ -191,7 +189,7 @@ func (r *analyticsRepo) Aggregate(ctx context.Context, kind business.AnalyticsKi } return nil }) - if withGlobal && !metricFiltered { + if withGlobal { group.Go(func() error { q := analyticsQuery(queryDB, scope, f, "tab_sw_report_day_key", mode) if err := q.Select("r.metric,COUNT(DISTINCT " + portraitIdentity(queryDB, scope.IDCardDedup) + ") AS count").Group("r.metric").Scan(&global).Error; err != nil { @@ -216,8 +214,8 @@ func (r *analyticsRepo) Aggregate(ctx context.Context, kind business.AnalyticsKi putAnalyticsCount(&rowFor(po).Counts, po.Metric, po.Count) } } - // Report rows come from facts in the selected period. Registration/payment - // filters narrow that same set; they must not add the entire channel catalog. + // Report rows come from facts in the selected period. Looking up channel + // metadata must not expand them into the entire channel catalog. if kind == business.ChannelAnalytics && !scope.Viewer.All { if err := filterAnalyticsRows(db, scope, f, rowMap); err != nil { return nil, err @@ -228,33 +226,6 @@ func (r *analyticsRepo) Aggregate(ctx context.Context, kind business.AnalyticsKi return nil, err } } - if metricFiltered { - for key, row := range rowMap { - pay, ok := new(big.Rat).SetString(row.Pay) - if !ok { - return nil, business.ErrStorage - } - if f.HasRegister != nil && (row.Counts.Register > 0) != *f.HasRegister || f.HasPay != nil && (pay.Sign() > 0) != *f.HasPay { - delete(rowMap, key) - } - } - // Recompute the administrator's distinct-player totals over matched - // channel trees, before pagination. Summing per-row ratios is incorrect. - if withGlobal && len(rowMap) > 0 { - keys := make([]business.AnalyticsKey, 0, len(rowMap)) - for key := range rowMap { - keys = append(keys, key) - } - q, id := analyticsRoot(db, kind, scope, f, "tab_sw_report_day_key", mode, false) - if err := q.Where("(r.source_db,"+id+") IN ?", analyticsPairs(keys)).Select("r.metric,COUNT(DISTINCT " + portraitIdentity(db, scope.IDCardDedup) + ") AS count").Group("r.metric").Scan(&global).Error; err != nil { - return nil, business.ErrStorage - } - q, id = analyticsRoot(db, kind, scope, f, "tab_sw_report_day", 0, true) - if err := q.Where("(r.source_db,"+id+") IN ?", analyticsPairs(keys)).Select("COALESCE(SUM(r.total_pay),0)").Scan(&globalPay).Error; err != nil { - return nil, business.ErrStorage - } - } - } if withGlobal { totals := toPortraitCounts(global) result.GlobalCounts, result.GlobalPay = &totals, globalPay diff --git a/internal/data/business/analytics_test.go b/internal/data/business/analytics_test.go index 9bc9d43..a3365de 100644 --- a/internal/data/business/analytics_test.go +++ b/internal/data/business/analytics_test.go @@ -61,7 +61,7 @@ func TestAnalyticsChannelTreeAndAdminOfficialRows(t *testing.T) { } } -func TestAnalyticsFiltersOnlyNarrowPeriodRowsAndRecalculateTotals(t *testing.T) { +func TestAnalyticsRowsOnlyComeFromSelectedPeriod(t *testing.T) { db, repo, scope, filter := prepareAnalyticsData(t) for _, sql := range []string{ "INSERT INTO tab_promote(id,source_db,account,promote_level,parent_id,top_promote_id,busier_id) VALUES(200,'lx','outside-period',1,0,0,14),(201,'lx','active-only',1,0,0,14),(202,'lx','never-active',1,0,0,14)", @@ -72,10 +72,8 @@ func TestAnalyticsFiltersOnlyNarrowPeriodRowsAndRecalculateTotals(t *testing.T) t.Fatal(err) } } - yes, no := true, false for _, viewer := range []business.UserScope{scope.Viewer, {All: true}} { scope.Viewer = viewer - filter.HasRegister, filter.HasPay = nil, nil baseline, err := repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter) if err != nil { t.Fatal(err) @@ -90,37 +88,16 @@ func TestAnalyticsFiltersOnlyNarrowPeriodRowsAndRecalculateTotals(t *testing.T) if !keys[business.AnalyticsKey{SourceDB: "lx", ID: 201}] { t.Fatal("仅有活跃、没有注册或充值的统计行不能遗漏") } - for _, flags := range [][2]*bool{{&no, &no}, {&no, nil}, {nil, &no}, {&yes, nil}, {nil, &yes}, {&yes, &yes}, {&no, &yes}, {&yes, &no}} { - filter.HasRegister, filter.HasPay = flags[0], flags[1] - data, err := repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter) - if err != nil { - t.Fatal(err) - } - for _, row := range data.Rows { - if !keys[row.AnalyticsKey] { - t.Fatalf("筛选不能扩大默认统计范围: %+v", row) - } - if flags[0] != nil && (row.Counts.Register > 0) != *flags[0] || flags[1] != nil && (portraitTestMoney(row.Pay) != "0.00") != *flags[1] { - t.Fatalf("筛选条件没有同时生效: %+v", row) - } - } - if flags[0] == &no && flags[1] == &no { - if len(data.Rows) != 1 || data.Rows[0].ID != 201 { - t.Fatalf("无注册且无充值仍应保留仅活跃渠道: %+v", data.Rows) - } - if viewer.All && (data.GlobalCounts.Register != 0 || data.GlobalCounts.Active != 1 || portraitTestMoney(data.GlobalPay) != "0.00") { - t.Fatalf("管理员合计未跟随过滤: %+v", data) - } - } + if viewer.All && (baseline.GlobalCounts.Register != 4 || baseline.GlobalCounts.Active != 3 || portraitTestMoney(baseline.GlobalPay) != "2070.60") { + t.Fatalf("区间外记录不能改变全量合计: %+v", baseline) } } - filter.HasRegister, filter.HasPay = &yes, &yes filter.Sources, filter.PromoteName = []string{"lx"}, "root-channel" data, err := repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter) if err != nil || len(data.Rows) != 1 || portraitTestMoney(data.GlobalPay) != "60.60" || data.GlobalCounts.Register != data.Rows[0].Counts.Register { - t.Fatalf("平台、名称及指标筛选须共同约束列表与全量合计: %+v %v", data, err) + t.Fatalf("平台、名称筛选须共同约束列表与全量合计: %+v %v", data, err) } - filter = business.AnalyticsFilter{Sources: []string{"lx", "hw"}, Begin: "2027-01-01", End: "2027-01-02", HasRegister: &no, HasPay: &no} + filter = business.AnalyticsFilter{Sources: []string{"lx", "hw"}, Begin: "2027-01-01", End: "2027-01-02"} data, err = repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter) if err != nil || len(data.Rows) != 0 || data.GlobalCounts.Register != 0 || portraitTestMoney(data.GlobalPay) != "0.00" { t.Fatalf("无报表记录的区间应返回空列表与零合计: %+v %v", data, err) diff --git a/internal/service/business/analytics.go b/internal/service/business/analytics.go index 5d12a26..52e479b 100644 --- a/internal/service/business/analytics.go +++ b/internal/service/business/analytics.go @@ -25,7 +25,7 @@ func analyticsRequest(req *dto.AnalyticsQuery) (business.AnalyticsFilter, error) if err != nil { return business.AnalyticsFilter{}, err } - f := business.AnalyticsFilter{Sources: sources, GameNames: splitQueryValues(req.GameNames), PromoteName: strings.TrimSpace(req.PromoteName), PromoteType: req.PromoteType, HasRegister: req.HasRegister, HasPay: req.HasPay, SortField: strings.TrimSpace(req.SortField), Ascending: strings.EqualFold(strings.TrimSpace(req.SortOrder), "asc")} + f := business.AnalyticsFilter{Sources: sources, GameNames: splitQueryValues(req.GameNames), PromoteName: strings.TrimSpace(req.PromoteName), PromoteType: req.PromoteType, SortField: strings.TrimSpace(req.SortField), Ascending: strings.EqualFold(strings.TrimSpace(req.SortOrder), "asc")} begin, end := strings.TrimSpace(req.BeginTime), strings.TrimSpace(req.EndTime) location := time.FixedZone("Asia/Shanghai", 8*3600) if begin != "" { diff --git a/internal/service/business/date_range_test.go b/internal/service/business/date_range_test.go index e996481..e26be9f 100644 --- a/internal/service/business/date_range_test.go +++ b/internal/service/business/date_range_test.go @@ -32,12 +32,11 @@ func TestRejectIncompleteAndReversedDateRanges(t *testing.T) { } } -func TestAnalyticsOpenEndedDatesAndMetricFilters(t *testing.T) { - no, yes := false, true +func TestAnalyticsDateBoundsPassThroughToUsecase(t *testing.T) { for _, dates := range [][2]string{{"", ""}, {"2026-11-01", ""}, {"", "2026-11-03"}} { - filter, err := analyticsRequest(&dto.AnalyticsQuery{BeginTime: dates[0], EndTime: dates[1], HasRegister: &no, HasPay: &yes}) - if err != nil || (filter.StartDate == nil) != (dates[0] == "") || (filter.EndDate == nil) != (dates[1] == "") || *filter.HasRegister || !*filter.HasPay { - t.Fatalf("独立起止日期及是否有数据筛选必须原样传递: %+v %v", filter, err) + filter, err := analyticsRequest(&dto.AnalyticsQuery{BeginTime: dates[0], EndTime: dates[1]}) + if err != nil || (filter.StartDate == nil) != (dates[0] == "") || (filter.EndDate == nil) != (dates[1] == "") { + t.Fatalf("独立起止日期必须原样传递给业务层填充默认值: %+v %v", filter, err) } } for _, dates := range [][2]string{{"bad", ""}, {"", "bad"}, {"2026-11-03", "2026-11-01"}} { diff --git a/internal/service/dto/analytics.go b/internal/service/dto/analytics.go index a172645..2b3a3b0 100644 --- a/internal/service/dto/analytics.go +++ b/internal/service/dto/analytics.go @@ -7,8 +7,6 @@ type AnalyticsQuery struct { Sources []string `form:"sourceDb"` GameNames []string `form:"gameName"` PromoteType *int `form:"promoteType"` - HasRegister *bool `form:"hasRegister"` - HasPay *bool `form:"hasPay"` PromoteName string `form:"promoteName"` BeginTime string `form:"beginTime"` EndTime string `form:"endTime"` diff --git a/web/src/view/sw/components/ReportAnalytics.vue b/web/src/view/sw/components/ReportAnalytics.vue index d7f5229..36adc4a 100644 --- a/web/src/view/sw/components/ReportAnalytics.vue +++ b/web/src/view/sw/components/ReportAnalytics.vue @@ -9,8 +9,6 @@ - -
至
{{ isChannel ? '搜索' : '查询' }} @@ -57,7 +55,7 @@ const startShortcuts = shortcuts.map(item => ({ text: item.text, value: () => it const endShortcuts = shortcuts.map(item => ({ text: item.text, value: () => item.value()[1] })) const sources = ref(Object.keys(platforms)), games = ref([]), gameOptions = ref([]), gameLoading = ref(false) const selectedGame = computed({ get: () => games.value[0] || '', set: value => { games.value = value ? [value] : [] } }) -const query = reactive({ pageNum: 1, pageSize: 10, promoteType: undefined, promoteName: '', hasRegister: undefined, hasPay: undefined, sortField: isChannel.value ? '' : 'totalPay', sortOrder: 'desc' }) +const query = reactive({ pageNum: 1, pageSize: 10, promoteType: undefined, promoteName: '', sortField: isChannel.value ? '' : 'totalPay', sortOrder: 'desc' }) const rows = ref([]), total = ref(0), summary = ref(null), result = ref(null), loading = ref(false), available = ref(true), error = ref('') const loadedQuery = ref(null), exporting = ref(false) let version = 0, gameVersion = 0