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 @@