Files
youzan-datahub/dashboard-ui/index.html

247 lines
15 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>餐饮零售数据中台 | 核心引擎</title>
<!-- System font stack for Apple-like Typography (no external CDN dependency) -->
<link rel="stylesheet" href="styles.css">
<!-- ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
</head>
<body>
<div class="app-container">
<!-- Sidebar Navigation -->
<aside class="sidebar">
<div class="logo">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
<span>DataHub Core</span>
</div>
<nav class="nav-menu">
<a href="#" class="nav-item active">大盘总览</a>
<a href="#" class="nav-item">商品洞察</a>
<a href="#" class="nav-item">会员画像</a>
<a href="#" class="nav-item">订货建议</a>
<a href="#" class="nav-item">运维管理</a>
</nav>
</aside>
<!-- Main Content -->
<main class="main-content">
<header class="top-nav">
<div class="page-title-row">
<h1 id="page-title">经营数据大盘概览</h1>
<span id="data-cutoff-badge" class="data-cutoff-badge">计算数据截止至 —</span>
</div>
<div class="header-actions">
<button class="btn-refresh" onclick="fetchData()">刷新数据</button>
<div class="user-profile">
<img src="https://ui-avatars.com/api/?name=Admin&background=000&color=fff" alt="Admin">
</div>
</div>
</header>
<!-- Page 1: 大盘总览 -->
<div id="page-overview" class="page-section active">
<div class="dashboard-grid">
<!-- Overview Cards -->
<div class="metrics-row">
<div class="glass-card metric-card">
<h3>过去14天总营收 <span class="info-icon" data-tooltip="SUM(实付金额), 仅统计 TRADE_SUCCESS 状态的订单, 时间范围: 近14天按 pay_time 筛选"></span></h3>
<div class="value" id="revenue-val">¥0.00</div>
<div class="trend positive"><span></span> 实时</div>
</div>
<div class="glass-card metric-card">
<h3>过去14天订单数 <span class="info-icon" data-tooltip="COUNT(DISTINCT tid), 近14天内有 pay_time 的不重复订单号数量"></span></h3>
<div class="value" id="orders-val">0</div>
<div class="trend positive"><span></span> 实时</div>
</div>
<div class="glass-card metric-card">
<h3>平均客单价 (ATV) <span class="info-icon" data-tooltip="= 过去14天总营收 ÷ 过去14天订单数, 每笔订单的平均消费金额"></span></h3>
<div class="value" id="atv-val">¥0.00</div>
<div class="trend neutral">稳定</div>
</div>
<div class="glass-card metric-card">
<h3>过去14天退款额 <span class="info-icon" data-tooltip="SUM(refund_fee), 近14天内创建的退款单退款金额总计"></span></h3>
<div class="value" id="refund-val">¥0.00</div>
<div class="trend negative"><span></span> 风控监测中</div>
</div>
</div>
<!-- Charts Area -->
<div class="charts-row">
<div class="glass-card chart-container">
<div class="chart-header">
<h2>14天营收曲线 (Sales Trend) <span class="info-icon" data-tooltip="X轴=日期, 蓝线=当日SUM(payment), 红虚线=当日COUNT(DISTINCT tid), 按 pay_time 分组"></span></h2>
</div>
<div id="trendChart" style="width: 100%; height: 350px;"></div>
</div>
</div>
</div>
</div>
<!-- Page 2: 商品洞察 -->
<div id="page-product" class="page-section" style="display: none;">
<div class="dashboard-grid">
<div class="glass-card chart-container">
<div class="chart-header">
<h2>商品复购率与波士顿矩阵 <span class="info-icon" data-tooltip="每日洞察计算任务生成, 统计各商品的购买/复购人数"></span></h2>
<div class="segment-control" id="repurchase-period">
<button class="segment-btn" data-days="7">7天</button>
<button class="segment-btn" data-days="15">15天</button>
<button class="segment-btn active" data-days="30">30天</button>
</div>
</div>
<div class="table-responsive">
<table class="data-table" id="repurchase-table">
<thead>
<tr>
<th>商品名称</th>
<th id="th-buyer-count">购买人数 <span class="info-icon info-icon-sm" data-tooltip="COUNT(DISTINCT yz_open_id), 该周期内购买过该商品的不重复客户数"></span></th>
<th id="th-repurchase-count">复购人数 <span class="info-icon info-icon-sm" data-tooltip="该周期内购买该商品≥2次的客户数"></span></th>
<th>复购率 <span class="info-icon info-icon-sm" data-tooltip="= 复购人数 ÷ 购买人数 × 100%"></span></th>
<th>波士顿矩阵打标 <span class="info-icon info-icon-sm" data-tooltip="购买人数高+复购率高=核心引流爆款; 购买人数高+复购率低=体验差需淘汰; 购买人数低+复购率高=小众潜力款; 其他=平庸款"></span></th>
</tr>
</thead>
<tbody>
<tr><td colspan="5" class="text-center">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
<div class="glass-card chart-container">
<div class="chart-header">
<h2>购物篮热门连带趋势 (Apriori Top20) <span class="info-icon" data-tooltip="Apriori关联规则挖掘, 基于近30天同一订单(tid)内共同出现的商品对"></span></h2>
</div>
<div class="table-responsive">
<table class="data-table" id="basket-table">
<thead>
<tr>
<th>核心商品 A</th>
<th>连带商品 B</th>
<th>共同出现订单数 <span class="info-icon info-icon-sm" data-tooltip="在同一笔订单中同时购买A和B的订单数"></span></th>
<th>搭配置信度 <span class="info-icon info-icon-sm" data-tooltip="= 同时购买A和B的订单数 ÷ 购买A的订单数 × 100%, 即买了A的人有多大概率也买B"></span></th>
</tr>
</thead>
<tbody>
<tr><td colspan="4" class="text-center">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Page 3: 会员画像 -->
<div id="page-customer" class="page-section" style="display: none;">
<div class="dashboard-grid">
<div class="metrics-row" id="rfm-cards">
<!-- RFM Cards rendered via JS -->
</div>
<div class="glass-card chart-container">
<div class="chart-header">
<h2>全域会员标签分布 <span class="info-icon" data-tooltip="基于 RFM 模型对客户分群打标后, 各标签的人数分布饼图"></span></h2>
</div>
<div id="tagChart" style="width: 100%; height: 350px;"></div>
</div>
</div>
</div>
<!-- Page 4: 订货建议 -->
<div id="page-advice" class="page-section" style="display: none;">
<div class="glass-card chart-container">
<div class="chart-header">
<h2>次日智能安全备货单 (过去14天流速推断) <span class="info-icon" data-tooltip="基于近14天每日平均销量(日均流速), 计算3天安全备货量"></span></h2>
</div>
<div class="table-responsive">
<table class="data-table" id="advice-table">
<thead>
<tr>
<th>商品名称</th>
<th>14天总销量 <span class="info-icon info-icon-sm" data-tooltip="近14天该商品的订单明细数量合计 (件数)"></span></th>
<th>日均流速 <span class="info-icon info-icon-sm" data-tooltip="= 14天总销量 ÷ 14, 平均每天销售几件"></span></th>
<th>建议安全补货量 (3天量) <span class="info-icon info-icon-sm" data-tooltip="= CEIL(日均流速 × 3), 向上取整确保安全库存"></span></th>
</tr>
</thead>
<tbody>
<tr><td colspan="4" class="text-center">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Page 5: 运维管理 -->
<div id="page-ops" class="page-section" style="display: none;">
<div class="dashboard-grid">
<div class="glass-card chart-container">
<div class="chart-header">
<h2>数据同步 & 洞察计算 手动触发</h2>
</div>
<p style="color: #86868b; margin: 0 0 1.5rem 0; font-size: 0.9rem;">
以下操作与每日定时任务相同,点击后将实时执行并返回结果。执行耗时视数据量而定,请耐心等待。
</p>
<!-- 日期选择器: 订单/退款同步可选起始日期 -->
<div class="ops-date-row">
<label for="ops-from-date" class="ops-date-label">指定起始日期</label>
<input type="date" id="ops-from-date" class="ops-date-input" />
<span class="ops-date-hint">留空 = 自动检测缺口 (智能模式)</span>
</div>
<div class="ops-grid">
<button class="ops-btn" onclick="triggerOps('sync-orders', this)">
<span class="ops-icon">📦</span>
<span class="ops-label">订单同步</span>
<span class="ops-desc">智能增量 / 指定日期</span>
</button>
<button class="ops-btn" onclick="triggerOps('sync-refunds', this)">
<span class="ops-icon">💰</span>
<span class="ops-label">退款同步</span>
<span class="ops-desc">智能增量 / 指定日期</span>
</button>
<button class="ops-btn" onclick="triggerOps('sync-items', this)">
<span class="ops-icon">🍱</span>
<span class="ops-label">商品同步</span>
<span class="ops-desc">全量商品目录</span>
</button>
<button class="ops-btn" onclick="triggerOps('sync-stores', this)">
<span class="ops-icon">🏪</span>
<span class="ops-label">门店同步</span>
<span class="ops-desc">门店与网点</span>
</button>
<button class="ops-btn" onclick="triggerOps('sync-inventory', this)">
<span class="ops-icon">📊</span>
<span class="ops-label">库存快照</span>
<span class="ops-desc">各门店库存</span>
</button>
<button class="ops-btn" onclick="triggerOps('sync-customers', this)">
<span class="ops-icon">👥</span>
<span class="ops-label">客户聚合</span>
<span class="ops-desc">订单驱动聚合</span>
</button>
<button class="ops-btn ops-btn-accent" onclick="triggerOps('compute-insights', this)">
<span class="ops-icon">🧠</span>
<span class="ops-label">洞察计算</span>
<span class="ops-desc">RFM+复购+购物篮</span>
</button>
</div>
<div class="ops-log-container">
<h3 style="margin: 0 0 0.5rem 0;">执行日志</h3>
<div id="ops-log" class="ops-log"><span class="log-entry log-placeholder"><span class="log-time"></span>等待操作...</span></div>
</div>
</div>
</div>
</div>
</main>
</div>
<script src="app.js"></script>
</body>
</html>