diff --git a/internal/finance/service.go b/internal/finance/service.go index 7cd4126..68dd128 100644 --- a/internal/finance/service.go +++ b/internal/finance/service.go @@ -803,7 +803,10 @@ func (s *Service) ensureWithdrawalEnabled(ctx context.Context, tenantID int64) e return err } var config map[string]any - if json.Unmarshal(raw, &config) != nil || !findBool(config, "withdrawal_enabled", "withdrawalEnabled", "WITHDRAWAL") { + if json.Unmarshal(raw, &config) != nil { + config = map[string]any{} + } + if enabled, found := findBoolValue(config, "withdrawal_enabled", "withdrawalEnabled", "WITHDRAWAL"); found && !enabled { return store.ErrWithdrawalDisabled } return nil @@ -1142,25 +1145,28 @@ func allDigits(value string) bool { return value != "" } -func findBool(config map[string]any, keys ...string) bool { +func findBoolValue(config map[string]any, keys ...string) (bool, bool) { for _, key := range keys { for candidate, value := range config { if strings.EqualFold(candidate, key) { switch typed := value.(type) { case bool: - return typed + return typed, true case float64: - return typed == 1 + return typed == 1, true case string: - return typed == "1" || strings.EqualFold(typed, "true") || strings.EqualFold(typed, "on") + return typed == "1" || strings.EqualFold(typed, "true") || strings.EqualFold(typed, "on"), true } + return false, true } } } for _, value := range config { - if nested, ok := value.(map[string]any); ok && findBool(nested, keys...) { - return true + if nested, ok := value.(map[string]any); ok { + if result, found := findBoolValue(nested, keys...); found { + return result, true + } } } - return false + return false, false } diff --git a/internal/finance/service_test.go b/internal/finance/service_test.go index 2692f4b..236b4a1 100644 --- a/internal/finance/service_test.go +++ b/internal/finance/service_test.go @@ -118,11 +118,18 @@ func TestQuoteCalculatesRateFeeAndLimits(t *testing.T) { } } -func TestQuoteFailsClosed(t *testing.T) { +func TestQuoteDefaultsToEnabledWithoutWithdrawalSwitch(t *testing.T) { service := &Service{repository: &fakeRepository{config: json.RawMessage(`{}`)}, ready: true, now: time.Now} + if err := service.ensureWithdrawalEnabled(context.Background(), 0); err != nil { + t.Fatalf("missing switch should default to enabled, got %v", err) + } +} + +func TestQuoteHonorsExplicitDisabledWithdrawalSwitch(t *testing.T) { + service := &Service{repository: &fakeRepository{config: json.RawMessage(`{"features":{"withdrawal_enabled":false}}`)}, ready: true, now: time.Now} _, err := service.Quote(context.Background(), 0, 1, QuoteInput{PaymentAccountID: 1, Amount: 100, Currency: "CNY"}) if !errors.Is(err, store.ErrWithdrawalDisabled) { - t.Fatalf("expected disabled error, got %v", err) + t.Fatalf("expected explicitly disabled withdrawal, got %v", err) } } diff --git a/internal/portal/service.go b/internal/portal/service.go index e8b5016..805e8fb 100644 --- a/internal/portal/service.go +++ b/internal/portal/service.go @@ -328,30 +328,40 @@ func maskedUsername(value string) string { func parseFeatures(raw json.RawMessage) Features { var config map[string]any if json.Unmarshal(raw, &config) != nil { - return Features{} + config = map[string]any{} } return Features{ - TaskEnabled: findBool(config, "task_enabled", "taskEnabled", "TASK"), - RechargeEnabled: findBool(config, "recharge_enabled", "rechargeEnabled", "RECHARGE"), - WithdrawalEnabled: findBool(config, "withdrawal_enabled", "withdrawalEnabled", "WITHDRAWAL"), - ManualMallEnabled: findBool(config, "manual_mall_enabled", "manualMallEnabled", "SHOP_STATUS"), + TaskEnabled: findBoolDefault(config, true, "task_enabled", "taskEnabled", "TASK"), + RechargeEnabled: findBoolDefault(config, true, "recharge_enabled", "rechargeEnabled", "RECHARGE"), + WithdrawalEnabled: findBoolDefault(config, true, "withdrawal_enabled", "withdrawalEnabled", "WITHDRAWAL"), + ManualMallEnabled: findBoolDefault(config, true, "manual_mall_enabled", "manualMallEnabled", "SHOP_STATUS"), } } -func findBool(config map[string]any, keys ...string) bool { - for _, key := range keys { - if value, ok := config[key]; ok { - return boolValue(value) - } +func findBoolDefault(config map[string]any, defaultValue bool, keys ...string) bool { + value, found := findBoolValue(config, keys...) + if !found { + return defaultValue } - if nested, ok := config["features"].(map[string]any); ok { - for _, key := range keys { - if value, found := nested[key]; found { - return boolValue(value) + return value +} + +func findBoolValue(config map[string]any, keys ...string) (bool, bool) { + for _, key := range keys { + for candidate, value := range config { + if strings.EqualFold(candidate, key) { + return boolValue(value), true } } } - return false + for _, value := range config { + if nested, ok := value.(map[string]any); ok { + if result, found := findBoolValue(nested, keys...); found { + return result, true + } + } + } + return false, false } func boolValue(value any) bool { diff --git a/internal/portal/service_test.go b/internal/portal/service_test.go index d324cb5..ff49b09 100644 --- a/internal/portal/service_test.go +++ b/internal/portal/service_test.go @@ -77,6 +77,18 @@ func TestParseFeaturesSupportsNestedAndLegacyKeys(t *testing.T) { } } +func TestParseFeaturesDefaultsMissingSwitchesToEnabled(t *testing.T) { + features := parseFeatures(json.RawMessage(`{}`)) + if !features.TaskEnabled || !features.RechargeEnabled || !features.WithdrawalEnabled || !features.ManualMallEnabled { + t.Fatalf("missing switches should default to enabled: %+v", features) + } + + features = parseFeatures(json.RawMessage(`{"features":{"task_enabled":false,"withdrawal_enabled":false}}`)) + if features.TaskEnabled || features.WithdrawalEnabled || !features.RechargeEnabled || !features.ManualMallEnabled { + t.Fatalf("explicitly disabled switches must remain disabled: %+v", features) + } +} + func TestBannersSanitizeTargets(t *testing.T) { service := New(fakeRepository{banners: []store.Banner{ {ID: 1, TargetType: 2, TargetValue: "/receive"}, diff --git a/internal/store/tasks.go b/internal/store/tasks.go index 7260272..50be719 100644 --- a/internal/store/tasks.go +++ b/internal/store/tasks.go @@ -205,7 +205,7 @@ func (s *Store) ClaimTask(ctx context.Context, input ClaimTaskInput) (*TaskOrder if wallet.Status != 1 { return nil, ErrAccountRestricted } - if member.AutoDispatch == 1 && (wallet.AvailableAmount <= 0 || wallet.AvailableAmount < input.MinimumAmount) { + if wallet.AvailableAmount < input.MinimumAmount { return nil, ErrInsufficientBalance } var pending int64 diff --git a/internal/tasks/service.go b/internal/tasks/service.go index db00067..bb57301 100644 --- a/internal/tasks/service.go +++ b/internal/tasks/service.go @@ -18,10 +18,11 @@ const ( defaultPageSize = 20 maxPageSize = 100 defaultDeadlineMinute = 15 + minimumClaimAmount = 29900 + businessDisplayStart = "09:00:00+08:00" + businessDisplayEnd = "21:00:00+08:00" ) -var shanghai = time.FixedZone("Asia/Shanghai", 8*60*60) - type Repository interface { CurrentSiteConfig(context.Context, int64) (json.RawMessage, error) TaskHalls(context.Context, int64, int64) ([]store.TaskHall, error) @@ -158,8 +159,6 @@ type taskPolicy struct { AutoDelay int AutoMinAmount int64 AutoMaxAmount int64 - Start string - End string Deadline time.Duration } @@ -194,20 +193,18 @@ func (s *Service) Eligibility(ctx context.Context, tenantID, memberID, hallID in } result := &Eligibility{Eligible: true, AvailableAmount: row.AvailableAmount, MinimumAmount: policy.MinimumAmount, TodayCount: row.TodayCount, DailyLimit: row.DailyLimit, PendingOrderID: row.PendingOrderID, - BusinessStartAt: policy.Start + "+08:00", BusinessEndAt: policy.End + "+08:00"} + BusinessStartAt: businessDisplayStart, BusinessEndAt: businessDisplayEnd} switch { case !policy.Enabled: result.reject("TASK_DISABLED", "任务功能未开启") - case !withinBusinessHours(s.now().In(shanghai), policy.Start, policy.End): - result.reject("OUTSIDE_BUSINESS_HOURS", "当前不在营业时间") case row.MemberStatus != 1: result.reject("ACCOUNT_RESTRICTED", "账户状态受限") case !row.HallEligible: result.reject("LEVEL_NOT_ELIGIBLE", "当前等级不能进入该任务大厅") case row.WalletStatus != 1: result.reject("ACCOUNT_RESTRICTED", "账户状态受限") - case row.AutoDispatch == 1 && (row.AvailableAmount <= 0 || row.AvailableAmount < policy.MinimumAmount): - result.reject("INSUFFICIENT_BALANCE", "可用余额不足") + case row.AvailableAmount < policy.MinimumAmount: + result.reject("INSUFFICIENT_BALANCE", "可用余额不足299元") case row.DailyLimit > 0 && row.TodayCount >= row.DailyLimit: result.reject("DAILY_LIMIT_REACHED", "已达当日领取上限") case row.PendingOrderID > 0: @@ -233,9 +230,6 @@ func (s *Service) Claim(ctx context.Context, tenantID, memberID, hallID int64) ( if !policy.Enabled { return nil, ErrTaskDisabled } - if !withinBusinessHours(s.now().In(shanghai), policy.Start, policy.End) { - return nil, ErrOutsideBusinessHour - } now := s.now().UTC() row, err := s.repository.ClaimTask(ctx, store.ClaimTaskInput{TenantID: tenantID, MemberID: memberID, HallID: hallID, MinimumAmount: policy.MinimumAmount, AutoDelay: policy.AutoDelay, @@ -379,14 +373,14 @@ func (s *Service) policy(ctx context.Context, tenantID int64) (taskPolicy, error if minutes <= 0 || minutes > 24*60 { minutes = defaultDeadlineMinute } - start := clockValue(findValue(config, "task_business_start_at", "business_start_at", "taskBusinessStartAt"), "00:00:00") - end := clockValue(findValue(config, "task_business_end_at", "business_end_at", "taskBusinessEndAt"), "23:59:59") - return taskPolicy{Enabled: boolValue(findValue(config, "task_enabled", "taskEnabled", "TASK")), - MinimumAmount: max64(0, int64Value(findValue(config, "task_minimum_amount", "minimum_balance_amount", "taskMinimumAmount"))), + enabledValue := findValue(config, "task_enabled", "taskEnabled", "TASK") + enabled := enabledValue == nil || boolValue(enabledValue) + return taskPolicy{Enabled: enabled, + MinimumAmount: minimumClaimAmount, AutoDelay: max(0, intValue(findValue(config, "auto_order_delay_seconds", "autoOrderDelaySeconds"))), AutoMinAmount: max64(0, int64Value(findValue(config, "auto_order_min_amount", "autoOrderMinAmount"))), AutoMaxAmount: max64(0, int64Value(findValue(config, "auto_order_max_amount", "autoOrderMaxAmount"))), - Start: start, End: end, Deadline: time.Duration(minutes) * time.Minute}, nil + Deadline: time.Duration(minutes) * time.Minute}, nil } func orderFromStore(row store.TaskOrder, detail bool) Order { @@ -506,38 +500,6 @@ func submissionStatusText(status int) string { return names[status] } -func withinBusinessHours(now time.Time, start, end string) bool { - current := now.Hour()*3600 + now.Minute()*60 + now.Second() - startSecond := parseClock(start) - endSecond := parseClock(end) - if startSecond <= endSecond { - return current >= startSecond && current <= endSecond - } - return current >= startSecond || current <= endSecond -} - -func parseClock(value string) int { - parsed, err := time.Parse("15:04:05", value) - if err != nil { - return 0 - } - return parsed.Hour()*3600 + parsed.Minute()*60 + parsed.Second() -} - -func clockValue(value any, fallback string) string { - raw, ok := value.(string) - if !ok { - return fallback - } - raw = strings.TrimSpace(raw) - for _, layout := range []string{"15:04:05", "15:04"} { - if parsed, err := time.Parse(layout, raw); err == nil { - return parsed.Format("15:04:05") - } - } - return fallback -} - func findValue(config map[string]any, keys ...string) any { for _, key := range keys { for candidate, value := range config { diff --git a/internal/tasks/service_test.go b/internal/tasks/service_test.go index 26ecf49..d11b772 100644 --- a/internal/tasks/service_test.go +++ b/internal/tasks/service_test.go @@ -62,58 +62,66 @@ func (f *fakeRepository) OrderLedgers(context.Context, int64, int64, []string) ( return []map[string]any{}, nil } -func TestEligibilityAppliesPublishedPolicy(t *testing.T) { - repository := &fakeRepository{config: json.RawMessage(`{"features":{"task_enabled":true},"task_minimum_amount":50000,"task_business_start_at":"09:00","task_business_end_at":"22:00"}`), - eligibility: &store.TaskEligibility{MemberStatus: 1, AutoDispatch: 1, HallEligible: true, AvailableAmount: 49999, WalletStatus: 1, DailyLimit: 5, TodayCount: 2}} +func TestEligibilityRequiresFixedMinimumBalance(t *testing.T) { + repository := &fakeRepository{config: json.RawMessage(`{"features":{"task_enabled":true},"task_minimum_amount":0}`), + eligibility: &store.TaskEligibility{MemberStatus: 1, AutoDispatch: 1, HallEligible: true, AvailableAmount: 29899, WalletStatus: 1, DailyLimit: 5, TodayCount: 2}} service := New(repository) - service.now = func() time.Time { return time.Date(2026, 10, 9, 10, 0, 0, 0, shanghai) } result, err := service.Eligibility(context.Background(), 0, 10, 1) if err != nil { t.Fatal(err) } - if result.Eligible || result.Reason != "INSUFFICIENT_BALANCE" || result.MinimumAmount != 50000 { + if result.Eligible || result.Reason != "INSUFFICIENT_BALANCE" || result.MinimumAmount != 29900 { t.Fatalf("unexpected eligibility: %#v", result) } } -func TestEligibilityAllowsManualDispatchBelowMinimumBalance(t *testing.T) { - repository := &fakeRepository{config: json.RawMessage(`{"features":{"task_enabled":true},"task_minimum_amount":50000,"task_business_start_at":"09:00","task_business_end_at":"22:00"}`), - eligibility: &store.TaskEligibility{MemberStatus: 1, AutoDispatch: 2, HallEligible: true, AvailableAmount: 0, WalletStatus: 1, DailyLimit: 5}} +func TestEligibilityAlsoRequiresMinimumForManualDispatch(t *testing.T) { + repository := &fakeRepository{config: json.RawMessage(`{"features":{"task_enabled":true}}`), + eligibility: &store.TaskEligibility{MemberStatus: 1, AutoDispatch: 2, HallEligible: true, AvailableAmount: 29899, WalletStatus: 1, DailyLimit: 5}} service := New(repository) - service.now = func() time.Time { return time.Date(2026, 10, 9, 10, 0, 0, 0, shanghai) } - - result, err := service.Eligibility(context.Background(), 0, 10, 1) - if err != nil { - t.Fatal(err) - } - if !result.Eligible { - t.Fatalf("manual dispatch should ignore the automatic minimum balance gate: %#v", result) - } -} - -func TestEligibilityRejectsAutoDispatchWithZeroBalanceWhenMinimumIsZero(t *testing.T) { - repository := &fakeRepository{config: json.RawMessage(`{"features":{"task_enabled":true},"task_minimum_amount":0,"task_business_start_at":"09:00","task_business_end_at":"22:00"}`), - eligibility: &store.TaskEligibility{MemberStatus: 1, AutoDispatch: 1, HallEligible: true, AvailableAmount: 0, WalletStatus: 1, DailyLimit: 5}} - service := New(repository) - service.now = func() time.Time { return time.Date(2026, 10, 9, 10, 0, 0, 0, shanghai) } result, err := service.Eligibility(context.Background(), 0, 10, 1) if err != nil { t.Fatal(err) } if result.Eligible || result.Reason != "INSUFFICIENT_BALANCE" { - t.Fatalf("zero balance must not allow automatic claiming: %#v", result) + t.Fatalf("manual dispatch must use the same minimum balance gate: %#v", result) } } -func TestClaimFailsClosedWithoutTaskSwitch(t *testing.T) { +func TestEligibilityDoesNotEnforceDisplayedBusinessHours(t *testing.T) { + repository := &fakeRepository{config: json.RawMessage(`{"features":{"task_enabled":true},"task_business_start_at":"09:00","task_business_end_at":"21:00"}`), + eligibility: &store.TaskEligibility{MemberStatus: 1, AutoDispatch: 1, HallEligible: true, AvailableAmount: 29900, WalletStatus: 1, DailyLimit: 5}} + service := New(repository) + service.now = func() time.Time { return time.Date(2026, 10, 9, 23, 0, 0, 0, time.FixedZone("Asia/Shanghai", 8*60*60)) } + + result, err := service.Eligibility(context.Background(), 0, 10, 1) + if err != nil { + t.Fatal(err) + } + if !result.Eligible || result.BusinessStartAt != "09:00:00+08:00" || result.BusinessEndAt != "21:00:00+08:00" { + t.Fatalf("business hours are display-only: %#v", result) + } +} + +func TestClaimDefaultsToEnabledWithoutTaskSwitch(t *testing.T) { repository := &fakeRepository{config: json.RawMessage(`{}`)} service := New(repository) + service.now = func() time.Time { return time.Date(2026, 10, 9, 2, 0, 0, 0, time.UTC) } + + if _, err := service.Claim(context.Background(), 0, 10, 1); err != nil { + t.Fatalf("missing switch should default to enabled, got %v", err) + } +} + +func TestClaimHonorsExplicitDisabledTaskSwitch(t *testing.T) { + repository := &fakeRepository{config: json.RawMessage(`{"features":{"task_enabled":false}}`)} + service := New(repository) _, err := service.Claim(context.Background(), 0, 10, 1) if !errors.Is(err, ErrTaskDisabled) { - t.Fatalf("expected task disabled, got %v", err) + t.Fatalf("expected explicitly disabled task, got %v", err) } } @@ -128,7 +136,7 @@ func TestClaimBuildsMatchingOrder(t *testing.T) { t.Fatal(err) } if result.Status != "matching" || repository.claimed.HallID != 2 || - !repository.claimed.DeadlineAt.Equal(now.Add(20*time.Minute)) { + repository.claimed.MinimumAmount != 29900 || !repository.claimed.DeadlineAt.Equal(now.Add(20*time.Minute)) { t.Fatalf("unexpected claim: result=%#v input=%#v", result, repository.claimed) } } diff --git a/web/src/mobile/api.ts b/web/src/mobile/api.ts index c787efc..54889aa 100644 --- a/web/src/mobile/api.ts +++ b/web/src/mobile/api.ts @@ -13,7 +13,7 @@ const reasonMessages: Record = { RATE_LIMITED: '操作过于频繁,请稍后再试', TASK_DISABLED: '领取功能暂未开放', OUTSIDE_BUSINESS_HOURS: '当前不在营业时间内', - INSUFFICIENT_BALANCE: '可用余额不足', + INSUFFICIENT_BALANCE: '可用余额不足299元,暂时无法领取', DAILY_LIMIT_REACHED: '今日领取次数已用完', PENDING_ORDER_EXISTS: '存在未完成的任务,请先处理', NO_TASK_AVAILABLE: '当前暂无可领取任务', diff --git a/web/src/mobile/styles.css b/web/src/mobile/styles.css index ac06954..dad0438 100644 --- a/web/src/mobile/styles.css +++ b/web/src/mobile/styles.css @@ -3760,10 +3760,18 @@ body { .m-rank-winner > strong, .m-rank-winner > em { max-width: 100%; + font-style: normal; +} +.m-rank-winner > strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - font-style: normal; +} +.m-rank-winner > em { + overflow: visible; + font-size: clamp(11px, 3vw, 14px); + line-height: 1.2; + overflow-wrap: anywhere; } .m-rank-winner > small { margin-top: 4px; @@ -3781,7 +3789,7 @@ body { .m-rank-table header, .m-rank-row { display: grid; - grid-template-columns: 48px minmax(0, 1.5fr) minmax(82px, 1fr) 70px; + grid-template-columns: 48px minmax(0, 1fr) max-content 70px; align-items: center; gap: 7px; } @@ -3823,6 +3831,7 @@ body { font-style: normal; } .m-rank-row strong { + white-space: nowrap; font-size: 17px; font-weight: 500; } @@ -3849,7 +3858,7 @@ body { .m-home-rank-list a { min-width: 0; display: grid; - grid-template-columns: 30px 34px minmax(0, 1fr) 72px 82px; + grid-template-columns: 30px 34px minmax(0, 1fr) max-content 82px; align-items: center; gap: 7px; color: var(--m-ink); @@ -3895,14 +3904,16 @@ body { .m-home-rank-list strong, .m-home-rank-list em { min-width: 0; - overflow: hidden; - text-overflow: ellipsis; white-space: nowrap; } .m-home-rank-list strong { + overflow: hidden; + text-overflow: ellipsis; font-weight: 500; } .m-home-rank-list em { + overflow: visible; + font-size: clamp(12px, 3.2vw, 15px); font-style: normal; text-align: right; font-weight: 600; @@ -4039,14 +4050,14 @@ body { } .m-rank-table header, .m-rank-row { - grid-template-columns: 38px minmax(0, 1.4fr) 72px 58px; + grid-template-columns: 38px minmax(0, 1fr) max-content 58px; gap: 5px; } .m-rank-table { padding-inline: 8px; } .m-home-rank-list a { - grid-template-columns: 26px 32px minmax(0, 1fr) 54px 72px; + grid-template-columns: 26px 32px minmax(0, 1fr) max-content 68px; gap: 5px; } .m-home-rank-list small { diff --git a/web/src/mobile/views/ClaimView.vue b/web/src/mobile/views/ClaimView.vue index d893196..a0d791c 100644 --- a/web/src/mobile/views/ClaimView.vue +++ b/web/src/mobile/views/ClaimView.vue @@ -22,21 +22,22 @@ -
+
- {{ eligibility.message || '暂不满足领取条件' }} - + 可用余额不足299元

活动规则

    -
  1. 平台运营时间每天 {{ businessHours }}。
  2. -
  3. 每一次储入请先咨询客服获取商家卡号,如有疑问请联系在线客服。
  4. -
  5. 领取后系统将自动分配任务,请按订单要求完成任务内容。
  6. -
  7. 领取时间根据会员等级不同,系统随机匹配订单。
  8. -
  9. 账户可用余额需达到 {{ money(eligibility?.minimum_amount) }} 才可领取。
  10. -
  11. 订单需要在规定时间内完成,请勿超时提交。
  12. +
  13. 平台运营时间每天上午9:00-晚上21:00点!
  14. +
  15. 每一次储入必须咨询客户获取商家卡号!如有不理解可联系在线客服!
  16. +
  17. 领取后系统将自动分配任务,请按订单要求完成任务内容!
  18. +
  19. 领取订单的时间是根据会员等级的不同!系统随机匹配订单!
  20. +
  21. 会员账户必须要拥有299启动资金才可进行领取!
  22. +
  23. 订单需要在规定时间内完成!请勿超时完成商品!
  24. +
  25. 平台硬性条件提现必须信用分值满足100分,请广大会员珍惜账户信用分值!信用分下降必须联系客服处理恢复100分才可正常提现,信用分提升金额具体根据会员等级规定,详细咨询平台客服。
  26. +
  27. 非本人充值资金需要提供支付人身份证信息验证充值资金,避免出现非必要的资金纠纷。
@@ -132,11 +133,12 @@ const eligibleHalls = computed(() => halls.value.filter((hall) => eligibilityByHall.value[hall.id]?.eligible) ); - const businessHours = computed(() => { - const start = String(eligibility.value?.business_start_at || '09:00').slice(0, 5); - const end = String(eligibility.value?.business_end_at || '21:00').slice(0, 5); - return `${start}-${end}`; - }); + const balanceInsufficient = computed(() => + Object.values(eligibilityByHall.value).some((item: any) => + Number(item?.minimum_amount || 0) > 0 && + Number(item?.available_amount || 0) < Number(item.minimum_amount) + ) + ); const isAutoMatching = computed(() => order.value?.dispatch_mode !== 'manual'); const matchingHint = computed(() => { if (order.value?.dispatch_mode === 'manual') return '订单已领取,正在等待后台匹配...'; @@ -348,10 +350,6 @@ closeResult(); router.push('/app/orders'); } - function openPendingOrder() { - const orderID = Number(eligibility.value?.pending_order_id || 0); - router.push(orderID > 0 ? `/app/orders/${orderID}` : '/app/orders'); - } function retryClaim() { closeResult(); void claim(); diff --git a/web/src/mobile/views/HomeView.vue b/web/src/mobile/views/HomeView.vue index fa5f16d..7d2e192 100644 --- a/web/src/mobile/views/HomeView.vue +++ b/web/src/mobile/views/HomeView.vue @@ -183,7 +183,7 @@ enabled: home.value?.features?.withdrawal_enabled === true, }, { - label: '商城', + label: '手工', path: '/app/mall', icon: mobileAssets.shortcutMall, enabled: home.value?.features?.manual_mall_enabled !== false,