Files
aurora-admin/.design_library/kole-ui/ui_kits/dashboard/index.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

385 lines
21 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">
<link rel="stylesheet" href="../../colors_and_type.css">
<link rel="stylesheet" href="../../components.css">
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://unpkg.com/lucide@1.8.0/dist/umd/lucide.min.js"></script>
<style>
:root{--uikit-sidebar-w:220px}
body{margin:0;background:var(--color-bg-page);color:var(--color-text-body);font-family:var(--font-family);font-size:var(--font-size-body);line-height:var(--line-height-body)}
.uikit-shell{width:100%;max-width:1184px;margin:0 auto;overflow:hidden;display:grid;grid-template-columns:var(--uikit-sidebar-w, 220px) minmax(0,1fr);gap:var(--space-4)}
.uikit-sidebar,.uikit-main,.uikit-toolbar{min-width:0}
.uikit-sidebar{overflow:hidden;max-width:100%;background:var(--color-bg-card);border-right:1px solid var(--color-border);padding:var(--space-16);display:flex;flex-direction:column;gap:var(--space-8);min-height:100vh;box-sizing:border-box}
[data-component]{min-width:0;max-width:100%;overflow:hidden}
.uikit-toolbar{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap}
.uikit-responsive-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-4)}
.uikit-table-wrap{max-width:100%;overflow-x:auto;overscroll-behavior-x:contain}
.uikit-truncate{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.uikit-nowrap{white-space:nowrap;flex-shrink:0}
.uikit-action-cell{display:flex;align-items:center;gap:8px;min-width:0;max-width:160px;overflow:hidden}
.uikit-action{min-width:0;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width: 900px){.uikit-shell{grid-template-columns:minmax(0,1fr)}.uikit-responsive-grid{grid-template-columns:minmax(0,1fr)}}
@media (max-width: 640px){.uikit-toolbar{flex-direction:column;align-items:stretch}.uikit-responsive-grid{grid-template-columns:minmax(0,1fr)}}
.uikit-main{padding:var(--space-24);display:flex;flex-direction:column;gap:var(--space-16);min-width:0}
.uikit-topbar{justify-content:flex-end}
.uikit-page-head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-16);flex-wrap:wrap}
.uikit-page-title{margin:0;font-size:var(--font-size-display);line-height:var(--line-height-display);font-weight:var(--font-weight-display);color:var(--color-text-title);word-break:keep-all;overflow-wrap:break-word}
.uikit-page-sub{margin:var(--space-4) 0 0;font-size:var(--font-size-caption);color:var(--color-text-secondary)}
.uikit-brand{display:flex;align-items:center;gap:var(--space-8);padding:var(--space-8) 0 var(--space-16);min-width:0}
.uikit-brand-mark{display:inline-flex;align-items:center;justify-content:center;width:var(--control-height-default);height:var(--control-height-default);border-radius:var(--radius-base);background:var(--color-brand);color:var(--color-text-inverse);flex-shrink:0}
.uikit-brand-name{font-size:var(--font-size-h1);font-weight:var(--font-weight-h1);color:var(--color-text-title)}
.uikit-nav{display:flex;flex-direction:column;gap:var(--space-4)}
.uikit-nav-item{display:flex;align-items:center;gap:var(--space-8);height:var(--control-height-default);padding:0 var(--space-12);border:none;background:none;border-radius:var(--radius-base);color:var(--color-text-body);font-size:var(--font-size-body);cursor:pointer;text-align:left;min-width:0;transition:background var(--duration-fast) var(--ease-standard)}
.uikit-nav-item:hover{background:var(--color-brand-bg)}
.uikit-nav-item.active{background:var(--color-brand-bg);color:var(--color-brand);font-weight:var(--font-weight-h2)}
.uikit-sidebar-foot{margin-top:auto;border-top:1px solid var(--color-border);padding-top:var(--space-12)}
.uikit-user{display:flex;align-items:center;gap:var(--space-8);color:var(--color-text-secondary);font-size:var(--font-size-caption);min-width:0}
.uikit-metric-label{font-size:var(--font-size-caption);color:var(--color-text-secondary)}
.uikit-metric-num{margin-top:var(--space-4);font-size:var(--font-size-display);line-height:var(--line-height-display);font-weight:var(--font-weight-display);font-family:var(--font-family-num);color:var(--color-text-title)}
.uikit-metric-delta{margin-top:var(--space-4);font-size:var(--font-size-caption);color:var(--color-text-secondary)}
.uikit-status-success{color:var(--color-success)}
.uikit-status-info{color:var(--color-info)}
.uikit-status-warning{color:var(--color-warning)}
.uikit-status-error{color:var(--color-error)}
.uikit-form{display:flex;flex-direction:column;gap:var(--space-12)}
.uikit-label{font-size:var(--font-size-body);color:var(--color-text-body)}
.uikit-view{animation:uikitFade var(--duration-base) var(--ease-out)}
@keyframes uikitFade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.uikit-cell-name{display:inline-block;max-width:160px}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;
const statusOptions=[{value:'all',label:'全部状态'},{value:'done',label:'已完成'},{value:'processing',label:'处理中'},{value:'pending',label:'待审核'},{value:'cancel',label:'已取消'}];
const regionOptions=[{value:'east',label:'华东区'},{value:'north',label:'华北区'},{value:'south',label:'华南区'},{value:'west',label:'西南区'}];
const levelOptions=[{value:'strategic',label:'战略客户'},{value:'key',label:'重点客户'},{value:'normal',label:'普通客户'}];
const orders=[
{id:'SO-20260817-001',cust:'华信精密制造',amount:'¥128,600.00',status:'已完成',sk:'success',date:'2026-08-17 09:24'},
{id:'SO-20260817-002',cust:'蓝海贸易集团',amount:'¥56,320.00',status:'处理中',sk:'info',date:'2026-08-17 10:02'},
{id:'SO-20260816-018',cust:'云帆科技股份',amount:'¥89,750.00',status:'待审核',sk:'warning',date:'2026-08-16 16:41'},
{id:'SO-20260816-015',cust:'恒达物流有限',amount:'¥23,480.00',status:'已完成',sk:'success',date:'2026-08-16 14:18'},
{id:'SO-20260815-032',cust:'中科智联电子',amount:'¥312,900.00',status:'处理中',sk:'info',date:'2026-08-15 11:36'},
{id:'SO-20260815-027',cust:'新锐传媒文化',amount:'¥45,120.00',status:'已取消',sk:'error',date:'2026-08-15 09:52'},
{id:'SO-20260814-041',cust:'天工重工机械',amount:'¥176,400.00',status:'已完成',sk:'success',date:'2026-08-14 15:07'},
{id:'SO-20260814-038',cust:'瑞丰生物科技',amount:'¥67,890.00',status:'待审核',sk:'warning',date:'2026-08-14 10:29'}
];
const customers=[
{name:'华信精密制造',level:'战略客户',contact:'王建国',status:'正常',sk:'success'},
{name:'蓝海贸易集团',level:'重点客户',contact:'李慧敏',status:'正常',sk:'success'},
{name:'云帆科技股份',level:'普通客户',contact:'陈志远',status:'暂停',sk:'warning'},
{name:'恒达物流有限',level:'重点客户',contact:'赵丽华',status:'正常',sk:'success'},
{name:'中科智联电子',level:'战略客户',contact:'孙浩然',status:'正常',sk:'success'},
{name:'新锐传媒文化',level:'普通客户',contact:'周晓彤',status:'流失',sk:'error'}
];
function Select({options,value,onChange,placeholder}){
const [open,setOpen]=useState(false);
const sel=options.find(o=>o.value===value);
return (
<div data-component="select" className={'select'+(open?' open':'')} onClick={()=>setOpen(!open)}>
{sel?<span className="value uikit-truncate">{sel.label}</span>:<span className="placeholder">{placeholder}</span>}
<i data-lucide="chevron-down" className="icon" style={{width:'16px',height:'16px',display:'inline-block'}}></i>
{open&&(
<div className="select-panel">
{options.map(o=>(
<div key={o.value} className={'select-option'+(o.value===value?' selected':'')} onClick={(e)=>{e.stopPropagation();onChange(o.value);setOpen(false);}}>
{o.value===value?<i data-lucide="check" style={{width:'16px',height:'16px',display:'inline-block'}}></i>:null}
<span className="uikit-truncate">{o.label}</span>
</div>
))}
</div>
)}
</div>
);
}
function Modal({title,children,footer,onClose}){
return (
<div className="modal-scene" style={{position:'fixed',inset:0,zIndex:50,display:'flex',alignItems:'center',justifyContent:'center'}} onClick={onClose}>
<div data-component="modal" className="modal modal-default" onClick={(e)=>e.stopPropagation()}>
<div className="modal-title">{title}</div>
<div className="modal-content">{children}</div>
<div className="modal-footer">{footer}</div>
</div>
</div>
);
}
function OrdersTable({rows,selectedRow}){
return (
<div className="tbl-wrap uikit-table-wrap">
<table data-component="table" className="tbl">
<thead><tr><th>订单编号</th><th>客户名称</th><th className="num">金额</th><th>状态</th><th>创建时间</th><th className="ops">操作</th></tr></thead>
<tbody>
{rows.map((r,i)=>(
<tr key={r.id} className={selectedRow===i?'selected':''}>
<td><span className="uikit-nowrap">{r.id}</span></td>
<td><span className="uikit-truncate uikit-cell-name">{r.cust}</span></td>
<td className="num"><span className="uikit-nowrap">{r.amount}</span></td>
<td><span className={'uikit-status-'+r.sk}>{r.status}</span></td>
<td><span className="uikit-nowrap">{r.date}</span></td>
<td className="ops">
<div className="uikit-action-cell">
<a className="uikit-action" href="javascript:void(0)">查看</a>
<a href="javascript:void(0)" title="编辑"><i data-lucide="edit" style={{width:'16px',height:'16px',display:'inline-block'}}></i></a>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
function CustomersTable({onDelete}){
return (
<div className="tbl-wrap uikit-table-wrap">
<table data-component="table" className="tbl">
<thead><tr><th>客户名称</th><th>客户等级</th><th>联系人</th><th>状态</th><th className="ops">操作</th></tr></thead>
<tbody>
{customers.map(c=>(
<tr key={c.name}>
<td><span className="uikit-truncate uikit-cell-name">{c.name}</span></td>
<td><span className="uikit-nowrap">{c.level}</span></td>
<td><span className="uikit-nowrap">{c.contact}</span></td>
<td><span className={'uikit-status-'+c.sk}>{c.status}</span></td>
<td className="ops">
<div className="uikit-action-cell">
<a className="uikit-action" href="javascript:void(0)">编辑</a>
<a href="javascript:void(0)" title="删除" onClick={onDelete}><i data-lucide="trash" style={{width:'16px',height:'16px',display:'inline-block'}}></i></a>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
function App(){
const [view,setView]=useState('overview');
const [modal,setModal]=useState(null);
const [status,setStatus]=useState('all');
const [region,setRegion]=useState('east');
const [level,setLevel]=useState('key');
const [region2,setRegion2]=useState('east');
useEffect(()=>{ if(window.lucide) lucide.createIcons(); });
const navItems=[
{key:'overview',icon:'layout-dashboard',label:'工作台'},
{key:'orders',icon:'package',label:'订单管理'},
{key:'customers',icon:'users',label:'客户管理'}
];
return (
<div className="uikit-shell" data-layout-guard="uikit-v1">
<aside className="uikit-sidebar">
<div className="uikit-brand">
<span className="uikit-brand-mark"><i data-lucide="layers" style={{width:'20px',height:'20px',display:'inline-block'}}></i></span>
<span className="uikit-brand-name uikit-truncate">Kole UI</span>
</div>
<nav className="uikit-nav">
{navItems.map(n=>(
<button key={n.key} className={'uikit-nav-item'+(view===n.key?' active':'')} onClick={()=>setView(n.key)}>
<i data-lucide={n.icon} style={{width:'16px',height:'16px',display:'inline-block'}}></i>
<span className="uikit-truncate">{n.label}</span>
</button>
))}
<button className="uikit-nav-item">
<i data-lucide="settings" style={{width:'16px',height:'16px',display:'inline-block'}}></i>
<span className="uikit-truncate">系统设置</span>
</button>
</nav>
<div className="uikit-sidebar-foot">
<div className="uikit-user">
<i data-lucide="circle-user-round" style={{width:'20px',height:'20px',display:'inline-block'}}></i>
<span className="uikit-truncate">管理员 · 运营中心</span>
</div>
</div>
</aside>
<main className="uikit-main">
<div className="uikit-toolbar uikit-topbar">
<div data-component="input" className="field">
<div className="kole-input">
<span className="affix"><i data-lucide="search" style={{width:'16px',height:'16px',display:'inline-block'}}></i></span>
<input placeholder="搜索订单、客户" />
</div>
</div>
<button data-component="button" className="btn btn-default btn-md"><i data-lucide="bell" style={{width:'16px',height:'16px',display:'inline-block'}}></i>通知</button>
<button data-component="button" className="btn btn-default btn-md"><i data-lucide="circle-user-round" style={{width:'16px',height:'16px',display:'inline-block'}}></i>管理员</button>
</div>
{view==='overview'&&(
<div className="uikit-view">
<div className="uikit-page-head">
<div>
<h1 className="uikit-page-title">工作台</h1>
<p className="uikit-page-sub">欢迎回来,今日有 12 笔订单待处理</p>
</div>
<button data-component="button" className="btn btn-primary btn-md" onClick={()=>setModal('new')}><i data-lucide="plus" style={{width:'16px',height:'16px',display:'inline-block'}}></i>新建订单</button>
</div>
<div className="uikit-responsive-grid">
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head"><span className="uikit-metric-label">本月销售额</span><i data-lucide="trending-up" style={{width:'20px',height:'20px',display:'inline-block',color:'var(--color-success)'}}></i></div>
<div className="uikit-metric-num">¥1,284,600</div>
<div className="uikit-metric-delta">较上月 +12.5%</div>
</div>
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head"><span className="uikit-metric-label">订单总数</span><i data-lucide="package" style={{width:'20px',height:'20px',display:'inline-block',color:'var(--color-info)'}}></i></div>
<div className="uikit-metric-num">3,842</div>
<div className="uikit-metric-delta">本月新增 286 笔</div>
</div>
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head"><span className="uikit-metric-label">待处理订单</span><i data-lucide="clock" style={{width:'20px',height:'20px',display:'inline-block',color:'var(--color-warning)'}}></i></div>
<div className="uikit-metric-num">12</div>
<div className="uikit-metric-delta">需今日跟进</div>
</div>
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head"><span className="uikit-metric-label">客户总数</span><i data-lucide="users" style={{width:'20px',height:'20px',display:'inline-block',color:'var(--color-brand)'}}></i></div>
<div className="uikit-metric-num">1,026</div>
<div className="uikit-metric-delta">本月新增 34 位</div>
</div>
</div>
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head">
<span className="card-title">最近订单</span>
<a className="card-link uikit-nowrap" href="javascript:void(0)">查看全部</a>
</div>
<OrdersTable rows={orders.slice(0,6)} selectedRow={2} />
</div>
</div>
)}
{view==='orders'&&(
<div className="uikit-view">
<div className="uikit-page-head">
<div>
<h1 className="uikit-page-title">订单管理</h1>
<p className="uikit-page-sub">共 3,842 笔订单,本月新增 286 笔</p>
</div>
<button data-component="button" className="btn btn-primary btn-md" onClick={()=>setModal('new')}><i data-lucide="plus" style={{width:'16px',height:'16px',display:'inline-block'}}></i>新建订单</button>
</div>
<div className="uikit-toolbar">
<div data-component="input" className="field">
<div className="kole-input">
<span className="affix"><i data-lucide="search" style={{width:'16px',height:'16px',display:'inline-block'}}></i></span>
<input placeholder="搜索订单编号 / 客户名称" />
</div>
</div>
<Select options={statusOptions} value={status} onChange={setStatus} placeholder="全部状态" />
<Select options={regionOptions} value={region} onChange={setRegion} placeholder="所属区域" />
<button data-component="button" className="btn btn-default btn-md">查询</button>
<button data-component="button" className="btn btn-text btn-md">重置</button>
<button data-component="button" className="btn btn-default btn-md" disabled>导出报表</button>
</div>
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head">
<span className="card-title">订单列表</span>
<span className="uikit-nowrap uikit-metric-label">共 3,842 条记录</span>
</div>
<div className="batchbar">
<span className="count uikit-nowrap">已选择 2 项</span>
<button data-component="button" className="btn btn-text btn-md">批量审核</button>
<button data-component="button" className="btn btn-text btn-md">批量导出</button>
</div>
<OrdersTable rows={orders} selectedRow={1} />
</div>
</div>
)}
{view==='customers'&&(
<div className="uikit-view">
<div className="uikit-page-head">
<div>
<h1 className="uikit-page-title">客户管理</h1>
<p className="uikit-page-sub">共 1,026 位客户,本月新增 34 位</p>
</div>
</div>
<div className="uikit-responsive-grid">
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head"><span className="card-title">客户信息</span></div>
<div className="uikit-form">
<div data-component="input" className="field">
<label className="uikit-label">客户名称</label>
<div className="kole-input"><input placeholder="请输入客户名称" /></div>
</div>
<div className="field">
<label className="uikit-label">所属区域</label>
<Select options={regionOptions} value={region2} onChange={setRegion2} placeholder="请选择区域" />
</div>
<div className="field">
<label className="uikit-label">客户等级</label>
<Select options={levelOptions} value={level} onChange={setLevel} placeholder="请选择等级" />
</div>
<div data-component="input" className="field">
<label className="uikit-label">联系电话</label>
<div className="kole-input is-error"><input placeholder="请输入联系电话" /></div>
<span className="error-text">联系电话格式不正确,请检查后重试</span>
</div>
<div className="card-actions">
<button data-component="button" className="btn btn-default btn-md">重置</button>
<button data-component="button" className="btn btn-primary btn-md">提交</button>
</div>
</div>
</div>
<div data-component="card" className="card card-bordered card-p16">
<div className="card-head">
<span className="card-title">客户列表</span>
<a className="card-link uikit-nowrap" href="javascript:void(0)">管理字段</a>
</div>
<CustomersTable onDelete={()=>setModal('del')} />
</div>
</div>
</div>
)}
</main>
{modal==='new'&&(
<Modal title="新建订单" onClose={()=>setModal(null)} footer={<>
<button data-component="button" className="btn btn-default btn-md" onClick={()=>setModal(null)}>取消</button>
<button data-component="button" className="btn btn-primary btn-md" onClick={()=>setModal(null)}>保存</button>
</>}>
<div className="uikit-form">
<div data-component="input" className="field">
<label className="uikit-label">客户名称</label>
<div className="kole-input"><input placeholder="请输入客户名称" /></div>
</div>
<div className="field">
<label className="uikit-label">所属区域</label>
<Select options={regionOptions} value={region2} onChange={setRegion2} placeholder="请选择区域" />
</div>
<div data-component="input" className="field">
<label className="uikit-label">订单金额</label>
<div className="kole-input"><input placeholder="请输入订单金额" /></div>
</div>
</div>
</Modal>
)}
{modal==='del'&&(
<Modal title="确认删除客户" onClose={()=>setModal(null)} footer={<>
<button data-component="button" className="btn btn-default btn-md" onClick={()=>setModal(null)}>取消</button>
<button data-component="button" className="btn btn-danger btn-md" onClick={()=>setModal(null)}>删除</button>
</>}>
<p style={{margin:0}}>删除后该客户的历史订单将保留,但无法恢复客户关联信息,确定继续吗?</p>
</Modal>
)}
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>
</body>
</html>