diff --git a/.gitignore b/.gitignore index a24df91..5c2506c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ logs/ success_images/ build/ config.json - +frontend/dist frontend/node_modules # Wails 自动生成的前端绑定 @@ -23,3 +23,4 @@ ck 对比.md *.exe *.app .DS_Store +frontend/dist/ diff --git a/app.go b/app.go index 689a71b..9a0d62a 100644 --- a/app.go +++ b/app.go @@ -210,6 +210,36 @@ func (a *App) QueryScore(accountName string) map[string]any { return map[string]any{"score": score} } +// VerifyExchange 查询兑换记录,用于复验抢购结果。 +func (a *App) VerifyExchange(accountName string) map[string]any { + if accountName == "" { + return map[string]any{"success": false, "error": "缺少账号名"} + } + cookie, ok := a.scheduler.AccountCookieByName(accountName) + if !ok || cookie == "" { + return map[string]any{"success": false, "error": fmt.Sprintf("账号不存在或 Cookie 为空: %s", accountName)} + } + + records, err := a.client.ExchangeList(cookie) + 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) + } + } + + return map[string]any{ + "success": true, + "records": matched, + "count": len(matched), + } +} + // GetVersion 返回应用版本号。 func (a *App) GetVersion() string { return constants.Version diff --git a/frontend/src/components/log/LogPanel.vue b/frontend/src/components/log/LogPanel.vue index 4ee613d..da3beca 100644 --- a/frontend/src/components/log/LogPanel.vue +++ b/frontend/src/components/log/LogPanel.vue @@ -1,12 +1,15 @@ @@ -73,8 +101,24 @@ const resultEntries = computed(() => Object.entries(results.value)) > 统计 + + 兑换复验 + + + + + {{ verifying ? '查询中...' : '🔍 复验' }} + + 清空 - 清空 @@ -129,6 +173,47 @@ const resultEntries = computed(() => Object.entries(results.value)) 待处理账号: {{ stats.pending }} 已选账号: {{ stats.selected }} / 总账号: {{ stats.total }} + + + + + 点击「🔍 复验」按钮查询斗鱼真实兑换记录 + + + + ✅ 已兑换: {{ verifyStats.verified }} + ⚠️ 无记录: {{ verifyStats.noRecord }} + ❌ 查询失败: {{ verifyStats.failed }} + + + + {{ entry.name }} + + + + {{ record.commodityName }} + {{ record.showName }} + + + 暂无兑换记录 + + {{ entry.error }} + + + + @@ -249,6 +334,105 @@ const resultEntries = computed(() => Object.entries(results.value)) height: 100%; } +/* 复验相关样式 */ +.log-actions { + display: flex; + gap: 6px; + align-items: center; +} + +.btn-verify { + background: var(--accent-soft); + color: var(--accent); + border-color: var(--accent-border); +} + +.btn-verify:hover { + background: var(--accent); + color: #fff; +} + +.btn-verify:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.verify-summary { + display: flex; + gap: 16px; + padding: 8px 12px; + margin-bottom: 12px; + background: var(--surface); + border-radius: var(--radius-sm); + border: 1px solid var(--line); + font-weight: 500; +} + +.verify-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.verify-item { + padding: 10px 12px; + background: var(--surface); + border-radius: var(--radius-sm); + border: 1px solid var(--line); +} + +.verify-success { + border-color: var(--success); + background: var(--success-soft); +} + +.verify-empty { + border-color: var(--warning); + background: var(--warning-soft); +} + +.verify-error { + border-color: var(--danger); + background: var(--danger-soft); +} + +.verify-account { + font-weight: 600; + color: var(--text-strong); + margin-bottom: 6px; +} + +.verify-records { + display: flex; + flex-direction: column; + gap: 4px; +} + +.verify-record { + display: flex; + gap: 12px; + font-size: 12px; +} + +.record-name { + color: var(--text); + font-weight: 500; +} + +.record-role { + color: var(--muted); +} + +.verify-no-record { + color: var(--muted); + font-size: 12px; +} + +.verify-error-msg { + color: var(--danger); + font-size: 12px; +} + @media (max-width: 1180px) { .log-wrap { height: 360px; diff --git a/frontend/src/composables/useAccounts.ts b/frontend/src/composables/useAccounts.ts index 37f5189..edca9d3 100644 --- a/frontend/src/composables/useAccounts.ts +++ b/frontend/src/composables/useAccounts.ts @@ -153,3 +153,50 @@ export function useAccounts() { buildAccountProducts } } + +export function useVerifyExchange() { + const { accounts } = useAccounts() + const verifyResults = ref>({}) + const verifying = ref(false) + + const verifyAccount = async (accountName: string) => { + try { + const result = await App.VerifyExchange(accountName) + verifyResults.value[accountName] = result + return result + } catch (e: any) { + verifyResults.value[accountName] = { success: false, error: e.message } + return { success: false, error: e.message } + } + } + + const verifyAll = async () => { + verifying.value = true + const results: Record = {} + + for (const account of accounts.value) { + try { + const result = await App.VerifyExchange(account.name) + results[account.name] = result + } catch (e: any) { + results[account.name] = { success: false, error: e.message } + } + } + + verifyResults.value = results + verifying.value = false + return results + } + + const clearResults = () => { + verifyResults.value = {} + } + + return { + verifyResults, + verifying, + verifyAccount, + verifyAll, + clearResults + } +} diff --git a/frontend/src/env.d.ts b/frontend/src/env.d.ts index cccfe2b..1e492b8 100644 --- a/frontend/src/env.d.ts +++ b/frontend/src/env.d.ts @@ -25,6 +25,7 @@ interface Window { GetVersion: () => Promise GetSettings: () => Promise SaveSettings: (cfg: any) => Promise + VerifyExchange: (accountName: string) => Promise } } } diff --git a/internal/client/client.go b/internal/client/client.go index 15fe599..a4207ba 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -406,6 +406,39 @@ func (c *DouyuClient) RoleName(cookie string) (string, error) { return result.Data.GameRole.RoleName, nil } +// ExchangeRecord 兑换记录。 +type ExchangeRecord struct { + CommodityID string `json:"commodityId"` + CommodityName string `json:"commodityName"` + NickName string `json:"nickName"` + ShowName string `json:"showName"` + ExchangeNum int `json:"exchangeNum"` + Time string `json:"time"` + Score string `json:"score"` +} + +// ExchangeListResponse 兑换列表响应。 +type ExchangeListResponse struct { + Error int `json:"error"` + Msg string `json:"msg"` + Data struct { + List []ExchangeRecord `json:"list"` + Count int `json:"count"` + } `json:"data"` +} + +// ExchangeList 查询兑换记录列表。 +func (c *DouyuClient) ExchangeList(cookie string) ([]ExchangeRecord, error) { + var result ExchangeListResponse + if err := c.getJSON(constants.ExchangeListURL, cookie, "兑换记录", &result); err != nil { + return nil, err + } + if result.Error != 0 { + return nil, fmt.Errorf("兑换记录查询失败: %s", result.Msg) + } + return result.Data.List, nil +} + func (c *DouyuClient) getJSON(url, cookie, label string, out any) error { req, err := http.NewRequest("GET", url, nil) if err != nil { diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 83304dd..6dea19a 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -18,6 +18,7 @@ const ( BatchLimitURL = BaseURL + "/wgapi/ordnc/activity/peace/batchExchangeLimit" PreExchangeURL = BaseURL + "/wgapi/ordnc/activity/peace/preExchange" ExchangeURL = BaseURL + "/wgapi/ordnc/activity/peace/exchange" + ExchangeListURL = BaseURL + "/wgapi/ordnc/activity/peace/exchangeList?manualID=" + ManualID + "&limit=50&offset=0" 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"