facc04aa65
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交 (5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。 一、docs 结构整改(整改 #14) 根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入, 随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录 树并存于 docs/,共 791 文件、双分类体系冲突。 修复动作: - b2 同名异主题文件改名迁移保全 9 个 - C 类 39 个孤立文件按主题正确归类 - A/B1 类 222 个重复文件删除(新结构已有内容副本) - 9 个旧独有空目录删除 - 270 处内部引用按 verified 映射改写 - 整改记录 #14 登记于 04-运维文档/部署运维 结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。 残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。 二、compose 双目录对齐(消除踩坑 A) - docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist 改为 src/frontend-*/dist(h5 / agent / admin / terminal) - docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/ - 效果:本地 docker compose up 不再把根目录 stale dist 挂回, 与线上一致,分叉隐患消除(已 docker compose config 校验通过) 防复发铁律: - 重构须提交;仓库修复须 git stash -u 或先 commit - 新结构须 git add 并提交,避免再次 untracked 复活 - H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
2633 lines
101 KiB
HTML
2633 lines
101 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN" data-theme="dark">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||
<title>IT智能服务台 · H5用户端原型 v2.3.6</title>
|
||
<style>
|
||
/* ============================================================================
|
||
CSS 变量 — 浅色/深色双主题
|
||
============================================================================ */
|
||
:root {
|
||
--accent: #3b82f6;
|
||
--accent-soft: rgba(59, 130, 246, 0.12);
|
||
--bg-primary: #f5f6fa;
|
||
--bg-secondary: #ffffff;
|
||
--bg-tertiary: #eef0f5;
|
||
--text-primary: #1a1a2e;
|
||
--text-secondary: #555770;
|
||
--text-tertiary: #9ca3af;
|
||
--text-placeholder: #b0b4c0;
|
||
--border-color: #e5e7eb;
|
||
--shadow: 0 1px 4px rgba(0,0,0,0.06);
|
||
--radius: 12px;
|
||
--transition: 0.2s ease;
|
||
--color-employee-bg: #3b82f6;
|
||
--color-agent-bg: #ffffff;
|
||
--color-agent-border: #e5e7eb;
|
||
--color-ai-bg: #e8f5e9;
|
||
--color-ai-text: #1b5e20;
|
||
--color-ai-tag-text: #2e7d32;
|
||
--color-ai-tag-bg: #c8e6c9;
|
||
--color-system-text: #9ca3af;
|
||
--color-system-bg: #eef0f5;
|
||
--color-warning: #ff9800;
|
||
--color-danger: #ef4444;
|
||
--color-success: #22c55e;
|
||
--color-guide-active: #ff9800;
|
||
--ts-done: #22c55e;
|
||
--ts-current: #3b82f6;
|
||
--ts-pending-bg: #eef0f5;
|
||
--ts-yes-bg: rgba(34,197,94,0.06);
|
||
--ts-yes-border: rgba(34,197,94,0.3);
|
||
--ts-no-bg: rgba(239,68,68,0.06);
|
||
--ts-no-border: rgba(239,68,68,0.3);
|
||
--color-ts-card-bg: #ffffff;
|
||
--color-ts-card-border: #e5e7eb;
|
||
--color-ts-card-header: rgba(59,130,246,0.08);
|
||
--resize-handle-color: #cbd5e1;
|
||
--tool-btn-bg: #eef0f5;
|
||
--tool-btn-text: #555770;
|
||
}
|
||
[data-theme="dark"] {
|
||
--accent: #3b82f6;
|
||
--accent-soft: rgba(59, 130, 246, 0.18);
|
||
--bg-primary: #0f172a;
|
||
--bg-secondary: #1e293b;
|
||
--bg-tertiary: #162032;
|
||
--text-primary: #e2e8f0;
|
||
--text-secondary: #94a3b8;
|
||
--text-tertiary: #64748b;
|
||
--text-placeholder: #475569;
|
||
--border-color: #334155;
|
||
--shadow: 0 1px 4px rgba(0,0,0,0.3);
|
||
--color-employee-bg: #2563eb;
|
||
--color-agent-bg: #1e293b;
|
||
--color-agent-border: #334155;
|
||
--color-ai-bg: #0d3320;
|
||
--color-ai-text: #86efac;
|
||
--color-ai-tag-text: #86efac;
|
||
--color-ai-tag-bg: #14532d;
|
||
--color-system-text: #64748b;
|
||
--color-system-bg: #162032;
|
||
--color-warning: #f97316;
|
||
--color-danger: #ef4444;
|
||
--color-success: #22c55e;
|
||
--color-guide-active: #f97316;
|
||
--ts-done: #22c55e;
|
||
--ts-current: #3b82f6;
|
||
--ts-pending-bg: #162032;
|
||
--ts-yes-bg: rgba(34,197,94,0.08);
|
||
--ts-yes-border: rgba(34,197,94,0.3);
|
||
--ts-no-bg: rgba(239,68,68,0.08);
|
||
--ts-no-border: rgba(239,68,68,0.3);
|
||
--color-ts-card-bg: #1e293b;
|
||
--color-ts-card-border: #334155;
|
||
--color-ts-card-header: rgba(59,130,246,0.12);
|
||
--resize-handle-color: #475569;
|
||
--tool-btn-bg: #162032;
|
||
--tool-btn-text: #94a3b8;
|
||
}
|
||
|
||
/* ============================================================================
|
||
基础重置
|
||
============================================================================ */
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
html, body {
|
||
height: 100%;
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||
background: #0a0f1a;
|
||
color: var(--text-primary);
|
||
-webkit-font-smoothing: antialiased;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* ============================================================================
|
||
页面级布局 — 单视图
|
||
============================================================================ */
|
||
.page-wrapper {
|
||
display: flex;
|
||
gap: 32px;
|
||
padding: 24px;
|
||
min-height: 100vh;
|
||
align-items: flex-start;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* 视图标签 */
|
||
.view-label {
|
||
text-align: center;
|
||
padding: 8px 0 12px;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: #94a3b8;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
}
|
||
.view-label .badge {
|
||
display: inline-block;
|
||
padding: 2px 8px;
|
||
border-radius: 4px;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
}
|
||
.badge--primary { background: rgba(59,130,246,0.2); color: #60a5fa; }
|
||
.badge--new { background: rgba(239,68,68,0.2); color: #f87171; }
|
||
|
||
/* ============================================================================
|
||
视图容器
|
||
============================================================================ */
|
||
.view-container { flex-shrink: 0; }
|
||
|
||
/* ===== 桌面端企微壳 ===== */
|
||
.desktop-shell {
|
||
width: 720px;
|
||
height: 940px;
|
||
border-radius: 16px;
|
||
border: 2px solid #334155;
|
||
overflow: hidden;
|
||
background: var(--bg-primary);
|
||
box-shadow: 0 8px 40px rgba(0,0,0,0.4);
|
||
position: relative;
|
||
}
|
||
/* 企微顶栏模拟 */
|
||
.desktop-shell__wecom-bar {
|
||
height: 36px;
|
||
background: #2a2a3e;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 12px;
|
||
gap: 8px;
|
||
border-bottom: 1px solid #3a3a5c;
|
||
flex-shrink: 0;
|
||
}
|
||
.wecom-tab { font-size: 12px; color: #888; padding: 4px 10px; border-radius: 4px; cursor: default; }
|
||
.wecom-tab--active { color: #e2e8f0; background: rgba(59,130,246,0.15); }
|
||
.wecom-title { font-size: 13px; color: #ccc; margin-left: auto; }
|
||
|
||
/* ============================================================================
|
||
主布局
|
||
============================================================================ */
|
||
.chat-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
background: var(--bg-primary);
|
||
}
|
||
|
||
/* ===== 桌面端双栏主体 ===== */
|
||
.desktop-body {
|
||
display: flex;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
/* 左侧:消息区 */
|
||
.desktop-left {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-width: 280px;
|
||
}
|
||
/* 拖拽手柄 */
|
||
.resize-handle-v {
|
||
width: 6px;
|
||
cursor: col-resize;
|
||
background: transparent;
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
z-index: 10;
|
||
transition: background 0.2s;
|
||
}
|
||
.resize-handle-v:hover,
|
||
.resize-handle-v--active {
|
||
background: var(--accent);
|
||
}
|
||
.resize-handle-v::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 2px;
|
||
height: 24px;
|
||
border-radius: 1px;
|
||
background: var(--resize-handle-color);
|
||
opacity: 0.5;
|
||
}
|
||
|
||
/* 右侧:三段式面板 - v1.9 新布局 */
|
||
.desktop-right {
|
||
width: 280px;
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
background: var(--bg-secondary);
|
||
min-width: 200px;
|
||
max-width: 400px;
|
||
}
|
||
|
||
/* ============================================================================
|
||
顶部标题栏
|
||
============================================================================ */
|
||
.chat-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 10px 16px;
|
||
background: var(--bg-secondary);
|
||
border-bottom: 1px solid var(--border-color);
|
||
flex-shrink: 0;
|
||
}
|
||
.chat-header__title {
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
.chat-header__title .logo-icon { font-size: 18px; }
|
||
.chat-header__actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
.chat-header__online {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
font-size: 11px;
|
||
color: var(--color-success);
|
||
}
|
||
.chat-header__online-dot {
|
||
width: 6px; height: 6px; border-radius: 50%;
|
||
background: var(--color-success);
|
||
animation: online-pulse 2s ease-in-out infinite;
|
||
}
|
||
.theme-switch {
|
||
display: flex; align-items: center; gap: 4px;
|
||
cursor: pointer; user-select: none;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
.switch-track {
|
||
width: 32px; height: 18px; border-radius: 9px;
|
||
background: var(--bg-tertiary); border: 1px solid var(--border-color);
|
||
position: relative; transition: background var(--transition);
|
||
}
|
||
.switch-thumb {
|
||
width: 14px; height: 14px; border-radius: 50%;
|
||
background: var(--accent); position: absolute; top: 1px; left: 1px;
|
||
transition: transform var(--transition);
|
||
}
|
||
[data-theme="dark"] .switch-thumb { transform: translateX(14px); }
|
||
|
||
/* ============================================================================
|
||
排查步骤 — 固定在消息区顶部
|
||
============================================================================ */
|
||
.ts-top-bar {
|
||
flex-shrink: 0;
|
||
background: var(--color-ts-card-bg);
|
||
border-bottom: 1px solid var(--color-ts-card-border);
|
||
overflow: hidden;
|
||
transition: max-height 0.3s ease;
|
||
z-index: 5;
|
||
}
|
||
.ts-top-bar__header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 6px 12px;
|
||
background: var(--color-ts-card-header);
|
||
border-bottom: 1px solid var(--border-color);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
cursor: pointer;
|
||
user-select: none;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
.ts-top-bar__header-icon { font-size: 12px; }
|
||
.ts-top-bar__header-title { flex: 1; }
|
||
.ts-top-bar__header-tag {
|
||
font-size: 9px;
|
||
padding: 1px 6px;
|
||
border-radius: 3px;
|
||
background: var(--accent-soft);
|
||
color: var(--accent);
|
||
font-weight: 600;
|
||
}
|
||
.ts-top-bar__toggle {
|
||
font-size: 10px;
|
||
color: var(--text-tertiary);
|
||
transition: transform 0.2s;
|
||
}
|
||
.ts-top-bar__toggle--collapsed { transform: rotate(180deg); }
|
||
|
||
.ts-top-bar__path {
|
||
padding: 6px 12px 4px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.ts-path-bar {
|
||
display: flex; align-items: center; gap: 2px;
|
||
overflow-x: auto; padding-bottom: 4px;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
.ts-path-bar::-webkit-scrollbar { height: 0; }
|
||
.ts-step { display: flex; align-items: center; gap: 4px; white-space: nowrap; flex-shrink: 0; }
|
||
.ts-dot {
|
||
width: 16px; height: 16px; border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 8px; font-weight: 700; flex-shrink: 0;
|
||
}
|
||
.ts-dot--done { background: var(--ts-done); color: #fff; }
|
||
.ts-dot--current { background: var(--ts-current); color: #fff; box-shadow: 0 0 0 2px var(--accent-soft); animation: ts-dot-pulse 2s ease-in-out infinite; }
|
||
.ts-dot--pending { background: var(--ts-pending-bg); color: var(--text-tertiary); border: 1px solid var(--border-color); }
|
||
.ts-label { font-size: 10px; color: var(--text-secondary); }
|
||
.ts-step--done .ts-label { color: var(--text-tertiary); text-decoration: line-through; }
|
||
.ts-step--current .ts-label { color: var(--accent); font-weight: 600; }
|
||
.ts-step--pending .ts-label { color: var(--text-tertiary); }
|
||
.ts-arrow { color: var(--text-tertiary); font-size: 8px; flex-shrink: 0; padding: 0 1px; }
|
||
.ts-arrow--active { color: var(--ts-done); }
|
||
|
||
.ts-top-bar__body {
|
||
padding: 8px 12px 10px;
|
||
}
|
||
|
||
/* 决策节点 */
|
||
.ts-question-header { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 8px; }
|
||
.ts-question-icon { font-size: 14px; flex-shrink: 0; margin-top: 1px; }
|
||
.ts-question-text { font-size: 13px; font-weight: 600; color: var(--text-primary); line-height: 1.5; }
|
||
.ts-options { display: flex; gap: 8px; margin-top: 2px; }
|
||
.ts-option {
|
||
flex: 1; display: flex; align-items: center; justify-content: center; gap: 4px;
|
||
padding: 8px 10px; border-radius: 8px;
|
||
border: 2px solid var(--border-color); background: var(--bg-primary);
|
||
color: var(--text-primary); font-size: 12px; font-weight: 600;
|
||
cursor: pointer; transition: all 0.2s; font-family: inherit;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
.ts-option:active { transform: scale(0.97); }
|
||
.ts-option--yes { border-color: var(--ts-yes-border); background: var(--ts-yes-bg); }
|
||
.ts-option--no { border-color: var(--ts-no-border); background: var(--ts-no-bg); }
|
||
.ts-option-icon { font-size: 12px; }
|
||
.ts-option--selected-yes { border-color: #22c55e !important; background: rgba(34,197,94,0.15) !important; box-shadow: 0 0 0 2px rgba(34,197,94,0.2); }
|
||
.ts-option--selected-no { border-color: #ef4444 !important; background: rgba(239,68,68,0.15) !important; box-shadow: 0 0 0 2px rgba(239,68,68,0.2); }
|
||
|
||
/* ============================================================================
|
||
消息列表
|
||
============================================================================ */
|
||
.chat-messages {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 8px 0;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
.chat-messages::-webkit-scrollbar { width: 3px; }
|
||
.chat-messages::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
|
||
|
||
/* ============================================================================
|
||
消息气泡
|
||
============================================================================ */
|
||
.msg {
|
||
display: flex; flex-direction: column;
|
||
padding: 4px 14px; max-width: 100%;
|
||
animation: bubble-in 0.3s ease-out;
|
||
}
|
||
.msg--employee { align-items: flex-end; }
|
||
.msg--agent, .msg--ai { align-items: flex-start; }
|
||
.msg--system { align-items: center; padding: 6px 14px; }
|
||
.msg--system .msg__system-text {
|
||
font-size: 11px; color: var(--color-system-text);
|
||
background: var(--color-system-bg);
|
||
padding: 3px 10px; border-radius: 10px;
|
||
text-align: center; line-height: 1.5;
|
||
}
|
||
.msg__sender { display: flex; align-items: center; gap: 4px; margin-bottom: 2px; padding-left: 4px; }
|
||
.msg__ai-tag {
|
||
font-size: 10px; color: var(--color-ai-tag-text);
|
||
background: var(--color-ai-tag-bg);
|
||
padding: 1px 5px; border-radius: 3px; font-weight: 600;
|
||
}
|
||
.msg__sender-name { font-size: 11px; color: var(--text-tertiary); }
|
||
.msg__bubble {
|
||
max-width: 75%; padding: 9px 13px; border-radius: 14px;
|
||
word-break: break-word; line-height: 1.6; font-size: 13px;
|
||
}
|
||
.msg--employee .msg__bubble { background: var(--color-employee-bg); color: #fff; border-top-right-radius: 4px; }
|
||
.msg--agent .msg__bubble { background: var(--color-agent-bg); color: var(--text-primary); border-top-left-radius: 4px; border: 1px solid var(--color-agent-border); }
|
||
.msg--ai .msg__bubble { background: var(--color-ai-bg); color: var(--color-ai-text); border-top-left-radius: 4px; }
|
||
.msg__time { font-size: 10px; color: var(--text-placeholder); margin-top: 2px; }
|
||
.msg--employee .msg__time { text-align: right; padding-right: 4px; }
|
||
.msg--agent .msg__time, .msg--ai .msg__time { text-align: left; padding-left: 4px; }
|
||
.msg__avatar {
|
||
width: 28px; height: 28px; border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 12px; flex-shrink: 0; margin-bottom: 2px;
|
||
}
|
||
.msg__avatar--agent { background: linear-gradient(135deg, #3b82f6, #6366f1); }
|
||
.msg__avatar--ai { background: linear-gradient(135deg, #22c55e, #14b8a6); }
|
||
.msg__avatar-row { display: flex; align-items: flex-end; gap: 6px; max-width: 88%; }
|
||
|
||
/* ============================================================================
|
||
输入栏
|
||
============================================================================ */
|
||
.input-bar {
|
||
background: var(--bg-secondary);
|
||
border-top: 1px solid var(--border-color);
|
||
flex-shrink: 0;
|
||
}
|
||
.input-toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2px;
|
||
padding: 4px 12px 2px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.tool-btn {
|
||
width: 32px; height: 32px; border-radius: 8px;
|
||
border: none; background: var(--tool-btn-bg);
|
||
color: var(--tool-btn-text); font-size: 15px;
|
||
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
||
transition: all 0.15s; flex-shrink: 0;
|
||
-webkit-tap-highlight-color: transparent; outline: none;
|
||
}
|
||
.tool-btn:active { transform: scale(0.92); background: var(--accent-soft); }
|
||
.tool-btn:hover { background: var(--accent-soft); color: var(--accent); }
|
||
.tool-sep {
|
||
width: 1px; height: 18px; background: var(--border-color);
|
||
margin: 0 4px; flex-shrink: 0;
|
||
}
|
||
.input-row {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
gap: 6px;
|
||
padding: 6px 12px;
|
||
padding-bottom: calc(6px + env(safe-area-inset-bottom, 6px));
|
||
}
|
||
.input-field {
|
||
flex: 1; background: var(--bg-tertiary); border-radius: 8px;
|
||
padding: 8px 10px; border: 1px solid var(--border-color);
|
||
font-size: 13px; font-family: inherit; color: var(--text-primary);
|
||
resize: none; outline: none; min-height: 54px; max-height: 120px;
|
||
line-height: 1.5; transition: border-color 0.2s;
|
||
}
|
||
.input-field:focus { border-color: var(--accent); }
|
||
.input-field::placeholder { color: var(--text-placeholder); }
|
||
.bell-btn {
|
||
position: relative; width: 34px; height: 34px; border-radius: 50%; border: none;
|
||
cursor: pointer; background: linear-gradient(135deg, var(--color-warning), #f97316);
|
||
display: flex; align-items: center; justify-content: center;
|
||
box-shadow: 0 2px 6px rgba(255, 152, 0, 0.25);
|
||
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
-webkit-tap-highlight-color: transparent; outline: none; flex-shrink: 0;
|
||
}
|
||
.bell-btn:active { transform: scale(0.92); }
|
||
.bell-btn__icon {
|
||
font-size: 16px; line-height: 1; display: inline-block;
|
||
}
|
||
.bell-btn__dot {
|
||
position: absolute; top: 1px; right: 1px;
|
||
width: 6px; height: 6px; border-radius: 50%;
|
||
background: var(--color-danger); border: 1px solid var(--bg-secondary);
|
||
}
|
||
.send-btn {
|
||
flex-shrink: 0; height: 34px; width: 34px; border-radius: 50%;
|
||
border: none; background: var(--accent); color: #fff;
|
||
font-size: 14px; cursor: pointer;
|
||
transition: all 0.2s; font-family: inherit;
|
||
display: flex; align-items: center; justify-content: center;
|
||
box-shadow: 0 2px 6px rgba(59, 130, 246, 0.25);
|
||
}
|
||
.send-btn:active { transform: scale(0.92); }
|
||
.send-btn:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }
|
||
|
||
|
||
/* ============================================================================
|
||
桌面端右侧面板 — v1.9 新布局(排队到底部)
|
||
============================================================================ */
|
||
.right-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* ===== ① 手风琴区域(设备信息 / 自助诊断)====== */
|
||
.accordion-section {
|
||
flex-shrink: 0;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.accordion-item {
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.accordion-item:last-child { border-bottom: none; }
|
||
.accordion-item__header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 10px 14px;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
}
|
||
.accordion-item__header:hover { background: var(--bg-tertiary); }
|
||
.accordion-item__icon { font-size: 14px; }
|
||
.accordion-item__title { flex: 1; font-size: 13px; font-weight: 600; color: var(--text-primary); }
|
||
.accordion-item__toggle { font-size: 12px; color: var(--text-tertiary); }
|
||
.accordion-item__content {
|
||
padding: 0 14px 12px;
|
||
display: none;
|
||
}
|
||
.accordion-item--active .accordion-item__content { display: block; }
|
||
.accordion-item--active .accordion-item__toggle { transform: rotate(180deg); }
|
||
|
||
/* 设备信息卡片 */
|
||
.device-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
.device-item { display: flex; justify-content: space-between; font-size: 11px; }
|
||
.device-item__label { color: var(--text-secondary); }
|
||
.device-item__value { color: var(--text-primary); font-weight: 500; }
|
||
|
||
/* ============================================================================
|
||
自助诊断 — v2.2:标题栏异常徽章(3 优化)+ 6 横向并排标签页(替代 3×2 网格)
|
||
============================================================================ */
|
||
|
||
/* 标题栏 */
|
||
.diag-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 8px 14px 6px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.diag-header__icon { font-size: 14px; }
|
||
.diag-header__title { flex: 1; font-size: 13px; font-weight: 600; color: var(--text-primary); display: flex; align-items: center; gap: 6px; }
|
||
|
||
/* 标题栏异常徽章 — v2.2 三态对比 */
|
||
.diag-header__badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
height: 18px;
|
||
padding: 0 7px;
|
||
border-radius: 9px;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
font-family: inherit;
|
||
white-space: nowrap;
|
||
}
|
||
/* 状态 1:0 异常 — 绿色 ✓ 全部正常 */
|
||
.diag-header__badge--ok {
|
||
background: rgba(34,197,94,0.15);
|
||
color: #16a34a;
|
||
}
|
||
/* 状态 2:N 异常 — 红色 ⚠ N(兼容旧版单数字徽章) */
|
||
.diag-header__badge--alert {
|
||
background: var(--color-danger, #ef4444);
|
||
color: #fff;
|
||
}
|
||
.diag-header__badge--alert .diag-header__badge-icon {
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
width: 12px; height: 12px; border-radius: 50%;
|
||
background: rgba(255,255,255,0.25);
|
||
font-size: 9px;
|
||
}
|
||
/* 状态 3 — 优化 ①:分级显示 ⚠ 5W · 1F(warning/fail 拆开)*/
|
||
.diag-header__badge--graded {
|
||
background: var(--color-danger, #ef4444);
|
||
color: #fff;
|
||
padding: 0 8px;
|
||
gap: 6px;
|
||
}
|
||
.diag-header__badge-segment {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 2px;
|
||
padding: 0 4px;
|
||
height: 14px;
|
||
border-radius: 7px;
|
||
background: rgba(255,255,255,0.22);
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||
}
|
||
.diag-header__badge-segment--W { color: #fef3c7; }
|
||
.diag-header__badge-segment--F { color: #fecaca; }
|
||
.diag-header__badge-sep { opacity: 0.55; font-weight: 400; font-size: 9px; }
|
||
|
||
/* 状态 4 — 优化 ③:0 异常达标动画(绿色脉冲 + 文字高亮) */
|
||
.diag-header__badge--celebrate {
|
||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
||
color: #fff;
|
||
animation: celebratePulse 2.4s ease-in-out infinite;
|
||
padding: 0 10px;
|
||
font-weight: 700;
|
||
}
|
||
.diag-header__badge--celebrate .diag-header__celebrate-icon {
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
width: 12px; height: 12px; border-radius: 50%;
|
||
background: rgba(255,255,255,0.25);
|
||
font-size: 9px;
|
||
animation: celebrateCheck 1.6s ease-in-out infinite;
|
||
}
|
||
@keyframes celebratePulse {
|
||
0%, 100% { box-shadow: 0 0 0 0 rgba(34,197,94,0.55); }
|
||
50% { box-shadow: 0 0 0 5px rgba(34,197,94,0); }
|
||
}
|
||
@keyframes celebrateCheck {
|
||
0%, 100% { transform: scale(1); }
|
||
50% { transform: scale(1.18); }
|
||
}
|
||
.diag-header__badge--celebrate .badge-tip {
|
||
display: block;
|
||
position: absolute;
|
||
top: -22px; left: 50%;
|
||
transform: translateX(-50%);
|
||
font-size: 9px;
|
||
font-weight: 600;
|
||
color: #16a34a;
|
||
white-space: nowrap;
|
||
font-family: inherit;
|
||
}
|
||
.diag-header__badge--celebrate {
|
||
position: relative;
|
||
}
|
||
|
||
.diag-header__action {
|
||
height: 24px;
|
||
padding: 0 10px;
|
||
border-radius: 12px;
|
||
border: none;
|
||
background: var(--accent);
|
||
color: #fff;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
flex-shrink: 0;
|
||
}
|
||
.diag-header__action:disabled { opacity: 0.5; cursor: not-allowed; }
|
||
|
||
/* ===== v2.2 6 Tab 横向并排标签页(替代原 3×2 网格)===== */
|
||
.diag-tabs {
|
||
display: flex;
|
||
align-items: stretch;
|
||
padding: 0 6px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
background: var(--bg-secondary);
|
||
overflow-x: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
.diag-tabs::-webkit-scrollbar { display: none; }
|
||
.diag-tab {
|
||
flex: 1 1 0;
|
||
min-width: 60px;
|
||
position: relative;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
height: 34px;
|
||
padding: 0 6px;
|
||
border: none;
|
||
border-bottom: 2px solid transparent;
|
||
background: transparent;
|
||
color: var(--text-secondary);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
white-space: nowrap;
|
||
transition: all 0.18s;
|
||
margin-bottom: -1px; /* 覆盖外层 border-bottom */
|
||
}
|
||
.diag-tab:hover { color: var(--accent); }
|
||
.diag-tab--active {
|
||
color: var(--accent);
|
||
border-bottom-color: var(--accent);
|
||
font-weight: 700;
|
||
}
|
||
/* 异常 Tab:底部双层下划线(红色 + 蓝) */
|
||
.diag-tab--has-abnormal:not(.diag-tab--active)::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -1px;
|
||
left: 0; right: 0;
|
||
height: 2px;
|
||
background: var(--color-danger, #ef4444);
|
||
}
|
||
.diag-tab--has-abnormal.diag-tab--active::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -1px;
|
||
left: 0; right: 0;
|
||
height: 2px;
|
||
background: var(--color-danger, #ef4444);
|
||
opacity: 0.35;
|
||
}
|
||
.diag-tab__label { font-size: 12px; }
|
||
.diag-tab__badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 14px;
|
||
height: 14px;
|
||
padding: 0 4px;
|
||
border-radius: 7px;
|
||
background: var(--color-danger, #ef4444);
|
||
color: #fff;
|
||
font-size: 9px;
|
||
font-weight: 700;
|
||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||
}
|
||
.diag-tab--active .diag-tab__badge {
|
||
background: var(--color-danger, #ef4444);
|
||
color: #fff;
|
||
}
|
||
/* Tab 内接入中提示(优化 ②) */
|
||
.diag-tab__pending-hint {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 1px;
|
||
font-size: 8.5px;
|
||
color: var(--text-tertiary);
|
||
font-weight: 400;
|
||
font-style: italic;
|
||
margin-left: 1px;
|
||
}
|
||
.diag-tab__pending-dot {
|
||
width: 5px; height: 5px; border-radius: 50%;
|
||
background: var(--text-tertiary);
|
||
opacity: 0.7;
|
||
}
|
||
|
||
/* Tab 内容区(默认折叠示例这里展示展开后的样子) */
|
||
.diag-content {
|
||
padding: 4px 10px 10px;
|
||
}
|
||
.diag-content__label {
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
color: var(--text-tertiary);
|
||
margin-bottom: 4px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
.diag-content__hint { font-size: 9px; color: var(--text-tertiary); }
|
||
|
||
.diag-risk-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
.diag-risk-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 6px 8px;
|
||
border-radius: 8px;
|
||
border: 1px solid var(--border-color);
|
||
background: var(--bg-primary);
|
||
}
|
||
.diag-risk-item--warning {
|
||
background: rgba(245,158,11,0.06);
|
||
border-color: rgba(245,158,11,0.3);
|
||
}
|
||
.diag-risk-item--danger {
|
||
background: rgba(239,68,68,0.06);
|
||
border-color: rgba(239,68,68,0.3);
|
||
}
|
||
.diag-risk-item__icon { font-size: 13px; flex-shrink: 0; }
|
||
.diag-risk-item__name { flex: 1; font-size: 11px; color: var(--text-primary); font-weight: 500; }
|
||
.diag-risk-item__status {
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
padding: 1px 6px;
|
||
border-radius: 4px;
|
||
}
|
||
.diag-risk-item__status--normal { background: rgba(34,197,94,0.15); color: #16a34a; }
|
||
.diag-risk-item__status--warning { background: rgba(245,158,11,0.15); color: #d97706; }
|
||
.diag-risk-item__status--danger { background: rgba(239,68,68,0.15); color: #dc2626; }
|
||
.diag-risk-item__status--pending { color: var(--text-tertiary); font-style: italic; }
|
||
.diag-risk-item__toggle { font-size: 10px; color: var(--text-tertiary); }
|
||
|
||
/* 注解:异常计数规则 */
|
||
.diag-legend {
|
||
margin: 6px 10px 0;
|
||
padding: 6px 8px;
|
||
border-radius: 6px;
|
||
background: rgba(59,130,246,0.06);
|
||
font-size: 10px;
|
||
line-height: 1.5;
|
||
color: var(--text-secondary);
|
||
}
|
||
.diag-legend b { color: var(--accent); font-weight: 600; }
|
||
|
||
/* ===== v2.2 异常数量徽章对照表(紧贴 H5 界面,便于一次性看 5 种状态)===== */
|
||
.diag-badge-gallery {
|
||
margin: 8px 10px 4px;
|
||
padding: 8px 10px;
|
||
border-radius: 8px;
|
||
background: var(--bg-secondary);
|
||
border: 1px dashed var(--accent);
|
||
}
|
||
.diag-badge-gallery__title {
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
margin-bottom: 6px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
.diag-badge-gallery__row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 4px 0;
|
||
font-size: 10px;
|
||
color: var(--text-secondary);
|
||
}
|
||
.diag-badge-gallery__row + .diag-badge-gallery__row {
|
||
border-top: 1px dashed var(--border-color);
|
||
}
|
||
.diag-badge-gallery__desc { flex: 1; line-height: 1.4; }
|
||
.diag-badge-gallery__desc b { color: var(--text-primary); }
|
||
.diag-badge-gallery__desc small { color: var(--text-tertiary); font-size: 9px; }
|
||
|
||
/* 接入中灰色角标(v2.2 优化 ②) */
|
||
.diag-pending-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
font-size: 9px;
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
background: var(--bg-tertiary);
|
||
color: var(--text-tertiary);
|
||
font-style: italic;
|
||
}
|
||
.diag-pending-tag::before {
|
||
content: '';
|
||
width: 5px; height: 5px; border-radius: 50%;
|
||
background: var(--text-tertiary);
|
||
}
|
||
|
||
/* ===== 风险项新风格(v2.2 内容区使用)===== */
|
||
.diag-risk-item--pending { opacity: 0.7; background: var(--bg-tertiary) !important; border-color: var(--border-color) !important; }
|
||
.diag-risk-item--pending .diag-risk-item__status--pending { color: var(--text-tertiary); }
|
||
|
||
/* ===== v2.3.6: 检测按钮(每条诊断项独立重检)===== */
|
||
.diag-risk-item__btn {
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
font-family: inherit;
|
||
padding: 2px 8px;
|
||
border-radius: 4px;
|
||
border: 1px solid var(--border-color, #e5e7eb);
|
||
background: var(--bg-primary, #fff);
|
||
color: var(--accent, #3b82f6);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
flex-shrink: 0;
|
||
}
|
||
.diag-risk-item__btn:hover {
|
||
background: var(--accent, #3b82f6);
|
||
color: #fff;
|
||
border-color: var(--accent, #3b82f6);
|
||
}
|
||
.diag-risk-item__btn:disabled {
|
||
opacity: 0.4;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* ===== v2.3.6: 标题栏外层 actions 区(徽章 + 一键诊断)===== */
|
||
.accordion-item__header-actions {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
flex-shrink: 0;
|
||
}
|
||
.header__total-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
height: 18px;
|
||
padding: 0 7px;
|
||
border-radius: 9px;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
font-family: inherit;
|
||
white-space: nowrap;
|
||
}
|
||
.header__total-badge--graded {
|
||
background: var(--color-danger, #ef4444);
|
||
color: #fff;
|
||
padding: 0 8px;
|
||
gap: 6px;
|
||
}
|
||
.header__total-badge--graded .badge-segment {
|
||
padding: 0 4px;
|
||
height: 14px;
|
||
background: rgba(255,255,255,0.22);
|
||
border-radius: 7px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
font-size: 10px;
|
||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||
}
|
||
.header__total-badge--graded .badge-segment--W { color: #fef3c7; }
|
||
.header__total-badge--graded .badge-segment--F { color: #fecaca; }
|
||
.header__total-badge--graded .badge-sep { opacity: 0.55; font-weight: 400; font-size: 9px; }
|
||
|
||
/* ===== v2.3.6: 未排队占位样式 ===== */
|
||
.qh-position-inline--idle small {
|
||
font-style: italic;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
/* ===== 分隔线 ===== */
|
||
.right-panel__divider {
|
||
height: 6px;
|
||
background: var(--bg-tertiary);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ===== ② 智能推荐(占据主要空间)====== */
|
||
.recommend-section {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
border-bottom: 1px solid var(--border-color);
|
||
min-height: 200px;
|
||
}
|
||
.recommend-section__header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 10px 14px;
|
||
cursor: pointer;
|
||
flex-shrink: 0;
|
||
}
|
||
.recommend-section__header:hover { background: var(--bg-tertiary); }
|
||
.recommend-section__icon { font-size: 14px; }
|
||
.recommend-section__title { flex: 1; font-size: 13px; font-weight: 600; color: var(--text-primary); }
|
||
.recommend-section__toggle { font-size: 12px; color: var(--text-tertiary); transition: transform 0.2s; }
|
||
.recommend-section--active .recommend-section__toggle { transform: rotate(180deg); }
|
||
|
||
.recommend-section__content {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 0 14px 12px;
|
||
display: none;
|
||
}
|
||
.recommend-section--active .recommend-section__content { display: block; }
|
||
|
||
.recommend-card {
|
||
padding: 10px;
|
||
border-radius: 10px;
|
||
margin-bottom: 8px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
.recommend-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
|
||
.recommend-card--green { border: 1px solid rgba(34,197,94,0.3); background: rgba(34,197,94,0.05); }
|
||
.recommend-card--orange { border: 1px solid rgba(249,115,22,0.3); background: rgba(249,115,22,0.05); }
|
||
.recommend-card--gray { border: 1px solid var(--border-color); background: var(--bg-primary); }
|
||
|
||
.recommend-card__title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin-bottom: 4px;
|
||
}
|
||
.recommend-card__desc {
|
||
font-size: 10px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.4;
|
||
}
|
||
.recommend-card__tags {
|
||
display: flex;
|
||
gap: 4px;
|
||
margin-top: 6px;
|
||
}
|
||
.recommend-card__tag {
|
||
font-size: 9px;
|
||
padding: 2px 5px;
|
||
border-radius: 3px;
|
||
background: var(--accent-soft);
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* ===== 分隔线 ===== */
|
||
|
||
/* ===== ③ 排队等待(底部)====== */
|
||
.queue-section {
|
||
flex-shrink: 0;
|
||
background: var(--bg-secondary);
|
||
}
|
||
.queue-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 10px 14px;
|
||
cursor: pointer;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.queue-header:hover { background: var(--bg-tertiary); }
|
||
.queue-header__left { display: flex; align-items: center; gap: 8px; }
|
||
.queue-header__icon { font-size: 14px; }
|
||
.queue-header__title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
|
||
.queue-header__position { font-size: 14px; font-weight: 700; color: var(--accent); }
|
||
|
||
/* ===== v2.3 排队标题栏:位置/LV/分 全部合并到标题栏 ===== */
|
||
.queue-header--v23 { padding: 10px 14px; gap: 6px; flex-wrap: wrap; }
|
||
.queue-header--v23 .queue-header__left { flex: 1; min-width: 0; gap: 6px; flex-wrap: wrap; }
|
||
.queue-header--v23 .queue-header__title { margin-right: 2px; }
|
||
.queue-header__position-inline {
|
||
display: inline-flex; align-items: baseline; gap: 3px;
|
||
font-size: 12px; color: var(--text-secondary);
|
||
padding: 1px 6px;
|
||
background: rgba(59,130,246,0.08);
|
||
border-radius: 4px;
|
||
}
|
||
.queue-header__position-inline b { font-size: 14px; font-weight: 700; color: var(--accent); }
|
||
.queue-header__position-inline small { font-size: 10px; color: var(--text-tertiary); margin-left: 2px; }
|
||
.queue-header__lv-inline {
|
||
display: inline-flex; align-items: baseline; gap: 1px;
|
||
font-size: 10px; color: var(--text-tertiary);
|
||
padding: 1px 6px;
|
||
background: var(--bg-tertiary);
|
||
border-radius: 4px;
|
||
}
|
||
.queue-header__lv-inline b { font-size: 12px; font-weight: 700; color: var(--text-primary); }
|
||
.queue-header__points-inline {
|
||
display: inline-flex; align-items: baseline; gap: 1px;
|
||
font-size: 10px; color: var(--text-tertiary);
|
||
}
|
||
.queue-header__points-inline { font-weight: 600; color: var(--text-primary); font-size: 12px; }
|
||
.queue-header__points-inline i { font-size: 9px; color: var(--text-tertiary); font-style: normal; margin-left: 1px; }
|
||
|
||
.queue-header__actions { display: flex; align-items: center; gap: 8px; }
|
||
.quiz-toggle-btn {
|
||
padding: 4px 10px;
|
||
border-radius: 12px;
|
||
border: none;
|
||
background: rgba(34,197,94,0.15);
|
||
color: #22c55e;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-family: inherit;
|
||
}
|
||
.quiz-toggle-btn:hover { background: rgba(34,197,94,0.25); }
|
||
|
||
.queue-content {
|
||
padding: 10px 14px;
|
||
display: none;
|
||
}
|
||
.queue-section--active .queue-content { display: block; }
|
||
|
||
.queue-position {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 10px;
|
||
}
|
||
.queue-position__info { display: flex; align-items: center; gap: 6px; }
|
||
.queue-position__icon { font-size: 14px; }
|
||
.queue-position__label { font-size: 12px; color: var(--text-secondary); }
|
||
.queue-position__value { font-size: 16px; font-weight: 700; color: var(--accent); }
|
||
.queue-position__ahead { font-size: 11px; color: var(--text-tertiary); margin-left: 4px; }
|
||
|
||
.queue-position__points { display: flex; align-items: center; gap: 6px; }
|
||
.points-badge {
|
||
padding: 2px 8px;
|
||
border-radius: 10px;
|
||
background: var(--bg-tertiary);
|
||
font-size: 10px;
|
||
color: var(--text-secondary);
|
||
}
|
||
.points-value { font-size: 11px; font-weight: 600; color: var(--text-primary); }
|
||
|
||
/* 答题区域(默认折叠) */
|
||
.quiz-section {
|
||
background: var(--bg-primary);
|
||
border-radius: 10px;
|
||
padding: 10px;
|
||
margin-top: 8px;
|
||
display: none;
|
||
}
|
||
.quiz-section--active { display: block; }
|
||
|
||
.quiz-question {
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin-bottom: 8px;
|
||
line-height: 1.5;
|
||
}
|
||
.quiz-options {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
.quiz-option {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 6px 10px;
|
||
border-radius: 8px;
|
||
border: 1px solid var(--border-color);
|
||
background: var(--bg-secondary);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-family: inherit;
|
||
}
|
||
.quiz-option:hover { border-color: var(--accent); background: var(--accent-soft); }
|
||
.quiz-option__label {
|
||
width: 18px; height: 18px; border-radius: 50%;
|
||
background: var(--bg-tertiary);
|
||
color: var(--text-secondary);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
flex-shrink: 0;
|
||
}
|
||
.quiz-option__text { font-size: 11px; color: var(--text-primary); }
|
||
|
||
/* ============================================================================
|
||
标注区
|
||
============================================================================ */
|
||
.annotations {
|
||
position: fixed; top: 20px; right: 20px; width: 320px;
|
||
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
||
border-radius: 12px; padding: 14px; font-size: 11px; line-height: 1.5;
|
||
color: var(--text-secondary); box-shadow: 0 4px 16px rgba(0,0,0,0.2);
|
||
z-index: 100; max-height: 90vh; overflow-y: auto;
|
||
}
|
||
.annotations h3 { font-size: 13px; color: var(--text-primary); margin-bottom: 6px; }
|
||
.annotations ul { list-style: none; padding: 0; }
|
||
.annotations li { padding: 4px 0; border-bottom: 1px solid var(--border-color); }
|
||
.annotations li:last-child { border-bottom: none; }
|
||
.annotations .tag { display: inline-block; padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 600; margin-right: 3px; }
|
||
.tag--new { background: rgba(239,68,68,0.15); color: #ef4444; }
|
||
.tag--layout { background: rgba(168,85,247,0.15); color: #a855f7; }
|
||
.tag--fix { background: rgba(168,85,247,0.15); color: #c084fc; }
|
||
|
||
/* ============================================================================
|
||
输入栏 v2.0:工具栏 + 输入框 + 控件区(人工坐席+语音+发送)
|
||
============================================================================ */
|
||
.input-bar {
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: var(--bg-secondary);
|
||
border-top: 1px solid var(--border-color);
|
||
}
|
||
|
||
/* 工具栏 */
|
||
.input-toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 8px 12px 6px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
|
||
.tool-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
background: var(--tool-btn-bg);
|
||
color: var(--tool-btn-text);
|
||
font-size: 16px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.15s;
|
||
}
|
||
.tool-btn:active { transform: scale(0.92); }
|
||
|
||
/* 输入行 v2.0 */
|
||
.input-row-v2 {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
gap: 8px;
|
||
padding: 8px 12px;
|
||
padding-bottom: calc(8px + env(safe-area-inset-bottom, 8px));
|
||
}
|
||
|
||
.input-field-v2 {
|
||
flex: 1;
|
||
background: var(--bg-tertiary);
|
||
border-radius: 10px;
|
||
padding: 8px 12px;
|
||
border: 1px solid var(--border-color);
|
||
font-size: 13px;
|
||
font-family: inherit;
|
||
color: var(--text-primary);
|
||
resize: none;
|
||
outline: none;
|
||
min-height: 44px;
|
||
max-height: 100px;
|
||
line-height: 1.5;
|
||
transition: border-color 0.2s;
|
||
}
|
||
.input-field-v2:focus { border-color: var(--accent); }
|
||
.input-field-v2::placeholder { color: var(--text-placeholder); }
|
||
|
||
/* 右侧控件区:两层布局 */
|
||
.input-controls {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 6px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* 第一层:人工坐席按钮 */
|
||
.call-agent-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
padding: 5px 10px;
|
||
border-radius: 16px;
|
||
border: none;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-family: inherit;
|
||
white-space: nowrap;
|
||
}
|
||
.call-agent-btn__icon { font-size: 12px; }
|
||
.call-agent-btn__text { line-height: 1; }
|
||
|
||
/* 人工坐席按钮 - 三态 */
|
||
.call-agent-btn--disabled {
|
||
background: var(--bg-tertiary);
|
||
color: var(--text-tertiary);
|
||
cursor: not-allowed;
|
||
}
|
||
.call-agent-btn--active {
|
||
background: rgba(59, 130, 246, 0.12);
|
||
color: var(--accent);
|
||
border: 1px solid rgba(59, 130, 246, 0.3);
|
||
}
|
||
.call-agent-btn--active:hover { background: rgba(59, 130, 246, 0.2); }
|
||
.call-agent-btn--urgent {
|
||
background: rgba(239, 68, 68, 0.12);
|
||
color: var(--color-danger);
|
||
border: 1px solid rgba(239, 68, 68, 0.3);
|
||
animation: urgent-pulse 1.5s ease-in-out infinite;
|
||
}
|
||
@keyframes urgent-pulse {
|
||
0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.2); }
|
||
50% { box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.1); }
|
||
}
|
||
|
||
/* 第二层:语音+发送按钮 */
|
||
.input-controls-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.voice-btn {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 50%;
|
||
border: 1px solid var(--border-color);
|
||
background: var(--bg-primary);
|
||
color: var(--text-secondary);
|
||
font-size: 15px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.2s;
|
||
}
|
||
.voice-btn:hover { border-color: var(--accent); background: var(--accent-soft); }
|
||
.voice-btn:active { transform: scale(0.92); }
|
||
|
||
.send-btn-v2 {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 50%;
|
||
border: none;
|
||
background: var(--accent);
|
||
color: #fff;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.2s;
|
||
box-shadow: 0 2px 6px rgba(59, 130, 246, 0.25);
|
||
}
|
||
.send-btn-v2:active { transform: scale(0.92); }
|
||
.send-btn-v2:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }
|
||
|
||
/* ============================================================================
|
||
动画
|
||
============================================================================ */
|
||
@keyframes online-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
|
||
@keyframes ts-dot-pulse { 0%, 100% { box-shadow: 0 0 0 2px var(--accent-soft); } 50% { box-shadow: 0 0 0 5px var(--accent-soft); } }
|
||
@keyframes bubble-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="page-wrapper">
|
||
|
||
<!-- ================================================================
|
||
桌面端视图 — v1.9 右边栏排队到底部
|
||
================================================================ -->
|
||
<div class="view-container">
|
||
<div class="view-label">
|
||
💻 企微桌面端 · 自建应用
|
||
<span class="badge badge--primary">v2.3.6</span>
|
||
<span class="badge badge--new">标题栏外提 + 统一 .diag-item</span>
|
||
</div>
|
||
<div class="desktop-shell">
|
||
<div class="desktop-shell__wecom-bar">
|
||
<span class="wecom-tab">消息</span>
|
||
<span class="wecom-tab wecom-tab--active">工作台</span>
|
||
<span class="wecom-tab">通讯录</span>
|
||
<span class="wecom-title">IT智能服务台</span>
|
||
</div>
|
||
<div class="desktop-body">
|
||
<!-- 左侧:消息区 -->
|
||
<div class="desktop-left">
|
||
<!-- 标题栏 -->
|
||
<div class="chat-header">
|
||
<div class="chat-header__title">
|
||
<span class="logo-icon">🛎️</span>
|
||
<span>IT智能服务台</span>
|
||
</div>
|
||
<div class="chat-header__actions">
|
||
<div class="chat-header__online">
|
||
<span class="chat-header__online-dot"></span>
|
||
<span>坐席在线</span>
|
||
</div>
|
||
<div class="theme-switch" onclick="toggleTheme()">
|
||
<div class="switch-track"><div class="switch-thumb"></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 排查步骤 -->
|
||
<div class="ts-top-bar">
|
||
<div class="ts-top-bar__header">
|
||
<span class="ts-top-bar__header-icon">🔧</span>
|
||
<span class="ts-top-bar__header-title">排查步骤</span>
|
||
<span class="ts-top-bar__header-tag">进行中</span>
|
||
<span class="ts-top-bar__toggle">▼ 收起</span>
|
||
</div>
|
||
<div>
|
||
<div class="ts-top-bar__path">
|
||
<div class="ts-path-bar">
|
||
<div class="ts-step ts-step--done">
|
||
<span class="ts-dot ts-dot--done">✓</span>
|
||
<span class="ts-label">确认问题</span>
|
||
</div>
|
||
<span class="ts-arrow ts-arrow--active">→</span>
|
||
<div class="ts-step ts-step--current">
|
||
<span class="ts-dot ts-dot--current">2</span>
|
||
<span class="ts-label">网络适配器</span>
|
||
</div>
|
||
<span class="ts-arrow">→</span>
|
||
<div class="ts-step ts-step--pending">
|
||
<span class="ts-dot ts-dot--pending">3</span>
|
||
<span class="ts-label">驱动检查</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="ts-top-bar__body">
|
||
<div class="ts-question-header">
|
||
<span class="ts-question-icon">❓</span>
|
||
<span class="ts-question-text">WiFi适配器是否显示"已禁用"?</span>
|
||
</div>
|
||
<div class="ts-options">
|
||
<button class="ts-option ts-option--yes">
|
||
<span class="ts-option-icon">✅</span><span>是,已禁用</span>
|
||
</button>
|
||
<button class="ts-option ts-option--no">
|
||
<span class="ts-option-icon">❌</span><span>否,正常</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 消息列表 -->
|
||
<div class="chat-messages">
|
||
<div class="msg msg--system">
|
||
<span class="msg__system-text">坐席 小宋 已接入会话</span>
|
||
</div>
|
||
<div class="msg msg--ai">
|
||
<div class="msg__sender"><span class="msg__ai-tag">AI回复</span></div>
|
||
<div class="msg__avatar-row">
|
||
<div class="msg__avatar msg__avatar--ai">🤖</div>
|
||
<div>
|
||
<div class="msg__bubble">您好!我是AI助手,请问有什么可以帮您的?</div>
|
||
<div class="msg__time">10:02</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="msg msg--employee">
|
||
<div class="msg__bubble">我的电脑连不上公司WiFi了,网络图标显示黄色感叹号</div>
|
||
<div class="msg__time">10:03</div>
|
||
</div>
|
||
<div class="msg msg--agent">
|
||
<div class="msg__avatar-row">
|
||
<div class="msg__avatar msg__avatar--agent">👨💻</div>
|
||
<div>
|
||
<div class="msg__bubble">你好,我来帮你排查WiFi问题。请在上方排查步骤中选择 👆</div>
|
||
<div class="msg__time">10:05</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="msg msg--system">
|
||
<span class="msg__system-text">排查步骤已同步至坐席端</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 输入栏 v2.0:工具栏 + 输入框 + 控件区(人工坐席+语音+发送) -->
|
||
<div class="input-bar">
|
||
<!-- 工具栏:表情 / 文件 -->
|
||
<div class="input-toolbar">
|
||
<button class="tool-btn">😊</button>
|
||
<button class="tool-btn">📎</button>
|
||
</div>
|
||
<!-- 输入行 -->
|
||
<div class="input-row-v2">
|
||
<textarea class="input-field-v2" rows="2" placeholder="请输入消息..."></textarea>
|
||
<!-- 右侧控件区:两层布局 -->
|
||
<div class="input-controls">
|
||
<!-- 第一层:人工坐席按钮 -->
|
||
<button class="call-agent-btn call-agent-btn--active">
|
||
<span class="call-agent-btn__icon">🎧</span>
|
||
<span class="call-agent-btn__text">人工坐席</span>
|
||
</button>
|
||
<!-- 第二层:语音按钮 + 发送按钮 -->
|
||
<div class="input-controls-row">
|
||
<button class="voice-btn" title="语音输入">
|
||
<span>🎤</span>
|
||
</button>
|
||
<button class="send-btn-v2" disabled>
|
||
<span>➤</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 拖拽手柄 -->
|
||
<div class="resize-handle-v"></div>
|
||
|
||
<!-- 右侧面板 - v1.9 新布局 -->
|
||
<div class="desktop-right">
|
||
<div class="right-panel">
|
||
|
||
<!-- ① 手风琴区域(设备信息 / 自助诊断) -->
|
||
<div class="accordion-section">
|
||
<!-- 设备信息 -->
|
||
<div class="accordion-item accordion-item--active">
|
||
<div class="accordion-item__header">
|
||
<span class="accordion-item__icon">💻</span>
|
||
<span class="accordion-item__title">设备信息</span>
|
||
<span class="accordion-item__toggle">▼</span>
|
||
</div>
|
||
<div class="accordion-item__content">
|
||
<div class="device-card">
|
||
<div class="device-item">
|
||
<span class="device-item__label">计算机名</span>
|
||
<span class="device-item__value">WIN-DEV-001</span>
|
||
</div>
|
||
<div class="device-item">
|
||
<span class="device-item__label">IP地址</span>
|
||
<span class="device-item__value">10.90.5.128</span>
|
||
</div>
|
||
<div class="device-item">
|
||
<span class="device-item__label">操作系统</span>
|
||
<span class="device-item__value">Windows 11</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 自助诊断 — v2.3.6:标题栏外提到 RightPanel 外层;内部仅 6 Tab + 统一 .diag-item 内容 -->
|
||
<div class="accordion-item accordion-item--active">
|
||
<!-- v2.3.6:外层标题栏(🩺 + 自助诊断 + 徽章 + 一键诊断),原本在 SelfDiagnosis 内部的 diag-header 移到这里 -->
|
||
<div class="accordion-item__header" style="background:rgba(59,130,246,0.04);">
|
||
<span class="accordion-item__icon">🩺</span>
|
||
<span class="accordion-item__title">自助诊断</span>
|
||
<!-- v2.3.6: 异常徽章(外层 actions 区) -->
|
||
<div class="accordion-item__header-actions" style="margin-left:auto;display:inline-flex;align-items:center;gap:6px;">
|
||
<span class="header__total-badge header__total-badge--graded" title="共 5 个待处理异常:5 警告 0 失败">
|
||
<span class="badge-segment badge-segment--W">5W</span>
|
||
<span class="badge-sep">·</span>
|
||
<span class="badge-segment badge-segment--F">0F</span>
|
||
</span>
|
||
<button class="diag-header__action" disabled title="检测到异常,建议先处理后再批量诊断">
|
||
<span>⚙</span> 一键诊断
|
||
</button>
|
||
</div>
|
||
<span class="accordion-item__toggle">▾</span>
|
||
</div>
|
||
<!-- v2.3.2: 6 Tab 横向并排标签页(简称 + 异常徽章 + 接入中角标) -->
|
||
<div class="diag-tabs">
|
||
<button class="diag-tab" title="0 个异常">
|
||
<span class="diag-tab__label">网络</span>
|
||
</button>
|
||
<button class="diag-tab diag-tab--has-abnormal" title="1 个异常">
|
||
<span class="diag-tab__label">账号</span>
|
||
<span class="diag-tab__badge">1</span>
|
||
</button>
|
||
<button class="diag-tab diag-tab--has-abnormal" title="1 个异常">
|
||
<span class="diag-tab__label">设备</span>
|
||
<span class="diag-tab__badge">1</span>
|
||
</button>
|
||
<button class="diag-tab diag-tab--active diag-tab--has-abnormal" title="2 个异常">
|
||
<span class="diag-tab__label">系统</span>
|
||
<span class="diag-tab__badge">2</span>
|
||
</button>
|
||
<button class="diag-tab" title="0 异常(2 项接入中)">
|
||
<span class="diag-tab__label">安全</span>
|
||
<span class="diag-tab__pending-hint"><span class="diag-tab__pending-dot"></span>2</span>
|
||
</button>
|
||
<button class="diag-tab diag-tab--has-abnormal" title="1 个异常">
|
||
<span class="diag-tab__label">合规</span>
|
||
<span class="diag-tab__badge">1</span>
|
||
</button>
|
||
</div>
|
||
<!-- Tab 内容示例(默认展开「系统软件」)展示统一 .diag-item 模板 + 检测按钮 + 多种状态 -->
|
||
<div class="diag-content">
|
||
<div class="diag-content__label">
|
||
<span>系统软件 · 诊断与风险项</span>
|
||
<span class="diag-content__hint">v2.3.4 统一 .diag-item + 检测按钮</span>
|
||
</div>
|
||
<div class="diag-risk-list">
|
||
<!-- 风险项(riskItems:账号/设备/系统/安全/合规) -->
|
||
<div class="diag-risk-item diag-risk-item--warning">
|
||
<span class="diag-risk-item__icon">🔧</span>
|
||
<span class="diag-risk-item__name">系统补丁</span>
|
||
<span class="diag-risk-item__status diag-risk-item__status--warning">2 个高危</span>
|
||
<button class="diag-risk-item__btn" title="重新检测该项">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
<div class="diag-risk-item diag-risk-item--warning">
|
||
<span class="diag-risk-item__icon">📧</span>
|
||
<span class="diag-risk-item__name">邮件客户端</span>
|
||
<span class="diag-risk-item__status diag-risk-item__status--warning">配置异常</span>
|
||
<button class="diag-risk-item__btn" title="重新检测该项">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
<div class="diag-risk-item">
|
||
<span class="diag-risk-item__icon">📦</span>
|
||
<span class="diag-risk-item__name">高危软件</span>
|
||
<span class="diag-risk-item__status diag-risk-item__status--normal">未发现</span>
|
||
<button class="diag-risk-item__btn" title="重新检测该项">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
<div class="diag-risk-item">
|
||
<span class="diag-risk-item__icon">🖨️</span>
|
||
<span class="diag-risk-item__name">打印机状态</span>
|
||
<span class="diag-risk-item__status diag-risk-item__status--normal">正常</span>
|
||
<button class="diag-risk-item__btn" title="重新检测该项">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
<!-- 诊断项(diagItems:网络/系统 Tab)—— 同一 UI 模板 -->
|
||
<div class="diag-risk-item">
|
||
<span class="diag-risk-item__icon">⚙️</span>
|
||
<span class="diag-risk-item__name">系统服务</span>
|
||
<span class="diag-risk-item__status diag-risk-item__status--normal">通过</span>
|
||
<button class="diag-risk-item__btn" title="重新检测该项">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
<div class="diag-risk-item diag-risk-item--danger">
|
||
<span class="diag-risk-item__icon">🔒</span>
|
||
<span class="diag-risk-item__name">证书检测</span>
|
||
<span class="diag-risk-item__status diag-risk-item__status--danger">失败</span>
|
||
<button class="diag-risk-item__btn" title="重新检测该项">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
</div>
|
||
<!-- 终端安全 Tab 预览(不在激活态,仅作为接入中角标样式参考) -->
|
||
<div class="diag-content" style="padding:0;border-top:1px dashed var(--border-color);margin-top:6px;">
|
||
<div class="diag-content__label" style="margin-top:6px;">
|
||
<span>终端安全 · 接入中示例</span>
|
||
<span class="diag-content__hint">pending 检测按钮禁用</span>
|
||
</div>
|
||
<div class="diag-risk-list">
|
||
<div class="diag-risk-item diag-risk-item--pending">
|
||
<span class="diag-risk-item__icon">⚔️</span>
|
||
<span class="diag-risk-item__name">内部攻击检测</span>
|
||
<span class="diag-pending-tag">接入中</span>
|
||
<button class="diag-risk-item__btn" disabled title="pending 状态不可检测">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
<div class="diag-risk-item diag-risk-item--pending">
|
||
<span class="diag-risk-item__icon">🌐</span>
|
||
<span class="diag-risk-item__name">网络代理审计</span>
|
||
<span class="diag-pending-tag">接入中</span>
|
||
<button class="diag-risk-item__btn" disabled title="pending 状态不可检测">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
<div class="diag-risk-item">
|
||
<span class="diag-risk-item__icon">🛡️</span>
|
||
<span class="diag-risk-item__name">火绒安装</span>
|
||
<span class="diag-risk-item__status diag-risk-item__status--normal">已安装 v2.4.1</span>
|
||
<button class="diag-risk-item__btn" title="重新检测该项">检测</button>
|
||
<span class="diag-risk-item__toggle">▾</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- v2.2: 异常数量徽章对照表(5 状态一目了然) -->
|
||
<div class="diag-badge-gallery">
|
||
<div class="diag-badge-gallery__title">⚙️ 异常数量徽章 · 5 状态对照</div>
|
||
|
||
<!-- 状态 1:分级显示 (当前态) -->
|
||
<div class="diag-badge-gallery__row">
|
||
<span class="diag-header__badge diag-header__badge--graded">
|
||
<span class="diag-header__badge-segment diag-header__badge-segment--W">5W</span>
|
||
<span class="diag-header__badge-sep">·</span>
|
||
<span class="diag-header__badge-segment diag-header__badge-segment--F">0F</span>
|
||
</span>
|
||
<span class="diag-badge-gallery__desc">
|
||
<b>① 分级显示</b>:warning/fail 拆分 <small>(当前 Mock)</small>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 状态 2:兼顾 fail -->
|
||
<div class="diag-badge-gallery__row">
|
||
<span class="diag-header__badge diag-header__badge--graded">
|
||
<span class="diag-header__badge-segment diag-header__badge-segment--W">2W</span>
|
||
<span class="diag-header__badge-sep">·</span>
|
||
<span class="diag-header__badge-segment diag-header__badge-segment--F">1F</span>
|
||
</span>
|
||
<span class="diag-badge-gallery__desc">
|
||
<b>② 含有 fail</b>:网连通 sys_cert 过期(样例)
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 状态 3:旧版单数字(兼容项) -->
|
||
<div class="diag-badge-gallery__row">
|
||
<span class="diag-header__badge diag-header__badge--alert">
|
||
<span class="diag-header__badge-icon">!</span>5
|
||
</span>
|
||
<span class="diag-badge-gallery__desc">
|
||
<b>③ 旧版兼容</b>:若只有 warning 时,徽章仍可显示总数(可选关闭)
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 状态 4:0 异常达标动画(优化 ③) -->
|
||
<div class="diag-badge-gallery__row">
|
||
<span class="diag-header__badge diag-header__badge--celebrate">
|
||
<span class="diag-header__badge--celebrate-text">✓ 今日安全</span>
|
||
</span>
|
||
<span class="diag-badge-gallery__desc">
|
||
<b>④ 达标动画</b>:所有异常处理完毕,2.4s 脉冲,3 秒后渐隐 <small>(优化 ③)</small>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 状态 5:纯绿色 -->
|
||
<div class="diag-badge-gallery__row">
|
||
<span class="diag-header__badge diag-header__badge--ok">✓ 全部正常</span>
|
||
<span class="diag-badge-gallery__desc">
|
||
<b>⑤ 静态正常</b>:稳态显示(动画停止后)
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 异常计数规则 -->
|
||
<div class="diag-legend">
|
||
<b>异常口径</b>:warning(W) + danger/fail(F) 计入;normal · pending(接入中) · idle(未执行) 不计入。<br>
|
||
<b>当前总数 = 5W·0F</b>(账号 1 + 设备 1 + 系统 2 + 合规 1)。Tab 数字徽章 = 各 Tab 内部 warning 数;安全 Tab 内部 2 项 pending 不计入但在 Tab 文字后显示"接入中"灰色角标(优化 ②)。
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 分隔线 -->
|
||
<div class="right-panel__divider"></div>
|
||
|
||
<!-- ② 智能推荐(占据主要空间) -->
|
||
<div class="recommend-section recommend-section--active">
|
||
<div class="recommend-section__header">
|
||
<span class="recommend-section__icon">⚡</span>
|
||
<span class="recommend-section__title">智能推荐</span>
|
||
<span class="recommend-section__toggle">▼</span>
|
||
</div>
|
||
<div class="recommend-section__content">
|
||
<!-- 绿色边框 - 相关推荐 -->
|
||
<div class="recommend-card recommend-card--green">
|
||
<div class="recommend-card__title">
|
||
<span>📖</span> WiFi连接问题处理指南
|
||
</div>
|
||
<div class="recommend-card__desc">相似问题处理方案,已解决 28 次</div>
|
||
<div class="recommend-card__tags">
|
||
<span class="recommend-card__tag">相似问题</span>
|
||
<span class="recommend-card__tag">WiFi</span>
|
||
</div>
|
||
</div>
|
||
<!-- 橙色边框 - 运维提醒 -->
|
||
<div class="recommend-card recommend-card--orange">
|
||
<div class="recommend-card__title">
|
||
<span>⚠️</span> 网络设备维护通知
|
||
</div>
|
||
<div class="recommend-card__desc">今晚 22:00-24:00 网络设备维护</div>
|
||
<div class="recommend-card__tags">
|
||
<span class="recommend-card__tag">运维提醒</span>
|
||
</div>
|
||
</div>
|
||
<!-- 灰色边框 - 常用资源 -->
|
||
<div class="recommend-card recommend-card--gray">
|
||
<div class="recommend-card__title">
|
||
<span>📋</span> 网络连接申请流程
|
||
</div>
|
||
<div class="recommend-card__desc">新员工网络连接申请审批流程</div>
|
||
<div class="recommend-card__tags">
|
||
<span class="recommend-card__tag">流程入口</span>
|
||
</div>
|
||
</div>
|
||
<div class="recommend-card recommend-card--gray">
|
||
<div class="recommend-card__title">
|
||
<span>📥</span> 无线网卡驱动下载
|
||
</div>
|
||
<div class="recommend-card__desc">Intel/Realtek 常用无线网卡驱动</div>
|
||
<div class="recommend-card__tags">
|
||
<span class="recommend-card__tag">软件下载</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 分隔线 -->
|
||
<div class="right-panel__divider"></div>
|
||
|
||
<!-- ③ 排队等待(底部)—— v2.3 改造:位置/LV/分全部合并到标题栏 -->
|
||
<div class="queue-section queue-section--active">
|
||
<div class="queue-header queue-header--v23">
|
||
<div class="queue-header__left">
|
||
<span class="queue-header__icon">⏳</span>
|
||
<span class="queue-header__title">排队等待</span>
|
||
<!-- v2.3:位置 / LV / 分 全部移到标题栏右侧 -->
|
||
<span class="queue-header__position-inline" title="当前排队位置">
|
||
#<b>5</b><small>前面4人</small>
|
||
</span>
|
||
<span class="queue-header__lv-inline" title="积分等级">LV.<b>3</b></span>
|
||
<span class="queue-header__points-inline" title="当前积分">120<i>分</i></span>
|
||
</div>
|
||
<div class="queue-header__actions">
|
||
<button class="quiz-toggle-btn">答题挑战</button>
|
||
</div>
|
||
</div>
|
||
<!-- v2.3:queue-content 仅保留答题区域,位置信息全部上移标题栏 -->
|
||
<div class="queue-content">
|
||
<div class="quiz-section quiz-section--active">
|
||
<div class="quiz-question">IT服务台电话分机号是?</div>
|
||
<div class="quiz-options">
|
||
<div class="quiz-option">
|
||
<span class="quiz-option__label">A</span>
|
||
<span class="quiz-option__text">8001</span>
|
||
</div>
|
||
<div class="quiz-option">
|
||
<span class="quiz-option__label">B</span>
|
||
<span class="quiz-option__text">8002</span>
|
||
</div>
|
||
<div class="quiz-option">
|
||
<span class="quiz-option__label">C</span>
|
||
<span class="quiz-option__text">8003</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- 标注区 -->
|
||
<div class="annotations">
|
||
<h3>📝 H5用户端原型 v2.3.6 — 标题栏外提 + 统一 .diag-item + 检测按钮 + 排队置底</h3>
|
||
<ul>
|
||
<li>
|
||
<span class="tag tag--new">v2.3.6 新增</span>
|
||
<b>排队标签置底 + 未排队占位</b>:RightPanel.vue `.right-panel__queue-section { margin-top: auto }`
|
||
在 flex column 容器中自动推至主轴底部;未排队时标题栏显示 <code>⏳ 排队等待 | 未排队 | LV.3 | 120分 | 答题挑战</code>(替换原本空荡的标题栏)。
|
||
<br><b>受益</b>:自助诊断展开 + 智能推荐内容多时,排队标签仍贴底部。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--new">v2.3.4 新增</span>
|
||
<b>网络/系统 Tab 统一 .diag-item + 检测按钮</b>:所有诊断项(diagItems + riskItems)渲染同一 UI 模板(图标+名称+状态徽章+<b>检测按钮</b>+折叠箭头)。<code>检测</code> 按钮点击触发该条重新检测(diagItem 走真实检测,riskItem 模拟 800ms)。
|
||
<br><b>受益</b>:6 个 Tab 内所有条目视觉一致,用户操作路径统一(先看 → 不放心 → 点检测)。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--new">v2.3.3 新增</span>
|
||
<b>标题栏外提 + 一键诊断</b>:自助诊断内部不再保留独立标题栏;徽章 + 一键诊断按钮从 SelfDiagnosis.vue 提升至 RightPanel.vue 的 accordion-item__header;SelfDiagnosis 通过 <code>defineExpose</code> 暴露 6 个 API(totalBadge / totalBadgeByLevel / showCelebrate / isRunningAll / hasAnyDiagItems / runAllDiag)。
|
||
<br><b>受益</b>:用户进右栏第一眼看到"自助诊断"区段的异常总数,无需展开即可掌握全局状态。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--new">v2.3.5 新增</span>
|
||
<b>内容高度自适应</b>:删除 <code>.accordion-item--active { max-height: 80% }</code> 硬限制;右栏 <code>overflow-y: auto</code> 整体可滚动。
|
||
<br><b>受益</b>:自助诊断完全展开后,所有 Tab 内容完整可见,无需逐 Tab 切换查找。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--layout">v2.3 保留</span>
|
||
<b>未排队态 vs 排队态对照</b>(v2.3.6 新增):
|
||
<div style="margin-top:6px;display:flex;gap:10px;flex-wrap:wrap;">
|
||
<div style="flex:1;min-width:240px;padding:6px 8px;border:1px solid var(--border-color);border-radius:6px;background:var(--bg-primary);">
|
||
<b style="color:var(--text-secondary);font-size:10px;">① 排队中</b>
|
||
<div style="margin-top:4px;display:flex;align-items:center;gap:6px;font-size:11px;">
|
||
<span>⏳</span><span>排队等待</span>
|
||
<span class="queue-header__position-inline" style="font-size:11px;padding:1px 5px;">#<b>5</b><small>前面4人</small></span>
|
||
<span class="queue-header__lv-inline" style="font-size:9px;padding:1px 5px;">LV.<b>3</b></span>
|
||
<span class="queue-header__points-inline" style="font-size:11px;"><b>120</b><i>分</i></span>
|
||
</div>
|
||
</div>
|
||
<div style="flex:1;min-width:240px;padding:6px 8px;border:1px dashed var(--accent);border-radius:6px;background:var(--bg-primary);">
|
||
<b style="color:var(--accent);font-size:10px;">② 未排队(v2.3.6 新增占位)</b>
|
||
<div style="margin-top:4px;display:flex;align-items:center;gap:6px;font-size:11px;">
|
||
<span>⏳</span><span>排队等待</span>
|
||
<span class="qh-position-inline qh-position-inline--idle"><small>未排队</small></span>
|
||
<span class="queue-header__lv-inline" style="font-size:9px;padding:1px 5px;">LV.<b>3</b></span>
|
||
<span class="queue-header__points-inline" style="font-size:11px;"><b>120</b><i>分</i></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--new">v2.2 新增</span>
|
||
<b>异常徽章 3 优化</b>已落地:
|
||
<ol>
|
||
<li><b>① 分级显示</b>:`5W · 0F` warning/fail 拆分(更直观对管理员)</li>
|
||
<li><b>② 接入中提示</b>:Tab 文字后挂灰色小角标"+ N"指示 pending 项数;行内展示"接入中"灰色 tag</li>
|
||
<li><b>③ 达标动画</b>:所有异常清零时绿色脉冲徽章 + ✓ 今日安全文字,2.4s 脉冲,3 秒渐隐</li>
|
||
</ol>
|
||
5 种状态对照在 H5 模拟下方"异常数量徽章对照表"。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--layout">v2.3 新增</span>
|
||
<b>排队标题栏合并位置/LV/分信息</b>:RightPanel.vue:101-113 改造 queue-header 为
|
||
<code>⏳ 排队等待 #5 前面4人 LV.3 120分 [答题挑战]</code>;queue-content 内不再单独显示 position-card(QueueWaiting 组件需新增 <code>show-position=false</code> prop)。
|
||
<br><b>收益</b>:queue-section 整体高度压缩 ~40px(≈50%),更多空间给答题区。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--new">v2.3 新增</span>
|
||
<b>移动端 toggle 切换开关</b>:ChatView.vue:80-89 移动端 <500px 直接 return false,现新增 toggle 模式让用户切换显示左对话框 vs 右栏。
|
||
<br>3 种方案对照(顶部双按钮 / 右下 FAB / 底部 Tab Bar)在原型图下方"v2.3 新增"面板中展示,<b>推荐方案 A 顶部双按钮</b>。
|
||
<br>桌面端(≥500px)维持原状不变,不引入新开关。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--fix">v2.3 行为</span>
|
||
<b>Tab 切换只显示当前诊断项</b>:用户需求"选择某项标签时下方只显示对应项"。
|
||
<br>代码 SelfDiagnosis.vue:499-501 <code>currentTab</code> 已 computed 自动过滤,切 Tab 时 Vue 自动卸载旧 DOM / 挂载新 DOM,<b>无需代码改动</b>,仅原型标注。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--new">v2.3 最终决策 M1 ✅</span>
|
||
<b>异常 + 接入混合显示:M1 双角标并存</b>。
|
||
<br>当某 Tab 同时有异常(W/F)和接入中(pending)时,Tab 文字右侧显示双角标:
|
||
<code>安全 1•2</code>(红数字徽章 + 灰色斜体小角标)。
|
||
<br>① 红数字徽章(<code>.diag-tab__badge</code>)= 异常项数;
|
||
② 灰斜体小角标(<code>.diag-tab__pending-hint</code>)= 接入中项数;两角标视觉区隔明显(颜色 + 字体)。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--fix">v2.3.6 决策汇总</span>
|
||
<b>本次会话决策 11 项(全部已落地)</b>:
|
||
<ol>
|
||
<li>Tab 文字:精简版(网络/账号/设备/系统/安全/合规)2 字简称</li>
|
||
<li>异常徽章:分级 5W·0F</li>
|
||
<li>接入中角标位置:A 文字右侧</li>
|
||
<li>桌面端 Tab 切换:只显示当前诊断项(已天然)</li>
|
||
<li>移动端 toggle 方案:A 顶部双按钮(💬 对话 / 🩺 信息)</li>
|
||
<li>queue 标题栏:位置/LV/分 合并</li>
|
||
<li>异常+接入混合:M1 双角标并存</li>
|
||
<li><b>v2.3.3 标题栏位置</b>:外提到 RightPanel accordion-item__header(SelfDiagnosis 通过 defineExpose 暴露)</li>
|
||
<li><b>v2.3.4 诊断项 UI 统一</b>:所有条目统一 `.diag-item` 模板 + 检测按钮</li>
|
||
<li><b>v2.3.5 内容高度策略</b>:内容自然撑开 + 右栏 overflow-y: auto</li>
|
||
<li><b>v2.3.6 排队位置策略</b>:queue-section margin-top: auto + 未排队时显示"未排队"占位</li>
|
||
</ol>
|
||
</li>
|
||
<span class="tag tag--fix">优化口径</span>
|
||
<b>异常计数</b>(v2.3.6 最终):warning(W) + danger/fail(F) 计入;normal · pending(接入中) · idle(未执行) 不计入。
|
||
当前 Mock = <b>5W·0F</b>。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--fix">内容示例</span>
|
||
<b>默认展开"系统软件"</b>(2 个 warning + 2 个 normal),下方展示"终端安全"接入中预览(2 个 pending + 1 个 normal)。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--fix">v2.1 兼容</span>
|
||
<b>3×2 网格已弃用</b>:v2.1 的 `.diag-tabs` 网格样式已替换为横向 flex 布局,旧定义已清除。
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--layout">v2.0 保留</span>
|
||
<b>输入栏重构</b>:工具栏 + 输入框 + 控件区(人工坐席+语音+发送);<b>人工坐席</b>:三态;<b>语音</b>:输入框第二层
|
||
</li>
|
||
<li>
|
||
<span class="tag tag--layout">v2.0 保留</span>
|
||
<b>右边栏布局</b>:设备信息 / 自助诊断 → 智能推荐(主) → 排队等待(底)
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- =====================================================================
|
||
⚠️ 决策对比 ①(横向滚动 vs 自动换行)已删除
|
||
原因:代码 ChatView.vue:80-89 — 移动端 <500px 直接 return false,
|
||
RightPanel 整个不渲染,6 Tab 在移动端根本不可见。
|
||
桌面端 ≥500px 默认窗口宽度足够放下 6 个 Tab,
|
||
「横向滚动」与「自动换行」的选择无实际意义。
|
||
===================================================================== -->
|
||
|
||
<!-- =====================================================================
|
||
决策对比面板 ②:接入中角标位置(3 方案对比)
|
||
适用前提:仅桌面端(≥500px)右栏 SelfDiagnosis 面板显示
|
||
===================================================================== -->
|
||
<div class="cmp-panel">
|
||
<h3 class="cmp-panel__title">
|
||
🅱️ 决策对比 ② — 接入中角标"+2"位置(A/B/C 三方案)
|
||
</h3>
|
||
<p class="cmp-panel__subtitle">
|
||
<b style="color:#16a34a">⚠️ 仅适用于桌面端(≥500px)右栏</b>,移动端(<500px)右栏整体不显示(ChatView.vue:80-89)。
|
||
以 Tab「安全」为例,3 种不同的视觉处理方式(当前激活态 = 系统软件):
|
||
</p>
|
||
|
||
<div class="cmp-grid">
|
||
<!-- 方案 A:文字右侧(当前 v2.2) -->
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#3b82f6;color:#fff;">方案 A:文字右侧 <span style="color:#86efac;">(当前 v2.2)</span></div>
|
||
<div class="cmp-card__sub">紧凑型 · 灰色斜体 · Tab 文字同级</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-zoom" style="font-size:18px;">
|
||
<button class="diag-tab diag-tab--has-abnormal" style="height:42px;border:2px dashed #3b82f6;">
|
||
<span class="diag-tab__label" style="font-size:14px;">安全</span>
|
||
<span class="diag-tab__pending-hint" style="font-size:11px;"><span class="diag-tab__pending-dot"></span>2</span>
|
||
</button>
|
||
</div>
|
||
<div class="cmp-pros-cons">
|
||
<div class="cmp-pro">✅ 紧凑,Tab 始终 34px 高</div>
|
||
<div class="cmp-pro">✅ 与异常数字徽章视觉区隔明显</div>
|
||
<div class="cmp-con">⚠️ 小屏 320px 时文字+角标约占用 50px</div>
|
||
<div class="cmp-con">⚠️ 数字"2"需斜体+小号才不抢眼</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 方案 B:替代数字徽章 -->
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#8b5cf6;color:#fff;">方案 B:替代数字徽章</div>
|
||
<div class="cmp-card__sub">复用现有红圆位置 · 改灰色方块 + "接入"文字</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-zoom" style="font-size:18px;">
|
||
<button class="diag-tab diag-tab--has-abnormal" style="height:42px;border:2px dashed #8b5cf6;">
|
||
<span class="diag-tab__label" style="font-size:14px;">安全</span>
|
||
<span class="diag-tab__badge" style="background:#9ca3af;color:#fff;font-size:9px;padding:0 5px;">接入2</span>
|
||
</button>
|
||
</div>
|
||
<div class="cmp-pros-cons">
|
||
<div class="cmp-pro">✅ 视觉对称性好(和异常 Tab 布局一致)</div>
|
||
<div class="cmp-pro">✅ 不挤占 Tab 文字空间</div>
|
||
<div class="cmp-con">⚠️ 异常与"接入"混在同一徽章位,需颜色区隔</div>
|
||
<div class="cmp-con">⚠️ "2项异常" + "2项接入"同时显示时容易混淆</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 方案 C:Tab 文字下方 -->
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#10b981;color:#fff;">方案 C:Tab 文字下方</div>
|
||
<div class="cmp-card__sub">双层结构 · 文字上 / 角标下 · 独立占 1 行</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-zoom" style="font-size:18px;">
|
||
<button class="diag-tab diag-tab--has-abnormal" style="height:54px;flex-direction:column;border:2px dashed #10b981;padding:2px 4px;">
|
||
<span class="diag-tab__label" style="font-size:13px;">安全</span>
|
||
<span class="diag-tab__pending-hint" style="font-size:10px;margin-left:0;"><span class="diag-tab__pending-dot"></span>2 项接入中</span>
|
||
</button>
|
||
</div>
|
||
<div class="cmp-pros-cons">
|
||
<div class="cmp-pro">✅ 信息量最大,可写"2 项接入中"</div>
|
||
<div class="cmp-pro">✅ 颜色区隔最明显(独立一行)</div>
|
||
<div class="cmp-con">⚠️ Tab 高度从 34px 增到 54px(占用贵)</div>
|
||
<div class="cmp-con">⚠️ 和其他 Tab 高度不一,破坏对齐</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cmp-summary">
|
||
<table class="cmp-table">
|
||
<thead>
|
||
<tr><th>方案</th><th>占用高度</th><th>视觉区隔</th><th>Tab 高度统一</th><th>总评</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr style="background:rgba(34,197,94,0.06);">
|
||
<td><b style="color:#3b82f6;">A 文字右侧</b><br><small>(当前 v2.2)</small></td>
|
||
<td>34px</td>
|
||
<td>强(斜体+小号)</td>
|
||
<td>✅ 与其他 Tab 一致</td>
|
||
<td><b style="color:#16a34a">推荐</b><br><small>和 v2.1 Tab 整体观感一致</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><b style="color:#8b5cf6;">B 替代数字徽章</b></td>
|
||
<td>34px</td>
|
||
<td>中(颜色区隔)</td>
|
||
<td>✅</td>
|
||
<td>可作备选<br><small>更适合 pending 数字较大场景</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><b style="color:#10b981;">C 文字下方</b></td>
|
||
<td>54px</td>
|
||
<td>最强</td>
|
||
<td>❌ 高度变高</td>
|
||
<td>信息量大但<b style="color:#dc2626">破坏对齐</b><br><small>不推荐</small></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p style="font-size:10px;color:var(--text-tertiary);margin-top:6px;">
|
||
💡 <b>说明</b>:方案 A 是当前 v2.2 已落地的方案,保持 Tab 高度统一(34px),文字+角标同级排列视觉简洁。
|
||
方案 B 是 Tab "安全" 同时有异常 + 接入(如 `1W·2接入`)时的备选,把数字徽章位置复用。
|
||
方案 C 因高度不统一,破坏横向并排视觉,<b>不推荐</b>。
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- =====================================================================
|
||
v2.3 新增:移动端拉动开关切换演示 + 3 方案对比
|
||
===================================================================== -->
|
||
<div class="cmp-panel">
|
||
<h3 class="cmp-panel__title">
|
||
🆕 v2.3 新增 — 移动端拉动开关:左对话框 ⇄ 右栏切换
|
||
</h3>
|
||
<p class="cmp-panel__subtitle">
|
||
<b style="color:#16a34a">⚠️ 仅适用于移动端(<500px)</b>:ChatView.vue:80-89 移动端不显示右栏,
|
||
新增 toggle 开关后切换显示左对话框 vs 右栏。桌面端(≥500px)维持原状不变。
|
||
</p>
|
||
|
||
<!-- v2.3 移动端模拟:默认态(左对话) + 切换态(右栏) -->
|
||
<div class="cmp-grid">
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#3b82f6;color:#fff;">📱 移动端 · 状态 A(默认显示左对话框)</div>
|
||
<div class="cmp-card__sub">375px · isMobile=true · 默认 view=chat</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-phone-mini" style="width:280px;">
|
||
<!-- 顶部导航条(含 toggle 按钮) -->
|
||
<div class="mobile-topbar">
|
||
<span class="mobile-topbar__title">💬 与 IT 助手对话</span>
|
||
<button class="mobile-topbar__toggle mobile-topbar__toggle--active">
|
||
💬 对话
|
||
</button>
|
||
<button class="mobile-topbar__toggle">
|
||
🩺 信息
|
||
</button>
|
||
</div>
|
||
<!-- 对话内容(默认显示) -->
|
||
<div class="mobile-chat">
|
||
<div class="mobile-chat__msg mobile-chat__msg--user">
|
||
我的打印机无法连接
|
||
</div>
|
||
<div class="mobile-chat__msg mobile-chat__msg--ai">
|
||
让我帮您诊断一下打印机问题...<br>请告诉我打印机型号?
|
||
</div>
|
||
</div>
|
||
<!-- 底部输入栏 -->
|
||
<div class="mobile-input">
|
||
<span style="color:var(--text-tertiary);font-size:10px;">[输入栏]</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#8b5cf6;color:#fff;">📱 移动端 · 状态 B(点击🩺切换后显示右栏)</div>
|
||
<div class="cmp-card__sub">375px · isMobile=true · view=right</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-phone-mini" style="width:280px;">
|
||
<div class="mobile-topbar">
|
||
<span class="mobile-topbar__title">🩺 信息面板</span>
|
||
<button class="mobile-topbar__toggle">
|
||
💬 对话
|
||
</button>
|
||
<button class="mobile-topbar__toggle mobile-topbar__toggle--active">
|
||
🩺 信息
|
||
</button>
|
||
</div>
|
||
<!-- 右栏内容(手风琴 + 智能推荐 + 排队) -->
|
||
<div class="mobile-rightpanel">
|
||
<div class="mobile-accordion">
|
||
<div class="mobile-accordion__item">💻 设备信息 <span>▸</span></div>
|
||
<div class="mobile-accordion__item">🩺 自助诊断 <span>1</span><span>▸</span></div>
|
||
<div class="mobile-accordion__item">⚡ 智能推荐 <span>2</span><span>▸</span></div>
|
||
</div>
|
||
<!-- v2.3 合并后:排队标题栏直接显示 #5 LV.3 120分 -->
|
||
<div class="mobile-queue-header-v23">
|
||
<span>⏳</span>
|
||
<span>排队等待</span>
|
||
<span class="qh-pos">#5</span>
|
||
<span class="qh-lv">LV.3</span>
|
||
<span class="qh-pts">120分</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#10b981;color:#fff;">💻 桌面端(≥500px)· 不受影响</div>
|
||
<div class="cmp-card__sub">维持双栏同时显示 · 无 toggle</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-phone-mini" style="width:680px;padding:8px;">
|
||
<div style="display:flex;gap:6px;font-size:10px;">
|
||
<div style="flex:1;border:1px solid var(--border-color);border-radius:6px;padding:8px;text-align:center;color:var(--text-secondary);">
|
||
左对话框<br>(始终可见)
|
||
</div>
|
||
<div style="flex:0 0 8px;border-left:1px dashed var(--border-color);text-align:center;color:var(--text-tertiary);font-size:10px;">
|
||
┊
|
||
</div>
|
||
<div style="flex:1;border:1px solid var(--border-color);border-radius:6px;padding:8px;text-align:center;color:var(--text-secondary);">
|
||
右栏<br>(始终可见 · 含自助诊断 / 智能推荐 / 排队)
|
||
</div>
|
||
</div>
|
||
<div class="cmp-scroll-hint" style="color:#16a34a;">✅ 桌面端维持原状,移动端 toggle 升级不影响</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 3 种 toggle 方案对比 -->
|
||
<h4 style="font-size:12px;font-weight:700;color:var(--accent);margin:10px 0 6px;">🆚 移动端 toggle 开关的 3 种方案对比</h4>
|
||
<div class="cmp-grid">
|
||
<!-- 方案 A:顶部导航条切换按钮(推荐) -->
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#3b82f6;color:#fff;">方案 A:顶部双按钮切换 ⭐推荐</div>
|
||
<div class="cmp-card__sub">状态 A / B 已演示 · 直观 · 0 学习成本</div>
|
||
<div class="cmp-pros-cons">
|
||
<div class="cmp-pro">✅ 视觉最直观,按钮文字明确"对话/信息"</div>
|
||
<div class="cmp-pro">✅ 当前选中态有蓝底高亮,状态清晰</div>
|
||
<div class="cmp-pro">✅ 单击即切换,无需滑动操作</div>
|
||
<div class="cmp-con">⚠️ 占顶部空间 36-40px(固定)</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 方案 B:右下浮动 FAB -->
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#8b5cf6;color:#fff;">方案 B:右下浮动 FAB</div>
|
||
<div class="cmp-card__sub">点击 → 右栏抽屉滑入(覆盖 80% 屏宽)</div>
|
||
<div class="cmp-card__screen" style="position:relative;height:180px;">
|
||
<div class="cmp-phone-mini" style="width:200px;height:160px;background:#fff;position:relative;border:1px solid #e5e7eb;">
|
||
<div style="padding:6px;font-size:9px;color:var(--text-tertiary);">[左对话框占位]</div>
|
||
<div style="position:absolute;bottom:14px;right:14px;width:38px;height:38px;border-radius:50%;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;font-size:14px;box-shadow:0 4px 12px rgba(0,0,0,0.2);cursor:pointer;">🩺</div>
|
||
<div style="position:absolute;bottom:22px;right:60px;font-size:9px;color:var(--text-tertiary);">← FAB 按钮</div>
|
||
</div>
|
||
</div>
|
||
<div class="cmp-pros-cons">
|
||
<div class="cmp-pro">✅ 不占顶部空间,对话区完整</div>
|
||
<div class="cmp-pro">✅ 抽屉式滑入有"展开感",视觉冲击</div>
|
||
<div class="cmp-con">⚠️ 点击后右栏"覆盖"左对话(破坏上下文)</div>
|
||
<div class="cmp-con">⚠️ 滑动操作 + 关闭按钮需要用户额外学习</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 方案 C:底部 Tab Bar -->
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#10b981;color:#fff;">方案 C:底部 Tab Bar</div>
|
||
<div class="cmp-card__sub">类似微信"消息 / 通讯录 / 我"</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-phone-mini" style="width:280px;height:160px;display:flex;flex-direction:column;background:#fff;border:1px solid #e5e7eb;">
|
||
<div style="flex:1;padding:6px;font-size:9px;color:var(--text-tertiary);display:flex;align-items:center;justify-content:center;">[对话/右栏 内容区]</div>
|
||
<div style="display:flex;border-top:1px solid var(--border-color);background:#f8fafc;">
|
||
<div style="flex:1;padding:8px 4px;text-align:center;font-size:10px;color:var(--accent);font-weight:700;">
|
||
💬<br>对话
|
||
</div>
|
||
<div style="flex:1;padding:8px 4px;text-align:center;font-size:10px;color:var(--text-secondary);">
|
||
🩺<br>信息
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="cmp-pros-cons">
|
||
<div class="cmp-pro">✅ 移动 App 习惯(微信/Telegram 都这么做)</div>
|
||
<div class="cmp-pro">✅ 单击即切换,零学习成本</div>
|
||
<div class="cmp-con">⚠️ 底部 Tab Bar 占 ~56px(比顶部切换更占地)</div>
|
||
<div class="cmp-con">⚠️ 桌面端 ≥500px 仍维持双栏,Tab Bar 仅移动端有,会让"开关在不同设备位置不同"造成混乱</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cmp-summary">
|
||
<table class="cmp-table">
|
||
<thead>
|
||
<tr><th>方案</th><th>占用空间</th><th>切换体验</th><th>学习成本</th><th>桌面端一致性</th><th>总评</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr style="background:rgba(34,197,94,0.06);">
|
||
<td><b style="color:#3b82f6;">A 顶部双按钮</b></td>
|
||
<td>顶部 ~38px</td>
|
||
<td>单击切换 · 直觉</td>
|
||
<td>极低</td>
|
||
<td>✅ 不出现</td>
|
||
<td><b style="color:#16a34a">推荐</b><br><small>视觉直白,状态一目了然</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><b style="color:#8b5cf6;">B 右下 FAB</b></td>
|
||
<td>右下 38×38px</td>
|
||
<td>点击展开抽屉</td>
|
||
<td>中(需关闭)</td>
|
||
<td>✅ 不出现</td>
|
||
<td>抽屉体验好<br><small>但覆盖对话丢失上下文</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><b style="color:#10b981;">C 底部 Tab Bar</b></td>
|
||
<td>底部 ~56px</td>
|
||
<td>单击切换 · 移动 App 范式</td>
|
||
<td>极低</td>
|
||
<td>❌ 仅移动端有</td>
|
||
<td>移动 App 习惯<br><small>但跨端一致性差</small></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p style="font-size:10px;color:var(--text-tertiary);margin-top:6px;">
|
||
💡 <b>说明</b>:方案 A 顶部双按钮最直白,单击即切换且状态高亮清晰。
|
||
方案 B FAB 抽屉式切换更有"展开感",但右栏会覆盖左对话框丢失上下文。
|
||
方案 C 底部 Tab Bar 是移动 App 主流,但桌面端(≥500px)仍维持双栏,<b>跨端控件位置不一致</b>会增加用户认知负担。
|
||
<b>推荐 A</b>。
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- =====================================================================
|
||
v2.3 新增:Tab 切换只显示当前诊断项(行为说明面板)
|
||
===================================================================== -->
|
||
<div class="cmp-panel">
|
||
<h3 class="cmp-panel__title">
|
||
🆕 v2.3 — Tab 切换行为:只显示当前 Tab 的诊断项
|
||
</h3>
|
||
<p class="cmp-panel__subtitle">
|
||
用户需求:「选择某一项标签时(网络),下方只显示网络的诊断项,不显示其他标签页诊断项」
|
||
<br>代码 SelfDiagnosis.vue 现状:line 499-501 `currentTab` 已 computed 自动过滤;
|
||
激活 Tab 切换时,下方内容区只渲染当前 Tab 的 `diagItems` + `riskItems`,其他 Tab 数据仅参与总异常数计算。
|
||
</p>
|
||
|
||
<div class="cmp-grid">
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#3b82f6;color:#fff;">当前:网络 Tab(6 项诊断项全展开)</div>
|
||
<div class="cmp-card__sub">切换激活态时,下方只显示此 Tab 内容</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-phone-mini" style="width:280px;">
|
||
<div class="diag-tabs" style="background:#f8fafc;border-bottom:1px solid var(--border-color);">
|
||
<button class="diag-tab diag-tab--active"><span class="diag-tab__label">网络</span></button>
|
||
<button class="diag-tab diag-tab--has-abnormal"><span class="diag-tab__label">账号</span><span class="diag-tab__badge">1</span></button>
|
||
<button class="diag-tab diag-tab--has-abnormal"><span class="diag-tab__label">设备</span><span class="diag-tab__badge">1</span></button>
|
||
<button class="diag-tab diag-tab--has-abnormal"><span class="diag-tab__label">系统</span><span class="diag-tab__badge">2</span></button>
|
||
<button class="diag-tab"><span class="diag-tab__label">安全</span></button>
|
||
<button class="diag-tab diag-tab--has-abnormal"><span class="diag-tab__label">合规</span><span class="diag-tab__badge">1</span></button>
|
||
</div>
|
||
<div style="padding:8px;font-size:10px;color:var(--text-secondary);background:#fff;">
|
||
<b>🌐 网络联通 · 6 项诊断</b>(仅显示此 Tab 数据)
|
||
<div style="margin-top:4px;font-size:9px;color:var(--text-tertiary);">→ 网络连通 / DNS / 网关 / 代理 / VPN / 文件共享</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#ef4444;color:#fff;">点击"账号"后:切换显示</div>
|
||
<div class="cmp-card__sub">网络 Tab 数据消失 · 账号 Tab 数据出现</div>
|
||
<div class="cmp-card__screen">
|
||
<div class="cmp-phone-mini" style="width:280px;">
|
||
<div class="diag-tabs" style="background:#f8fafc;border-bottom:1px solid var(--border-color);">
|
||
<button class="diag-tab"><span class="diag-tab__label">网络</span></button>
|
||
<button class="diag-tab diag-tab--active diag-tab--has-abnormal"><span class="diag-tab__label">账号</span><span class="diag-tab__badge">1</span></button>
|
||
<button class="diag-tab diag-tab--has-abnormal"><span class="diag-tab__label">设备</span><span class="diag-tab__badge">1</span></button>
|
||
<button class="diag-tab diag-tab--has-abnormal"><span class="diag-tab__label">系统</span><span class="diag-tab__badge">2</span></button>
|
||
<button class="diag-tab"><span class="diag-tab__label">安全</span></button>
|
||
<button class="diag-tab diag-tab--has-abnormal"><span class="diag-tab__label">合规</span><span class="diag-tab__badge">1</span></button>
|
||
</div>
|
||
<div style="padding:8px;font-size:10px;color:var(--text-secondary);background:#fff;">
|
||
<b>🔑 账号权限 · 4 项风险</b>(仅显示此 Tab 数据)
|
||
<div style="margin-top:4px;font-size:9px;color:var(--text-tertiary);">→ 域账号 / 零信任 / 云盘 / 邮箱</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cmp-card">
|
||
<div class="cmp-card__title" style="background:#10b981;color:#fff;">✅ 行为已天然满足需求</div>
|
||
<div class="cmp-card__sub">无需代码改动 · 仅在原型标注</div>
|
||
<div class="cmp-pros-cons">
|
||
<div class="cmp-pro">✅ SelfDiagnosis.vue:499-501 currentTab 已 computed 过滤</div>
|
||
<div class="cmp-pro">✅ 切 Tab 时 Vue 自动卸载旧 DOM / 挂载新 DOM</div>
|
||
<div class="cmp-pro">✅ 用户感知是"切换"而非"同时显示"</div>
|
||
<div class="cmp-con">⚠️ 切换时无过渡动画(可后续加 transition)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
/* ===== 决策对比面板 ===== */
|
||
.cmp-panel {
|
||
margin: 16px 12px;
|
||
padding: 14px;
|
||
border-radius: 12px;
|
||
background: linear-gradient(135deg, rgba(59,130,246,0.04), rgba(139,92,246,0.04));
|
||
border: 1px solid rgba(59,130,246,0.2);
|
||
}
|
||
.cmp-panel__title {
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
margin-bottom: 4px;
|
||
}
|
||
.cmp-panel__subtitle {
|
||
font-size: 11px;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 12px;
|
||
}
|
||
.cmp-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 10px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.cmp-card {
|
||
background: var(--bg-primary);
|
||
border: 1px solid var(--border-color);
|
||
border-radius: 10px;
|
||
padding: 8px;
|
||
overflow: hidden;
|
||
}
|
||
.cmp-card__title {
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
padding: 4px 8px;
|
||
border-radius: 6px;
|
||
background: var(--bg-tertiary);
|
||
margin-bottom: 2px;
|
||
}
|
||
.cmp-card__sub {
|
||
font-size: 9px;
|
||
color: var(--text-tertiary);
|
||
margin-bottom: 6px;
|
||
padding: 0 4px;
|
||
}
|
||
.cmp-card__screen {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
padding: 4px;
|
||
background: var(--bg-secondary);
|
||
border-radius: 6px;
|
||
overflow: hidden;
|
||
}
|
||
.cmp-card__phone-label {
|
||
font-size: 9px;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
text-align: center;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
.cmp-phone-mini {
|
||
margin: 0 auto;
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
border: 1px solid #e5e7eb;
|
||
overflow: hidden;
|
||
}
|
||
.cmp-scroll-hint {
|
||
font-size: 9px;
|
||
text-align: center;
|
||
color: var(--text-tertiary);
|
||
padding: 2px;
|
||
font-style: italic;
|
||
}
|
||
.cmp-zoom {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 64px;
|
||
padding: 12px;
|
||
background: var(--bg-secondary);
|
||
border-radius: 6px;
|
||
margin-bottom: 6px;
|
||
}
|
||
.cmp-pros-cons {
|
||
font-size: 10px;
|
||
line-height: 1.5;
|
||
padding: 2px 4px;
|
||
}
|
||
.cmp-pro { color: #16a34a; }
|
||
.cmp-con { color: #d97706; }
|
||
.cmp-summary {
|
||
background: var(--bg-primary);
|
||
padding: 8px 10px;
|
||
border-radius: 8px;
|
||
border: 1px solid var(--border-color);
|
||
}
|
||
.cmp-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 10px;
|
||
}
|
||
.cmp-table th, .cmp-table td {
|
||
padding: 4px 6px;
|
||
text-align: left;
|
||
border-bottom: 1px solid var(--border-color);
|
||
vertical-align: top;
|
||
}
|
||
.cmp-table th {
|
||
background: var(--bg-tertiary);
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
}
|
||
.cmp-table small { color: var(--text-tertiary); font-size: 9px; }
|
||
|
||
@media (max-width: 1200px) {
|
||
.cmp-grid { grid-template-columns: 1fr; }
|
||
}
|
||
|
||
/* ===== v2.3 移动端 toggle 切换演示 ===== */
|
||
.mobile-topbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 8px;
|
||
background: linear-gradient(135deg, var(--bg-secondary), #fff);
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.mobile-topbar__title {
|
||
flex: 1;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
}
|
||
.mobile-topbar__toggle {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
height: 24px;
|
||
padding: 0 8px;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: 12px;
|
||
background: #fff;
|
||
color: var(--text-secondary);
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
transition: all 0.2s;
|
||
}
|
||
.mobile-topbar__toggle--active {
|
||
background: var(--accent);
|
||
color: #fff;
|
||
border-color: var(--accent);
|
||
}
|
||
.mobile-topbar__toggle:not(.mobile-topbar__toggle--active):hover {
|
||
border-color: var(--accent);
|
||
color: var(--accent);
|
||
}
|
||
.mobile-chat {
|
||
padding: 10px 8px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
background: var(--bg-secondary);
|
||
min-height: 100px;
|
||
}
|
||
.mobile-chat__msg {
|
||
max-width: 80%;
|
||
padding: 6px 8px;
|
||
border-radius: 8px;
|
||
font-size: 10px;
|
||
line-height: 1.4;
|
||
}
|
||
.mobile-chat__msg--user {
|
||
align-self: flex-end;
|
||
background: var(--accent);
|
||
color: #fff;
|
||
border-bottom-right-radius: 2px;
|
||
}
|
||
.mobile-chat__msg--ai {
|
||
align-self: flex-start;
|
||
background: #fff;
|
||
color: var(--text-primary);
|
||
border: 1px solid var(--border-color);
|
||
border-bottom-left-radius: 2px;
|
||
}
|
||
.mobile-input {
|
||
height: 32px;
|
||
background: #fff;
|
||
border-top: 1px solid var(--border-color);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.mobile-rightpanel {
|
||
padding: 8px;
|
||
background: var(--bg-secondary);
|
||
min-height: 100px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
.mobile-accordion {
|
||
background: #fff;
|
||
border-radius: 6px;
|
||
border: 1px solid var(--border-color);
|
||
overflow: hidden;
|
||
}
|
||
.mobile-accordion__item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 8px;
|
||
font-size: 11px;
|
||
color: var(--text-primary);
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
.mobile-accordion__item:last-child { border-bottom: none; }
|
||
.mobile-accordion__item span:last-child {
|
||
margin-left: auto;
|
||
color: var(--text-tertiary);
|
||
font-size: 10px;
|
||
}
|
||
.mobile-accordion__item span:nth-last-child(2) {
|
||
background: var(--color-danger, #ef4444);
|
||
color: #fff;
|
||
font-size: 9px;
|
||
font-weight: 700;
|
||
padding: 0 5px;
|
||
border-radius: 8px;
|
||
min-width: 14px;
|
||
text-align: center;
|
||
}
|
||
.mobile-queue-header-v23 {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
padding: 7px 8px;
|
||
background: #fff;
|
||
border-radius: 6px;
|
||
border: 1px solid var(--border-color);
|
||
font-size: 11px;
|
||
}
|
||
.mobile-queue-header-v23 .qh-pos {
|
||
background: rgba(59,130,246,0.1);
|
||
color: var(--accent);
|
||
font-weight: 700;
|
||
padding: 1px 5px;
|
||
border-radius: 4px;
|
||
}
|
||
.mobile-queue-header-v23 .qh-lv {
|
||
background: var(--bg-tertiary);
|
||
color: var(--text-secondary);
|
||
padding: 1px 5px;
|
||
border-radius: 4px;
|
||
font-size: 10px;
|
||
}
|
||
.mobile-queue-header-v23 .qh-pts {
|
||
margin-left: auto;
|
||
color: var(--text-primary);
|
||
font-weight: 600;
|
||
font-size: 11px;
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
function toggleTheme() {
|
||
const html = document.documentElement;
|
||
html.setAttribute('data-theme', html.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|