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 未做部分)
622 lines
31 KiB
HTML
622 lines
31 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/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, '&').replace(/</g, '<').replace(/"/g, '"'); }
|
||
|
||
/* ── 示范数据 ─────────────────────────────────────────── */
|
||
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>
|