From c4507caf37fc87d49a9f4436778c78c93fa75094 Mon Sep 17 00:00:00 2001
From: yml2213
Date: Tue, 18 Aug 2026 20:39:13 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B4=A6=E5=8F=B7=E5=87=8C?=
=?UTF-8?q?=E6=99=A8=E5=93=8D=E5=BA=94=E6=A0=87=E8=AE=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../modules/listing/external_upload.go | 8 +--
.../internal/modules/listing/public_filter.go | 54 +++----------------
.../modules/listing/public_filter_test.go | 32 +++++------
.../internal/modules/listing/service_test.go | 3 ++
.../src/features/listings/views/HomeView.vue | 2 +-
.../listings/views/MobileHomeView.vue | 2 +-
.../seller/composables/usePublishDraft.ts | 1 +
.../seller/composables/usePublishForm.ts | 5 ++
.../views/MobileSellerListingCreateView.css | 4 ++
.../views/MobileSellerListingCreateView.vue | 22 ++++++++
.../seller/views/SellerListingCreateView.css | 4 ++
.../seller/views/SellerListingCreateView.vue | 10 ++++
frontend/src/shared/types/publish.ts | 2 +
13 files changed, 79 insertions(+), 70 deletions(-)
diff --git a/backend/internal/modules/listing/external_upload.go b/backend/internal/modules/listing/external_upload.go
index 3c467cd..83832ca 100644
--- a/backend/internal/modules/listing/external_upload.go
+++ b/backend/internal/modules/listing/external_upload.go
@@ -275,9 +275,11 @@ func externalAccountToCreateRequest(
"resources": resources,
"skin_groups": externalSkinGroups(skins),
"online_time_text": onlineTimeText,
- "ban_record": normalizeBanRecord(item.BanRecord),
- "common_regions": commonRegions(item.CommonRegion),
- "remark": remark,
+ // 外部导入没有该字段时按不可凌晨响应处理,避免旧数据误入夜间专区。
+ "early_morning_response": "否",
+ "ban_record": normalizeBanRecord(item.BanRecord),
+ "common_regions": commonRegions(item.CommonRegion),
+ "remark": remark,
"import_meta": map[string]any{
"uploader_name": uploaderName,
"client_upload_time": uploadTime,
diff --git a/backend/internal/modules/listing/public_filter.go b/backend/internal/modules/listing/public_filter.go
index 701de0e..2a0647a 100644
--- a/backend/internal/modules/listing/public_filter.go
+++ b/backend/internal/modules/listing/public_filter.go
@@ -403,53 +403,13 @@ func isNightAvailableSummary(summary map[string]any) bool {
if summary == nil {
return false
}
- onlineTime, ok := summary["online_time"].(map[string]any)
- if !ok {
+ // 夜间专区只认号主明确确认的凌晨响应能力,旧数据缺失时默认不进入专区。
+ switch value := summary["early_morning_response"].(type) {
+ case string:
+ return strings.TrimSpace(value) == "是"
+ case bool:
+ return value
+ default:
return false
}
- start, okStart := parseTimeMinuteValue(onlineTime["start"])
- end, okEnd := parseTimeMinuteValue(onlineTime["end"])
- if !okStart || !okEnd {
- return false
- }
- return timeRangeOverlapsMinutes(start, end, 0, 8*60)
-}
-
-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
- }
- minute, err := strconv.Atoi(parts[1])
- if err != nil || minute < 0 || minute > 59 {
- return 0, false
- }
- return hour*60 + minute, true
-}
-
-func timeRangeOverlapsMinutes(start int, end int, targetStart int, targetEnd int) bool {
- if start == end {
- return true
- }
- for _, segment := range splitMinuteRange(start, end) {
- if segment[0] <= targetEnd && segment[1] >= targetStart {
- return true
- }
- }
- 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 7eb5145..bf8e9bb 100644
--- a/backend/internal/modules/listing/public_filter_test.go
+++ b/backend/internal/modules/listing/public_filter_test.go
@@ -178,31 +178,27 @@ func TestSortPublicListingsDefaultUsesShuffleKey(t *testing.T) {
}
}
-func TestIsNightAvailableSummaryUsesMidnightToEight(t *testing.T) {
+func TestIsNightAvailableSummaryUsesEarlyMorningResponse(t *testing.T) {
tests := []struct {
- name string
- start string
- end string
- want bool
+ name string
+ response any
+ 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},
+ {name: "明确响应", response: "是", want: true},
+ {name: "明确不响应", response: "否", want: false},
+ {name: "兼容布尔值", response: true, want: true},
+ {name: "缺失字段", response: nil, 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,
- },
- })
+ summary := map[string]any{}
+ if tt.response != nil {
+ summary["early_morning_response"] = tt.response
+ }
+ got := isNightAvailableSummary(summary)
if got != tt.want {
- t.Fatalf("isNightAvailableSummary(%s-%s) = %v, want %v", tt.start, tt.end, got, tt.want)
+ t.Fatalf("isNightAvailableSummary(%#v) = %v, want %v", tt.response, got, tt.want)
}
})
}
diff --git a/backend/internal/modules/listing/service_test.go b/backend/internal/modules/listing/service_test.go
index c623461..21a014a 100644
--- a/backend/internal/modules/listing/service_test.go
+++ b/backend/internal/modules/listing/service_test.go
@@ -530,6 +530,9 @@ func TestExternalAccountToCreateRequestMapsUploadFields(t *testing.T) {
if req.AssetSummary["online_time_text"] != "08:00 至 01:00" {
t.Fatalf("online_time_text = %#v", req.AssetSummary["online_time_text"])
}
+ if req.AssetSummary["early_morning_response"] != "否" {
+ t.Fatalf("early_morning_response = %#v, want 否", req.AssetSummary["early_morning_response"])
+ }
onlineTime, ok := req.AssetSummary["online_time"].(map[string]any)
if !ok {
t.Fatalf("online_time missing: %#v", req.AssetSummary["online_time"])
diff --git a/frontend/src/features/listings/views/HomeView.vue b/frontend/src/features/listings/views/HomeView.vue
index 507927d..8856452 100644
--- a/frontend/src/features/listings/views/HomeView.vue
+++ b/frontend/src/features/listings/views/HomeView.vue
@@ -136,7 +136,7 @@ const zoneOptions = computed(() => [
{
key: 'night',
label: '夜间专区',
- hint: '0-8点可上号',
+ hint: '0-2点可响应上号',
count: zoneCount('night'),
},
{
diff --git a/frontend/src/features/listings/views/MobileHomeView.vue b/frontend/src/features/listings/views/MobileHomeView.vue
index 5caab05..d646fd6 100644
--- a/frontend/src/features/listings/views/MobileHomeView.vue
+++ b/frontend/src/features/listings/views/MobileHomeView.vue
@@ -104,7 +104,7 @@ const zoneOptions = [
{ key: 'all', label: '全部', hint: '当前可租' },
{ key: 'sale', label: '特惠', hint: '价格更划算' },
{ key: 'gift', label: '赠送', hint: '含赠送物品' },
- { key: 'night', label: '夜间', hint: '0-8点可上号' },
+ { key: 'night', label: '夜间', hint: '0-2点可响应上号' },
{ key: 'password', label: '账密', hint: '交接更快' },
{ key: 'highCoin', label: '高币', hint: '100M以上' },
]
diff --git a/frontend/src/features/seller/composables/usePublishDraft.ts b/frontend/src/features/seller/composables/usePublishDraft.ts
index 6ef97e8..08048de 100644
--- a/frontend/src/features/seller/composables/usePublishDraft.ts
+++ b/frontend/src/features/seller/composables/usePublishDraft.ts
@@ -17,6 +17,7 @@ export function defaultPublishForm(): PublishForm {
login_method: '',
online_start: '',
online_end: '',
+ early_morning_response: '否',
can_change_game_name: '',
all_hero: '',
ban_record: '',
diff --git a/frontend/src/features/seller/composables/usePublishForm.ts b/frontend/src/features/seller/composables/usePublishForm.ts
index cf343cd..23dd391 100644
--- a/frontend/src/features/seller/composables/usePublishForm.ts
+++ b/frontend/src/features/seller/composables/usePublishForm.ts
@@ -308,6 +308,7 @@ export function usePublishForm(options: UsePublishFormOptions) {
login_method: listing.login_platform || '',
online_start: stringValue(onlineTime.start),
online_end: stringValue(onlineTime.end),
+ early_morning_response: stringValue(summary.early_morning_response) || '否',
can_change_game_name: stringValue(summary.can_change_game_name),
all_hero: stringValue(summary.all_hero),
ban_record: stringValue(summary.ban_record),
@@ -700,6 +701,9 @@ export function usePublishForm(options: UsePublishFormOptions) {
if (!dailyLossOptions.includes(pricing.dailyLossMAmount.value)) return '请选择每日损耗'
const onlineTimeError = validateOnlineTime()
if (onlineTimeError) return onlineTimeError
+ if (form.early_morning_response !== '是' && form.early_morning_response !== '否') {
+ return '请选择凌晨0-2点是否可响应上号'
+ }
if (pricing.hasAcceleratedSaleRatioInput()) {
const ratio = Number(form.accelerated_sale_ratio)
if (!Number.isFinite(ratio) || ratio <= 0) return '加速出售比例格式不正确'
@@ -818,6 +822,7 @@ export function usePublishForm(options: UsePublishFormOptions) {
start: form.online_start,
end: form.online_end,
},
+ early_morning_response: form.early_morning_response,
can_change_game_name: form.can_change_game_name,
all_hero: form.all_hero,
ban_record: form.ban_record,
diff --git a/frontend/src/features/seller/views/MobileSellerListingCreateView.css b/frontend/src/features/seller/views/MobileSellerListingCreateView.css
index d5e03f7..6e6c8e0 100644
--- a/frontend/src/features/seller/views/MobileSellerListingCreateView.css
+++ b/frontend/src/features/seller/views/MobileSellerListingCreateView.css
@@ -88,6 +88,10 @@
font-size: 16px;
}
+.early-morning-response-field :deep(.van-field__label) {
+ width: 128px;
+}
+
.hint-label,
.backend-hint-target.has-hint,
.upload-title.has-hint {
diff --git a/frontend/src/features/seller/views/MobileSellerListingCreateView.vue b/frontend/src/features/seller/views/MobileSellerListingCreateView.vue
index 120c630..b9bd082 100644
--- a/frontend/src/features/seller/views/MobileSellerListingCreateView.vue
+++ b/frontend/src/features/seller/views/MobileSellerListingCreateView.vue
@@ -121,6 +121,7 @@ function selectRadio(value: T, setter: (value: T) => void) {
const canChangeGameNameOptions = ['是', '否']
const allHeroOptions = ['是', '否']
+const earlyMorningResponseOptions = ['是', '否']
// 在线时间:通栏自定义块 + 底部时间选择,避免 van-field 窄列截断原生 time
const onlineTimePickerVisible = ref(false)
@@ -481,6 +482,27 @@ const screenshotGuides: Record = {
请填写能百分百联系上您的时间。该时段联系不上可能影响上架或扣款,请预留扫码与冻结人脸时间。
+
+
+
+
+
+
+
+
activeAgreement.value?.content ||
const canChangeGameNameOptions = ['是', '否']
const allHeroOptions = ['是', '否']
+const earlyMorningResponseOptions = ['是', '否']
// 截图槽位的指导示例图(仅展示、点击放大,不占用上传数量)
const screenshotGuides: Record = {
@@ -396,6 +397,15 @@ function selectDailyLoss(value: string | number) {
+
+
+
+
+