From 1149565702c767c46072831f682a44a7cb7f2179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=9D=E5=8D=9C?= Date: Mon, 16 Mar 2026 10:19:17 +0800 Subject: [PATCH] feat(admin-dashboard): add mini rank chart for 7d merchant revenue --- public/css/admin-components.css | 61 ++++++++++++++++ public/js/admin.js | 69 +++++++++++++++++++ resources/views/admin/dashboard.blade.php | 14 ++++ ...chantRevenueRank7dCardShouldRenderTest.php | 1 + 4 files changed, 145 insertions(+) diff --git a/public/css/admin-components.css b/public/css/admin-components.css index 82ea576..c7b7b78 100644 --- a/public/css/admin-components.css +++ b/public/css/admin-components.css @@ -354,6 +354,67 @@ background:var(--adm-primary-tint-06, rgba(22, 119, 255, .06)); } +/* 可复用:迷你排行(渐进增强:由 admin.js 渲染,页面无 JS 时为空但不影响表格) */ +.adm-mini-rank{ + margin-top:10px; + width:100%; + display:flex; + flex-direction:column; + gap:8px; + padding:10px 10px; + border:1px solid var(--adm-border-color, #e5e7eb); + border-radius:var(--adm-radius, 12px); + background:var(--adm-surface-tint, rgba(15, 23, 42, .02)); + box-shadow:var(--adm-shadow-sm); +} + +.adm-mini-rank.is-empty{ + align-items:center; + justify-content:center; + color:var(--adm-text-muted, #94a3b8); + font-size:12px; +} + +.adm-mini-rank-row{ + display:flex; + align-items:center; + gap:10px; +} + +.adm-mini-rank-name{ + width:72px; + min-width:72px; + max-width:72px; + font-size:12px; + color:var(--adm-text-secondary, #64748b); + white-space:nowrap; + overflow:hidden; + text-overflow:ellipsis; +} + +.adm-mini-rank-bar-wrap{ + flex:1; + min-width:0; + height:12px; + border-radius:999px; + background:rgba(15, 23, 42, .06); + overflow:hidden; +} + +.adm-mini-rank-bar{ + height:100%; + border-radius:999px; + background:linear-gradient(90deg, rgba(22, 119, 255, .55), rgba(22, 119, 255, .18)); +} + +.adm-mini-rank-value{ + width:92px; + min-width:92px; + text-align:right; + font-size:12px; + color:var(--adm-text, #0f172a); +} + .kpi-grid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); diff --git a/public/js/admin.js b/public/js/admin.js index 9e54051..f7df946 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -126,6 +126,75 @@ }); })(); + // 仪表盘:迷你排行(近7天站点收入 Top5) + (function () { + var el = qs('[data-role="merchant-revenue-rank-7d-chart"][data-points]'); + if (!el) { + return; + } + + var raw = el.getAttribute('data-points') || '[]'; + var points = []; + try { + points = JSON.parse(raw) || []; + } catch (e) { + points = []; + } + + if (!points || points.length === 0) { + el.classList.add('is-empty'); + el.textContent = '暂无排行数据'; + return; + } + + var max = 0; + points.forEach(function (p) { + var v = Number(p && p.paid_sum ? p.paid_sum : 0); + if (v > max) { + max = v; + } + }); + if (!max || max <= 0) { + max = 1; + } + + el.innerHTML = ''; + + points.forEach(function (p, idx) { + var paid = Number(p && p.paid_sum ? p.paid_sum : 0); + var ratio = Math.max(0, Math.min(1, paid / max)); + + var row = document.createElement('div'); + row.className = 'adm-mini-rank-row'; + + var name = document.createElement('div'); + name.className = 'adm-mini-rank-name'; + // 仅展示 #排名(站点名在表格里可看;后续可把真实名字也塞进 data-points) + name.textContent = '#' + (idx + 1); + + var wrap = document.createElement('div'); + wrap.className = 'adm-mini-rank-bar-wrap'; + + var bar = document.createElement('div'); + bar.className = 'adm-mini-rank-bar'; + bar.style.width = Math.round(ratio * 100) + '%'; + + wrap.appendChild(bar); + + var val = document.createElement('div'); + val.className = 'adm-mini-rank-value'; + val.textContent = '¥' + paid.toFixed(2); + + row.title = 'Top' + (idx + 1) + ':已付 ¥' + paid.toFixed(2) + ',订单数 ' + String(p && p.count != null ? p.count : 0); + + row.appendChild(name); + row.appendChild(wrap); + row.appendChild(val); + + el.appendChild(row); + }); + })(); + // 通用:将后端 flash 信息同步到 toast(更像 Ant Design Pro 的反馈方式) // 说明:渐进增强。页面仍保留原本的提示块,不依赖 JS。 (function () { diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index 392c184..446188d 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -144,6 +144,20 @@
Top5 合计已付 ¥{{ number_format($rankTotal, 2) }}
+ @php + // 用于前端渐进增强渲染迷你排行(JS 读取 data-points) + $rankPoints = []; + foreach ($rankRows as $r) { + $rankPoints[] = [ + 'merchant_id' => (int) ($r['merchant_id'] ?? 0), + 'count' => (int) ($r['count'] ?? 0), + 'paid_sum' => (float) ($r['paid_sum'] ?? 0), + ]; + } + @endphp + +
+ diff --git a/tests/Feature/AdminDashboardMerchantRevenueRank7dCardShouldRenderTest.php b/tests/Feature/AdminDashboardMerchantRevenueRank7dCardShouldRenderTest.php index 7711b81..70fc97d 100644 --- a/tests/Feature/AdminDashboardMerchantRevenueRank7dCardShouldRenderTest.php +++ b/tests/Feature/AdminDashboardMerchantRevenueRank7dCardShouldRenderTest.php @@ -27,6 +27,7 @@ class AdminDashboardMerchantRevenueRank7dCardShouldRenderTest extends TestCase $res->assertOk(); $res->assertSee('排行(近7天站点收入 Top5)', false); + $res->assertSee('data-role="merchant-revenue-rank-7d-chart"', false); $res->assertSee('data-role="merchant-revenue-rank-7d"', false); // 链接应携带 back(保持仪表盘治理链路一致性)