优化抢购逻辑:移除手动提前量、冷却累计停止、默认包数2
- 移除用户手动提前量设置,改为固定 100ms 内部提前量 - 新增冷却累计停止:单账号冷却 ≥5 次自动放弃 - 默认发包数从 1 改为 2 - 前端移除提前量输入框和 localStorage 存取
This commit is contained in:
@@ -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)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -47,17 +46,6 @@ const handleSchedule = () => {
|
||||
step="1"
|
||||
>
|
||||
</div>
|
||||
<div class="schedule-item">
|
||||
<label>提前</label>
|
||||
<input
|
||||
v-model.number="advance"
|
||||
type="number"
|
||||
min="0"
|
||||
max="5000"
|
||||
step="100"
|
||||
>
|
||||
<span style="color: var(--muted); font-size: 11.5px">ms</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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 通用响应。
|
||||
|
||||
Reference in New Issue
Block a user