feat(admin-dashboard): add mini rank chart for 7d merchant revenue
This commit is contained in:
@@ -354,6 +354,67 @@
|
|||||||
background:var(--adm-primary-tint-06, rgba(22, 119, 255, .06));
|
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{
|
.kpi-grid{
|
||||||
display:grid;
|
display:grid;
|
||||||
grid-template-columns:repeat(4,minmax(0,1fr));
|
grid-template-columns:repeat(4,minmax(0,1fr));
|
||||||
|
|||||||
@@ -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 的反馈方式)
|
// 通用:将后端 flash 信息同步到 toast(更像 Ant Design Pro 的反馈方式)
|
||||||
// 说明:渐进增强。页面仍保留原本的提示块,不依赖 JS。
|
// 说明:渐进增强。页面仍保留原本的提示块,不依赖 JS。
|
||||||
(function () {
|
(function () {
|
||||||
|
|||||||
@@ -144,6 +144,20 @@
|
|||||||
|
|
||||||
<div class="muted">Top5 合计已付 ¥{{ number_format($rankTotal, 2) }}</div>
|
<div class="muted">Top5 合计已付 ¥{{ number_format($rankTotal, 2) }}</div>
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
<div class="adm-mini-rank" data-role="merchant-revenue-rank-7d-chart" data-points='@json($rankPoints)'></div>
|
||||||
|
|
||||||
<table class="mt-10" data-role="merchant-revenue-rank-7d">
|
<table class="mt-10" data-role="merchant-revenue-rank-7d">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class AdminDashboardMerchantRevenueRank7dCardShouldRenderTest extends TestCase
|
|||||||
$res->assertOk();
|
$res->assertOk();
|
||||||
|
|
||||||
$res->assertSee('排行(近7天站点收入 Top5)', false);
|
$res->assertSee('排行(近7天站点收入 Top5)', false);
|
||||||
|
$res->assertSee('data-role="merchant-revenue-rank-7d-chart"', false);
|
||||||
$res->assertSee('data-role="merchant-revenue-rank-7d"', false);
|
$res->assertSee('data-role="merchant-revenue-rank-7d"', false);
|
||||||
|
|
||||||
// 链接应携带 back(保持仪表盘治理链路一致性)
|
// 链接应携带 back(保持仪表盘治理链路一致性)
|
||||||
|
|||||||
Reference in New Issue
Block a user