抢购控制台支持查看精英手册兑换记录,发布0.3.7
此前只有和平小店能在控制台查兑换记录,精英/电竞手册只能去别的页面或客户端看。 现在账号作战表直接带上"兑换记录"列:查询一次就能看到每个账号兑换了什么、什么时候、 花多少积分,点"记录"看该账号全部明细。 - 新增 QueryExchangeRecords 批量查询(手册类活动):复用既有的并发 lookupExchangeRecords, 记录不做任何过滤("看我的兑换记录"不该藏东西),记录自带商品名与积分 - 商品筛选为可选项:不选=看全部记录;选了则额外标记该账号是否兑换过它(已兑换/未兑换) - 手册的商品筛选用本地状态,不写回全局商品选择——免得只是想看记录却把抢购目标改掉; 和平小店沿用原来的全局商品选择 - 账号表"兑换记录"列对所有活动可见;手册侧展示条数与最近一条(商品名 + 时间), 小店的"已兑换/未兑换 + 订单状态"保持原样 - 每行"记录"弹窗:若已批量查询过就直接复用结果不再打接口;否则手册走 VerifyExchange, 小店走原有订单查询。弹窗表格按活动切换列(手册:商品/数量/兑换时间/积分/昵称) - 聚合逻辑抽成纯函数 buildExchangeRecordsResult 并补测试 (记录不过滤、命中按商品统计、空 Cookie 与查询失败分开计数、未选商品不做命中判断)
This commit is contained in:
@@ -8,8 +8,10 @@ import { useActivity } from '@/composables/useActivity'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import {
|
||||
ExportLatestXiaodianReport,
|
||||
QueryExchangeRecords,
|
||||
QueryXiaodianAccountExchangeRecords,
|
||||
QueryXiaodianExchangeRecords
|
||||
QueryXiaodianExchangeRecords,
|
||||
VerifyExchange
|
||||
} from '@wails/go/app/App'
|
||||
|
||||
const {
|
||||
@@ -56,6 +58,11 @@ watch(selectedProductId, () => {
|
||||
exchangeLookup.value = null
|
||||
})
|
||||
|
||||
watch(currentActivity, () => {
|
||||
exchangeLookup.value = null
|
||||
lookupProductId.value = ''
|
||||
})
|
||||
|
||||
const handleDocumentClick = (event: MouseEvent) => {
|
||||
const target = event.target
|
||||
if (!(target instanceof Element) || !target.closest('.account-product-picker')) {
|
||||
@@ -168,6 +175,21 @@ const selectedLookupProduct = computed(() =>
|
||||
products.value.find(product => product.commodityId === selectedProductId.value)
|
||||
)
|
||||
|
||||
// lookupProductId 只用于"手册类活动的兑换记录筛选",刻意不写回全局商品选择——
|
||||
// 免得只是想看看记录,却把抢购目标商品改掉了。
|
||||
const lookupProductId = ref('')
|
||||
|
||||
const lookupCommodity = computed(() => {
|
||||
if (isXiaodian.value) {
|
||||
return {
|
||||
id: selectedLookupProduct.value?.commodityId || '',
|
||||
name: selectedLookupProduct.value?.commodityName || ''
|
||||
}
|
||||
}
|
||||
const product = products.value.find(item => item.commodityId === lookupProductId.value)
|
||||
return { id: lookupProductId.value, name: product?.commodityName || '' }
|
||||
})
|
||||
|
||||
const handleLookupProductChange = (event: Event) => {
|
||||
const productID = (event.target as HTMLSelectElement).value
|
||||
const product = products.value.find(item => item.commodityId === productID)
|
||||
@@ -179,15 +201,19 @@ const handleLookupProductChange = (event: Event) => {
|
||||
}
|
||||
|
||||
const querySelectedExchangeRecords = async () => {
|
||||
if (!selectedLookupProduct.value) {
|
||||
// 和平小店必须选商品(记录按商品归属);手册类活动的记录自带商品名,商品可不选
|
||||
if (isXiaodian.value && !selectedLookupProduct.value) {
|
||||
showToast('提示', '请先选择要查询的商品', 'warn')
|
||||
return
|
||||
}
|
||||
|
||||
const { commodityId, commodityName } = selectedLookupProduct.value
|
||||
const commodityId = lookupCommodity.value.id
|
||||
const commodityName = lookupCommodity.value.name
|
||||
exchangeLookup.value = { productId: commodityId, productName: commodityName, loading: true, results: {} }
|
||||
try {
|
||||
const result = await QueryXiaodianExchangeRecords(commodityId, commodityName)
|
||||
const result = isXiaodian.value
|
||||
? await QueryXiaodianExchangeRecords(commodityId, commodityName)
|
||||
: await QueryExchangeRecords(commodityId, commodityName)
|
||||
if (!exchangeLookup.value || exchangeLookup.value.productId !== commodityId) return
|
||||
exchangeLookup.value.loading = false
|
||||
exchangeLookup.value.results = result.results || {}
|
||||
@@ -195,15 +221,44 @@ const querySelectedExchangeRecords = async () => {
|
||||
showToast('查询失败', result.error || '兑换记录接口未返回成功', 'error')
|
||||
return
|
||||
}
|
||||
const matched = Object.values(result.results || {}).filter((item: any) => item.success && item.matched).length
|
||||
const failed = Object.values(result.results || {}).filter((item: any) => !item.success).length
|
||||
showToast('查询完成', `${commodityName}:${matched} 个账号有兑换记录${failed ? `,${failed} 个查询失败` : ''}`, failed ? 'warn' : 'success')
|
||||
const items = Object.values(result.results || {}) as any[]
|
||||
const failed = items.filter((item) => !item.success).length
|
||||
const total = items.reduce((sum, item) => sum + (item.records?.length || 0), 0)
|
||||
if (commodityId) {
|
||||
const matched = items.filter((item) => item.success && item.matched).length
|
||||
showToast('查询完成', `${commodityName}:${matched} 个账号有兑换记录${failed ? `,${failed} 个查询失败` : ''}`, failed ? 'warn' : 'success')
|
||||
} else {
|
||||
showToast('查询完成', `共 ${total} 条兑换记录${failed ? `,${failed} 个账号查询失败` : ''}`, failed ? 'warn' : 'success')
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (exchangeLookup.value?.productId === commodityId) exchangeLookup.value.loading = false
|
||||
showToast('查询失败', e?.message || '兑换记录查询失败', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// recordSummary 取账号最新的兑换记录,用于表格里的紧凑展示。
|
||||
const recordSummary = (accountName: string) => {
|
||||
const records = getLookupResult(accountName)?.records || []
|
||||
if (!records.length) return ''
|
||||
const latest = records[0]
|
||||
const name = latest.commodityName || latest.commodityId || '-'
|
||||
const time = formatShortTime(latest.time || latest.buyTime || '')
|
||||
return time ? `${name} · ${time}` : name
|
||||
}
|
||||
|
||||
const formatShortTime = (value: string) => {
|
||||
if (!value) return ''
|
||||
const text = String(value)
|
||||
const match = text.match(/(\d{2})[-/](\d{2})\s+(\d{2}:\d{2})/)
|
||||
if (match) return `${match[1]}-${match[2]} ${match[3]}`
|
||||
const numeric = Number(text)
|
||||
if (Number.isFinite(numeric) && numeric > 0) {
|
||||
const date = new Date(numeric < 10_000_000_000 ? numeric * 1000 : numeric)
|
||||
return `${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
||||
}
|
||||
return text.replace('T', ' ').slice(0, 16)
|
||||
}
|
||||
|
||||
const getLookupResult = (accountName: string) => exchangeLookup.value?.results[accountName]
|
||||
|
||||
const getMatchedRecord = (accountName: string) => {
|
||||
@@ -264,9 +319,18 @@ const orderStatus = (status: string) => {
|
||||
}
|
||||
|
||||
const openExchangeRecords = async (accountName: string) => {
|
||||
// 已经批量查过就直接用现成结果,避免同一个账号再打一次接口
|
||||
const cached = getLookupResult(accountName)
|
||||
if (cached?.success && Array.isArray(cached.records)) {
|
||||
recordsModal.value = { accountName, loading: false, error: '', records: cached.records }
|
||||
return
|
||||
}
|
||||
|
||||
recordsModal.value = { accountName, loading: true, error: '', records: [] }
|
||||
try {
|
||||
const result = await QueryXiaodianAccountExchangeRecords(accountName)
|
||||
const result = isXiaodian.value
|
||||
? await QueryXiaodianAccountExchangeRecords(accountName)
|
||||
: await VerifyExchange(accountName)
|
||||
if (!recordsModal.value || recordsModal.value.accountName !== accountName) return
|
||||
recordsModal.value.loading = false
|
||||
recordsModal.value.error = result.error || ''
|
||||
@@ -292,8 +356,23 @@ const closeExchangeRecords = () => {
|
||||
<span class="panel-title">账号作战表</span>
|
||||
<span class="panel-sub">{{ accounts.length }} 个账号,已选 {{ selectedIndices.size }} 个</span>
|
||||
</div>
|
||||
<div v-if="isXiaodian" class="exchange-lookup-actions">
|
||||
<div class="exchange-lookup-actions">
|
||||
<!-- 手册类活动:只看记录,筛选用本地值,不动抢购目标商品 -->
|
||||
<select
|
||||
v-if="!isXiaodian"
|
||||
v-model="lookupProductId"
|
||||
class="exchange-lookup-product"
|
||||
:disabled="exchangeLookup?.loading"
|
||||
aria-label="按商品筛选兑换记录"
|
||||
>
|
||||
<option value="">全部商品</option>
|
||||
<option v-for="product in products" :key="product.commodityId" :value="product.commodityId">
|
||||
{{ product.commodityName }}
|
||||
</option>
|
||||
</select>
|
||||
<!-- 和平小店:沿用全局商品选择 -->
|
||||
<select
|
||||
v-else
|
||||
class="exchange-lookup-product"
|
||||
:value="selectedProductId || ''"
|
||||
:disabled="products.length === 0 || exchangeLookup?.loading"
|
||||
@@ -307,18 +386,20 @@ const closeExchangeRecords = () => {
|
||||
</select>
|
||||
<button
|
||||
class="btn btn-compact btn-records"
|
||||
:disabled="!selectedLookupProduct || exchangeLookup?.loading"
|
||||
:disabled="exchangeLookup?.loading || (isXiaodian && !selectedLookupProduct)"
|
||||
@click="querySelectedExchangeRecords"
|
||||
>
|
||||
{{ exchangeLookup?.loading ? '查询中...' : '查询兑换记录' }}
|
||||
</button>
|
||||
<select v-model="reportFormat" class="report-format" :disabled="exportingReport" aria-label="选择报告导出格式">
|
||||
<option value="xlsx">Excel</option>
|
||||
<option value="csv">CSV</option>
|
||||
</select>
|
||||
<button class="btn btn-compact btn-export-report" :disabled="exportingReport" @click="exportXiaodianReport">
|
||||
{{ exportingReport ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
<template v-if="isXiaodian">
|
||||
<select v-model="reportFormat" class="report-format" :disabled="exportingReport" aria-label="选择报告导出格式">
|
||||
<option value="xlsx">Excel</option>
|
||||
<option value="csv">CSV</option>
|
||||
</select>
|
||||
<button class="btn btn-compact btn-export-report" :disabled="exportingReport" @click="exportXiaodianReport">
|
||||
{{ exportingReport ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -343,7 +424,7 @@ const closeExchangeRecords = () => {
|
||||
<th>{{ isXiaodian ? '点券' : '积分' }}</th>
|
||||
<th v-if="isXiaodian">扭蛋碎片</th>
|
||||
<th v-if="isXiaodian">角色信息</th>
|
||||
<th v-if="isXiaodian" class="exchange-record-col">兑换记录</th>
|
||||
<th class="exchange-record-col">兑换记录</th>
|
||||
<th class="status-col">状态</th>
|
||||
<th>最后结果</th>
|
||||
<th class="account-action-col">操作</th>
|
||||
@@ -351,7 +432,7 @@ const closeExchangeRecords = () => {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-if="accounts.length === 0">
|
||||
<td :colspan="isXiaodian ? 12 : 9" class="empty-state">暂无账号,请加载账号</td>
|
||||
<td :colspan="isXiaodian ? 12 : 10" class="empty-state">暂无账号,请加载账号</td>
|
||||
</tr>
|
||||
<template v-else>
|
||||
<tr
|
||||
@@ -457,16 +538,30 @@ const closeExchangeRecords = () => {
|
||||
{{ getXiaodianRole(account.name)?.error || '-' }}
|
||||
</span>
|
||||
</td>
|
||||
<td v-if="isXiaodian" class="exchange-record-cell">
|
||||
<td class="exchange-record-cell">
|
||||
<template v-if="exchangeLookup">
|
||||
<span v-if="exchangeLookup.loading" class="exchange-query-state">查询中</span>
|
||||
<span v-else-if="!getLookupResult(account.name)?.success" class="exchange-query-state exchange-query-error" :title="getLookupResult(account.name)?.error || '查询失败'">查询失败</span>
|
||||
<span v-else-if="getLookupResult(account.name)?.matched" class="exchange-query-state exchange-query-matched">已兑换</span>
|
||||
<span v-else class="exchange-query-state exchange-query-empty">未兑换</span>
|
||||
<span v-if="getMatchedRecord(account.name)" class="order-status" :class="orderStatus(getMatchedRecord(account.name).status).cls">
|
||||
{{ orderStatus(getMatchedRecord(account.name).status).text }}
|
||||
</span>
|
||||
<template v-else-if="isXiaodian">
|
||||
<span v-if="getLookupResult(account.name)?.matched" class="exchange-query-state exchange-query-matched">已兑换</span>
|
||||
<span v-else class="exchange-query-state exchange-query-empty">未兑换</span>
|
||||
<span v-if="getMatchedRecord(account.name)" class="order-status" :class="orderStatus(getMatchedRecord(account.name).status).cls">
|
||||
{{ orderStatus(getMatchedRecord(account.name).status).text }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 手册:记录自带商品名,商品不选时也能直接看条数与最近一条 -->
|
||||
<span v-if="exchangeLookup.productId" class="exchange-query-state" :class="getLookupResult(account.name)?.matched ? 'exchange-query-matched' : 'exchange-query-empty'">
|
||||
{{ getLookupResult(account.name)?.matched ? '已兑换' : '未兑换' }}
|
||||
</span>
|
||||
<span class="exchange-count">{{ getLookupResult(account.name)?.records?.length || 0 }} 条</span>
|
||||
</template>
|
||||
</template>
|
||||
<div
|
||||
v-if="!isXiaodian && exchangeLookup && getLookupResult(account.name)?.records?.length"
|
||||
class="exchange-latest"
|
||||
:title="recordSummary(account.name)"
|
||||
>{{ recordSummary(account.name) }}</div>
|
||||
<button class="btn btn-compact btn-records" @click.stop="openExchangeRecords(account.name)">记录</button>
|
||||
</td>
|
||||
<td class="status-td">
|
||||
@@ -499,10 +594,10 @@ const closeExchangeRecords = () => {
|
||||
</div>
|
||||
|
||||
<div v-if="recordsModal" class="qr-backdrop" @click.self="closeExchangeRecords">
|
||||
<section class="record-modal" role="dialog" aria-modal="true" aria-label="和平小店兑换记录">
|
||||
<section class="record-modal" role="dialog" aria-modal="true" :aria-label="isXiaodian ? '和平小店兑换记录' : '兑换记录'">
|
||||
<div class="qr-modal-head">
|
||||
<div>
|
||||
<div class="panel-title">和平小店兑换记录</div>
|
||||
<div class="panel-title">{{ isXiaodian ? '和平小店兑换记录' : '兑换记录' }}</div>
|
||||
<div class="panel-sub">用户 {{ recordsModal.accountName }},共 {{ recordsModal.records.length }} 条</div>
|
||||
</div>
|
||||
<button class="btn btn-ghost icon-btn" title="关闭" aria-label="关闭" @click="closeExchangeRecords">×</button>
|
||||
@@ -512,7 +607,25 @@ const closeExchangeRecords = () => {
|
||||
<div v-else-if="recordsModal.error" class="record-modal-error">{{ recordsModal.error }}</div>
|
||||
<div v-else-if="recordsModal.records.length === 0" class="record-modal-empty">暂无兑换记录</div>
|
||||
<div v-else class="record-table-scroll">
|
||||
<table class="exchange-record-table">
|
||||
<!-- 手册类活动:商品/数量/兑换时间/积分/昵称 -->
|
||||
<table v-if="!isXiaodian" class="exchange-record-table">
|
||||
<thead>
|
||||
<tr><th>商品</th><th>数量</th><th>兑换时间</th><th>积分</th><th>昵称</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(record, index) in recordsModal.records" :key="`${record.commodityId}-${record.time}-${index}`">
|
||||
<td>
|
||||
<div class="record-product">{{ record.commodityName || record.commodityId }}</div>
|
||||
<div v-if="record.showName" class="account-sub">{{ record.showName }}</div>
|
||||
</td>
|
||||
<td>×{{ record.exchangeNum || 1 }}</td>
|
||||
<td>{{ formatTime(record.time) }}</td>
|
||||
<td>{{ record.score || '-' }}</td>
|
||||
<td>{{ record.nickName || '-' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table v-else class="exchange-record-table">
|
||||
<thead>
|
||||
<tr><th>商品</th><th>兑换时间</th><th>支付时间</th><th>价格</th><th>状态</th><th>角色</th></tr>
|
||||
</thead>
|
||||
@@ -750,6 +863,16 @@ tbody tr:hover {
|
||||
min-width: 130px;
|
||||
}
|
||||
|
||||
.exchange-count { color: var(--muted); font-size: 11px; }
|
||||
.exchange-latest {
|
||||
margin-top: 2px;
|
||||
max-width: 190px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: var(--muted-2);
|
||||
font-size: 11px;
|
||||
}
|
||||
.exchange-record-col,
|
||||
.exchange-record-cell {
|
||||
width: 148px;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"douyu_go/internal/types"
|
||||
)
|
||||
|
||||
// TestBuildExchangeRecordsResult 覆盖抢购控制台"查询兑换记录"的整理逻辑:
|
||||
// 记录不过滤、命中按商品统计、空 Cookie 与查询失败分开计数。
|
||||
func TestBuildExchangeRecordsResult(t *testing.T) {
|
||||
lookups := []exchangeLookupResult{
|
||||
{
|
||||
Account: types.Account{Name: "a"},
|
||||
Records: []types.ExchangeRecord{
|
||||
{CommodityID: "goods-1", CommodityName: "冥河战士大礼包", ExchangeNum: 1, Time: "2026-10-03 19:39:01", Score: "20"},
|
||||
{CommodityID: "goods-2", CommodityName: "幸运币礼包", ExchangeNum: 2, Time: "2026-10-03 12:00:00", Score: "10"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Account: types.Account{Name: "b"},
|
||||
Records: []types.ExchangeRecord{
|
||||
{CommodityID: "goods-2", CommodityName: "幸运币礼包", ExchangeNum: 1},
|
||||
},
|
||||
},
|
||||
{Account: types.Account{Name: "c"}, EmptyCookie: true},
|
||||
{Account: types.Account{Name: "d"}, Err: errors.New("接口超时")},
|
||||
// 商品ID为空的记录也要保留("看记录"不该藏东西)
|
||||
{Account: types.Account{Name: "e"}, Records: []types.ExchangeRecord{{CommodityName: "无ID记录"}}},
|
||||
}
|
||||
|
||||
result := buildExchangeRecordsResult(lookups, "goods-1", "冥河战士大礼包")
|
||||
if !result.Success {
|
||||
t.Fatal("结果应为成功")
|
||||
}
|
||||
if result.Total != 4 {
|
||||
t.Fatalf("记录总数 = %d, want 4", result.Total)
|
||||
}
|
||||
if result.Matched != 1 {
|
||||
t.Fatalf("命中当前商品账号数 = %d, want 1", result.Matched)
|
||||
}
|
||||
if result.Failed != 2 {
|
||||
t.Fatalf("失败账号数 = %d, want 2", result.Failed)
|
||||
}
|
||||
if got := result.Results["a"]; !got.Success || !got.Matched || len(got.Records) != 2 {
|
||||
t.Fatalf("a = %#v", got)
|
||||
}
|
||||
if got := result.Results["b"]; !got.Success || got.Matched {
|
||||
t.Fatalf("b 不应命中 goods-1: %#v", got)
|
||||
}
|
||||
if got := result.Results["c"]; got.Error != "Cookie 为空" {
|
||||
t.Fatalf("c 错误 = %q", got.Error)
|
||||
}
|
||||
if got := result.Results["d"]; got.Error != "接口超时" {
|
||||
t.Fatalf("d 错误 = %q", got.Error)
|
||||
}
|
||||
if got := result.Results["e"]; len(got.Records) != 1 {
|
||||
t.Fatalf("无商品ID的记录不应被过滤: %#v", got)
|
||||
}
|
||||
|
||||
// 不选商品时不做命中判断,但仍然返回全部记录
|
||||
all := buildExchangeRecordsResult(lookups, "", "")
|
||||
if all.Matched != 0 {
|
||||
t.Fatalf("未选商品时命中数应为 0, got %d", all.Matched)
|
||||
}
|
||||
if all.Total != 4 {
|
||||
t.Fatalf("未选商品时记录总数 = %d, want 4", all.Total)
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,66 @@ func (a *App) BindXiaodianRole(accountName string) types.XiaodianRole {
|
||||
return role
|
||||
}
|
||||
|
||||
// QueryExchangeRecords 批量查询手册类活动(精英手册/电竞手册)的兑换记录。
|
||||
//
|
||||
// 与和平小店的批量查询并列,供抢购控制台直接查看"每个账号兑换过什么",
|
||||
// 省得再去别的页面或客户端查。手册记录自带商品名与积分,商品可以不选;
|
||||
// 选了商品就额外标记该账号是否兑换过它。
|
||||
func (a *App) QueryExchangeRecords(commodityID, commodityName string) types.ExchangeRecordsBatchResult {
|
||||
result := types.ExchangeRecordsBatchResult{
|
||||
ProductID: strings.TrimSpace(commodityID),
|
||||
ProductName: strings.TrimSpace(commodityName),
|
||||
Results: make(map[string]types.ExchangeAccountRecords),
|
||||
}
|
||||
if a.getClient().Activity.IsXiaodian {
|
||||
result.Error = "和平小店请使用订单查询"
|
||||
return result
|
||||
}
|
||||
|
||||
accounts := a.scheduler.AccountSnapshot()
|
||||
result.Success = true
|
||||
if len(accounts) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
return buildExchangeRecordsResult(a.lookupExchangeRecords("兑换记录", accounts), result.ProductID, result.ProductName)
|
||||
}
|
||||
|
||||
// buildExchangeRecordsResult 把批量查询结果整理成界面用的结构(纯函数,便于测试)。
|
||||
//
|
||||
// 刻意不对记录做过滤:这是"看我的兑换记录",任何一条都不该被藏起来。
|
||||
func buildExchangeRecordsResult(lookups []exchangeLookupResult, productID, productName string) types.ExchangeRecordsBatchResult {
|
||||
result := types.ExchangeRecordsBatchResult{
|
||||
Success: true,
|
||||
ProductID: productID,
|
||||
ProductName: productName,
|
||||
Results: make(map[string]types.ExchangeAccountRecords, len(lookups)),
|
||||
}
|
||||
for _, lookup := range lookups {
|
||||
item := types.ExchangeAccountRecords{}
|
||||
switch {
|
||||
case lookup.EmptyCookie:
|
||||
item.Error = "Cookie 为空"
|
||||
case lookup.Err != nil:
|
||||
item.Error = lookup.Err.Error()
|
||||
default:
|
||||
item.Success = true
|
||||
item.Records = lookup.Records
|
||||
item.Matched = productID != "" && hasCommodityRecord(item.Records, productID, 0, 0)
|
||||
}
|
||||
if item.Error != "" {
|
||||
result.Failed++
|
||||
} else {
|
||||
result.Total += len(item.Records)
|
||||
if item.Matched {
|
||||
result.Matched++
|
||||
}
|
||||
}
|
||||
result.Results[lookup.Account.Name] = item
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// VerifyExchange 查询兑换记录,用于复验抢购结果。
|
||||
func (a *App) VerifyExchange(accountName string) types.ExchangeRecordsResult {
|
||||
if accountName == "" {
|
||||
|
||||
@@ -3,7 +3,7 @@ package constants
|
||||
import "time"
|
||||
|
||||
// Version 应用版本号,与 wails.json version 同步。
|
||||
const Version = "0.3.6"
|
||||
const Version = "0.3.7"
|
||||
|
||||
// BuildTime 构建时间,由编译时 ldflags 注入。
|
||||
var BuildTime = "unknown"
|
||||
|
||||
@@ -89,6 +89,28 @@ type XiaodianAssetsResult struct {
|
||||
Results map[string]XiaodianAssets `json:"results"`
|
||||
}
|
||||
|
||||
// ExchangeRecordsBatchResult 手册类活动(精英手册/电竞手册)的兑换记录批量查询结果。
|
||||
// 与和平小店的批量查询对应,区别是手册记录自带商品名与积分,商品可以不选;
|
||||
// 选了商品就在每个账号上标记是否兑换过它(对应界面的"已兑换/未兑换")。
|
||||
type ExchangeRecordsBatchResult struct {
|
||||
Success bool `json:"success"`
|
||||
ProductID string `json:"productId,omitempty"`
|
||||
ProductName string `json:"productName,omitempty"`
|
||||
Results map[string]ExchangeAccountRecords `json:"results"`
|
||||
Total int `json:"total"`
|
||||
Matched int `json:"matched"`
|
||||
Failed int `json:"failed"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ExchangeAccountRecords 单个账号的兑换记录。
|
||||
type ExchangeAccountRecords struct {
|
||||
Success bool `json:"success"`
|
||||
Records []ExchangeRecord `json:"records,omitempty"`
|
||||
Matched bool `json:"matched"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ExchangeRecordsResult 兑换记录查询结果。
|
||||
type ExchangeRecordsResult struct {
|
||||
Success bool `json:"success"`
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://wails.io/schemas/config.v2.json",
|
||||
"name": "douyu_go",
|
||||
"outputfilename": "douyu_go",
|
||||
"version": "0.3.6",
|
||||
"version": "0.3.7",
|
||||
"frontend:dir": "frontend",
|
||||
"frontend:install": "npm install",
|
||||
"frontend:build": "npm run build",
|
||||
@@ -15,6 +15,6 @@
|
||||
"email": "yml@example.com"
|
||||
},
|
||||
"info": {
|
||||
"productVersion": "0.3.6"
|
||||
"productVersion": "0.3.7"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user