From c90f80045e892e50bb962af239540247e9499841 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sat, 27 Jun 2026 08:07:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8A=A2=E8=B4=AD=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E6=97=A5=E5=BF=97=E5=92=8C=E5=A4=8D=E9=AA=8C=E6=80=A7?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.go | 232 +++++++++++------- frontend/src/components/log/LogPanel.vue | 18 ++ .../src/components/modal/SettingsModal.vue | 6 +- frontend/src/composables/useLogs.ts | 22 +- frontend/src/composables/useSettings.ts | 7 +- internal/config/config.go | 7 +- internal/logger/log_store.go | 10 +- internal/logger/logger.go | 133 ++++++++-- internal/seckill/scheduler.go | 172 +++++++++---- internal/types/types.go | 19 +- 10 files changed, 446 insertions(+), 180 deletions(-) diff --git a/app.go b/app.go index e9ede85..6968c9c 100644 --- a/app.go +++ b/app.go @@ -43,6 +43,15 @@ type App struct { closeTrace func() } +const exchangeLookupConcurrency = 8 + +type exchangeLookupResult struct { + Account types.Account + Records []client.ExchangeRecord + Err error + EmptyCookie bool +} + // NewApp 创建 App 实例。 func NewApp() *App { return &App{} @@ -228,14 +237,7 @@ func (a *App) VerifyExchange(accountName string) map[string]any { if err != nil { return map[string]any{"success": false, "error": "查询失败: " + err.Error()} } - - // 过滤当前活动的记录 - var matched []client.ExchangeRecord - for _, r := range records { - if r.CommodityID != "" { - matched = append(matched, r) - } - } + matched := filterExchangeRecords(records) return map[string]any{ "success": true, @@ -244,43 +246,31 @@ func (a *App) VerifyExchange(accountName string) map[string]any { } } -// VerifyAllExchange 批量查询兑换记录,带间隔避免请求过快。 +// VerifyAllExchange 批量查询兑换记录,使用有限并发减少等待时间。 func (a *App) VerifyAllExchange() map[string]any { accounts := a.scheduler.AccountSnapshot() results := make(map[string]any) + lookups := a.lookupExchangeRecords("复验", accounts) - for i, account := range accounts { - if i > 0 { - // 每个请求间隔 200ms,避免太快 - time.Sleep(200 * time.Millisecond) - } - - if account.Cookie == "" { - results[account.Name] = map[string]any{ + for _, lookup := range lookups { + if lookup.EmptyCookie { + results[lookup.Account.Name] = map[string]any{ "success": false, "error": "Cookie 为空", } continue } - records, err := a.client.ExchangeList(account.Cookie) - if err != nil { - results[account.Name] = map[string]any{ + if lookup.Err != nil { + results[lookup.Account.Name] = map[string]any{ "success": false, - "error": "查询失败: " + err.Error(), + "error": "查询失败: " + lookup.Err.Error(), } continue } - // 过滤当前活动的记录 - var matched []client.ExchangeRecord - for _, r := range records { - if r.CommodityID != "" { - matched = append(matched, r) - } - } - - results[account.Name] = map[string]any{ + matched := filterExchangeRecords(lookup.Records) + results[lookup.Account.Name] = map[string]any{ "success": true, "records": matched, "count": len(matched), @@ -296,49 +286,38 @@ func (a *App) VerifyAndExport(commodityID string) map[string]any { results := make(map[string]any) hitAccounts := make([]string, 0) missAccounts := make([]string, 0) + lookups := a.lookupExchangeRecords("复验", accounts) - for i, account := range accounts { - if i > 0 { - time.Sleep(200 * time.Millisecond) - } - - if account.Cookie == "" { - missAccounts = append(missAccounts, account.Name) - results[account.Name] = map[string]any{ + for _, lookup := range lookups { + if lookup.EmptyCookie { + missAccounts = append(missAccounts, lookup.Account.Name) + results[lookup.Account.Name] = map[string]any{ "success": false, "error": "Cookie 为空", } continue } - records, err := a.client.ExchangeList(account.Cookie) - if err != nil { - missAccounts = append(missAccounts, account.Name) - results[account.Name] = map[string]any{ + if lookup.Err != nil { + missAccounts = append(missAccounts, lookup.Account.Name) + results[lookup.Account.Name] = map[string]any{ "success": false, - "error": "查询失败: " + err.Error(), + "error": "查询失败: " + lookup.Err.Error(), } continue } // 检查是否抢到了指定商品 - hit := false - for _, r := range records { - if r.CommodityID == commodityID { - hit = true - break - } - } - + hit := hasCommodityRecord(lookup.Records, commodityID, 0, 0) if hit { - hitAccounts = append(hitAccounts, account.Name) - results[account.Name] = map[string]any{ + hitAccounts = append(hitAccounts, lookup.Account.Name) + results[lookup.Account.Name] = map[string]any{ "success": true, "hit": true, } } else { - missAccounts = append(missAccounts, account.Name) - results[account.Name] = map[string]any{ + missAccounts = append(missAccounts, lookup.Account.Name) + results[lookup.Account.Name] = map[string]any{ "success": true, "hit": false, } @@ -346,15 +325,110 @@ func (a *App) VerifyAndExport(commodityID string) map[string]any { } return map[string]any{ - "success": true, - "hitCount": len(hitAccounts), - "missCount": len(missAccounts), - "hitAccounts": hitAccounts, - "missAccounts": missAccounts, - "details": results, + "success": true, + "hitCount": len(hitAccounts), + "missCount": len(missAccounts), + "hitAccounts": hitAccounts, + "missAccounts": missAccounts, + "details": results, } } +func (a *App) lookupExchangeRecords(category string, accounts []types.Account) []exchangeLookupResult { + results := make([]exchangeLookupResult, len(accounts)) + if len(accounts) == 0 { + return results + } + + workerCount := exchangeLookupConcurrency + if len(accounts) < workerCount { + workerCount = len(accounts) + } + start := time.Now() + logger.LogEvent(category, "info", "兑换记录批量查询开始: 账号=%d 并发=%d", len(accounts), workerCount) + + jobs := make(chan int) + var wg sync.WaitGroup + for worker := 0; worker < workerCount; worker++ { + wg.Add(1) + go func() { + defer wg.Done() + for idx := range jobs { + account := accounts[idx] + lookup := exchangeLookupResult{Account: account} + if strings.TrimSpace(account.Cookie) == "" { + lookup.EmptyCookie = true + results[idx] = lookup + continue + } + records, err := a.client.ExchangeList(account.Cookie) + lookup.Records = records + lookup.Err = err + results[idx] = lookup + } + }() + } + for idx := range accounts { + jobs <- idx + } + close(jobs) + wg.Wait() + + errors := 0 + empty := 0 + for _, result := range results { + if result.EmptyCookie { + empty++ + } + if result.Err != nil { + errors++ + } + } + level := "success" + if errors > 0 { + level = "warn" + } + logger.LogEvent(category, level, "兑换记录批量查询完成: 账号=%d 空CK=%d 失败=%d 耗时=%s", + len(accounts), empty, errors, time.Since(start).Round(time.Millisecond)) + return results +} + +func filterExchangeRecords(records []client.ExchangeRecord) []client.ExchangeRecord { + matched := make([]client.ExchangeRecord, 0, len(records)) + for _, r := range records { + if r.CommodityID != "" { + matched = append(matched, r) + } + } + return matched +} + +func hasCommodityRecord(records []client.ExchangeRecord, commodityID string, startTime, endTime int64) bool { + if commodityID == "" { + return false + } + for _, r := range records { + if r.CommodityID != commodityID { + continue + } + if startTime == 0 && endTime == 0 { + return true + } + recordTime, err := strconv.ParseInt(r.Time, 10, 64) + if err != nil { + continue + } + if startTime > 0 && recordTime < startTime { + continue + } + if endTime > 0 && recordTime > endTime { + continue + } + return true + } + return false +} + // ExportAccounts 导出指定账号到文件。 func (a *App) ExportAccounts(accountNames []string, filename string) map[string]any { if len(accountNames) == 0 { @@ -437,40 +511,18 @@ func (a *App) OrganizeAccounts(commodityID, commodityName string, startTime, end accounts := a.scheduler.AccountSnapshot() hitAccounts := make([]string, 0) missAccounts := make([]string, 0) + lookups := a.lookupExchangeRecords("整理", accounts) - for i, account := range accounts { - if i > 0 { - time.Sleep(200 * time.Millisecond) - } - - if account.Cookie == "" { - missAccounts = append(missAccounts, account.Name) + for _, lookup := range lookups { + if lookup.EmptyCookie || lookup.Err != nil { + missAccounts = append(missAccounts, lookup.Account.Name) continue } - records, err := a.client.ExchangeList(account.Cookie) - if err != nil { - missAccounts = append(missAccounts, account.Name) - continue - } - - // 检查是否在指定时间段内抢到了指定商品 - hit := false - for _, r := range records { - if r.CommodityID == commodityID { - // 检查时间范围 - recordTime, _ := strconv.ParseInt(r.Time, 10, 64) - if startTime == 0 || (recordTime >= startTime && recordTime <= endTime) { - hit = true - break - } - } - } - - if hit { - hitAccounts = append(hitAccounts, account.Name) + if hasCommodityRecord(lookup.Records, commodityID, startTime, endTime) { + hitAccounts = append(hitAccounts, lookup.Account.Name) } else { - missAccounts = append(missAccounts, account.Name) + missAccounts = append(missAccounts, lookup.Account.Name) } } diff --git a/frontend/src/components/log/LogPanel.vue b/frontend/src/components/log/LogPanel.vue index 8035bcb..081c9c9 100644 --- a/frontend/src/components/log/LogPanel.vue +++ b/frontend/src/components/log/LogPanel.vue @@ -156,7 +156,9 @@ const handleVerify = async () => { >