469 lines
19 KiB
HTML
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>
|