Files
aurora-admin/site/scenario/order-list.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

622 lines
31 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/Pagination.css">
<link rel="stylesheet" href="../../frameworks/MessagePro.css">
<link rel="stylesheet" href="../../frameworks/EmptyPro.css">
<link rel="stylesheet" href="../../frameworks/Tag.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); }
.ol-topbar {
height: 56px; background: var(--kole-color-card-bg); border-bottom: 1px solid var(--kole-color-border);
display: flex; align-items: center; gap: var(--kole-space-16); padding: 0 var(--kole-space-24);
position: sticky; top: 0; z-index: 20;
}
.ol-mark {
width: 28px; height: 28px; border-radius: var(--kole-radius-large);
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;
}
.ol-brand { font-size: var(--kole-type-h2-size); font-weight: var(--kole-type-h2-weight); color: var(--kole-color-text-title); }
.ol-topnav { margin-left: auto; display: flex; gap: var(--kole-space-20); font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
.ol-topnav a { color: var(--kole-color-text-secondary); }
.ol-topnav a[aria-current="page"] { color: var(--kole-color-brand); font-weight: 500; }
.ol-main { max-width: 1280px; margin: 0 auto; padding: var(--kole-space-24); display: flex; flex-direction: column; gap: var(--kole-space-16); }
.ol-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--kole-space-16); flex-wrap: wrap; }
.ol-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); }
.ol-sub { margin: var(--kole-space-4) 0 0; font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
.ol-head-actions { display: flex; gap: var(--kole-space-8); flex-wrap: wrap; }
/* 筛选区 */
.ol-filter { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)) auto; gap: var(--kole-space-12); align-items: end; }
.ol-filter .field { width: 100%; }
.ol-filter .field > label { font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
.ol-filter .kole-input { width: 100%; }
.ol-filter .kole-input input { flex: 1; min-width: 0; }
/* 表格 */
.ol-tablewrap { overflow-x: auto; overscroll-behavior-x: contain; background: var(--kole-color-card-bg); }
.ol-tablewrap .tbl { min-width: 960px; }
.ol-num { font-family: var(--kole-font-family-num); font-variant-numeric: tabular-nums; }
.ol-strong { color: var(--kole-color-text-title); font-weight: 500; }
.ol-truncate { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: bottom; }
.ol-actions { display: flex; gap: var(--kole-space-8); justify-content: flex-end; }
.ol-actions .btn-link { min-width: auto; }
.ol-cust { display: inline-flex; align-items: center; gap: var(--kole-space-8); }
.ol-avatar {
width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
background: var(--kole-color-brand-bg); color: var(--kole-color-brand);
display: inline-flex; align-items: center; justify-content: center;
font-size: var(--kole-type-caption-size); font-weight: 500;
}
/* 底部:总数 + 每页条数 + 分页 */
.ol-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--kole-space-12); padding: var(--kole-space-12) var(--kole-space-16); flex-wrap: wrap; border-top: 1px solid var(--kole-color-border); }
.ol-foot-left { display: flex; align-items: center; gap: var(--kole-space-12); font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
.ol-foot-left select {
height: var(--kole-control-height-small); border: 1px solid var(--kole-color-border);
border-radius: var(--kole-radius-base); background: var(--kole-color-card-bg);
color: var(--kole-color-text-body); font-family: inherit; font-size: var(--kole-type-caption-size);
padding: 0 var(--kole-space-4); cursor: pointer;
}
/* 批量操作条:复用 components.css 的 .batchbar */
.ol-batchbar { display: none; }
.ol-batchbar.is-open { display: flex; }
.ol-batchbar .count strong { color: var(--kole-color-brand); font-family: var(--kole-font-family-num); }
.ol-batchbar .spacer { flex: 1; }
/* 详情抽屉 */
.ol-mask {
position: fixed; inset: 0; background: var(--kole-color-mask);
display: none; justify-content: flex-end; z-index: 100;
}
.ol-mask.is-open { display: flex; }
.ol-drawer {
width: min(480px, 100%); height: 100%; background: var(--kole-color-card-bg);
box-shadow: var(--kole-shadow-high); display: flex; flex-direction: column;
animation: olSlide var(--kole-duration-base) var(--kole-ease-out);
}
@keyframes olSlide { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
.ol-drawer-head { padding: var(--kole-space-16) var(--kole-space-24); border-bottom: 1px solid var(--kole-color-border); display: flex; align-items: center; justify-content: space-between; gap: var(--kole-space-12); }
.ol-drawer-title { font-size: var(--kole-type-h1-size); line-height: var(--kole-type-h1-height); font-weight: var(--kole-type-h1-weight); color: var(--kole-color-text-title); }
.ol-drawer-body { padding: var(--kole-space-24); overflow-y: auto; display: flex; flex-direction: column; gap: var(--kole-space-16); }
.ol-drawer-foot { margin-top: auto; padding: var(--kole-space-12) var(--kole-space-24); border-top: 1px solid var(--kole-color-border); display: flex; justify-content: flex-end; gap: var(--kole-space-8); }
.ol-close { border: none; background: none; cursor: pointer; color: var(--kole-color-text-secondary); font-size: 18px; line-height: 1; padding: var(--kole-space-4); border-radius: var(--kole-radius-base); }
.ol-close:hover { background: var(--kole-color-brand-bg); color: var(--kole-color-brand); }
.ol-dl { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--kole-space-8) var(--kole-space-16); font-size: var(--kole-type-body-size); }
.ol-dl dt { color: var(--kole-color-text-secondary); }
.ol-dl dd { margin: 0; color: var(--kole-color-text-body); word-break: break-all; }
.ol-steps-item { border-left: 2px solid var(--kole-color-border); padding: 0 0 var(--kole-space-16) var(--kole-space-16); position: relative; }
.ol-steps-item:last-child { padding-bottom: 0; border-left-color: transparent; }
.ol-steps-item::before {
content: ''; position: absolute; left: -5px; top: 5px; width: 8px; height: 8px; border-radius: 50%;
background: var(--kole-color-border-strong);
}
.ol-steps-item.is-done::before { background: var(--kole-color-success); }
.ol-steps-item.is-now::before { background: var(--kole-color-brand); }
.ol-steps-item h4 { margin: 0; font-size: var(--kole-type-body-size); font-weight: 500; color: var(--kole-color-text-title); }
.ol-steps-item p { margin: var(--kole-space-4) 0 0; font-size: var(--kole-type-caption-size); color: var(--kole-color-text-secondary); }
.ol-empty { display: none; }
.ol-empty.is-open { display: block; }
@media (max-width: 1080px) { .ol-filter { grid-template-columns: repeat(2, minmax(0, 1fr)); } .ol-filter .ol-filter-actions { grid-column: 1 / -1; } }
@media (max-width: 640px) { .ol-filter { grid-template-columns: minmax(0, 1fr); } .ol-topnav { display: none; } }
</style>
</head>
<body>
<header class="ol-topbar">
<span class="ol-mark">K</span>
<span class="ol-brand">Kole UI · 管理控制台</span>
<nav class="ol-topnav">
<a href="dashboard.html">工作台</a>
<a href="order-list.html" aria-current="page">订单列表</a>
<a href="user-management.html">用户管理</a>
<a href="settings.html">系统设置</a>
</nav>
</header>
<main class="ol-main">
<div class="ol-head">
<div>
<h1 class="ol-title">订单列表</h1>
<p class="ol-sub">模板页库示范:筛选 + 表格 + 批量操作 + 分页 + 详情抽屉</p>
</div>
<div class="ol-head-actions">
<button class="btn btn-default btn-md" type="button" id="ol-export">导出</button>
<button class="btn btn-primary btn-md" type="button" id="ol-new">新建订单</button>
</div>
</div>
<!-- 筛选表单 -->
<section class="card card-bordered card-p16">
<form class="ol-filter" id="ol-filter" role="search">
<div class="field">
<label for="ol-kw">关键词</label>
<div class="kole-input">
<input id="ol-kw" type="search" placeholder="订单号 / 客户名称">
</div>
</div>
<div class="field">
<label for="ol-status">状态</label>
<div class="kole-input">
<select id="ol-status" style="border:none;outline:none;background:transparent;font:inherit;color:inherit;flex:1;min-width:0;height:100%;cursor:pointer">
<option value="">全部状态</option>
<option value="待审核">待审核</option>
<option value="处理中">处理中</option>
<option value="已完成">已完成</option>
<option value="已取消">已取消</option>
</select>
</div>
</div>
<div class="field">
<label for="ol-channel">销售渠道</label>
<div class="kole-input">
<select id="ol-channel" style="border:none;outline:none;background:transparent;font:inherit;color:inherit;flex:1;min-width:0;height:100%;cursor:pointer">
<option value="">全部渠道</option>
<option value="直销">直销</option>
<option value="渠道商">渠道商</option>
<option value="线上商城">线上商城</option>
</select>
</div>
</div>
<div class="field">
<label for="ol-date">下单日期</label>
<div class="kole-input">
<input id="ol-date" type="date">
</div>
</div>
<div class="ol-filter-actions" style="display:flex; gap:8px;">
<button class="btn btn-primary btn-md" type="submit">查询</button>
<button class="btn btn-default btn-md" type="reset" id="ol-reset">重置</button>
</div>
</form>
</section>
<!-- 表格 -->
<section class="card card-bordered" style="overflow:hidden; padding:0">
<div class="batchbar ol-batchbar" id="ol-batchbar">
<span class="count">已选 <strong id="ol-sel-count">0</strong> 项</span>
<span class="spacer"></span>
<button class="btn btn-text btn-sm" type="button" id="ol-batch-approve">批量审核</button>
<button class="btn btn-text btn-sm" type="button" id="ol-batch-export">批量导出</button>
<button class="btn btn-text btn-sm" type="button" style="color:var(--kole-color-error)" id="ol-batch-cancel">批量取消</button>
<button class="btn btn-text btn-sm" type="button" id="ol-batch-clear">取消选择</button>
</div>
<div class="ol-tablewrap">
<table class="tbl">
<thead>
<tr>
<th style="width:44px">
<input type="checkbox" class="sel" id="ol-check-all" aria-label="全选本页">
</th>
<th style="width:170px">订单编号</th>
<th>客户名称</th>
<th style="width:130px">销售渠道</th>
<th style="width:130px" class="num">订单金额</th>
<th style="width:100px">状态</th>
<th style="width:170px">下单时间</th>
<th style="width:132px" class="ops">操作</th>
</tr>
</thead>
<tbody id="ol-tbody"></tbody>
</table>
</div>
<div class="ol-empty" id="ol-empty">
<div class="kole-empty">
<div class="kole-empty-icon" aria-hidden="true">🔍</div>
<div class="kole-empty-title">没有匹配的订单</div>
<div class="kole-empty-desc">当前筛选条件下没有结果。试试放宽状态或渠道,或清空关键词后重新查询。</div>
<div class="kole-empty-actions">
<button class="kole-empty-btn primary" type="button" id="ol-empty-reset">清空筛选条件</button>
</div>
</div>
</div>
<div class="ol-foot">
<div class="ol-foot-left">
<span>共 <strong id="ol-total" class="ol-num">0</strong> 条</span>
<label style="display:inline-flex; align-items:center; gap:6px">
每页
<select id="ol-size" aria-label="每页条数">
<option value="5">5</option>
<option value="8" selected>8</option>
<option value="12">12</option>
</select>
条
</label>
<span id="ol-range"></span>
</div>
<div class="kole-pagination">
<div class="kole-pagination-pager" id="ol-pager" role="group" aria-label="分页"></div>
</div>
</div>
</section>
<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 class="ol-mask" id="ol-mask">
<aside class="ol-drawer" role="dialog" aria-modal="true" aria-labelledby="ol-drawer-title">
<div class="ol-drawer-head">
<div>
<div class="ol-drawer-title" id="ol-drawer-title">订单详情</div>
<div style="font-size:var(--kole-type-caption-size);color:var(--kole-color-text-secondary)" id="ol-drawer-id"></div>
</div>
<button class="ol-close" type="button" id="ol-drawer-close" aria-label="关闭详情">✕</button>
</div>
<div class="ol-drawer-body">
<dl class="ol-dl" id="ol-drawer-dl"></dl>
<div>
<div style="font-size:var(--kole-type-h2-size);font-weight:var(--kole-type-h2-weight);color:var(--kole-color-text-title);margin-bottom:var(--kole-space-12)">流转记录</div>
<div id="ol-drawer-steps"></div>
</div>
</div>
<div class="ol-drawer-foot">
<button class="btn btn-default btn-md" type="button" id="ol-drawer-close2">关闭</button>
<button class="btn btn-primary btn-md" type="button" id="ol-drawer-approve">审核通过</button>
</div>
</aside>
</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;').replace(/"/g, '&quot;'); }
/* ── 示范数据 ─────────────────────────────────────────── */
var CUSTS = ['华信精密制造','蓝海贸易集团','云帆科技股份','恒达物流有限','中科智联电子','新锐传媒文化','天工重工机械','瑞丰生物科技','启元新材料','九方供应链'];
var CHANNELS = ['直销','渠道商','线上商城'];
var STATUS = [
{ name: '待审核', cls: 'kole-tag kole-tag-orange' },
{ name: '处理中', cls: 'kole-tag' },
{ name: '已完成', cls: 'kole-tag kole-tag-green' },
{ name: '已取消', cls: 'kole-tag kole-tag-gray' }
];
var db = [];
(function seed() {
for (var i = 0; i < 37; i++) {
var st = STATUS[i % 4 === 3 ? 3 : i % 3];
var day = 20 - (i % 9);
db.push({
id: 'SO-202609' + (day < 10 ? '0' : '') + day + '-' + String(100 + i).slice(1) + (i < 10 ? '1' : ''),
cust: CUSTS[i % CUSTS.length],
channel: CHANNELS[i % 3],
amount: 12600 + ((i * 7919) % 380000),
status: st.name,
cls: st.cls,
time: '2026-09-' + (day < 10 ? '0' : '') + day + ' ' + (9 + (i % 9)) + ':' + (i * 7 % 60 < 10 ? '0' : '') + (i * 7 % 60),
date: '2026-09-' + (day < 10 ? '0' : '') + day,
owner: ['林晚舟','沈知言','顾清晏','陆则鸣'][i % 4],
contract: 'HT-2026-' + (1000 + i)
});
}
})();
/* ── 状态 ─────────────────────────────────────────────── */
var state = { kw: '', status: '', channel: '', date: '', page: 1, size: 8, selected: {} };
var tbody = document.getElementById('ol-tbody');
var pagerEl = document.getElementById('ol-pager');
var emptyEl = document.getElementById('ol-empty');
var batchbar = document.getElementById('ol-batchbar');
function filtered() {
return db.filter(function (o) {
if (state.kw && (o.id + o.cust).toLowerCase().indexOf(state.kw.toLowerCase()) < 0) return false;
if (state.status && o.status !== state.status) return false;
if (state.channel && o.channel !== state.channel) return false;
if (state.date && o.date !== state.date) return false;
return true;
});
}
function selectedIds() {
return Object.keys(state.selected).filter(function (k) { return state.selected[k]; });
}
function syncBatchbar() {
var n = selectedIds().length;
document.getElementById('ol-sel-count').textContent = n;
batchbar.classList.toggle('is-open', n > 0);
}
function render() {
var list = filtered();
var pages = Math.max(1, Math.ceil(list.length / state.size));
if (state.page > pages) state.page = pages;
var start = (state.page - 1) * state.size;
var slice = list.slice(start, start + state.size);
document.getElementById('ol-total').textContent = list.length;
document.getElementById('ol-range').textContent = list.length ? '显示第 ' + (start + 1) + '–' + (start + slice.length) + ' 条' : '';
emptyEl.classList.toggle('is-open', list.length === 0);
tbody.innerHTML = '';
slice.forEach(function (o) {
var tr = document.createElement('tr');
tr.className = state.selected[o.id] ? 'selected' : '';
tr.innerHTML =
'<td><input type="checkbox" class="sel ol-row-check" data-id="' + esc(o.id) + '" aria-label="选择 ' + esc(o.id) + '"' + (state.selected[o.id] ? ' checked' : '') + '></td>' +
'<td><span class="ol-num ol-strong">' + esc(o.id) + '</span></td>' +
'<td><span class="ol-cust"><span class="ol-avatar">' + esc(o.cust.slice(0, 1)) + '</span><span class="ol-truncate" title="' + esc(o.cust) + '">' + esc(o.cust) + '</span></span></td>' +
'<td>' + esc(o.channel) + '</td>' +
'<td class="num ol-num">¥' + num(o.amount) + '</td>' +
'<td><span class="' + o.cls + '">' + esc(o.status) + '</span></td>' +
'<td class="ol-num">' + esc(o.time) + '</td>' +
'<td class="ops"><span class="ol-actions">' +
'<button class="btn btn-link btn-sm ol-detail" type="button" data-id="' + esc(o.id) + '">详情</button>' +
'<button class="btn btn-link btn-sm ol-approve" type="button" data-id="' + esc(o.id) + '"' + (o.status === '待审核' ? '' : ' disabled title="仅待审核订单可操作"') + '>审核</button>' +
'</span></td>';
tbody.appendChild(tr);
});
tbody.querySelectorAll('.ol-row-check').forEach(function (cb) {
cb.addEventListener('change', function () {
var id = cb.getAttribute('data-id');
if (cb.checked) state.selected[id] = true; else delete state.selected[id];
cb.closest('tr').classList.toggle('selected', cb.checked);
/* 表头全选态跟随本页勾选情况(含半选) */
var box = tbody.querySelectorAll('.ol-row-check');
var on = tbody.querySelectorAll('.ol-row-check:checked');
var all = document.getElementById('ol-check-all');
all.checked = box.length > 0 && on.length === box.length;
all.indeterminate = on.length > 0 && on.length < box.length;
syncBatchbar();
});
});
tbody.querySelectorAll('.ol-detail').forEach(function (b) {
b.addEventListener('click', function () { openDrawer(b.getAttribute('data-id')); });
});
tbody.querySelectorAll('.ol-approve').forEach(function (b) {
b.addEventListener('click', function () { approve(b.getAttribute('data-id')); });
});
var all = document.getElementById('ol-check-all');
all.checked = slice.length > 0 && slice.every(function (o) { return state.selected[o.id]; });
all.indeterminate = !all.checked && slice.some(function (o) { return state.selected[o.id]; });
all.disabled = slice.length === 0;
/* 分页 */
pagerEl.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)) return;
state.page = target;
render();
});
pagerEl.appendChild(b);
}
mk('上一页', state.page - 1, { disabled: state.page === 1 });
var win = [];
for (var p = 1; p <= pages; p++) if (p === 1 || p === pages || Math.abs(p - state.page) <= 1) win.push(p);
var prev = 0;
win.forEach(function (p) {
if (prev && p - prev > 1) {
var gap = document.createElement('span');
gap.className = 'kole-pagination-desc';
gap.textContent = '…';
pagerEl.appendChild(gap);
}
mk(String(p), p, { current: p === state.page });
prev = p;
});
mk('下一页', state.page + 1, { disabled: state.page === pages });
syncBatchbar();
}
/* ── 操作 ─────────────────────────────────────────────── */
function approve(id) {
var o = db.find(function (x) { return x.id === id; });
if (!o || o.status !== '待审核') return;
o.status = '处理中';
o.cls = 'kole-tag';
render();
flash('订单 ' + id + ' 已审核通过,进入处理中');
}
function cancelOrder(id) {
var o = db.find(function (x) { return x.id === id; });
if (!o) return;
o.status = '已取消';
o.cls = 'kole-tag kole-tag-gray';
}
/* ── 详情抽屉 ─────────────────────────────────────────── */
var mask = document.getElementById('ol-mask');
var lastFocus = null;
function openDrawer(id) {
var o = db.find(function (x) { return x.id === id; });
if (!o) return;
lastFocus = document.activeElement;
document.getElementById('ol-drawer-id').textContent = o.id;
document.getElementById('ol-drawer-dl').innerHTML =
'<dt>客户名称</dt><dd>' + esc(o.cust) + '</dd>' +
'<dt>订单金额</dt><dd class="ol-num">¥' + num(o.amount) + '</dd>' +
'<dt>销售渠道</dt><dd>' + esc(o.channel) + '</dd>' +
'<dt>当前状态</dt><dd><span class="' + o.cls + '">' + esc(o.status) + '</span></dd>' +
'<dt>下单时间</dt><dd class="ol-num">' + esc(o.time) + '</dd>' +
'<dt>负责人</dt><dd>' + esc(o.owner) + '</dd>' +
'<dt>合同编号</dt><dd class="ol-num">' + esc(o.contract) + '</dd>';
var done = o.status === '已完成' || o.status === '处理中';
var canceled = o.status === '已取消';
document.getElementById('ol-drawer-steps').innerHTML =
'<div class="ol-steps-item is-done"><h4>创建订单</h4><p>' + esc(o.time) + ' · ' + esc(o.owner) + '</p></div>' +
'<div class="ol-steps-item ' + (done ? 'is-done' : canceled ? '' : 'is-now') + '"><h4>订单审核</h4><p>' +
(canceled ? '已取消,未通过审核' : done ? '审核通过' : '等待审核') + '</p></div>' +
'<div class="ol-steps-item ' + (o.status === '已完成' ? 'is-done' : done ? 'is-now' : '') + '"><h4>发货处理</h4><p>' +
(o.status === '已完成' ? '已完成发货' : done ? '处理中' : '未开始') + '</p></div>' +
'<div class="ol-steps-item ' + (o.status === '已完成' ? 'is-done' : '') + '"><h4>订单完成</h4><p>' +
(o.status === '已完成' ? '客户已签收' : '未开始') + '</p></div>';
var approveBtn = document.getElementById('ol-drawer-approve');
approveBtn.disabled = o.status !== '待审核';
approveBtn.setAttribute('data-id', o.id);
mask.classList.add('is-open');
document.getElementById('ol-drawer-close').focus();
}
function closeDrawer() {
mask.classList.remove('is-open');
if (lastFocus && lastFocus.isConnected) lastFocus.focus();
}
document.getElementById('ol-drawer-close').addEventListener('click', closeDrawer);
document.getElementById('ol-drawer-close2').addEventListener('click', closeDrawer);
mask.addEventListener('click', function (e) { if (e.target === mask) closeDrawer(); });
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && mask.classList.contains('is-open')) closeDrawer();
});
document.getElementById('ol-drawer-approve').addEventListener('click', function () {
var id = this.getAttribute('data-id');
approve(id);
closeDrawer();
});
/* ── 轻提示(MessagePro 组件样式) ────────────────────── */
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('ol-filter').addEventListener('submit', function (e) {
e.preventDefault();
state.kw = document.getElementById('ol-kw').value.trim();
state.status = document.getElementById('ol-status').value;
state.channel = document.getElementById('ol-channel').value;
state.date = document.getElementById('ol-date').value;
state.page = 1;
state.selected = {};
document.getElementById('ol-check-all').checked = false;
document.getElementById('ol-check-all').indeterminate = false;
render();
var n = filtered().length;
flash(n ? '查询完成,共 ' + n + ' 条结果' : '未找到匹配的订单');
});
document.getElementById('ol-reset').addEventListener('click', function () {
/* reset 事件在原生重置前触发,故延后一拍取清零后的值 */
setTimeout(function () {
state.kw = state.status = state.channel = state.date = '';
state.page = 1;
state.selected = {};
render();
flash('筛选条件已重置');
}, 0);
});
document.getElementById('ol-empty-reset').addEventListener('click', function () {
document.getElementById('ol-filter').reset();
state.kw = state.status = state.channel = state.date = '';
state.page = 1;
render();
flash('筛选条件已清空');
});
document.getElementById('ol-size').addEventListener('change', function () {
state.size = Number(this.value);
state.page = 1;
render();
});
/* ── 全选 / 批量操作 ──────────────────────────────────── */
document.getElementById('ol-check-all').addEventListener('change', function () {
var list = filtered();
var start = (state.page - 1) * state.size;
var slice = list.slice(start, start + state.size);
slice.forEach(function (o) { if (this.checked) state.selected[o.id] = true; else delete state.selected[o.id]; }, this);
render();
});
document.getElementById('ol-batch-clear').addEventListener('click', function () {
state.selected = {};
render();
});
document.getElementById('ol-batch-approve').addEventListener('click', function () {
var ids = selectedIds();
var n = 0;
ids.forEach(function (id) {
var o = db.find(function (x) { return x.id === id; });
if (o && o.status === '待审核') { approve(o.id); n++; }
});
state.selected = {};
render();
flash(n ? '已审核 ' + n + ' 条订单' : '所选订单中没有待审核的记录');
});
document.getElementById('ol-batch-export').addEventListener('click', function () {
var n = selectedIds().length;
state.selected = {};
render();
flash('已导出 ' + n + ' 条订单(示范交互,未产生文件)');
});
document.getElementById('ol-batch-cancel').addEventListener('click', function () {
var ids = selectedIds();
ids.forEach(function (id) { cancelOrder(id); });
state.selected = {};
render();
flash('已取消 ' + ids.length + ' 条订单');
});
document.getElementById('ol-export').addEventListener('click', function () {
var btn = this;
btn.disabled = true;
btn.textContent = '导出中…';
setTimeout(function () {
btn.disabled = false;
btn.textContent = '导出';
flash('当前筛选结果已导出(示范交互,未产生文件)');
}, 700);
});
document.getElementById('ol-new').addEventListener('click', function () {
var id = 'SO-20260920-' + String(50 + Math.floor(Math.random() * 40));
db.unshift({
id: id, cust: '新建客户(待补充)', channel: '直销', amount: 0,
status: '待审核', cls: 'kole-tag kole-tag-orange',
time: '2026-09-20 ' + new Date().toTimeString().slice(0, 5),
date: '2026-09-20', owner: '林晚舟', contract: 'HT-2026-NEW'
});
state.page = 1;
render();
flash('已创建订单 ' + id + '(示范交互)');
});
render();
})();
</script>
</body>
</html>