diff --git a/frontend/src/components/console/ControlStrip.vue b/frontend/src/components/console/ControlStrip.vue index 359692b..d95ad94 100644 --- a/frontend/src/components/console/ControlStrip.vue +++ b/frontend/src/components/console/ControlStrip.vue @@ -7,12 +7,11 @@ const { scheduleActive, startNow, startSchedule, cancelSchedule, restoreSchedule const { reloadAccounts, queryAllScore } = useAccounts() // 从本地缓存恢复定时设置 -const { savedTime, savedAdv } = restoreSchedule() +const { savedTime } = restoreSchedule() const targetTime = ref(savedTime || '18:00:00') -const advance = ref(savedAdv) const handleSchedule = () => { - startSchedule(targetTime.value, advance.value) + startSchedule(targetTime.value) } @@ -47,17 +46,6 @@ const handleSchedule = () => { step="1" > -
- - - ms -
diff --git a/frontend/src/composables/useScheduler.ts b/frontend/src/composables/useScheduler.ts index 71cefe9..b85bf2b 100644 --- a/frontend/src/composables/useScheduler.ts +++ b/frontend/src/composables/useScheduler.ts @@ -47,7 +47,7 @@ export function useScheduler() { } } - const startSchedule = async (targetTime: string, advance: number) => { + const startSchedule = async (targetTime: string) => { const ap = buildAccountProducts(selectedProductId.value || '') if (!ap) return @@ -72,13 +72,12 @@ export function useScheduler() { clearLocalResults() markSelectedPending('定时配置中,等待后端确认') setRunState('定时配置中') - addLocalLog(`设置定时: ${fullTime}, 提前=${advance}ms`, 'i') + addLocalLog(`设置定时: ${fullTime}`, 'i') try { const d = await App.SetSchedule({ accountProducts: ap, - targetTime: fullTime, - advance + targetTime: fullTime }) if (d?.success === false) { throw new Error(d.error || '定时设置失败') @@ -86,7 +85,6 @@ export function useScheduler() { scheduleActive.value = true localStorage.setItem('targetTime', timeStr) - localStorage.setItem('advance', String(advance)) markSelectedPending(`定时等待触发: ${d.triggerTime || fullTime}`) setRunState(`定时已开启,触发 ${d.triggerTime}`) @@ -113,7 +111,6 @@ export function useScheduler() { scheduleActive.value = false localStorage.removeItem('targetTime') - localStorage.removeItem('advance') stopCountdown() setRunState('定时已停止') showToast('定时已停止', '抢购任务已取消', 'warn') @@ -153,8 +150,7 @@ export function useScheduler() { const restoreSchedule = () => { const savedTime = localStorage.getItem('targetTime') - const savedAdv = localStorage.getItem('advance') - return { savedTime, savedAdv: savedAdv ? parseInt(savedAdv) : 300 } + return { savedTime } } return { diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 92ac158..119e0a8 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -25,7 +25,7 @@ const ( BindInfoURL = BaseURL + "/japi/carnivalApi/v2/tencent/bindInfo?actAlias=" + ActAlias ScoreURL = BaseURL + "/japi/oms/web/peace/credit/balance" UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36" - DefaultAttempts = 1 + DefaultAttempts = 2 DefaultConcurrency = 150 ProductCacheTTL = 30 * time.Second diff --git a/internal/seckill/scheduler.go b/internal/seckill/scheduler.go index 834b125..4971384 100644 --- a/internal/seckill/scheduler.go +++ b/internal/seckill/scheduler.go @@ -33,6 +33,8 @@ const ( seckillMaxDuration = 75 * time.Second behaviorCooldown = 5 * time.Second clickFastCooldown = 3 * time.Second + internalAdvance = 100 * time.Millisecond + maxCooldownCount = 5 ) type roundOutcome struct { @@ -386,6 +388,7 @@ func (s *Scheduler) RunNow(accountProducts map[string]string) { stoppedAccounts := make(map[string]string) stoppedProducts := make(map[string]string) cooldownAccounts := make(map[string]time.Time) + cooldownCount := make(map[string]int) totalAccounts := uniqueAttemptAccounts(allAttempts) totalAttempts := 0 startTime := time.Now() @@ -463,8 +466,13 @@ func (s *Scheduler) RunNow(accountProducts map[string]string) { for account, until := range outcome.cooldownAccounts { if until.After(cooldownAccounts[account]) { cooldownAccounts[account] = until - logger.LogAccountEvent("抢购", "warn", account, "账号临时降频: 账号=%s 冷却至=%s", - account, until.In(constants.CST).Format("15:04:05.000")) + cooldownCount[account]++ + logger.LogAccountEvent("抢购", "warn", account, "账号临时降频: 账号=%s 冷却至=%s (第%d次)", + account, until.In(constants.CST).Format("15:04:05.000"), cooldownCount[account]) + if cooldownCount[account] >= maxCooldownCount { + stoppedAccounts[account] = "冷却次数过多" + logger.LogAccountEvent("抢购", "warn", account, "账号停止重试: 账号=%s 原因=冷却次数过多(%d次)", account, cooldownCount[account]) + } } } @@ -1092,8 +1100,7 @@ func (s *Scheduler) ScheduleRun(req types.SeckillRequest) (map[string]any, error calibration := s.calibrateDouyuTime("定时") serverTime := calibration.EstimatedServerNow() - advance := time.Duration(req.Advance) * time.Millisecond - triggerTime := targetTime.Add(-advance) + triggerTime := targetTime.Add(-internalAdvance) remain := triggerTime.Sub(serverTime) if remain <= 0 { return nil, errors.New("目标时间已过") @@ -1127,7 +1134,7 @@ func (s *Scheduler) ScheduleRun(req types.SeckillRequest) (map[string]any, error logger.LogEvent("定时", "success", "定时已设置: 目标=%s 触发=%s 提前=%dms 斗鱼估算=%s 本地偏移=%dms 误差<=%dms RTT=%dms 预热=%s 复校=%s", targetTime.In(constants.CST).Format("2006-01-02 15:04:05.000"), triggerTime.In(constants.CST).Format("2006-01-02 15:04:05.000"), - req.Advance, + internalAdvance.Milliseconds(), serverTime.In(constants.CST).Format("2006-01-02 15:04:05.000"), calibration.Offset.Milliseconds(), calibration.ErrorBound.Milliseconds(), @@ -1139,10 +1146,7 @@ func (s *Scheduler) ScheduleRun(req types.SeckillRequest) (map[string]any, error return map[string]any{ "success": true, "targetTime": targetTime.In(constants.CST).Format("2006-01-02 15:04:05"), - "triggerTime": triggerTime.In(constants.CST).Format("2006-01-02 15:04:05.000"), - "advance": req.Advance, - "remainSecond": int(remain.Seconds()), - "serverTime": serverTime.In(constants.CST).Format("2006-01-02 15:04:05.000"), + "triggerTime": triggerTime.In(constants.CST).Format("2006-01-02 15:04:05"), "offsetMs": calibration.Offset.Milliseconds(), "errorBoundMs": calibration.ErrorBound.Milliseconds(), "rttMs": calibration.RTT.Milliseconds(), diff --git a/internal/types/types.go b/internal/types/types.go index c815fea..75c53b1 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -90,7 +90,6 @@ type AccountView struct { type SeckillRequest struct { AccountProducts map[string]string `json:"accountProducts"` TargetTime string `json:"targetTime"` - Advance int `json:"advance"` } // APIResponse 斗鱼 API 通用响应。