From 83001cfda9298226dc14b8c41c19a1ac11a21f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=96=B9=E6=88=90?= Date: Thu, 15 Jan 2026 16:44:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=87=AD=E8=AF=81=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages-user/orders/detail.vue | 132 +++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 14 deletions(-) diff --git a/pages-user/orders/detail.vue b/pages-user/orders/detail.vue index 50dae82..e521592 100644 --- a/pages-user/orders/detail.vue +++ b/pages-user/orders/detail.vue @@ -184,20 +184,6 @@ 算法版本 {{ receipt.algo_version }} - - 服务端种子哈希 - - {{ receipt.server_seed_hash }} - 复制 - - - - 子种子 - - {{ receipt.server_sub_seed }} - 复制 - - 客户端种子 {{ receipt.client_seed }} @@ -219,6 +205,11 @@ 🔒 以上数据可用于验证抽奖结果的公正性 + + + 📋 + 复制验证凭据 + @@ -445,6 +436,92 @@ function showProofHelp() { showCancel: false }) } + +// 导出验证凭据JSON +function exportReceipt() { + if (!order.value || !order.value.draw_receipts || order.value.draw_receipts.length === 0) { + uni.showToast({ title: '无抽奖凭据', icon: 'none' }) + return + } + + // 构建验证凭据JSON + const receipts = order.value.draw_receipts.map((r, idx) => { + // 解析items_snapshot + let weightsStr = '' + let rewardsStr = '' + let salt = '' + let randValue = 0 + + if (r.items_snapshot) { + try { + const snapshot = typeof r.items_snapshot === 'string' + ? JSON.parse(r.items_snapshot) + : r.items_snapshot + + // 从snapshot中提取salt和rand(后端存储的实际值) + if (snapshot.salt) { + salt = snapshot.salt + } + if (snapshot.rand !== undefined) { + randValue = snapshot.rand + } + + // 提取并排序items + let items = [] + if (Array.isArray(snapshot)) { + items = snapshot + } else if (snapshot.items && Array.isArray(snapshot.items)) { + items = snapshot.items + } + + if (items.length > 0) { + // 必须按ID排序以匹配后端计算逻辑 + items.sort((a, b) => { + const idA = Number(a.id || a.ID || 0) + const idB = Number(b.id || b.ID || 0) + return idA - idB + }) + + weightsStr = items.map(item => `${item.id || item.ID}:${item.weight || item.Weight || item.count || 1}`).join(',') + rewardsStr = items.map(item => `${item.id || item.ID}:${item.count || item.Count || 1}`).join(',') + } + } catch (e) { + console.warn('items_snapshot解析失败:', e) + } + } + + return { + mode: r.selected_index > 0 ? 'ichiban' : 'unlimited', + version: r.algo_version || 'v1.0', + seed: r.server_sub_seed || '', + issue_id: r.round_id || 0, + user_id: r.client_id || 0, + salt: salt, // 使用items_snapshot中的salt + rand_value: randValue, // 实际随机数(用于验证比对) + slot_index: r.selected_index || 0, + weights: weightsStr, + rewards: rewardsStr, + weights_total: r.weights_total || 0, + timestamp: r.timestamp || 0, + draw_index: idx + 1, + items_snapshot: r.items_snapshot + } + }) + + // 如果只有一条凭据,直接导出单个对象;否则导出数组 + const exportData = receipts.length === 1 ? receipts[0] : receipts + const jsonStr = JSON.stringify(exportData, null, 2) + + uni.setClipboardData({ + data: jsonStr, + success: () => { + uni.showToast({ title: '凭据已复制', icon: 'success' }) + }, + fail: () => { + uni.showToast({ title: '复制失败', icon: 'none' }) + } + }) +}