feat(BIZ-105): 记录-比对 中奖金额展示 v1.2 实施
PRD v1.2 §4.3 落地,参考 BIZ-102 PRD 与 UI 原型。
后端(app.py):
- 新增 PRIZE_AMOUNT / PRIZE_KEY_MAP 常量双表(PRD §4.3)
- 新增 format_amount 千分位格式化(PRD §3.2:紧邻「元」不空格)
- 新增 compute_prize_summary 聚合函数
- api_compare_record 接口扩展:
- 单注:prize_amount + prize_amount_display 字段
- 顶层:total_prize / total_prize_display / has_variable_prize /
prize_summary / prize_display 字段
- 一/二等奖标记为浮动奖(历史数据无奖池字段),不计入 total_prize
前端(index.html):
- 总中奖金额字段(橙色「含浮动奖」角标)
- 中奖奖项汇总表(不含浮动奖金额)
- 浮动奖橙色提示条(区别于固定奖绿色 #1e8e4a)
- 每注金额 badge(固定奖绿 / 浮动奖橙)
测试(tests/test_compare_prize.py):
- 31 个用例,100% 通过
- 覆盖:6 档奖金档 / 未中奖 / waiting 契约 / 0 注 / 全中奖 /
仅有浮动奖 / 混合 / Mock 一致性(验收 #16)/ 响应结构契约
- running: pytest tests/test_compare_prize.py -v → 31 passed
不变项:比对算法 / 归期规则 / Excel 解析 / 认证 — 全部不动。
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
+88
-1
@@ -600,6 +600,64 @@
|
||||
}
|
||||
.prize-badge.win { background: #27ae60; color: white; }
|
||||
.prize-badge.lose { background: #f0f0f0; color: var(--text-light); }
|
||||
/* PRD v1.2 BIZ-105:每注中奖金额(紧邻「元」不空格) */
|
||||
.ticket-amount {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-left: 4px;
|
||||
background: rgba(30, 142, 74, 0.1);
|
||||
color: #1e8e4a;
|
||||
}
|
||||
.ticket-amount.floating {
|
||||
background: rgba(230, 126, 34, 0.1);
|
||||
color: #e67e22;
|
||||
}
|
||||
/* PRD v1.2 BIZ-105:浮动奖顶部提示条 */
|
||||
.variable-prize-tip {
|
||||
background: #fff3e0;
|
||||
color: #e67e22;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
/* PRD v1.2 BIZ-105:奖项汇总表 */
|
||||
.prize-table-wrap {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.prize-table-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.prize-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 13px;
|
||||
}
|
||||
.prize-table th, .prize-table td {
|
||||
padding: 6px 4px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
.prize-table th {
|
||||
font-size: 12px;
|
||||
color: var(--text-light);
|
||||
font-weight: 500;
|
||||
}
|
||||
.prize-table tr:last-child td { border-bottom: none; }
|
||||
.prize-table .col-level { text-align: left; color: var(--text); font-weight: 500; }
|
||||
.prize-table .col-count { color: var(--text-light); }
|
||||
.prize-table .col-amount { font-weight: 600; color: #1e8e4a; }
|
||||
.prize-table .col-amount.floating { color: #e67e22; }
|
||||
.compare-ticket-info {
|
||||
font-size: 12px;
|
||||
color: var(--text-light);
|
||||
@@ -1400,14 +1458,36 @@ async function compareRecord(id) {
|
||||
const draw = d.draw;
|
||||
const results = d.results;
|
||||
const winCount = d.win_count;
|
||||
// PRD v1.2 BIZ-105:中奖金额汇总字段
|
||||
const totalPrize = d.total_prize || 0;
|
||||
const totalPrizeDisplay = d.total_prize_display || '0元';
|
||||
const hasVariablePrize = !!d.has_variable_prize;
|
||||
const prizeDisplay = d.prize_display || [];
|
||||
|
||||
let html = '<div class="compare-summary">';
|
||||
html += `<div class="item"><div class="label">生成时间</div><div class="value" style="font-size:14px;">${d.gen_time}</div></div>`;
|
||||
html += `<div class="item"><div class="label">比对开奖期</div><div class="value" style="font-size:14px;">${draw.period} · ${draw.date}</div></div>`;
|
||||
html += `<div class="item"><div class="label">总注数</div><div class="value">${d.total}</div></div>`;
|
||||
html += `<div class="item"><div class="label">中奖注数</div><div class="value" style="color:${winCount > 0 ? '#27ae60' : 'var(--text-light)'};">${winCount}</div></div>`;
|
||||
html += `<div class="item"><div class="label">总中奖金额${hasVariablePrize ? '<span style="font-size:10px;color:#e67e22;font-weight:400;margin-left:4px;">含浮动奖</span>' : ''}</div><div class="value" style="color:${totalPrize > 0 ? '#27ae60' : 'var(--text-light)'};">${totalPrizeDisplay}</div></div>`;
|
||||
html += '</div>';
|
||||
|
||||
// PRD v1.2 BIZ-105:按奖项分行汇总(不展示浮动奖金额)
|
||||
if (prizeDisplay.length > 0) {
|
||||
html += '<div class="prize-table-wrap">';
|
||||
html += '<div class="prize-table-title">中奖奖项汇总</div>';
|
||||
html += '<table class="prize-table"><thead><tr><th class="col-level">奖级</th><th class="col-count">中奖注数</th><th class="col-amount">单注金额</th></tr></thead><tbody>';
|
||||
prizeDisplay.forEach(row => {
|
||||
html += `<tr><td class="col-level">${row.level}</td><td class="col-count">${row.count} 注</td><td class="col-amount">${row.amount}</td></tr>`;
|
||||
});
|
||||
html += '</tbody></table></div>';
|
||||
}
|
||||
|
||||
// PRD v1.2 BIZ-105:浮动奖提示(一/二等奖金额仅参考,不计入总金额)
|
||||
if (hasVariablePrize) {
|
||||
html += '<div class="variable-prize-tip">说明:一/二等奖金额为占位值,实际按奖池浮动,不计入「总中奖金额」。</div>';
|
||||
}
|
||||
|
||||
// Show draw result
|
||||
html += `<div style="margin-bottom:12px;background:#f0f0f0;padding:10px;border-radius:8px;">
|
||||
<span style="font-size:13px;font-weight:600;margin-right:8px;">开奖号码:</span>
|
||||
@@ -1428,12 +1508,19 @@ async function compareRecord(id) {
|
||||
const prizeBadge = r.is_win
|
||||
? `<span class="prize-badge win">${r.prize_level}</span>`
|
||||
: `<span class="prize-badge lose">未中奖</span>`;
|
||||
// PRD v1.2 BIZ-105:每注中奖金额(未中奖不展示)
|
||||
let amountBadge = '';
|
||||
if (r.is_win) {
|
||||
const isFloating = r.prize_level === '一等奖' || r.prize_level === '二等奖';
|
||||
const amountDisplay = r.prize_amount_display || `${r.prize_amount || 0}元`;
|
||||
amountBadge = `<span class="ticket-amount${isFloating ? ' floating' : ''}">${amountDisplay}</span>`;
|
||||
}
|
||||
const matchInfo = `<span class="match-info ${r.red_matches > 0 ? 'match' : ''}">红${r.red_matches}</span> <span class="match-info ${r.blue_match ? 'match' : ''}">蓝${r.blue_match ? '✓' : '✗'}</span>`;
|
||||
|
||||
html += `<div class="compare-ticket${r.is_win ? ' win' : ''}">
|
||||
<span style="font-size:12px;color:var(--text-light);min-width:36px;">${String(r.index).padStart(3,'0')}</span>
|
||||
${redBalls}${blueBall}
|
||||
${prizeBadge}
|
||||
${prizeBadge}${amountBadge}
|
||||
<span class="compare-ticket-info">${matchInfo} ${r.prize_desc || ''}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user