300 lines
17 KiB
HTML
300 lines
17 KiB
HTML
<!-- 订单分析 stat-order -->
|
||
<style>
|
||
.so-page { display:flex; flex-direction:column; gap:20px; }
|
||
|
||
/* 筛选栏 */
|
||
.so-filter { display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
|
||
.so-date-input { height:34px; padding:0 10px; border:1px solid var(--g-border); border-radius:var(--g-radius-sm); font-size:13px; color:var(--g-text); outline:none; transition:var(--g-transition); }
|
||
.so-date-input:focus { border-color:var(--primary); }
|
||
.so-date-sep { color:var(--g-text-muted); font-size:13px; }
|
||
.so-quick-btns { display:flex; gap:6px; }
|
||
.so-quick-btn { height:30px; padding:0 12px; border:1px solid var(--g-border); border-radius:var(--g-radius-sm); background:#fff; font-size:12px; color:var(--g-text-secondary); cursor:pointer; transition:var(--g-transition); }
|
||
.so-quick-btn:hover { border-color:var(--primary); color:var(--primary); }
|
||
.so-quick-btn.active { background:var(--primary-light); border-color:var(--primary); color:var(--primary); font-weight:500; }
|
||
.so-channel-btns { display:flex; gap:0; margin-left:auto; }
|
||
.so-channel-btn { height:30px; padding:0 14px; border:1px solid var(--g-border); background:#fff; font-size:12px; color:var(--g-text-secondary); cursor:pointer; transition:var(--g-transition); }
|
||
.so-channel-btn:first-child { border-radius:var(--g-radius-sm) 0 0 var(--g-radius-sm); }
|
||
.so-channel-btn:last-child { border-radius:0 var(--g-radius-sm) var(--g-radius-sm) 0; }
|
||
.so-channel-btn + .so-channel-btn { border-left:none; }
|
||
.so-channel-btn:hover { color:var(--primary); }
|
||
.so-channel-btn.active { background:var(--primary); border-color:var(--primary); color:#fff; }
|
||
|
||
/* 统计卡片 */
|
||
.so-kpi-row { display:grid; grid-template-columns:repeat(4,1fr); gap:16px; }
|
||
.so-kpi { border-radius:var(--g-radius); padding:20px 24px; background:#fff; border:1px solid var(--g-border); transition:var(--g-transition); display:flex; flex-direction:column; gap:8px; }
|
||
.so-kpi:hover { box-shadow:var(--g-shadow-md); }
|
||
.so-kpi-label { font-size:13px; color:var(--g-text-muted); display:flex; align-items:center; gap:6px; }
|
||
.so-kpi-label i { width:16px; height:16px; }
|
||
.so-kpi-value { font-size:28px; font-weight:700; color:var(--g-text); letter-spacing:-0.5px; }
|
||
.so-kpi-sub { font-size:12px; color:var(--g-text-muted); display:flex; align-items:center; gap:4px; }
|
||
.so-kpi-sub .up { color:var(--g-success); font-weight:500; }
|
||
.so-kpi-sub .down { color:var(--g-danger); font-weight:500; }
|
||
|
||
/* Section 标题 */
|
||
.so-section-hd { font-size:15px; font-weight:600; color:var(--g-text); padding-left:10px; border-left:3px solid var(--primary); margin-bottom:16px; }
|
||
|
||
/* 趋势图 */
|
||
.so-chart-wrap { position:relative; }
|
||
.so-chart-svg { width:100%; height:220px; }
|
||
.so-chart-summary { display:flex; gap:32px; margin-top:12px; }
|
||
.so-chart-stat { font-size:13px; color:var(--g-text-secondary); }
|
||
.so-chart-stat strong { color:var(--g-text); font-weight:600; }
|
||
|
||
/* 热力图 */
|
||
.so-heat-wrap { display:flex; gap:20px; align-items:flex-start; }
|
||
.so-heat-grid { display:grid; grid-template-columns:48px repeat(14, 36px); gap:2px; }
|
||
.so-heat-header { font-size:11px; color:var(--g-text-muted); display:flex; align-items:center; justify-content:center; height:20px; }
|
||
.so-heat-row-label { font-size:12px; color:var(--g-text-secondary); display:flex; align-items:center; height:28px; }
|
||
.so-heat-cell { width:36px; height:28px; border-radius:3px; transition:var(--g-transition); cursor:default; }
|
||
.so-heat-cell:hover { outline:2px solid var(--primary); outline-offset:-1px; }
|
||
.so-heat-l0 { background:hsl(212,60%,95%); }
|
||
.so-heat-l1 { background:hsl(212,70%,82%); }
|
||
.so-heat-l2 { background:hsl(212,80%,65%); }
|
||
.so-heat-l3 { background:hsl(212,90%,45%); }
|
||
.so-heat-legend { display:flex; flex-direction:column; gap:6px; padding-top:24px; }
|
||
.so-heat-legend-item { display:flex; align-items:center; gap:6px; font-size:12px; color:var(--g-text-secondary); }
|
||
.so-heat-legend-dot { width:16px; height:12px; border-radius:2px; }
|
||
|
||
/* 渠道对比 */
|
||
.so-channel-row { display:grid; grid-template-columns:repeat(3,1fr); gap:16px; }
|
||
.so-ch-card { border-radius:var(--g-radius); padding:24px; background:#fff; border:1px solid var(--g-border); transition:var(--g-transition); }
|
||
.so-ch-card:hover { box-shadow:var(--g-shadow-md); }
|
||
.so-ch-hd { display:flex; align-items:center; gap:10px; margin-bottom:16px; }
|
||
.so-ch-icon { width:36px; height:36px; border-radius:var(--g-radius-sm); display:flex; align-items:center; justify-content:center; }
|
||
.so-ch-icon.waimai { background:hsl(212,100%,95%); color:var(--primary); }
|
||
.so-ch-icon.ziti { background:hsl(150,60%,94%); color:var(--g-success); }
|
||
.so-ch-icon.tangshi { background:hsl(30,90%,94%); color:var(--g-warning); }
|
||
.so-ch-name { font-size:15px; font-weight:600; color:var(--g-text); }
|
||
.so-ch-metrics { display:flex; flex-direction:column; gap:10px; margin-bottom:16px; }
|
||
.so-ch-metric { display:flex; justify-content:space-between; font-size:13px; }
|
||
.so-ch-metric-label { color:var(--g-text-muted); }
|
||
.so-ch-metric-val { color:var(--g-text); font-weight:500; }
|
||
.so-ch-bar-bg { height:8px; background:#f0f0f0; border-radius:4px; overflow:hidden; }
|
||
.so-ch-bar-fill { height:100%; border-radius:4px; transition:width 0.6s cubic-bezier(.2,0,0,1); }
|
||
.so-ch-bar-fill.waimai { background:linear-gradient(90deg,#1890ff,#69c0ff); }
|
||
.so-ch-bar-fill.ziti { background:linear-gradient(90deg,#52c41a,#95de64); }
|
||
.so-ch-bar-fill.tangshi { background:linear-gradient(90deg,#fa8c16,#ffc069); }
|
||
</style>
|
||
|
||
<div class="so-page" style="padding:4px 0;">
|
||
|
||
<!-- 顶部筛选 -->
|
||
<div class="g-card" style="padding:16px 20px;">
|
||
<div class="so-filter">
|
||
<input type="date" class="so-date-input" value="2026-01-30">
|
||
<span class="so-date-sep">至</span>
|
||
<input type="date" class="so-date-input" value="2026-02-12">
|
||
<div class="so-quick-btns">
|
||
<button class="so-quick-btn" onclick="pickQuick(this)">今天</button>
|
||
<button class="so-quick-btn" onclick="pickQuick(this)">近7天</button>
|
||
<button class="so-quick-btn active" onclick="pickQuick(this)">近14天</button>
|
||
<button class="so-quick-btn" onclick="pickQuick(this)">本月</button>
|
||
</div>
|
||
<div class="so-channel-btns">
|
||
<button class="so-channel-btn active" onclick="pickChannel(this)">全部</button>
|
||
<button class="so-channel-btn" onclick="pickChannel(this)">外卖</button>
|
||
<button class="so-channel-btn" onclick="pickChannel(this)">自提</button>
|
||
<button class="so-channel-btn" onclick="pickChannel(this)">堂食</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 统计卡片 -->
|
||
<div class="so-kpi-row">
|
||
<div class="so-kpi">
|
||
<div class="so-kpi-label"><i data-lucide="file-text" style="width:16px;height:16px;"></i> 总订单数</div>
|
||
<div class="so-kpi-value">3,420</div>
|
||
<div class="so-kpi-sub">较上期 <span class="up">+5.2%</span></div>
|
||
</div>
|
||
<div class="so-kpi">
|
||
<div class="so-kpi-label"><i data-lucide="circle-check" style="width:16px;height:16px;"></i> 有效订单</div>
|
||
<div class="so-kpi-value">3,286</div>
|
||
<div class="so-kpi-sub">完成率 <strong style="color:var(--g-success);">96.1%</strong></div>
|
||
</div>
|
||
<div class="so-kpi">
|
||
<div class="so-kpi-label"><i data-lucide="banknote" style="width:16px;height:16px;"></i> 总销售额</div>
|
||
<div class="so-kpi-value">¥128,600</div>
|
||
<div class="so-kpi-sub">较上期 <span class="up">+8.7%</span></div>
|
||
</div>
|
||
<div class="so-kpi">
|
||
<div class="so-kpi-label"><i data-lucide="receipt" style="width:16px;height:16px;"></i> 平均客单价</div>
|
||
<div class="so-kpi-value">¥39.1</div>
|
||
<div class="so-kpi-sub">环比 <span class="up">+2.3%</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 区块1: 订单趋势 -->
|
||
<div class="g-card" style="padding:20px 24px;">
|
||
<div class="so-section-hd">订单趋势</div>
|
||
<div class="so-chart-wrap">
|
||
<svg class="so-chart-svg" viewBox="0 0 700 200" preserveAspectRatio="none">
|
||
<!-- 网格线 -->
|
||
<line x1="40" y1="10" x2="40" y2="170" stroke="#f0f0f0" stroke-width="1"/>
|
||
<line x1="40" y1="170" x2="690" y2="170" stroke="#f0f0f0" stroke-width="1"/>
|
||
<line x1="40" y1="130" x2="690" y2="130" stroke="#f5f5f5" stroke-width="1" stroke-dasharray="4"/>
|
||
<line x1="40" y1="90" x2="690" y2="90" stroke="#f5f5f5" stroke-width="1" stroke-dasharray="4"/>
|
||
<line x1="40" y1="50" x2="690" y2="50" stroke="#f5f5f5" stroke-width="1" stroke-dasharray="4"/>
|
||
<!-- Y轴标签 -->
|
||
<text x="34" y="174" text-anchor="end" font-size="10" fill="#999">100</text>
|
||
<text x="34" y="134" text-anchor="end" font-size="10" fill="#999">200</text>
|
||
<text x="34" y="94" text-anchor="end" font-size="10" fill="#999">300</text>
|
||
<text x="34" y="54" text-anchor="end" font-size="10" fill="#999">400</text>
|
||
<!-- 面积 -->
|
||
<polygon points="87,98 133,106 180,112 226,118 273,130 319,148 366,138 412,78 459,92 505,102 552,96 598,108 645,104 690,100 690,170 87,170"
|
||
fill="url(#soGrad)" opacity="0.15"/>
|
||
<defs>
|
||
<linearGradient id="soGrad" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0%" stop-color="hsl(212,100%,45%)"/>
|
||
<stop offset="100%" stop-color="hsl(212,100%,45%)" stop-opacity="0"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<!-- 折线 -->
|
||
<polyline points="87,98 133,106 180,112 226,118 273,130 319,148 366,138 412,78 459,92 505,102 552,96 598,108 645,104 690,100"
|
||
fill="none" stroke="var(--primary)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round"/>
|
||
<!-- 关键数据点 -->
|
||
<circle cx="319" cy="148" r="4" fill="#fff" stroke="var(--g-danger)" stroke-width="2"/>
|
||
<text x="319" y="164" text-anchor="middle" font-size="10" fill="var(--g-danger)">186</text>
|
||
<circle cx="412" cy="78" r="4" fill="#fff" stroke="var(--g-success)" stroke-width="2"/>
|
||
<text x="412" y="72" text-anchor="middle" font-size="10" fill="var(--g-success)">312</text>
|
||
<circle cx="690" cy="100" r="4" fill="#fff" stroke="var(--primary)" stroke-width="2"/>
|
||
<text x="690" y="94" text-anchor="middle" font-size="10" fill="var(--primary)">248</text>
|
||
<!-- X轴日期 -->
|
||
<text x="87" y="186" text-anchor="middle" font-size="10" fill="#999">1/30</text>
|
||
<text x="180" y="186" text-anchor="middle" font-size="10" fill="#999">2/1</text>
|
||
<text x="273" y="186" text-anchor="middle" font-size="10" fill="#999">2/3</text>
|
||
<text x="319" y="186" text-anchor="middle" font-size="10" fill="#999">2/5</text>
|
||
<text x="412" y="186" text-anchor="middle" font-size="10" fill="#999">2/8</text>
|
||
<text x="505" y="186" text-anchor="middle" font-size="10" fill="#999">2/10</text>
|
||
<text x="645" y="186" text-anchor="middle" font-size="10" fill="#999">2/11</text>
|
||
<text x="690" y="186" text-anchor="middle" font-size="10" fill="#999">2/12</text>
|
||
</svg>
|
||
</div>
|
||
<div class="so-chart-summary">
|
||
<div class="so-chart-stat">日均订单 <strong>244</strong></div>
|
||
<div class="so-chart-stat">峰值 <strong>312</strong>(2/8)</div>
|
||
<div class="so-chart-stat">谷值 <strong>186</strong>(2/5)</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 区块2: 时段分布热力图 -->
|
||
<div class="g-card" style="padding:20px 24px;">
|
||
<div class="so-section-hd">时段分布</div>
|
||
<div class="so-heat-wrap">
|
||
<div class="so-heat-grid" id="heatGrid"></div>
|
||
<div class="so-heat-legend">
|
||
<div class="so-heat-legend-item"><div class="so-heat-legend-dot so-heat-l0"></div>少</div>
|
||
<div class="so-heat-legend-item"><div class="so-heat-legend-dot so-heat-l1"></div>较少</div>
|
||
<div class="so-heat-legend-item"><div class="so-heat-legend-dot so-heat-l2"></div>较多</div>
|
||
<div class="so-heat-legend-item"><div class="so-heat-legend-dot so-heat-l3"></div>多</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 区块3: 渠道对比 -->
|
||
<div class="g-card" style="padding:20px 24px;">
|
||
<div class="so-section-hd">渠道对比</div>
|
||
<div class="so-channel-row">
|
||
<!-- 外卖 -->
|
||
<div class="so-ch-card">
|
||
<div class="so-ch-hd">
|
||
<div class="so-ch-icon waimai"><i data-lucide="bike" style="width:20px;height:20px;"></i></div>
|
||
<div class="so-ch-name">外卖</div>
|
||
<span class="g-tag g-tag-blue" style="margin-left:auto;">主力渠道</span>
|
||
</div>
|
||
<div class="so-ch-metrics">
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">订单数</span><span class="so-ch-metric-val">1,881</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">销售额</span><span class="so-ch-metric-val">¥70,730</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">客单价</span><span class="so-ch-metric-val">¥37.6</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">占比</span><span class="so-ch-metric-val">55%</span></div>
|
||
</div>
|
||
<div class="so-ch-bar-bg"><div class="so-ch-bar-fill waimai" style="width:55%;"></div></div>
|
||
</div>
|
||
<!-- 自提 -->
|
||
<div class="so-ch-card">
|
||
<div class="so-ch-hd">
|
||
<div class="so-ch-icon ziti"><i data-lucide="package" style="width:20px;height:20px;"></i></div>
|
||
<div class="so-ch-name">自提</div>
|
||
</div>
|
||
<div class="so-ch-metrics">
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">订单数</span><span class="so-ch-metric-val">855</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">销售额</span><span class="so-ch-metric-val">¥32,150</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">客单价</span><span class="so-ch-metric-val">¥37.6</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">占比</span><span class="so-ch-metric-val">25%</span></div>
|
||
</div>
|
||
<div class="so-ch-bar-bg"><div class="so-ch-bar-fill ziti" style="width:25%;"></div></div>
|
||
</div>
|
||
<!-- 堂食 -->
|
||
<div class="so-ch-card">
|
||
<div class="so-ch-hd">
|
||
<div class="so-ch-icon tangshi"><i data-lucide="utensils" style="width:20px;height:20px;"></i></div>
|
||
<div class="so-ch-name">堂食</div>
|
||
</div>
|
||
<div class="so-ch-metrics">
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">订单数</span><span class="so-ch-metric-val">684</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">销售额</span><span class="so-ch-metric-val">¥25,720</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">客单价</span><span class="so-ch-metric-val">¥37.6</span></div>
|
||
<div class="so-ch-metric"><span class="so-ch-metric-label">占比</span><span class="so-ch-metric-val">20%</span></div>
|
||
</div>
|
||
<div class="so-ch-bar-bg"><div class="so-ch-bar-fill tangshi" style="width:20%;"></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
/* 快捷日期按钮 */
|
||
function pickQuick(el) {
|
||
el.parentElement.querySelectorAll('.so-quick-btn').forEach(function(b){ b.classList.remove('active'); });
|
||
el.classList.add('active');
|
||
}
|
||
/* 渠道按钮 */
|
||
function pickChannel(el) {
|
||
el.parentElement.querySelectorAll('.so-channel-btn').forEach(function(b){ b.classList.remove('active'); });
|
||
el.classList.add('active');
|
||
}
|
||
|
||
/* 生成热力图 */
|
||
(function(){
|
||
var days = ['周一','周二','周三','周四','周五','周六','周日'];
|
||
var hours = [];
|
||
for(var h=9; h<=22; h++) hours.push(h+':00');
|
||
var grid = document.getElementById('heatGrid');
|
||
// 模拟数据:周末午晚高峰密度高
|
||
var data = [
|
||
[0,0,1,1,2,1,1,0,0,1,2,2,1,0],
|
||
[0,0,1,1,2,1,0,0,0,1,2,1,1,0],
|
||
[0,1,1,2,2,1,1,0,1,2,2,2,1,0],
|
||
[0,0,1,2,2,1,1,0,1,2,3,2,1,0],
|
||
[0,1,2,2,3,2,1,1,2,3,3,2,1,0],
|
||
[1,2,2,3,3,2,2,1,2,3,3,3,2,1],
|
||
[1,2,2,3,3,2,1,1,2,3,3,2,2,1]
|
||
];
|
||
// 表头行
|
||
var blank = document.createElement('div');
|
||
blank.className = 'so-heat-header';
|
||
grid.appendChild(blank);
|
||
hours.forEach(function(h){
|
||
var hd = document.createElement('div');
|
||
hd.className = 'so-heat-header';
|
||
hd.textContent = h;
|
||
grid.appendChild(hd);
|
||
});
|
||
// 数据行
|
||
days.forEach(function(day, di){
|
||
var label = document.createElement('div');
|
||
label.className = 'so-heat-row-label';
|
||
label.textContent = day;
|
||
grid.appendChild(label);
|
||
data[di].forEach(function(v){
|
||
var cell = document.createElement('div');
|
||
cell.className = 'so-heat-cell so-heat-l' + v;
|
||
grid.appendChild(cell);
|
||
});
|
||
});
|
||
})();
|
||
|
||
/* Lucide 图标初始化 */
|
||
if (typeof lucide !== 'undefined') { lucide.createIcons(); }
|
||
</script>
|