Files

331 lines
17 KiB
HTML

<!-- 财务概览驾驶舱 -->
<style>
.fo-page { display:flex; flex-direction:column; gap:16px; }
/* KPI 指标卡片行 */
.fo-kpi-row { display:grid; grid-template-columns:repeat(5,1fr); gap:14px; }
.fo-kpi { background:#fff; border-radius:var(--g-radius); border:1px solid var(--g-border); padding:18px 20px; display:flex; flex-direction:column; gap:10px; transition:var(--g-transition); }
.fo-kpi:hover { box-shadow:var(--g-shadow-md); transform:translateY(-1px); }
.fo-kpi-top { display:flex; align-items:center; justify-content:space-between; }
.fo-kpi-label { font-size:13px; color:var(--g-text-secondary); }
.fo-kpi-icon { width:36px; height:36px; border-radius:var(--g-radius); display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.fo-kpi-icon.blue { background:hsl(212,100%,95%); color:hsl(212,100%,45%); }
.fo-kpi-icon.green { background:#f0fdf4; color:var(--g-success); }
.fo-kpi-icon.red { background:#fef2f2; color:var(--g-danger); }
.fo-kpi-icon.purple { background:#f5f3ff; color:#7c3aed; }
.fo-kpi-icon.orange { background:#fffbeb; color:var(--g-warning); }
.fo-kpi-value { font-size:26px; font-weight:800; color:var(--g-text); letter-spacing:-0.5px; }
.fo-kpi-change { font-size:12px; display:flex; align-items:center; gap:4px; }
.fo-kpi-change.up { color:var(--g-success); }
.fo-kpi-change.down { color:var(--g-danger); }
/* 区块标题 */
.fo-section-hd { font-size:15px; font-weight:600; color:var(--g-text); padding-left:10px; border-left:3px solid var(--primary); }
.fo-hd-row { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
/* Pill 切换 */
.fo-pills { display:flex; gap:6px; }
.fo-pill { padding:4px 14px; border-radius:20px; font-size:12px; color:var(--g-text-secondary); background:#f5f5f5; cursor:pointer; border:none; transition:var(--g-transition); }
.fo-pill.active { background:var(--primary); color:#fff; }
/* 折线图占位 */
.fo-chart-area { position:relative; height:200px; background:linear-gradient(180deg,hsl(212,100%,97%) 0%,#fff 100%); border-radius:var(--g-radius); border:1px dashed var(--g-border); overflow:hidden; }
.fo-chart-line { position:absolute; bottom:0; left:0; right:0; height:100%; }
.fo-chart-svg { width:100%; height:100%; }
.fo-chart-label { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); font-size:13px; color:var(--g-text-muted); pointer-events:none; }
.fo-chart-x { display:flex; justify-content:space-between; padding:8px 12px 0; font-size:11px; color:var(--g-text-muted); }
/* 两列布局 */
.fo-two-col { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
/* 圆环图 */
.fo-donut-wrap { display:flex; align-items:center; gap:28px; padding:8px 0; }
.fo-donut { width:150px; height:150px; border-radius:50%; position:relative; flex-shrink:0; }
.fo-donut-center { position:absolute; inset:32px; background:#fff; border-radius:50%; display:flex; flex-direction:column; align-items:center; justify-content:center; }
.fo-donut-center .num { font-size:18px; font-weight:700; color:var(--g-text); }
.fo-donut-center .txt { font-size:11px; color:var(--g-text-muted); }
.fo-legend { display:flex; flex-direction:column; gap:10px; flex:1; }
.fo-legend-item { display:flex; align-items:center; gap:8px; font-size:13px; color:var(--g-text); }
.fo-legend-dot { width:8px; height:8px; border-radius:2px; flex-shrink:0; }
.fo-legend-val { margin-left:auto; font-weight:600; font-size:13px; }
.fo-legend-pct { color:var(--g-text-muted); font-size:12px; width:36px; text-align:right; }
/* 利润走势 */
.fo-profit-area { position:relative; height:180px; background:linear-gradient(180deg,hsl(212,100%,97%) 0%,#fff 100%); border-radius:var(--g-radius); border:1px dashed var(--g-border); overflow:hidden; }
.fo-profit-legend { display:flex; gap:20px; margin-top:10px; }
.fo-profit-legend-item { display:flex; align-items:center; gap:6px; font-size:12px; color:var(--g-text-secondary); }
.fo-profit-legend-line { width:20px; height:3px; border-radius:2px; }
/* TOP10 表格 */
.fo-rank-table { width:100%; border-collapse:collapse; }
.fo-rank-table th { text-align:left; font-size:12px; color:var(--g-text-muted); font-weight:500; padding:10px 12px; border-bottom:1px solid var(--g-border); background:#fafafa; }
.fo-rank-table th:first-child { border-radius:var(--g-radius) 0 0 0; }
.fo-rank-table th:last-child { border-radius:0 var(--g-radius) 0 0; }
.fo-rank-table td { padding:10px 12px; font-size:13px; color:var(--g-text); border-bottom:1px solid #f5f5f5; }
.fo-rank-table tr:hover td { background:color-mix(in srgb, var(--primary) 3%, #fff); }
.fo-rank-num { width:22px; height:22px; border-radius:4px; display:inline-flex; align-items:center; justify-content:center; font-size:11px; font-weight:700; color:#fff; }
.fo-rank-num.t1 { background:linear-gradient(135deg,#ef4444,#f97316); }
.fo-rank-num.t2 { background:linear-gradient(135deg,#f59e0b,#fbbf24); }
.fo-rank-num.t3 { background:linear-gradient(135deg,#1890ff,#69c0ff); }
.fo-rank-num.tn { background:#e5e7eb; color:#4b5563; }
.fo-progress-bg { width:100%; max-width:120px; height:6px; background:#e5e7eb; border-radius:3px; overflow:hidden; }
.fo-progress-fill { height:100%; border-radius:3px; background:linear-gradient(90deg,hsl(212,100%,45%),hsl(212,100%,65%)); }
@keyframes foFadeIn { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:translateY(0); } }
.fo-page > * { animation:foFadeIn 0.4s ease both; }
.fo-page > *:nth-child(2) { animation-delay:0.05s; }
.fo-page > *:nth-child(3) { animation-delay:0.1s; }
.fo-page > *:nth-child(4) { animation-delay:0.15s; }
.fo-page > *:nth-child(5) { animation-delay:0.2s; }
</style>
<div class="fo-page">
<!-- 1. 核心指标卡片 -->
<div class="fo-kpi-row">
<div class="fo-kpi">
<div class="fo-kpi-top">
<span class="fo-kpi-label">今日营业额</span>
<div class="fo-kpi-icon blue"><i data-lucide="coins" style="width:18px;height:18px"></i></div>
</div>
<div class="fo-kpi-value">&yen;8,620</div>
<div class="fo-kpi-change up"><i data-lucide="trending-up" style="width:14px;height:14px"></i> 12% 较昨日</div>
</div>
<div class="fo-kpi">
<div class="fo-kpi-top">
<span class="fo-kpi-label">实收</span>
<div class="fo-kpi-icon green"><i data-lucide="badge-check" style="width:18px;height:18px"></i></div>
</div>
<div class="fo-kpi-value">&yen;7,980</div>
<div class="fo-kpi-change up"><i data-lucide="trending-up" style="width:14px;height:14px"></i> 8% 较昨日</div>
</div>
<div class="fo-kpi">
<div class="fo-kpi-top">
<span class="fo-kpi-label">退款</span>
<div class="fo-kpi-icon red"><i data-lucide="undo-2" style="width:18px;height:18px"></i></div>
</div>
<div class="fo-kpi-value">&yen;640</div>
<div class="fo-kpi-change down"><i data-lucide="trending-down" style="width:14px;height:14px"></i> 3% 较昨日</div>
</div>
<div class="fo-kpi">
<div class="fo-kpi-top">
<span class="fo-kpi-label">净收入</span>
<div class="fo-kpi-icon purple"><i data-lucide="wallet" style="width:18px;height:18px"></i></div>
</div>
<div class="fo-kpi-value">&yen;6,850</div>
<div class="fo-kpi-change up"><i data-lucide="trending-up" style="width:14px;height:14px"></i> 5% 较昨日</div>
</div>
<div class="fo-kpi">
<div class="fo-kpi-top">
<span class="fo-kpi-label">可提现余额</span>
<div class="fo-kpi-icon orange"><i data-lucide="landmark" style="width:18px;height:18px"></i></div>
</div>
<div class="fo-kpi-value">&yen;32,400</div>
<div class="fo-kpi-change up"><i data-lucide="trending-up" style="width:14px;height:14px"></i> 15% 较上周</div>
</div>
</div>
<!-- 2. 收入趋势 -->
<div class="g-card" style="padding:20px">
<div class="fo-hd-row">
<div class="fo-section-hd">收入趋势</div>
<div class="fo-pills">
<button class="fo-pill active" onclick="foSwitchPill(this)">近7天</button>
<button class="fo-pill" onclick="foSwitchPill(this)">近30天</button>
</div>
</div>
<div class="fo-chart-area">
<svg class="fo-chart-svg" viewBox="0 0 700 200" preserveAspectRatio="none">
<defs>
<linearGradient id="foGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="hsl(212,100%,45%)" stop-opacity="0.2"/>
<stop offset="100%" stop-color="hsl(212,100%,45%)" stop-opacity="0.02"/>
</linearGradient>
</defs>
<polyline fill="url(#foGrad)" stroke="none" points="0,200 0,140 100,100 200,120 300,60 400,80 500,40 600,70 700,30 700,200"/>
<polyline fill="none" stroke="hsl(212,100%,45%)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" points="0,140 100,100 200,120 300,60 400,80 500,40 600,70 700,30"/>
<circle cx="0" cy="140" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
<circle cx="100" cy="100" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
<circle cx="200" cy="120" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
<circle cx="300" cy="60" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
<circle cx="400" cy="80" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
<circle cx="500" cy="40" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
<circle cx="600" cy="70" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
<circle cx="700" cy="30" r="4" fill="#fff" stroke="hsl(212,100%,45%)" stroke-width="2"/>
</svg>
</div>
<div class="fo-chart-x">
<span>02/06</span><span>02/07</span><span>02/08</span><span>02/09</span><span>02/10</span><span>02/11</span><span>02/12</span>
</div>
</div>
<!-- 3. 收入构成 + 成本占比 -->
<div class="fo-two-col">
<!-- 收入构成 -->
<div class="g-card" style="padding:20px">
<div class="fo-section-hd" style="margin-bottom:16px">收入构成</div>
<div class="fo-donut-wrap">
<div class="fo-donut" style="background:conic-gradient(hsl(212,100%,45%) 0% 58%,#22c55e 58% 83%,#f59e0b 83% 100%)">
<div class="fo-donut-center">
<span class="num">&yen;7,980</span>
<span class="txt">总实收</span>
</div>
</div>
<div class="fo-legend">
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:hsl(212,100%,45%)"></span>
外卖
<span class="fo-legend-pct">58%</span>
<span class="fo-legend-val">&yen;4,628</span>
</div>
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:#22c55e"></span>
自提
<span class="fo-legend-pct">25%</span>
<span class="fo-legend-val">&yen;1,995</span>
</div>
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:#f59e0b"></span>
堂食
<span class="fo-legend-pct">17%</span>
<span class="fo-legend-val">&yen;1,357</span>
</div>
</div>
</div>
</div>
<!-- 成本占比 -->
<div class="g-card" style="padding:20px">
<div class="fo-section-hd" style="margin-bottom:16px">成本占比</div>
<div class="fo-donut-wrap">
<div class="fo-donut" style="background:conic-gradient(#ef4444 0% 42%,#f59e0b 42% 70%,#8b5cf6 70% 88%,#06b6d4 88% 95%,#94a3b8 95% 100%)">
<div class="fo-donut-center">
<span class="num">&yen;1,130</span>
<span class="txt">总成本</span>
</div>
</div>
<div class="fo-legend">
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:#ef4444"></span>
食材
<span class="fo-legend-pct">42%</span>
<span class="fo-legend-val">&yen;475</span>
</div>
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:#f59e0b"></span>
人工
<span class="fo-legend-pct">28%</span>
<span class="fo-legend-val">&yen;316</span>
</div>
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:#8b5cf6"></span>
固定
<span class="fo-legend-pct">18%</span>
<span class="fo-legend-val">&yen;203</span>
</div>
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:#06b6d4"></span>
包装
<span class="fo-legend-pct">7%</span>
<span class="fo-legend-val">&yen;79</span>
</div>
<div class="fo-legend-item">
<span class="fo-legend-dot" style="background:#94a3b8"></span>
平台
<span class="fo-legend-pct">5%</span>
<span class="fo-legend-val">&yen;57</span>
</div>
</div>
</div>
</div>
</div>
<!-- 4. 利润走势 -->
<div class="g-card" style="padding:20px">
<div class="fo-hd-row">
<div class="fo-section-hd">利润走势</div>
<div class="fo-pills">
<button class="fo-pill active" onclick="foSwitchPill(this)">近7天</button>
<button class="fo-pill" onclick="foSwitchPill(this)">近30天</button>
</div>
</div>
<div class="fo-profit-area">
<svg class="fo-chart-svg" viewBox="0 0 700 180" preserveAspectRatio="none">
<!-- 营收线 -->
<polyline fill="none" stroke="hsl(212,100%,45%)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" points="0,120 100,90 200,100 300,50 400,65 500,35 600,55 700,25"/>
<!-- 成本线 -->
<polyline fill="none" stroke="#ef4444" stroke-width="2" stroke-dasharray="6,3" stroke-linejoin="round" stroke-linecap="round" points="0,150 100,140 200,145 300,125 400,130 500,120 600,128 700,115"/>
<!-- 净利润线 -->
<polyline fill="none" stroke="#22c55e" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" points="0,160 100,145 200,150 300,120 400,128 500,108 600,118 700,95"/>
</svg>
</div>
<div class="fo-chart-x">
<span>02/06</span><span>02/07</span><span>02/08</span><span>02/09</span><span>02/10</span><span>02/11</span><span>02/12</span>
</div>
<div class="fo-profit-legend">
<div class="fo-profit-legend-item"><span class="fo-profit-legend-line" style="background:hsl(212,100%,45%)"></span>营收</div>
<div class="fo-profit-legend-item"><span class="fo-profit-legend-line" style="background:#ef4444"></span>成本</div>
<div class="fo-profit-legend-item"><span class="fo-profit-legend-line" style="background:#22c55e"></span>净利润</div>
</div>
</div>
<!-- 5. TOP10 商品营收排行 -->
<div class="g-card" style="padding:20px">
<div class="fo-section-hd" style="margin-bottom:16px">TOP10 商品营收排行</div>
<table class="fo-rank-table">
<thead>
<tr>
<th style="width:60px">排名</th>
<th>商品名称</th>
<th style="width:80px">销量</th>
<th style="width:100px">营收</th>
<th style="width:160px">占比</th>
</tr>
</thead>
<tbody id="foRankBody"></tbody>
</table>
</div>
</div>
<script>
(function(){
// TOP10 数据
var items = [
{ name:'招牌黄焖鸡米饭', sales:186, revenue:5580, pct:18.2 },
{ name:'香辣鸡腿堡套餐', sales:152, revenue:4560, pct:14.9 },
{ name:'麻辣小龙虾拌面', sales:134, revenue:4020, pct:13.1 },
{ name:'经典牛肉面', sales:128, revenue:3200, pct:10.4 },
{ name:'鱼香肉丝盖饭', sales:115, revenue:2875, pct:9.4 },
{ name:'宫保鸡丁套餐', sales:98, revenue:2450, pct:8.0 },
{ name:'番茄鸡蛋面', sales:92, revenue:1840, pct:6.0 },
{ name:'红烧排骨饭', sales:85, revenue:2550, pct:8.3 },
{ name:'皮蛋瘦肉粥', sales:76, revenue:1140, pct:3.7 },
{ name:'冰柠檬水', sales:210, revenue:1260, pct:4.1 }
];
var maxPct = items[0].pct;
var tbody = document.getElementById('foRankBody');
items.forEach(function(it, i){
var cls = i === 0 ? 't1' : i === 1 ? 't2' : i === 2 ? 't3' : 'tn';
var tr = document.createElement('tr');
tr.innerHTML =
'<td><span class="fo-rank-num ' + cls + '">' + (i+1) + '</span></td>' +
'<td>' + it.name + '</td>' +
'<td>' + it.sales + '</td>' +
'<td style="font-weight:600">&yen;' + it.revenue.toLocaleString() + '</td>' +
'<td><div style="display:flex;align-items:center;gap:8px"><div class="fo-progress-bg"><div class="fo-progress-fill" style="width:' + (it.pct / maxPct * 100) + '%"></div></div><span style="font-size:12px;color:var(--g-text-muted)">' + it.pct + '%</span></div></td>';
tbody.appendChild(tr);
});
})();
// Pill 切换
function foSwitchPill(el) {
var siblings = el.parentElement.querySelectorAll('.fo-pill');
siblings.forEach(function(s){ s.classList.remove('active'); });
el.classList.add('active');
}
// Lucide 图标初始化
if (typeof lucide !== 'undefined') { lucide.createIcons(); }
</script>