Files
zkxw/docs/ui-demos/scheme-b-command-rail.html
T
2026-06-12 10:37:56 +08:00

469 lines
19 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>方案 B · 图标轨 + 命令搜索 — 中科兴皖</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<style>
:root {
--primary: #10b981;
--primary-dark: #059669;
--primary-glow: rgba(16,185,129,0.4);
--bg-deep: #0f172a;
--bg-elevated: #1e293b;
--bg-card: rgba(30,41,59,0.65);
--text: #f1f5f9;
--text-muted: #94a3b8;
--border: rgba(71,85,105,0.5);
--radius: 12px;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
font-family: Inter, -apple-system, sans-serif;
font-size: 14px;
color: var(--text);
background: var(--bg-deep);
}
.bg-ambient {
position: fixed; inset: 0; z-index: 0;
background:
radial-gradient(ellipse 50% 40% at 20% 10%, rgba(16,185,129,0.12), transparent),
radial-gradient(ellipse 40% 30% at 80% 90%, rgba(14,165,233,0.08), transparent),
var(--bg-deep);
}
.layout { display: flex; min-height: 100vh; position: relative; z-index: 1; }
/* 64px 图标轨 */
.icon-rail {
width: 64px;
flex-shrink: 0;
background: rgba(15,23,42,0.95);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
align-items: center;
padding: 16px 0;
gap: 4px;
}
.rail-logo {
width: 36px; height: 36px;
border-radius: 10px;
background: linear-gradient(135deg, var(--primary), #0ea5e9);
display: flex; align-items: center; justify-content: center;
margin-bottom: 16px;
box-shadow: 0 0 20px var(--primary-glow);
}
.rail-item {
width: 44px; height: 44px;
border-radius: 10px;
display: flex; align-items: center; justify-content: center;
color: var(--text-muted);
cursor: pointer;
transition: all 0.15s;
position: relative;
}
.rail-item:hover { background: rgba(16,185,129,0.1); color: var(--text); }
.rail-item.active {
background: rgba(16,185,129,0.15);
color: var(--primary);
box-shadow: inset 0 0 0 1px rgba(16,185,129,0.3);
}
.rail-item.active::before {
content: "";
position: absolute;
left: -12px;
width: 3px; height: 20px;
background: var(--primary);
border-radius: 0 2px 2px 0;
box-shadow: 0 0 8px var(--primary-glow);
}
.rail-divider { width: 32px; height: 1px; background: var(--border); margin: 8px 0; }
.rail-search {
width: 44px; height: 44px;
border-radius: 10px;
background: rgba(16,185,129,0.12);
border: 1px dashed rgba(16,185,129,0.4);
display: flex; align-items: center; justify-content: center;
color: var(--primary);
cursor: pointer;
margin-top: auto;
margin-bottom: 8px;
}
.rail-search:hover { background: rgba(16,185,129,0.2); }
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.header {
height: 56px;
padding: 0 24px;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(30,41,59,0.5);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
}
.crumb { font-size: 13px; color: var(--text-muted); }
.crumb b { color: var(--text); font-weight: 600; }
.cmd-trigger {
display: flex; align-items: center; gap: 10px;
padding: 6px 14px;
border-radius: 8px;
background: rgba(15,23,42,0.6);
border: 1px solid var(--border);
color: var(--text-muted);
font-size: 13px;
cursor: pointer;
transition: border-color 0.15s;
}
.cmd-trigger:hover { border-color: var(--primary); color: var(--text); }
.cmd-trigger kbd {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
padding: 2px 6px;
border-radius: 4px;
background: rgba(71,85,105,0.4);
border: 1px solid var(--border);
}
.content { padding: 24px; flex: 1; }
.welcome-banner {
background: var(--bg-card);
backdrop-filter: blur(12px);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.welcome-banner h1 { margin: 0 0 6px; font-size: 20px; font-weight: 700; }
.welcome-banner p { margin: 0; color: var(--text-muted); font-size: 13px; }
.quick-actions { display: flex; gap: 8px; }
.btn {
display: inline-flex; align-items: center; gap: 6px;
padding: 8px 16px; border-radius: 8px;
font-size: 13px; font-weight: 600; cursor: pointer;
border: 1px solid var(--border);
background: rgba(30,41,59,0.8);
color: var(--text);
transition: all 0.15s;
}
.btn:hover { border-color: var(--primary); }
.btn-primary {
background: linear-gradient(135deg, var(--primary), #059669);
border: none;
box-shadow: 0 0 16px var(--primary-glow);
}
.panel {
background: var(--bg-card);
backdrop-filter: blur(12px);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.panel-top {
padding: 16px 20px;
border-bottom: 1px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
}
.panel-top h2 { margin: 0; font-size: 15px; font-weight: 700; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
padding: 10px 16px; text-align: left;
font-weight: 600; color: var(--text-muted);
background: rgba(15,23,42,0.4);
border-bottom: 1px solid var(--border);
}
td { padding: 12px 16px; border-bottom: 1px solid rgba(71,85,105,0.3); color: var(--text); }
tr:hover td { background: rgba(16,185,129,0.05); }
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 12px; font-weight: 600; }
.tag.success { background: rgba(16,185,129,0.2); color: #6ee7b7; }
.tag.warning { background: rgba(217,119,6,0.2); color: #fbbf24; }
.mono { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--text-muted); }
/* 命令面板 */
.cmd-overlay {
position: fixed; inset: 0;
background: rgba(15,23,42,0.7);
backdrop-filter: blur(4px);
z-index: 200;
display: none;
align-items: flex-start;
justify-content: center;
padding-top: 15vh;
}
.cmd-overlay.open { display: flex; }
.cmd-panel {
width: 560px;
max-width: 90vw;
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: 0 24px 48px rgba(0,0,0,0.4), 0 0 0 1px rgba(16,185,129,0.1);
overflow: hidden;
animation: cmd-in 0.2s ease;
}
@keyframes cmd-in {
from { opacity: 0; transform: scale(0.96) translateY(-8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
.cmd-input-wrap {
display: flex; align-items: center; gap: 10px;
padding: 14px 16px;
border-bottom: 1px solid var(--border);
}
.cmd-input-wrap input {
flex: 1;
background: none; border: none; outline: none;
font-size: 15px; color: var(--text);
font-family: inherit;
}
.cmd-input-wrap input::placeholder { color: var(--text-muted); }
.cmd-results { max-height: 320px; overflow-y: auto; padding: 8px; }
.cmd-group-label {
padding: 8px 12px 4px;
font-size: 11px;
font-weight: 700;
color: var(--text-muted);
letter-spacing: 0.05em;
text-transform: uppercase;
}
.cmd-item {
display: flex; align-items: center; gap: 12px;
padding: 10px 12px;
border-radius: 8px;
cursor: pointer;
transition: background 0.1s;
}
.cmd-item:hover, .cmd-item.focused { background: rgba(16,185,129,0.12); }
.cmd-item-icon {
width: 32px; height: 32px;
border-radius: 8px;
background: rgba(16,185,129,0.1);
display: flex; align-items: center; justify-content: center;
color: var(--primary);
}
.cmd-item-text { flex: 1; }
.cmd-item-title { font-weight: 600; font-size: 13px; }
.cmd-item-path { font-size: 12px; color: var(--text-muted); }
.cmd-item kbd {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--text-muted);
}
.cmd-footer {
padding: 10px 16px;
border-top: 1px solid var(--border);
font-size: 12px;
color: var(--text-muted);
display: flex; gap: 16px;
}
.scheme-badge {
position: fixed; bottom: 16px; right: 16px;
padding: 8px 14px;
background: rgba(15,23,42,0.9);
color: var(--text-muted);
border-radius: 8px;
font-size: 12px; z-index: 100;
}
.scheme-badge a { color: #6ee7b7; text-decoration: none; }
</style>
</head>
<body>
<div class="bg-ambient"></div>
<div class="layout">
<nav class="icon-rail" aria-label="模块导航">
<div class="rail-logo">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/></svg>
</div>
<div class="rail-item" title="细胞存储" data-module="storage">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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>
</div>
<div class="rail-item active" title="质检管理" data-module="qc">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
</div>
<div class="rail-item" title="生产管理" data-module="prod">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2"/></svg>
</div>
<div class="rail-item" title="临床应用" data-module="clinical">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
</div>
<div class="rail-item" title="市场信息" data-module="market">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>
</div>
<div class="rail-divider"></div>
<div class="rail-item" title="系统设置">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
</div>
<div class="rail-search" id="openCmd" title="打开命令面板 (⌘K)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
</div>
</nav>
<div class="main">
<header class="header">
<div class="crumb">质检管理 / <b>质检工单</b></div>
<div class="cmd-trigger" id="openCmd2">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
搜索页面、功能…
<kbd>⌘K</kbd>
</div>
</header>
<div class="content">
<div class="welcome-banner">
<div>
<h1>质检工单</h1>
<p>侧栏仅保留 6 个模块图标,其余 60+ 页面通过 ⌘K 命令面板秒达</p>
</div>
<div class="quick-actions">
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
新增工单
</button>
</div>
</div>
<div class="panel">
<div class="panel-top"><h2>工单列表</h2></div>
<table>
<thead>
<tr><th>工单编号</th><th>样本编号</th><th>检测项目</th><th>状态</th></tr>
</thead>
<tbody>
<tr>
<td class="mono">QC-2026-0312</td>
<td class="mono">SMP-A10284</td>
<td>细胞活性检测</td>
<td><span class="tag warning">进行中</span></td>
</tr>
<tr>
<td class="mono">QC-2026-0311</td>
<td class="mono">SMP-B22015</td>
<td>支原体检测</td>
<td><span class="tag success">已完成</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 命令面板 -->
<div class="cmd-overlay" id="cmdOverlay" role="dialog" aria-label="命令面板">
<div class="cmd-panel">
<div class="cmd-input-wrap">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
<input type="text" id="cmdInput" placeholder="输入页面名称、功能关键词…" autocomplete="off" />
<kbd>ESC</kbd>
</div>
<div class="cmd-results" id="cmdResults">
<div class="cmd-group-label">最近访问</div>
<div class="cmd-item focused" data-title="质检工单">
<div class="cmd-item-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11l3 3L22 4"/></svg></div>
<div class="cmd-item-text">
<div class="cmd-item-title">质检工单</div>
<div class="cmd-item-path">质检管理</div>
</div>
</div>
<div class="cmd-item" data-title="样本接收">
<div class="cmd-item-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg></div>
<div class="cmd-item-text">
<div class="cmd-item-title">样本接收</div>
<div class="cmd-item-path">质检管理</div>
</div>
</div>
<div class="cmd-group-label">细胞存储</div>
<div class="cmd-item" data-title="采集协议单">
<div class="cmd-item-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/></svg></div>
<div class="cmd-item-text">
<div class="cmd-item-title">采集协议单</div>
<div class="cmd-item-path">细胞存储</div>
</div>
</div>
<div class="cmd-item" data-title="入库放行审核">
<div class="cmd-item-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
<div class="cmd-item-text">
<div class="cmd-item-title">入库放行审核</div>
<div class="cmd-item-path">细胞存储</div>
</div>
</div>
<div class="cmd-group-label">生产管理</div>
<div class="cmd-item" data-title="生产工单">
<div class="cmd-item-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="7" width="20" height="14" rx="2"/></svg></div>
<div class="cmd-item-text">
<div class="cmd-item-title">生产工单</div>
<div class="cmd-item-path">生产管理</div>
</div>
</div>
<div class="cmd-item" data-title="耗材管理">
<div class="cmd-item-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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></div>
<div class="cmd-item-text">
<div class="cmd-item-title">耗材管理</div>
<div class="cmd-item-path">生产基础信息</div>
</div>
</div>
</div>
<div class="cmd-footer">
<span>↑↓ 选择</span>
<span>↵ 跳转</span>
<span>ESC 关闭</span>
</div>
</div>
</div>
<div class="scheme-badge">方案 B · 图标轨 + 命令搜索 · <a href="index.html">返回对比</a></div>
<script>
const overlay = document.getElementById('cmdOverlay')
const input = document.getElementById('cmdInput')
const results = document.getElementById('cmdResults')
function openCmd() {
overlay.classList.add('open')
input.value = ''
filterItems('')
setTimeout(() => input.focus(), 50)
}
function closeCmd() { overlay.classList.remove('open') }
document.getElementById('openCmd').onclick = openCmd
document.getElementById('openCmd2').onclick = openCmd
overlay.addEventListener('click', e => { if (e.target === overlay) closeCmd() })
document.addEventListener('keydown', e => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); openCmd() }
if (e.key === 'Escape') closeCmd()
})
function filterItems(q) {
const items = results.querySelectorAll('.cmd-item')
const lower = q.toLowerCase()
items.forEach(item => {
const title = item.dataset.title || ''
const path = item.querySelector('.cmd-item-path')?.textContent || ''
const match = !q || title.includes(q) || path.includes(q) || title.toLowerCase().includes(lower)
item.style.display = match ? '' : 'none'
})
results.querySelectorAll('.cmd-group-label').forEach(label => {
let next = label.nextElementSibling
let hasVisible = false
while (next && !next.classList.contains('cmd-group-label')) {
if (next.classList.contains('cmd-item') && next.style.display !== 'none') hasVisible = true
next = next.nextElementSibling
}
label.style.display = hasVisible ? '' : 'none'
})
}
input.addEventListener('input', () => filterItems(input.value.trim()))
</script>
</body>
</html>