Files
wecom_it_smart_desk/docs/01-产品文档/05-用户端H5/原型-REQ-用户-007-自助诊断面板优化-v1.0.html
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .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-*/
2026-08-07 22:31:32 +08:00

2633 lines
101 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN" 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 · 1Fwarning/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.3queue-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__headerSelfDiagnosis 通过 <code>defineExpose</code> 暴露 6 个 APItotalBadge / 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-cardQueueWaiting 组件需新增 <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 移动端 &lt;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__headerSelfDiagnosis 通过 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>,移动端(&lt;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>
<!-- 方案 CTab 文字下方 -->
<div class="cmp-card">
<div class="cmp-card__title" style="background:#10b981;color:#fff;">方案 CTab 文字下方</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">⚠️ 仅适用于移动端(&lt;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>