Files
aurora-admin/site/scenario/dashboard.html
T
aurora-admin f1fbfc2ddb
Regression / regression (push) Canceled after 0s
feat(品牌标识): 几何 K 图标(favicon/顶栏标记/theme-color) + 并行会话成果入库
## 品牌标识(本次会话)

起因:品牌此前没有任何图形标识 —— 唯一 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 未做部分)
2026-09-21 10:05:48 +08:00

459 lines
27 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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, '&amp;').replace(/</g, '&lt;'); }
/* ── 数据(示范数据,不发起任何请求) ─────────────────── */
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>