diff --git a/public/css/admin-components.css b/public/css/admin-components.css index ac1d56a..82ea576 100644 --- a/public/css/admin-components.css +++ b/public/css/admin-components.css @@ -308,6 +308,52 @@ } /* 可复用:KPI 卡片栅格(参考 Ant Design Pro Analysis:第一行 4 个等宽卡片) */ + +/* 可复用:迷你图表(渐进增强:由 admin.js 渲染,页面无 JS 时为空但不影响表格) */ +.adm-mini-chart{ + margin-top:10px; + height:86px; + width:100%; + display:flex; + align-items:flex-end; + 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-chart.is-empty{ + align-items:center; + justify-content:center; + color:var(--adm-text-muted, #94a3b8); + font-size:12px; +} + +.adm-mini-chart-bar{ + flex:1; + min-width:0; + height:10px; + border-radius:10px 10px 4px 4px; + border:1px solid var(--adm-primary-border-35, rgba(22, 119, 255, .35)); + background:var(--adm-primary-tint-08, rgba(22, 119, 255, .08)); + position:relative; + overflow:hidden; +} + +.adm-mini-chart-bar::after{ + content:""; + position:absolute; + inset:0; + background:linear-gradient(180deg, rgba(22, 119, 255, .22), rgba(22, 119, 255, .04)); +} + +.adm-mini-chart-bar:hover{ + border-color:var(--adm-primary-border-45, rgba(22, 119, 255, .45)); + background:var(--adm-primary-tint-06, rgba(22, 119, 255, .06)); +} + .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 f28bf21..9e54051 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -74,6 +74,58 @@ }); })(); + // 仪表盘:迷你图表(趋势图渐进增强) + // 说明:不引入图表库,避免构建链;用 div bar 方式渲染。 + (function () { + var el = qs('[data-role="platform-order-trend-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; + } + + // 清空(避免 SSR/重复执行污染) + el.innerHTML = ''; + + points.forEach(function (p) { + var paid = Number(p && p.paid_sum ? p.paid_sum : 0); + var h = Math.round(Math.max(6, (paid / max) * 72)); + + var bar = document.createElement('div'); + bar.className = 'adm-mini-chart-bar'; + bar.style.height = h + 'px'; + + var date = (p && p.date) ? String(p.date) : ''; + var count = (p && p.count != null) ? String(p.count) : '0'; + bar.title = date + ':' + count + ' 单,已付 ¥' + paid.toFixed(2); + + el.appendChild(bar); + }); + })(); + // 通用:将后端 flash 信息同步到 toast(更像 Ant Design Pro 的反馈方式) // 说明:渐进增强。页面仍保留原本的提示块,不依赖 JS。 (function () { diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index 9e23dac..392c184 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -84,8 +84,19 @@ @php $trendRows = (array) ($platformOrderTrend7d ?? []); + // 用于前端渐进增强渲染迷你图表(JS 读取 data-points) + $trendPoints = []; + foreach ($trendRows as $r) { + $trendPoints[] = [ + 'date' => (string) ($r['date'] ?? ''), + 'count' => (int) ($r['count'] ?? 0), + 'paid_sum' => (float) ($r['paid_sum'] ?? 0), + ]; + } @endphp +
+