Regression / regression (push) Canceled after 0s
## 品牌标识(本次会话) 起因:品牌此前没有任何图形标识 —— 唯一 favicon 是内联 data-URI 里的字母「A」, 那是 v2.0.0「Aurora Admin → Kole UI」改名漏掉的一处(PC 顶栏也是「A」, 移动端站已是「K」;移动端文档站则完全没有 favicon)。 - 几何:24 网格三个互不接触的笔画(竖 + 两斜),圆头描边; 描边 2.25 → 16px 标签页尺寸下正好 1.5px = 规范原文「描边1.5px」 - 取色分两套(刻意):favicon 硬编码品牌蓝/白(渲染在浏览器标签栏,不继承 kole-dark); 顶栏标记走 currentColor(实测暗色下自动转 rgb(20,22,28)) - 新增 theme-color 双条(light #FFFFFF / dark #1C1F26,取 --kole-color-card-bg) - 修 site/app.js hero 标语 KOLE ADMIN → KOLE UI(改名变形残留) - 移动端 7 个模板补 favicon(此前计数 0) 验收:门禁 9 条全 OK(site-routing/site-routes/mobile-docs/mobile-site/isolation/ theme/nav/i18n/icons);PC 回归 1464/1464 · 移动端 807/807,各连跑 8 次一致; 两端 favicon 405 字节逐字节一致;PC 站控制台错误 1→0。 ## 并行会话成果(本次一并入库) - 图标系统:2576 图标(TDesign/Element Plus,MIT)+ 11 端注入 + 5 个构建门禁工具 + IconPreview 预览页 + ICON-SPEC.md 冻结规格 - 移动端平台:47 组件 × 6 端 + 文档站 53 页 + 隔离门禁 - PC 组件:103 个大后台组件 / 组件11 批次 - uni-app:PC 端试点 + 移动端端实现 + 真实编译验证 ## 工程 - .gitignore 补 .scratch/ 与 .zcode-preexisting-*.txt(会话中间产物,实测 9.1MB,不入库) - CHANGELOG 补品牌标识条目 - ROADMAP 登 S8-P4(品牌标识任务包 + og:image/apple-touch-icon 未做部分)
459 lines
27 KiB
HTML
459 lines
27 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>模板 · 数据看板 - Kole UI</title>
|
||
<meta name="description" content="Kole UI 模板页库 · 数据看板:侧边导航 + 指标卡 + 图表面板 + 概览表格,全部视觉来自设计令牌与 components.css。">
|
||
<link rel="stylesheet" href="../../.design_library/kole-ui/colors_and_type.css">
|
||
<link rel="stylesheet" href="../../.design_library/kole-ui/components.css">
|
||
<!-- 扩展组件样式:components.css 只聚合 6 个核心组件;下列组件各自的样式表按需引入 -->
|
||
<link rel="stylesheet" href="../../frameworks/DashboardCard.css">
|
||
<link rel="stylesheet" href="../../frameworks/ChartPanel.css">
|
||
<link rel="stylesheet" href="../../frameworks/ProgressVariants.css">
|
||
<link rel="stylesheet" href="../../frameworks/Segmented.css">
|
||
<link rel="stylesheet" href="../../frameworks/MessagePro.css">
|
||
<link rel="stylesheet" href="../../frameworks/Tag.css">
|
||
<link rel="stylesheet" href="../../frameworks/Pagination.css">
|
||
<style>
|
||
/* 模板页布局:仅排版类样式,组件视觉全部来自 colors_and_type.css 令牌 + components.css */
|
||
* { box-sizing: border-box; }
|
||
body {
|
||
margin: 0; background: var(--kole-color-page-bg);
|
||
font-family: var(--kole-font-family); color: var(--kole-color-text-body);
|
||
font-size: var(--kole-type-body-size); line-height: var(--kole-type-body-height);
|
||
}
|
||
a { color: var(--kole-color-brand); text-decoration: none; }
|
||
a:hover { color: var(--kole-color-brand-hover); }
|
||
|
||
.db-shell { display: grid; grid-template-columns: 220px minmax(0, 1fr); min-height: 100vh; }
|
||
|
||
/* ── 侧边导航 ─────────────────────────────────────────── */
|
||
.db-side {
|
||
background: var(--kole-color-card-bg); border-right: 1px solid var(--kole-color-border);
|
||
padding: var(--kole-space-16); display: flex; flex-direction: column; gap: var(--kole-space-8);
|
||
}
|
||
.db-brand { display: flex; align-items: center; gap: var(--kole-space-8); padding: var(--kole-space-8) 0 var(--kole-space-16); }
|
||
.db-mark {
|
||
width: var(--kole-control-height-default); height: var(--kole-control-height-default);
|
||
border-radius: var(--kole-radius-base); background: var(--kole-color-brand); color: var(--kole-color-text-inverse);
|
||
display: flex; align-items: center; justify-content: center; font-weight: 600; flex-shrink: 0;
|
||
}
|
||
.db-brand-name { font-size: var(--kole-type-h2-size); font-weight: var(--kole-type-h2-weight); color: var(--kole-color-text-title); }
|
||
.db-nav { display: flex; flex-direction: column; gap: var(--kole-space-4); }
|
||
.db-nav-item {
|
||
display: flex; align-items: center; gap: var(--kole-space-8); height: var(--kole-control-height-default);
|
||
padding: 0 var(--kole-space-12); border: none; background: none; border-radius: var(--kole-radius-base);
|
||
color: var(--kole-color-text-body); font-size: var(--kole-type-body-size); font-family: inherit;
|
||
cursor: pointer; text-align: left; width: 100%;
|
||
transition: background var(--kole-duration-fast) var(--kole-ease-standard), color var(--kole-duration-fast) var(--kole-ease-standard);
|
||
}
|
||
.db-nav-item:hover { background: var(--kole-color-brand-bg); }
|
||
.db-nav-item[aria-current="page"] { background: var(--kole-color-brand-bg); color: var(--kole-color-brand); font-weight: var(--kole-type-h2-weight); }
|
||
.db-nav-item svg { width: var(--kole-icon-size-16); height: var(--kole-icon-size-16); flex-shrink: 0; }
|
||
.db-side-foot { margin-top: auto; border-top: 1px solid var(--kole-color-border); padding-top: var(--kole-space-12); display: flex; align-items: center; gap: var(--kole-space-8); }
|
||
.db-avatar {
|
||
width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
|
||
background: var(--kole-color-brand-bg); color: var(--kole-color-brand);
|
||
display: flex; align-items: center; justify-content: center; font-size: var(--kole-type-caption-size); font-weight: 500;
|
||
}
|
||
.db-user { min-width: 0; font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
|
||
.db-user strong { display: block; color: var(--kole-color-text-body); font-size: var(--kole-type-body-size); font-weight: 400; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
|
||
/* ── 主区 ─────────────────────────────────────────────── */
|
||
.db-main { padding: var(--kole-space-24); display: flex; flex-direction: column; gap: var(--kole-space-16); min-width: 0; }
|
||
.db-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--kole-space-16); flex-wrap: wrap; }
|
||
.db-title { margin: 0; font-size: var(--kole-type-display-size); line-height: var(--kole-type-display-height); font-weight: var(--kole-type-display-weight); color: var(--kole-color-text-title); }
|
||
.db-sub { margin: var(--kole-space-4) 0 0; font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
|
||
|
||
/* 指标卡:复用 DashboardCard 组件样式 .kole-dashcard */
|
||
.db-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--kole-space-16); }
|
||
.db-dashcard-value { font-family: var(--kole-font-family-num); font-variant-numeric: tabular-nums; }
|
||
|
||
/* 图表与表格并排:宽屏两列,窄屏单列 */
|
||
.db-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: var(--kole-space-16); align-items: start; }
|
||
|
||
/* 趋势图:柱状 + 折线,纯 CSS/SVG 绘制,数据由脚本写入 */
|
||
.db-chart { display: flex; flex-direction: column; gap: var(--kole-space-8); }
|
||
.db-chart-svg { width: 100%; height: 180px; display: block; overflow: visible; }
|
||
.db-chart-axis { display: flex; justify-content: space-between; font-size: var(--kole-type-caption-size); color: var(--kole-color-text-placeholder); font-family: var(--kole-font-family-num); }
|
||
.db-chart-legend { display: flex; gap: var(--kole-space-16); font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
|
||
.db-chart-legend span { display: inline-flex; align-items: center; gap: var(--kole-space-4); }
|
||
.db-dot { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
|
||
.db-dot-brand { background: var(--kole-color-brand); }
|
||
.db-dot-info { background: var(--kole-color-info); }
|
||
|
||
/* 表格容器:横向可滚,避免窄屏溢出 */
|
||
.db-tablewrap { overflow-x: auto; overscroll-behavior-x: contain; }
|
||
.db-tablewrap .tbl { min-width: 520px; }
|
||
.db-num { font-family: var(--kole-font-family-num); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||
.db-cell-strong { color: var(--kole-color-text-title); font-weight: 500; }
|
||
.db-truncate { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: bottom; }
|
||
.db-cardhead { display: flex; align-items: center; justify-content: space-between; gap: var(--kole-space-8); margin-bottom: var(--kole-space-12); }
|
||
|
||
/* 进度条:复用 ProgressVariants 组件样式 */
|
||
.db-progress-row { display: flex; flex-direction: column; gap: var(--kole-space-12); }
|
||
.db-progress-item { display: grid; grid-template-columns: 72px minmax(0, 1fr) 44px; gap: var(--kole-space-8); align-items: center; font-size: var(--kole-type-caption-size); }
|
||
.db-progress-item .label { color: var(--kole-color-text-secondary); }
|
||
.db-progress-item .pct { text-align: right; font-family: var(--kole-font-family-num); color: var(--kole-color-text-body); }
|
||
|
||
.db-empty { display: flex; align-items: center; justify-content: center; min-height: 140px; }
|
||
|
||
@media (max-width: 1080px) { .db-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } .db-grid { grid-template-columns: minmax(0, 1fr); } }
|
||
@media (max-width: 860px) {
|
||
.db-shell { grid-template-columns: minmax(0, 1fr); }
|
||
.db-side { border-right: none; border-bottom: 1px solid var(--kole-color-border); }
|
||
.db-nav { flex-direction: row; flex-wrap: wrap; }
|
||
.db-nav-item { width: auto; }
|
||
.db-side-foot { display: none; }
|
||
}
|
||
@media (max-width: 560px) { .db-metrics { grid-template-columns: minmax(0, 1fr); } }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="db-shell">
|
||
<aside class="db-side">
|
||
<div class="db-brand">
|
||
<span class="db-mark">K</span>
|
||
<span class="db-brand-name">Kole UI</span>
|
||
</div>
|
||
<nav class="db-nav" aria-label="主导航">
|
||
<button class="db-nav-item" type="button" aria-current="page">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="9" rx="1"/><rect x="14" y="3" width="7" height="5" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/><rect x="3" y="16" width="7" height="5" rx="1"/></svg>
|
||
<span>工作台</span>
|
||
</button>
|
||
<button class="db-nav-item" type="button">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>
|
||
<span>订单管理</span>
|
||
</button>
|
||
<button class="db-nav-item" type="button">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
||
<span>客户管理</span>
|
||
</button>
|
||
<button class="db-nav-item" type="button">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||
<span>系统设置</span>
|
||
</button>
|
||
</nav>
|
||
<div class="db-side-foot">
|
||
<span class="db-avatar">林</span>
|
||
<span class="db-user"><strong>林晚舟</strong>运营管理员</span>
|
||
</div>
|
||
</aside>
|
||
|
||
<main class="db-main">
|
||
<div class="db-head">
|
||
<div>
|
||
<h1 class="db-title">工作台</h1>
|
||
<p class="db-sub">数据截至 2026-09-20 09:30 · 模板页库示范数据</p>
|
||
</div>
|
||
<div style="display:flex; gap:8px; align-items:center;">
|
||
<div class="kole-segmented" role="group" aria-label="时间范围" id="db-range">
|
||
<button class="kole-segmented-item is-active" type="button" data-range="7">近 7 天</button>
|
||
<button class="kole-segmented-item" type="button" data-range="30">近 30 天</button>
|
||
<button class="kole-segmented-item is-disabled" type="button" data-range="90" aria-disabled="true">近 90 天</button>
|
||
</div>
|
||
<button class="btn btn-default btn-md" type="button" id="db-refresh">刷新</button>
|
||
<button class="btn btn-primary btn-md" type="button" id="db-export">导出报表</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 指标卡:DashboardCard 组件样式 -->
|
||
<div class="db-metrics">
|
||
<div class="kole-dashcard">
|
||
<div class="kole-dashcard-head"><span class="kole-dashcard-title">订单总额</span><span class="kole-dashcard-icon">¥</span></div>
|
||
<div class="kole-dashcard-value db-dashcard-value" id="db-m1">0</div>
|
||
<div class="kole-dashcard-trend up" id="db-m1-t">↑ 0% 较上周期</div>
|
||
</div>
|
||
<div class="kole-dashcard">
|
||
<div class="kole-dashcard-head"><span class="kole-dashcard-title">订单数</span><span class="kole-dashcard-icon">📦</span></div>
|
||
<div class="kole-dashcard-value db-dashcard-value" id="db-m2">0</div>
|
||
<div class="kole-dashcard-trend up" id="db-m2-t">↑ 0% 较上周期</div>
|
||
</div>
|
||
<div class="kole-dashcard">
|
||
<div class="kole-dashcard-head"><span class="kole-dashcard-title">新增客户</span><span class="kole-dashcard-icon">👥</span></div>
|
||
<div class="kole-dashcard-value db-dashcard-value" id="db-m3">0</div>
|
||
<div class="kole-dashcard-trend up" id="db-m3-t">↑ 0% 较上周期</div>
|
||
</div>
|
||
<div class="kole-dashcard">
|
||
<div class="kole-dashcard-head"><span class="kole-dashcard-title">退款率</span><span class="kole-dashcard-icon">↩️</span></div>
|
||
<div class="kole-dashcard-value db-dashcard-value" id="db-m4">0</div>
|
||
<div class="kole-dashcard-trend down" id="db-m4-t">↑ 0% 需关注</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="db-grid">
|
||
<!-- 图表面板:ChartPanel 组件样式 -->
|
||
<div class="kole-chartpanel" id="db-panel">
|
||
<div class="kole-chartpanel-head">
|
||
<span class="kole-chartpanel-title">下单趋势</span>
|
||
<div class="kole-chartpanel-tools">
|
||
<button class="kole-chartpanel-tool" type="button" id="db-panel-toggle" aria-expanded="true">收起</button>
|
||
</div>
|
||
</div>
|
||
<div class="kole-chartpanel-body">
|
||
<div class="db-chart">
|
||
<div class="db-chart-legend">
|
||
<span><i class="db-dot db-dot-brand"></i>订单数</span>
|
||
<span><i class="db-dot db-dot-info"></i>成交额(万元)</span>
|
||
</div>
|
||
<svg class="db-chart-svg" id="db-svg" viewBox="0 0 720 180" preserveAspectRatio="none" role="img" aria-label="近 7 天下单趋势折线图"></svg>
|
||
<div class="db-chart-axis" id="db-axis"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 渠道占比:进度条用 ProgressVariants 组件样式 -->
|
||
<div class="card card-bordered card-p16">
|
||
<div class="db-cardhead">
|
||
<span class="card-title">渠道占比</span>
|
||
<a class="card-link" href="order-list.html">查看订单 →</a>
|
||
</div>
|
||
<div class="db-progress-row" id="db-channels"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 待办表格 -->
|
||
<div class="card card-bordered card-p16">
|
||
<div class="db-cardhead">
|
||
<span class="card-title">待处理事项</span>
|
||
<span style="font-size:var(--kole-type-caption-size);color:var(--kole-color-text-secondary)" id="db-todo-count"></span>
|
||
</div>
|
||
<div class="db-tablewrap">
|
||
<table class="tbl">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:150px">单据号</th>
|
||
<th>事项</th>
|
||
<th style="width:110px">提交人</th>
|
||
<th style="width:120px">金额</th>
|
||
<th style="width:96px">状态</th>
|
||
<th style="width:104px">提交时间</th>
|
||
<th style="width:88px">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="db-tbody"></tbody>
|
||
</table>
|
||
</div>
|
||
<div style="display:flex; align-items:center; justify-content:space-between; gap:var(--kole-space-12); margin-top:var(--kole-space-12); flex-wrap:wrap;">
|
||
<span class="kole-pagination-desc" id="db-page-desc"></span>
|
||
<div class="kole-pagination">
|
||
<div class="kole-pagination-pager" id="db-pager" role="group" aria-label="分页"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<p style="margin:0; font-size:var(--kole-type-caption-size); color:var(--kole-color-text-secondary)">
|
||
模板页库 · 全部视觉来自 <a href="../../.design_library/kole-ui/colors_and_type.css">设计令牌</a> 与
|
||
<a href="../../.design_library/kole-ui/components.css">components.css</a>;
|
||
<a href="../index.html">← 返回组件文档</a>
|
||
</p>
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
'use strict';
|
||
var num = function (n) { return n.toLocaleString('zh-CN'); };
|
||
function esc(s) { return String(s).replace(/&/g, '&').replace(/</g, '<'); }
|
||
|
||
/* ── 数据(示范数据,不发起任何请求) ─────────────────── */
|
||
var RANGES = {
|
||
7: { total: 3862400, orders: 1284, customers: 46, refund: 2.3, delta: [12.5, 8.2, -3.1, 0.4],
|
||
chart: [168, 205, 182, 240, 216, 268, 294], axis: ['09-14','09-15','09-16','09-17','09-18','09-19','09-20'], amount: [42, 51, 46, 60, 54, 67, 74] },
|
||
30: { total: 15248000, orders: 5126, customers: 183, refund: 1.9, delta: [9.4, 6.7, 5.2, -0.6],
|
||
chart: [602, 688, 641, 725, 697, 742, 811], axis: ['09-01','09-04','09-08','09-12','09-15','09-18','09-20'], amount: [158, 176, 168, 192, 184, 199, 214] }
|
||
};
|
||
var CHANNELS = [
|
||
{ label: '直销', pct: 42 },
|
||
{ label: '渠道商', pct: 28 },
|
||
{ label: '线上商城', pct: 19 },
|
||
{ label: '其他', pct: 11 }
|
||
];
|
||
var TODO = [
|
||
{ id: 'SO-20260920-014', title: '华信精密制造 · 合同金额复核', who: '王建国', amount: 128600, status: '待审核', sk: 'orange', time: '09:24' },
|
||
{ id: 'SO-20260920-013', title: '蓝海贸易集团 · 折扣申请', who: '李慧敏', amount: 56320, status: '处理中', sk: '', time: '08:47' },
|
||
{ id: 'SO-20260919-042', title: '云帆科技股份 · 发票信息变更', who: '陈志远', amount: 89750, status: '待审核', sk: 'orange', time: '昨天 17:36' },
|
||
{ id: 'SO-20260919-038', title: '恒达物流有限 · 收货地址修改', who: '赵丽华', amount: 23480, status: '已完成', sk: 'green', time: '昨天 15:02' },
|
||
{ id: 'SO-20260919-030', title: '中科智联电子 · 大额订单复核', who: '孙浩然', amount: 312900, status: '处理中', sk: '', time: '昨天 11:36' },
|
||
{ id: 'SO-20260918-027', title: '新锐传媒文化 · 退单申请', who: '周晓彤', amount: 45120, status: '已驳回', sk: 'red', time: '09-18 09:52' },
|
||
{ id: 'SO-20260918-019', title: '天工重工机械 · 分期付款确认', who: '吴书禾', amount: 176400, status: '已完成', sk: 'green', time: '09-18 09:11' },
|
||
{ id: 'SO-20260917-052', title: '瑞丰生物科技 · 资质补传', who: '郑一鸣', amount: 67890, status: '待审核', sk: 'orange', time: '09-17 16:29' }
|
||
];
|
||
var TAG_CLASS = { green: 'kole-tag kole-tag-green', red: 'kole-tag kole-tag-red', orange: 'kole-tag kole-tag-orange', '': 'kole-tag kole-tag-gray' };
|
||
|
||
/* ── 指标卡 ───────────────────────────────────────────── */
|
||
function renderMetrics(key) {
|
||
var d = RANGES[key];
|
||
document.getElementById('db-m1').textContent = '¥' + num(d.total);
|
||
document.getElementById('db-m2').textContent = num(d.orders);
|
||
document.getElementById('db-m3').textContent = num(d.customers);
|
||
document.getElementById('db-m4').textContent = d.refund + '%';
|
||
[1, 2, 3, 4].forEach(function (i) {
|
||
var el = document.getElementById('db-m' + i + '-t');
|
||
var v = d.delta[i - 1];
|
||
var up = v >= 0;
|
||
/* 退款率上升是坏消息:方向与语义色由业务决定,不跟数值正负绑定 */
|
||
var good = (i === 4) ? !up : up;
|
||
el.className = 'kole-dashcard-trend ' + (good ? 'up' : 'down');
|
||
el.textContent = (up ? '↑ ' : '↓ ') + Math.abs(v) + '% ' + (i === 4 ? (up ? '需关注' : '环比改善') : '较上周期');
|
||
});
|
||
}
|
||
|
||
/* ── 趋势图:柱状 + 折线,纯 SVG 绘制 ─────────────────── */
|
||
function renderChart(key) {
|
||
var d = RANGES[key];
|
||
var W = 720, H = 180, PAD = 8;
|
||
var max = Math.max.apply(null, d.chart) * 1.12;
|
||
var step = (W - PAD * 2) / d.chart.length;
|
||
var bw = Math.min(40, step * 0.44);
|
||
var parts = [];
|
||
|
||
/* 基线 */
|
||
parts.push('<line x1="0" y1="' + (H - PAD) + '" x2="' + W + '" y2="' + (H - PAD) + '" stroke="var(--kole-color-border)" stroke-width="1"/>');
|
||
|
||
d.chart.forEach(function (v, i) {
|
||
var h = (v / max) * (H - PAD * 2);
|
||
var x = PAD + step * i + (step - bw) / 2;
|
||
parts.push('<rect x="' + x.toFixed(1) + '" y="' + (H - PAD - h).toFixed(1) + '" width="' + bw.toFixed(1) +
|
||
'" height="' + h.toFixed(1) + '" rx="3" fill="var(--kole-color-brand)" opacity="0.16"/>');
|
||
});
|
||
|
||
var maxAmt = Math.max.apply(null, d.amount) * 1.12;
|
||
var pts = d.amount.map(function (v, i) {
|
||
return (PAD + step * i + step / 2).toFixed(1) + ',' + (H - PAD - (v / maxAmt) * (H - PAD * 2)).toFixed(1);
|
||
});
|
||
parts.push('<polyline points="' + pts.join(' ') + '" fill="none" stroke="var(--kole-color-info)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>');
|
||
pts.forEach(function (p) {
|
||
var xy = p.split(',');
|
||
parts.push('<circle cx="' + xy[0] + '" cy="' + xy[1] + '" r="3.5" fill="var(--kole-color-card-bg)" stroke="var(--kole-color-info)" stroke-width="2"/>');
|
||
});
|
||
|
||
var svg = document.getElementById('db-svg');
|
||
svg.innerHTML = parts.join('');
|
||
svg.setAttribute('aria-label', '订单数柱状与成交额折线趋势图,共 ' + d.chart.length + ' 个数据点,数据见下方表格');
|
||
document.getElementById('db-axis').innerHTML = d.axis.map(function (t) { return '<span>' + esc(t) + '</span>'; }).join('');
|
||
}
|
||
|
||
/* ── 渠道占比(进度条) ───────────────────────────────── */
|
||
function renderChannels() {
|
||
document.getElementById('db-channels').innerHTML = CHANNELS.map(function (c) {
|
||
return '<div class="db-progress-item">' +
|
||
'<span class="label">' + esc(c.label) + '</span>' +
|
||
'<span class="kole-progress" role="progressbar" aria-valuenow="' + c.pct + '" aria-valuemin="0" aria-valuemax="100" aria-label="' + esc(c.label) + '占比">' +
|
||
'<span class="kole-progress-line-wrap">' +
|
||
'<span class="kole-progress-line"><span class="kole-progress-line-fill" style="width:' + c.pct + '%; display:block"></span></span>' +
|
||
'</span>' +
|
||
'</span>' +
|
||
'<span class="pct">' + c.pct + '%</span>' +
|
||
'</div>';
|
||
}).join('');
|
||
}
|
||
|
||
/* ── 待办表格 + 分页 ──────────────────────────────────── */
|
||
var page = 1, SIZE = 5;
|
||
function renderTable() {
|
||
var pages = Math.max(1, Math.ceil(TODO.length / SIZE));
|
||
if (page > pages) page = pages;
|
||
var slice = TODO.slice((page - 1) * SIZE, page * SIZE);
|
||
var tbody = document.getElementById('db-tbody');
|
||
tbody.innerHTML = '';
|
||
slice.forEach(function (r) {
|
||
var tr = document.createElement('tr');
|
||
tr.innerHTML =
|
||
'<td class="db-num">' + esc(r.id) + '</td>' +
|
||
'<td><span class="db-cell-strong db-truncate" title="' + esc(r.title) + '">' + esc(r.title) + '</span></td>' +
|
||
'<td>' + esc(r.who) + '</td>' +
|
||
'<td class="db-num">¥' + num(r.amount) + '</td>' +
|
||
'<td><span class="' + TAG_CLASS[r.sk] + '">' + esc(r.status) + '</span></td>' +
|
||
'<td class="db-num">' + esc(r.time) + '</td>' +
|
||
'<td><a href="order-list.html">查看</a></td>';
|
||
tbody.appendChild(tr);
|
||
});
|
||
document.getElementById('db-todo-count').textContent = '共 ' + TODO.length + ' 条';
|
||
document.getElementById('db-page-desc').textContent = '第 ' + page + ' / ' + pages + ' 页';
|
||
|
||
var pager = document.getElementById('db-pager');
|
||
pager.innerHTML = '';
|
||
function mk(label, target, opts) {
|
||
var b = document.createElement('button');
|
||
b.type = 'button';
|
||
b.className = 'kole-pagination-page' + (opts && opts.current ? ' is-current' : '');
|
||
b.textContent = label;
|
||
if (opts && opts.disabled) { b.disabled = true; b.style.opacity = '.55'; b.style.cursor = 'not-allowed'; }
|
||
if (opts && opts.current) b.setAttribute('aria-current', 'page');
|
||
b.addEventListener('click', function () { if (!(opts && opts.disabled) && !(opts && opts.current)) { page = target; renderTable(); } });
|
||
pager.appendChild(b);
|
||
}
|
||
mk('上一页', page - 1, { disabled: page === 1 });
|
||
for (var p = 1; p <= pages; p++) mk(String(p), p, { current: p === page });
|
||
mk('下一页', page + 1, { disabled: page === pages });
|
||
}
|
||
|
||
/* ── 交互 ─────────────────────────────────────────────── */
|
||
var rangeEl = document.getElementById('db-range');
|
||
rangeEl.addEventListener('click', function (e) {
|
||
var btn = e.target.closest('.kole-segmented-item');
|
||
if (!btn || btn.classList.contains('is-disabled')) return;
|
||
rangeEl.querySelectorAll('.kole-segmented-item').forEach(function (b) { b.classList.remove('is-active'); });
|
||
btn.classList.add('is-active');
|
||
var key = btn.getAttribute('data-range');
|
||
renderMetrics(key);
|
||
renderChart(key);
|
||
page = 1;
|
||
renderTable();
|
||
flash('已切换到' + btn.textContent.trim() + '数据');
|
||
});
|
||
|
||
var panel = document.getElementById('db-panel');
|
||
var panelToggle = document.getElementById('db-panel-toggle');
|
||
panelToggle.addEventListener('click', function () {
|
||
var collapsed = panel.classList.toggle('is-collapsed');
|
||
panelToggle.textContent = collapsed ? '展开' : '收起';
|
||
panelToggle.setAttribute('aria-expanded', String(!collapsed));
|
||
});
|
||
|
||
var msgWrap = null, msgTimer = null;
|
||
function flash(text) {
|
||
if (!msgWrap) {
|
||
msgWrap = document.createElement('div');
|
||
msgWrap.className = 'kole-message-wrap';
|
||
msgWrap.setAttribute('role', 'status');
|
||
msgWrap.setAttribute('aria-live', 'polite');
|
||
document.body.appendChild(msgWrap);
|
||
}
|
||
msgWrap.innerHTML = '<div class="kole-message is-success"><span class="kole-message-icon">✓</span>' +
|
||
'<span class="kole-message-content">' + esc(text) + '</span></div>';
|
||
clearTimeout(msgTimer);
|
||
msgTimer = setTimeout(function () { msgWrap.innerHTML = ''; }, 1800);
|
||
}
|
||
|
||
document.getElementById('db-refresh').addEventListener('click', function () {
|
||
/* 刷新:按时间范围重新计算,指标轻微浮动以体现「有反馈」 */
|
||
var key = rangeEl.querySelector('.is-active').getAttribute('data-range');
|
||
RANGES[key].orders += Math.round(Math.random() * 8);
|
||
renderMetrics(key);
|
||
renderTable();
|
||
flash('数据已刷新');
|
||
});
|
||
document.getElementById('db-export').addEventListener('click', function () {
|
||
var btn = this;
|
||
btn.disabled = true;
|
||
btn.textContent = '导出中…';
|
||
setTimeout(function () {
|
||
btn.disabled = false;
|
||
btn.textContent = '导出报表';
|
||
flash('报表已生成(示范交互,未产生文件)');
|
||
}, 800);
|
||
});
|
||
|
||
/* ── 键盘可达:图表折叠按钮与分段控件可 Tab 到 ────────── */
|
||
renderMetrics('7');
|
||
renderChart('7');
|
||
renderChannels();
|
||
renderTable();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|