diff --git a/backend/internal/modules/listing/public_filter.go b/backend/internal/modules/listing/public_filter.go index 9b3648f..8858ae8 100644 --- a/backend/internal/modules/listing/public_filter.go +++ b/backend/internal/modules/listing/public_filter.go @@ -386,33 +386,49 @@ func isNightAvailableSummary(summary map[string]any) bool { if !ok { return false } - start, okStart := parseTimeHourValue(onlineTime["start"]) - end, okEnd := parseTimeHourValue(onlineTime["end"]) + start, okStart := parseTimeMinuteValue(onlineTime["start"]) + end, okEnd := parseTimeMinuteValue(onlineTime["end"]) if !okStart || !okEnd { return false } - return timeRangeCoversHour(start, end, 22) || timeRangeCoversHour(start, end, 23) || timeRangeCoversHour(start, end, 0) + return timeRangeOverlapsMinutes(start, end, 0, 8*60) } -func parseTimeHourValue(value any) (int, bool) { +func parseTimeMinuteValue(value any) (int, bool) { text, ok := value.(string) if !ok { return 0, false } parts := strings.Split(text, ":") + if len(parts) != 2 { + return 0, false + } hour, err := strconv.Atoi(parts[0]) if err != nil || hour < 0 || hour > 23 { return 0, false } - return hour, true + minute, err := strconv.Atoi(parts[1]) + if err != nil || minute < 0 || minute > 59 { + return 0, false + } + return hour*60 + minute, true } -func timeRangeCoversHour(start int, end int, hour int) bool { +func timeRangeOverlapsMinutes(start int, end int, targetStart int, targetEnd int) bool { if start == end { return true } - if start < end { - return hour >= start && hour <= end + for _, segment := range splitMinuteRange(start, end) { + if segment[0] <= targetEnd && segment[1] >= targetStart { + return true + } } - return hour >= start || hour <= end + return false +} + +func splitMinuteRange(start int, end int) [][2]int { + if start < end { + return [][2]int{{start, end}} + } + return [][2]int{{start, 23*60 + 59}, {0, end}} } diff --git a/backend/internal/modules/listing/public_filter_test.go b/backend/internal/modules/listing/public_filter_test.go index f0c341d..c94568e 100644 --- a/backend/internal/modules/listing/public_filter_test.go +++ b/backend/internal/modules/listing/public_filter_test.go @@ -44,3 +44,33 @@ func TestSortPublicListingsDefaultUsesShuffleKey(t *testing.T) { } } } + +func TestIsNightAvailableSummaryUsesMidnightToEight(t *testing.T) { + tests := []struct { + name string + start string + end string + want bool + }{ + {name: "全天可上号", start: "00:00", end: "23:59", want: true}, + {name: "覆盖夜间新区间", start: "00:00", end: "08:00", want: true}, + {name: "刚好八点开始", start: "08:00", end: "12:00", want: true}, + {name: "八点半开始不算夜间", start: "08:30", end: "12:00", want: false}, + {name: "跨零点覆盖夜间", start: "23:00", end: "02:00", want: true}, + {name: "旧夜间晚间时段不再命中", start: "22:00", end: "23:00", want: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := isNightAvailableSummary(map[string]any{ + "online_time": map[string]any{ + "start": tt.start, + "end": tt.end, + }, + }) + if got != tt.want { + t.Fatalf("isNightAvailableSummary(%s-%s) = %v, want %v", tt.start, tt.end, got, tt.want) + } + }) + } +} diff --git a/frontend/src/features/listings/views/HomeView.vue b/frontend/src/features/listings/views/HomeView.vue index 0184434..c7a00b2 100644 --- a/frontend/src/features/listings/views/HomeView.vue +++ b/frontend/src/features/listings/views/HomeView.vue @@ -118,7 +118,7 @@ const zoneOptions = computed(() => [ { key: 'night', label: '夜间专区', - hint: '夜间也好上号', + hint: '0-8点可上号', count: zoneCount('night'), }, { diff --git a/frontend/src/features/listings/views/MobileHomeView.vue b/frontend/src/features/listings/views/MobileHomeView.vue index 28518fe..b0770b0 100644 --- a/frontend/src/features/listings/views/MobileHomeView.vue +++ b/frontend/src/features/listings/views/MobileHomeView.vue @@ -93,7 +93,7 @@ const zoneOptions = [ { key: 'all', label: '全部', hint: '当前可租' }, { key: 'sale', label: '特惠', hint: '价格更划算' }, { key: 'gift', label: '赠送', hint: '含赠送物品' }, - { key: 'night', label: '夜间', hint: '夜间好上号' }, + { key: 'night', label: '夜间', hint: '0-8点可上号' }, { key: 'password', label: '账密', hint: '交接更快' }, { key: 'highCoin', label: '高币', hint: '100M以上' }, ]