2026-06-14 16:49:18 +08:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<title>IT智能服务台 · 坐席工作台 v5.4</title>
|
|
|
|
|
|
<style>
|
|
|
|
|
|
:root {
|
|
|
|
|
|
--bg-primary: #f5f7fa;
|
|
|
|
|
|
--bg-secondary: #ffffff;
|
|
|
|
|
|
--bg-tertiary: #f0f2f5;
|
|
|
|
|
|
--bg-hover: #e8ecf1;
|
|
|
|
|
|
--bg-active: #dce3ec;
|
|
|
|
|
|
--border: #e2e8f0;
|
|
|
|
|
|
--border-light: #cbd5e1;
|
|
|
|
|
|
--text-primary: #1e293b;
|
|
|
|
|
|
--text-secondary: #64748b;
|
|
|
|
|
|
--text-muted: #94a3b8;
|
|
|
|
|
|
--accent: #3b82f6;
|
|
|
|
|
|
--accent-soft: #dbeafe;
|
|
|
|
|
|
--success: #22c55e;
|
|
|
|
|
|
--success-soft: #dcfce7;
|
|
|
|
|
|
--warning: #f59e0b;
|
|
|
|
|
|
--warning-soft: #fef3c7;
|
|
|
|
|
|
--danger: #ef4444;
|
|
|
|
|
|
--danger-soft: #fee2e2;
|
|
|
|
|
|
--info: #60a5fa;
|
|
|
|
|
|
--purple: #8b5cf6;
|
|
|
|
|
|
--purple-soft: #ede9fe;
|
|
|
|
|
|
--orange: #f97316;
|
|
|
|
|
|
--orange-soft: #fff7ed;
|
|
|
|
|
|
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
|
|
|
|
|
|
--shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
|
|
|
|
--radius: 6px;
|
|
|
|
|
|
--radius-lg: 10px;
|
|
|
|
|
|
--transition: 0.25s cubic-bezier(0.4,0,0.2,1);
|
|
|
|
|
|
|
|
|
|
|
|
/* 快速回复 L1 主类颜色 */
|
|
|
|
|
|
--qr-c0: #3b82f6; /* 电脑 - 蓝 */
|
|
|
|
|
|
--qr-c1: #22c55e; /* 软件 - 绿 */
|
|
|
|
|
|
--qr-c2: #f97316; /* 外设 - 橙 */
|
|
|
|
|
|
--qr-c3: #8b5cf6; /* 网络 - 紫 */
|
|
|
|
|
|
--qr-c4: #ef4444; /* 安全 - 红 */
|
|
|
|
|
|
--qr-c5: #0ea5e9; /* 资产 - 青 */
|
|
|
|
|
|
--qr-c6: #6b7280; /* 其他 - 灰 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[data-theme="dark"] {
|
|
|
|
|
|
--bg-primary: #0f1923;
|
|
|
|
|
|
--bg-secondary: #151f2b;
|
|
|
|
|
|
--bg-tertiary: #1a2736;
|
|
|
|
|
|
--bg-hover: #1e3044;
|
|
|
|
|
|
--bg-active: #243b52;
|
|
|
|
|
|
--border: #1e3044;
|
|
|
|
|
|
--border-light: #2a3f56;
|
|
|
|
|
|
--text-primary: #e8edf2;
|
|
|
|
|
|
--text-secondary: #8ba1b7;
|
|
|
|
|
|
--text-muted: #5c7185;
|
|
|
|
|
|
--accent: #4da6ff;
|
|
|
|
|
|
--accent-soft: #2b5f8a;
|
|
|
|
|
|
--success: #34d399;
|
|
|
|
|
|
--success-soft: #1a3a2a;
|
|
|
|
|
|
--warning: #fbbf24;
|
|
|
|
|
|
--warning-soft: #3a2f10;
|
|
|
|
|
|
--danger: #f87171;
|
|
|
|
|
|
--danger-soft: #3a1a1a;
|
|
|
|
|
|
--info: #60a5fa;
|
|
|
|
|
|
--purple: #a78bfa;
|
|
|
|
|
|
--purple-soft: #2d2060;
|
|
|
|
|
|
--orange: #fb923c;
|
|
|
|
|
|
--orange-soft: #3d1f08;
|
|
|
|
|
|
--shadow-sm: 0 1px 2px rgba(0,0,0,0.2);
|
|
|
|
|
|
--shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
|
|
|
|
|
|
|
|
|
|
/* 快速回复 L1 主类颜色(深色主题:同色系稍亮版本) */
|
|
|
|
|
|
--qr-c0: #60a5fa;
|
|
|
|
|
|
--qr-c1: #4ade80;
|
|
|
|
|
|
--qr-c2: #fb923c;
|
|
|
|
|
|
--qr-c3: #a78bfa;
|
|
|
|
|
|
--qr-c4: #f87171;
|
|
|
|
|
|
--qr-c5: #22d3ee;
|
|
|
|
|
|
--qr-c6: #9ca3af;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
|
|
body {
|
|
|
|
|
|
font-family: 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', sans-serif;
|
|
|
|
|
|
background: var(--bg-primary);
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
transition: background 0.3s, color 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== TOP BAR ========== */
|
|
|
|
|
|
.theme-toggle-bar {
|
|
|
|
|
|
position: fixed; top: 0; left: 0; right: 0;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
display: flex; align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
|
z-index: 100;
|
|
|
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
|
|
}
|
|
|
|
|
|
.bar-left { display: flex; align-items: center; gap: 10px; font-size: 13px; font-weight: 600; }
|
|
|
|
|
|
.bar-left .logo-sm {
|
|
|
|
|
|
width: 26px; height: 26px;
|
|
|
|
|
|
background: linear-gradient(135deg, var(--accent), var(--purple));
|
|
|
|
|
|
border-radius: 6px; display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-weight: 700; font-size: 10px; color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bar-left .sys-name {
|
|
|
|
|
|
font-size: 13px; font-weight: 700;
|
|
|
|
|
|
background: linear-gradient(135deg, var(--accent), var(--purple));
|
|
|
|
|
|
-webkit-background-clip: text;
|
|
|
|
|
|
-webkit-text-fill-color: transparent;
|
|
|
|
|
|
background-clip: text;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bar-left .sys-tagline {
|
|
|
|
|
|
font-size: 10px; color: var(--text-muted);
|
|
|
|
|
|
font-weight: 400; margin-left: 4px;
|
|
|
|
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
|
|
|
|
max-width: 280px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bar-right { display: flex; align-items: center; gap: 14px; }
|
|
|
|
|
|
.theme-switch { display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
|
|
|
|
|
|
.theme-switch .switch-icon { font-size: 15px; }
|
|
|
|
|
|
.theme-switch .switch-track {
|
|
|
|
|
|
width: 40px; height: 22px;
|
|
|
|
|
|
background: var(--border-light); border-radius: 11px;
|
|
|
|
|
|
position: relative; transition: background 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
[data-theme="dark"] .theme-switch .switch-track { background: var(--accent); }
|
|
|
|
|
|
.theme-switch .switch-thumb {
|
|
|
|
|
|
width: 18px; height: 18px; background: #fff;
|
|
|
|
|
|
border-radius: 50%; position: absolute;
|
|
|
|
|
|
top: 2px; left: 2px; transition: transform 0.3s;
|
|
|
|
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
|
|
|
|
}
|
|
|
|
|
|
[data-theme="dark"] .theme-switch .switch-thumb { transform: translateX(18px); }
|
|
|
|
|
|
.bar-user-info { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-secondary); }
|
|
|
|
|
|
.bar-user-avatar {
|
|
|
|
|
|
width: 28px; height: 28px; border-radius: 50%;
|
|
|
|
|
|
background: #f3f4f6; color: #374151;
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 11px; font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== LAYOUT (3 columns) ========== */
|
|
|
|
|
|
.workspace {
|
|
|
|
|
|
display: flex; height: calc(100vh - 40px); margin-top: 40px;
|
|
|
|
|
|
width: 100%; transition: var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== LEFT SIDEBAR ========== */
|
|
|
|
|
|
.sidebar-left {
|
|
|
|
|
|
width: 280px; min-width: 200px;
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border-right: none;
|
|
|
|
|
|
display: flex; flex-direction: column; overflow: hidden;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Search */
|
|
|
|
|
|
.conv-search { padding: 10px 12px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== v5.4: 拖拽调整边框手柄 ===== */
|
|
|
|
|
|
.resize-handle {
|
|
|
|
|
|
width: 6px; cursor: col-resize;
|
|
|
|
|
|
background: var(--border);
|
|
|
|
|
|
position: relative; flex-shrink: 0;
|
|
|
|
|
|
transition: background 0.2s;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
.resize-handle:hover,
|
|
|
|
|
|
.resize-handle.dragging {
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 手柄中间的拖拽指示纹 */
|
|
|
|
|
|
.resize-handle::after {
|
|
|
|
|
|
content: '⋮';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 50%; left: 50%;
|
|
|
|
|
|
transform: translate(-50%, -50%);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
transition: opacity 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.resize-handle:hover::after,
|
|
|
|
|
|
.resize-handle.dragging::after {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-search-input-wrap { position: relative; }
|
|
|
|
|
|
.conv-search-input {
|
|
|
|
|
|
width: 100%; background: var(--bg-tertiary);
|
|
|
|
|
|
border: 1px solid var(--border); border-radius: var(--radius);
|
|
|
|
|
|
padding: 7px 10px 7px 30px;
|
|
|
|
|
|
color: var(--text-primary); font-size: 12px; font-family: inherit;
|
|
|
|
|
|
outline: none; transition: border-color var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-search-input:focus { border-color: var(--accent); }
|
|
|
|
|
|
.conv-search-input::placeholder { color: var(--text-muted); }
|
|
|
|
|
|
.conv-search-icon {
|
|
|
|
|
|
position: absolute; left: 10px; top: 50%;
|
|
|
|
|
|
transform: translateY(-50%); font-size: 12px;
|
|
|
|
|
|
color: var(--text-muted); pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-search-tabs { display: flex; gap: 2px; margin-top: 6px; }
|
|
|
|
|
|
.conv-search-tab {
|
|
|
|
|
|
font-size: 11px; padding: 3px 10px; border-radius: 10px;
|
|
|
|
|
|
cursor: pointer; transition: var(--transition);
|
|
|
|
|
|
color: var(--text-muted); background: transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-search-tab:hover { color: var(--text-secondary); background: var(--bg-hover); }
|
|
|
|
|
|
.conv-search-tab.active { color: var(--accent); background: var(--accent-soft); font-weight: 500; }
|
|
|
|
|
|
|
|
|
|
|
|
/* Sections */
|
|
|
|
|
|
.conv-sections { flex: 1; overflow-y: auto; padding: 0; }
|
|
|
|
|
|
.conv-sections::-webkit-scrollbar { width: 4px; }
|
|
|
|
|
|
.conv-sections::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
|
|
|
|
|
|
|
|
|
|
|
.conv-section-header {
|
|
|
|
|
|
padding: 7px 12px; font-size: 11px; font-weight: 600;
|
|
|
|
|
|
color: var(--text-muted); text-transform: uppercase;
|
|
|
|
|
|
letter-spacing: 0.5px; display: flex; align-items: center;
|
|
|
|
|
|
justify-content: space-between; user-select: none;
|
|
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
border-top: 1px solid var(--border);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
transition: var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-section-header .cs-count {
|
|
|
|
|
|
font-weight: 400; color: var(--text-muted);
|
|
|
|
|
|
background: var(--bg-secondary); padding: 1px 7px;
|
|
|
|
|
|
border-radius: 8px; font-size: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-section-body { overflow: hidden; }
|
|
|
|
|
|
|
|
|
|
|
|
/* Priority icons on conv item (NO IT level badge) */
|
|
|
|
|
|
/* conv-item 样式已移至 v5.4 头像区块中 */
|
|
|
|
|
|
|
|
|
|
|
|
.conv-item .conv-top {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
|
|
|
|
margin-bottom: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-item .conv-name-row { display: flex; align-items: center; gap: 5px; }
|
|
|
|
|
|
.conv-item .conv-name { font-size: 12px; font-weight: 500; color: var(--text-primary); }
|
|
|
|
|
|
|
|
|
|
|
|
.priority-icons {
|
|
|
|
|
|
display: flex; align-items: center; gap: 3px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.pi-icon {
|
|
|
|
|
|
width: 16px; height: 16px; border-radius: 3px;
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 8px; flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.pi-blocked { background: var(--danger-soft); color: var(--danger); }
|
|
|
|
|
|
.pi-block { background: var(--danger-soft); color: var(--danger); }
|
|
|
|
|
|
.pi-impact { background: var(--warning-soft); color: var(--warning); }
|
|
|
|
|
|
.pi-impact.high { background: var(--danger-soft); color: var(--danger); }
|
|
|
|
|
|
.pi-role { background: var(--purple-soft); color: var(--purple); }
|
|
|
|
|
|
.pi-repeat { background: var(--orange-soft); color: var(--orange); }
|
|
|
|
|
|
.pi-confused { background: #e0e7ff; color: #6366f1; }
|
|
|
|
|
|
.pi-angry { background: #fee2e2; color: #ef4444; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 会话标签 */
|
|
|
|
|
|
.conv-tag-warn, .conv-tag-new, .conv-tag-vip, .conv-tag-urgent {
|
|
|
|
|
|
font-size: 9px; padding: 1px 5px; border-radius: 4px; flex-shrink: 0; font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-tag-warn { background: #fef3c7; color: #d97706; }
|
|
|
|
|
|
.conv-tag-new { background: #dbeafe; color: #2563eb; }
|
|
|
|
|
|
.conv-tag-vip { background: #fce7f3; color: #db2777; }
|
|
|
|
|
|
.conv-tag-urgent{ background: #fee2e2; color: #ef4444; }
|
|
|
|
|
|
.conv-pin-badge { font-size: 9px; color: #ef4444; flex-shrink: 0; }
|
|
|
|
|
|
|
|
|
|
|
|
.conv-item .conv-time { font-size: 10px; color: var(--text-muted); flex-shrink: 0; }
|
|
|
|
|
|
.conv-item .conv-preview {
|
|
|
|
|
|
font-size: 11px; color: var(--text-secondary);
|
|
|
|
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-item .conv-waiting {
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
background: var(--danger); color: #fff;
|
|
|
|
|
|
padding: 1px 6px; border-radius: 8px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-item .conv-agent-tag {
|
|
|
|
|
|
font-size: 10px; color: var(--text-muted);
|
|
|
|
|
|
background: var(--bg-tertiary); padding: 1px 6px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== v5.4: 会话头像 + 新消息圆点 + 处理对象缩略头像 ===== */
|
|
|
|
|
|
.conv-item {
|
|
|
|
|
|
display: flex; align-items: center; gap: 8px;
|
|
|
|
|
|
padding: 8px 10px; margin: 1px 6px;
|
|
|
|
|
|
border-radius: var(--radius); cursor: pointer;
|
|
|
|
|
|
transition: var(--transition);
|
|
|
|
|
|
border: 1px solid transparent; position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-item:hover { background: var(--bg-hover); }
|
|
|
|
|
|
.conv-item.active { background: var(--accent-soft); border-color: var(--accent); }
|
|
|
|
|
|
|
|
|
|
|
|
/* 头像容器(含圆点) */
|
|
|
|
|
|
.conv-avatar-wrap {
|
|
|
|
|
|
position: relative; flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 头像圆形 — 浅色主题:浅底+深色字 */
|
|
|
|
|
|
.conv-avatar {
|
|
|
|
|
|
width: 34px; height: 34px; border-radius: 50%;
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 13px; font-weight: 600;
|
|
|
|
|
|
color: #1e293b;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 浅色主题:各头像色系用浅底色 */
|
|
|
|
|
|
.conv-avatar.av-blue { background: #dbeafe; color: #1e40af; }
|
|
|
|
|
|
.conv-avatar.av-green { background: #dcfce7; color: #166534; }
|
|
|
|
|
|
.conv-avatar.av-orange { background: #fff7ed; color: #9a3412; }
|
|
|
|
|
|
.conv-avatar.av-purple { background: #ede9fe; color: #5b21b6; }
|
|
|
|
|
|
.conv-avatar.av-red { background: #fee2e2; color: #991b1b; }
|
|
|
|
|
|
.conv-avatar.av-teal { background: #f0fdfa; color: #115e59; }
|
|
|
|
|
|
.conv-avatar.av-pink { background: #fce7f3; color: #9d174d; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 新消息圆点(在头像右上角) */
|
|
|
|
|
|
.new-msg-dot {
|
|
|
|
|
|
position: absolute; top: -1px; right: -1px;
|
|
|
|
|
|
width: 10px; height: 10px; border-radius: 50%;
|
|
|
|
|
|
border: 2px solid var(--bg-secondary);
|
|
|
|
|
|
z-index: 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
.new-msg-dot.dot-urgent { background: var(--danger); } /* 紧急:红色 */
|
|
|
|
|
|
.new-msg-dot.dot-normal { background: var(--accent); } /* 普通:蓝色 */
|
|
|
|
|
|
.new-msg-dot.dot-muted { background: var(--text-muted); }/* 低优:灰色 */
|
|
|
|
|
|
|
|
|
|
|
|
/* 会话内容区(姓名+预览+标签,夹在头像和右侧缩略头像之间) */
|
|
|
|
|
|
.conv-content {
|
|
|
|
|
|
flex: 1; min-width: 0; /* 允许文字截断 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 处理对象缩略头像(右侧小头像)— 浅色主题:浅底+深色字 */
|
|
|
|
|
|
.conv-target-avatar {
|
|
|
|
|
|
width: 22px; height: 22px; border-radius: 50%;
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 9px; font-weight: 600;
|
|
|
|
|
|
flex-shrink: 0; margin-left: auto;
|
|
|
|
|
|
color: #1e293b;
|
|
|
|
|
|
}
|
|
|
|
|
|
.conv-target-avatar.ta-blue { background: #dbeafe; color: #1e40af; }
|
|
|
|
|
|
.conv-target-avatar.ta-green { background: #dcfce7; color: #166534; }
|
|
|
|
|
|
.conv-target-avatar.ta-orange { background: #fff7ed; color: #9a3412; }
|
|
|
|
|
|
.conv-target-avatar.ta-purple { background: #ede9fe; color: #5b21b6; }
|
|
|
|
|
|
.conv-target-avatar.ta-red { background: #fee2e2; color: #991b1b; }
|
|
|
|
|
|
.conv-target-avatar.ta-teal { background: #f0fdfa; color: #115e59; }
|
|
|
|
|
|
.conv-target-avatar.ta-pink { background: #fce7f3; color: #9d174d; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 待办事项缩略头像 — 浅色主题:浅底+深色字 */
|
|
|
|
|
|
.kanban-item .ki-avatar {
|
|
|
|
|
|
width: 20px; height: 20px; border-radius: 50%;
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 9px; font-weight: 600;
|
|
|
|
|
|
flex-shrink: 0; margin-left: auto;
|
|
|
|
|
|
color: #1e293b;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ki-avatar.ka-blue { background: #dbeafe; color: #1e40af; }
|
|
|
|
|
|
.ki-avatar.ka-green { background: #dcfce7; color: #166534; }
|
|
|
|
|
|
.ki-avatar.ka-orange { background: #fff7ed; color: #9a3412; }
|
|
|
|
|
|
.ki-avatar.ka-purple { background: #ede9fe; color: #5b21b6; }
|
|
|
|
|
|
.ki-avatar.ka-red { background: #fee2e2; color: #991b1b; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 深色主题:头像恢复渐变亮色 */
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar {
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar.av-blue { background: linear-gradient(135deg, #3b82f6, #6366f1); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar.av-green { background: linear-gradient(135deg, #22c55e, #14b8a6); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar.av-orange { background: linear-gradient(135deg, #f97316, #eab308); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar.av-purple { background: linear-gradient(135deg, #8b5cf6, #ec4899); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar.av-red { background: linear-gradient(135deg, #ef4444, #f97316); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar.av-teal { background: linear-gradient(135deg, #0ea5e9, #6366f1); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-avatar.av-pink { background: linear-gradient(135deg, #ec4899, #f43f5e); color: #fff; }
|
|
|
|
|
|
|
|
|
|
|
|
[data-theme="dark"] .conv-target-avatar.ta-blue { background: linear-gradient(135deg, #3b82f6, #6366f1); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-target-avatar.ta-green { background: linear-gradient(135deg, #22c55e, #14b8a6); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-target-avatar.ta-orange { background: linear-gradient(135deg, #f97316, #eab308); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-target-avatar.ta-purple { background: linear-gradient(135deg, #8b5cf6, #ec4899); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-target-avatar.ta-red { background: linear-gradient(135deg, #ef4444, #f97316); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-target-avatar.ta-teal { background: linear-gradient(135deg, #0ea5e9, #6366f1); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .conv-target-avatar.ta-pink { background: linear-gradient(135deg, #ec4899, #f43f5e); color: #fff; }
|
|
|
|
|
|
|
|
|
|
|
|
[data-theme="dark"] .bar-user-avatar {
|
|
|
|
|
|
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[data-theme="dark"] .user-avatar {
|
|
|
|
|
|
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[data-theme="dark"] .ki-avatar.ka-blue { background: linear-gradient(135deg, #3b82f6, #6366f1); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .ki-avatar.ka-green { background: linear-gradient(135deg, #22c55e, #14b8a6); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .ki-avatar.ka-orange { background: linear-gradient(135deg, #f97316, #eab308); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .ki-avatar.ka-purple { background: linear-gradient(135deg, #8b5cf6, #ec4899); color: #fff; }
|
|
|
|
|
|
[data-theme="dark"] .ki-avatar.ka-red { background: linear-gradient(135deg, #ef4444, #f97316); color: #fff; }
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== 待办事项 ===== */
|
|
|
|
|
|
.kanban { flex-shrink: 0; border-top: 1px solid var(--border); padding: 8px 12px; max-height: 220px; overflow-y: auto; }
|
|
|
|
|
|
.kanban::-webkit-scrollbar { width: 4px; }
|
|
|
|
|
|
.kanban::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
|
|
|
|
|
.kanban-title { font-size: 11px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; display: flex; align-items: center; justify-content: space-between; }
|
|
|
|
|
|
.kanban-title .count { font-size: 10px; color: var(--danger); }
|
|
|
|
|
|
.kanban-item { display: flex; align-items: center; gap: 8px; padding: 7px 8px; border-radius: var(--radius); font-size: 11px; margin-bottom: 3px; cursor: pointer; transition: var(--transition); }
|
|
|
|
|
|
.kanban-item:hover { background: var(--bg-hover); }
|
|
|
|
|
|
.kanban-item.active { background: var(--accent-soft); border: 1px solid var(--accent); }
|
|
|
|
|
|
.kanban-item .ki-priority { width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0; }
|
|
|
|
|
|
.ki-priority.urgent { background: var(--danger); }
|
|
|
|
|
|
.ki-priority.high { background: var(--warning); }
|
|
|
|
|
|
.ki-priority.normal { background: var(--accent); }
|
|
|
|
|
|
.ki-priority.done { background: var(--success); }
|
|
|
|
|
|
.kanban-item.resolved { opacity: 0.6; }
|
|
|
|
|
|
.kanban-item .ki-text { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-secondary); }
|
|
|
|
|
|
.kanban-item .ki-type {
|
|
|
|
|
|
font-size: 9px; padding: 1px 5px; border-radius: 4px;
|
|
|
|
|
|
flex-shrink: 0; font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ki-type.ticket { background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent); }
|
|
|
|
|
|
.ki-type.approval { background: var(--purple-soft); color: var(--purple); border: 1px solid var(--purple); }
|
|
|
|
|
|
.ki-type.device { background: var(--orange-soft); color: var(--orange); border: 1px solid var(--orange); }
|
|
|
|
|
|
.kanban-item .ki-time { font-size: 10px; color: var(--text-muted); flex-shrink: 0; }
|
|
|
|
|
|
.kanban-stats { display: flex; gap: 8px; margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); font-size: 10px; color: var(--text-muted); }
|
|
|
|
|
|
.kanban-stats span { display: flex; align-items: center; gap: 4px; }
|
|
|
|
|
|
.kanban-stats .dot { width: 6px; height: 6px; border-radius: 50%; }
|
|
|
|
|
|
.dot-online { background: var(--success); }
|
|
|
|
|
|
.dot-busy { background: var(--warning); }
|
|
|
|
|
|
.dot-offline { background: var(--text-muted); }
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== CENTER COLUMN ========== */
|
|
|
|
|
|
.center-column {
|
|
|
|
|
|
flex: 1; min-width: 340px;
|
|
|
|
|
|
display: flex; flex-direction: column;
|
|
|
|
|
|
background: var(--bg-primary); overflow: hidden;
|
|
|
|
|
|
transition: var(--transition);
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* --- Chat View (default) --- */
|
|
|
|
|
|
.chat-view { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
|
|
|
|
|
|
.chat-view.hidden { display: none; }
|
|
|
|
|
|
|
|
|
|
|
|
/* IT Level Badge */
|
|
|
|
|
|
.it-level-badge {
|
|
|
|
|
|
display: inline-flex; align-items: center; gap: 3px;
|
|
|
|
|
|
padding: 2px 7px; border-radius: 10px;
|
|
|
|
|
|
font-size: 10px; font-weight: 600;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
position: relative; cursor: help;
|
|
|
|
|
|
}
|
|
|
|
|
|
.it-level-badge.bronze { background: linear-gradient(135deg, #78350f, #92400e); color: #fef3c7; border: 1px solid #b45309; }
|
|
|
|
|
|
.it-level-badge.silver { background: linear-gradient(135deg, #374151, #6b7280); color: #f3f4f6; border: 1px solid #9ca3af; }
|
|
|
|
|
|
.it-level-badge.gold { background: linear-gradient(135deg, #92400e, #d97706); color: #fffbeb; border: 1px solid #f59e0b; }
|
|
|
|
|
|
.it-level-badge.platinum { background: linear-gradient(135deg, #164e63, #0e7490); color: #cffafe; border: 1px solid #22d3ee; }
|
|
|
|
|
|
.it-level-badge.diamond { background: linear-gradient(135deg, #312e81, #4338ca); color: #e0e7ff; border: 1px solid #818cf8; }
|
|
|
|
|
|
.it-level-badge.star { background: linear-gradient(135deg, #831843, #be185d); color: #fce7f3; border: 1px solid #ec4899; }
|
|
|
|
|
|
.it-level-badge.king { background: linear-gradient(135deg, #7c2d12, #c2410c); color: #ffedd5; border: 1px solid #f97316;
|
|
|
|
|
|
animation: king-glow 2s ease-in-out infinite alternate;
|
|
|
|
|
|
}
|
|
|
|
|
|
@keyframes king-glow {
|
|
|
|
|
|
from { box-shadow: 0 0 4px rgba(249,115,22,0.3); }
|
|
|
|
|
|
to { box-shadow: 0 0 10px rgba(249,115,22,0.6); }
|
|
|
|
|
|
}
|
|
|
|
|
|
.it-level-badge .level-icon { font-size: 11px; }
|
|
|
|
|
|
.it-level-badge .level-num { font-size: 9px; opacity: 0.8; }
|
|
|
|
|
|
|
|
|
|
|
|
/* User info bar */
|
|
|
|
|
|
.user-info-bar {
|
|
|
|
|
|
padding: 10px 16px; background: var(--bg-secondary);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
display: flex; align-items: center; gap: 10px;
|
|
|
|
|
|
flex-shrink: 0; flex-wrap: wrap; cursor: pointer;
|
|
|
|
|
|
transition: var(--transition); position: relative;
|
|
|
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-info-bar:hover { background: var(--bg-hover); }
|
|
|
|
|
|
.user-avatar {
|
|
|
|
|
|
width: 36px; height: 36px; border-radius: 50%;
|
|
|
|
|
|
background: #f3f4f6; color: #374151;
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 14px; font-weight: 600; flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-name-section { display: flex; flex-direction: column; gap: 1px; }
|
|
|
|
|
|
.user-name { font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 6px; }
|
|
|
|
|
|
.user-dept { font-size: 11px; color: var(--text-secondary); }
|
|
|
|
|
|
.info-chips { display: flex; gap: 5px; flex-wrap: wrap; }
|
|
|
|
|
|
.info-chip { font-size: 11px; padding: 2px 8px; border-radius: 10px; display: flex; align-items: center; gap: 4px; }
|
|
|
|
|
|
.info-chip.emotion { background: var(--warning-soft); color: var(--warning); border: 1px solid var(--warning); }
|
|
|
|
|
|
.info-chip.default { background: var(--bg-tertiary); color: var(--text-secondary); border: 1px solid var(--border); }
|
|
|
|
|
|
.info-chip.repeat { background: var(--danger-soft); color: var(--danger); border: 1px solid var(--danger); }
|
|
|
|
|
|
.info-chip.remark { background: var(--purple-soft); color: var(--purple); border: 1px solid var(--purple); }
|
|
|
|
|
|
|
|
|
|
|
|
/* Device status icons row */
|
|
|
|
|
|
.device-status-row {
|
|
|
|
|
|
display: flex; align-items: center; gap: 8px;
|
|
|
|
|
|
margin-left: 6px; padding-left: 8px;
|
|
|
|
|
|
border-left: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dev-icon {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
width: 26px; height: 26px; border-radius: 6px;
|
|
|
|
|
|
font-size: 14px; cursor: default; position: relative;
|
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
|
background: var(--bg-tertiary); border: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dev-icon:hover { transform: scale(1.15); }
|
|
|
|
|
|
.dev-icon .dev-tooltip {
|
|
|
|
|
|
display: none; position: absolute; bottom: calc(100% + 6px); left: 50%;
|
|
|
|
|
|
transform: translateX(-50%); white-space: nowrap;
|
|
|
|
|
|
background: var(--bg-primary); color: var(--text-primary);
|
|
|
|
|
|
border: 1px solid var(--border); border-radius: 6px;
|
|
|
|
|
|
padding: 4px 8px; font-size: 10px; z-index: 99;
|
|
|
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dev-icon:hover .dev-tooltip { display: block; }
|
|
|
|
|
|
.dev-icon .dev-tooltip::after {
|
|
|
|
|
|
content: ''; position: absolute; top: 100%; left: 50%;
|
|
|
|
|
|
transform: translateX(-50%); border: 4px solid transparent;
|
|
|
|
|
|
border-top-color: var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Device icon status variants */
|
|
|
|
|
|
.dev-icon.online { color: #22c55e; border-color: rgba(34,197,94,0.3); background: rgba(34,197,94,0.08); }
|
|
|
|
|
|
.dev-icon.offline { color: var(--text-muted); opacity: 0.5; }
|
|
|
|
|
|
.dev-icon.safe { color: #22c55e; border-color: rgba(34,197,94,0.3); background: rgba(34,197,94,0.08); }
|
|
|
|
|
|
.dev-icon.risk { color: var(--danger); border-color: rgba(239,68,68,0.3); background: rgba(239,68,68,0.08); animation: pulse-risk 2s infinite; }
|
|
|
|
|
|
.dev-icon.warn { color: var(--warning); border-color: rgba(234,179,8,0.3); background: rgba(234,179,8,0.08); }
|
|
|
|
|
|
.dev-icon.certified { color: var(--accent); border-color: rgba(59,130,246,0.3); background: rgba(59,130,246,0.08); }
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes pulse-risk {
|
|
|
|
|
|
0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0.3); }
|
|
|
|
|
|
50% { box-shadow: 0 0 0 3px rgba(239,68,68,0.1); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Device badge (small superscript indicator) */
|
|
|
|
|
|
.dev-icon .dev-badge {
|
|
|
|
|
|
position: absolute; top: -3px; right: -3px;
|
|
|
|
|
|
width: 8px; height: 8px; border-radius: 50%;
|
|
|
|
|
|
border: 1.5px solid var(--bg-secondary);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dev-icon .dev-badge.green { background: #22c55e; }
|
|
|
|
|
|
.dev-icon .dev-badge.red { background: #ef4444; }
|
|
|
|
|
|
.dev-icon .dev-badge.yellow { background: #eab308; }
|
|
|
|
|
|
.dev-icon .dev-badge.gray { background: var(--text-muted); }
|
|
|
|
|
|
|
|
|
|
|
|
[data-theme="dark"] .dev-icon.online { background: rgba(34,197,94,0.15); }
|
|
|
|
|
|
[data-theme="dark"] .dev-icon.safe { background: rgba(34,197,94,0.15); }
|
|
|
|
|
|
[data-theme="dark"] .dev-icon.risk { background: rgba(239,68,68,0.15); }
|
|
|
|
|
|
[data-theme="dark"] .dev-icon.warn { background: rgba(234,179,8,0.15); }
|
|
|
|
|
|
[data-theme="dark"] .dev-icon.certified { background: rgba(59,130,246,0.15); }
|
|
|
|
|
|
|
|
|
|
|
|
.user-info-bar .expand-icon { margin-left: auto; color: var(--text-muted); font-size: 11px; transition: transform 0.3s; }
|
|
|
|
|
|
.user-info-bar.expanded .expand-icon { transform: rotate(90deg); }
|
|
|
|
|
|
|
|
|
|
|
|
/* User detail panel */
|
|
|
|
|
|
.user-detail-panel {
|
|
|
|
|
|
max-height: 0; overflow: hidden;
|
|
|
|
|
|
transition: max-height 0.35s ease, padding 0.35s ease;
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border-bottom: 0px solid var(--border);
|
|
|
|
|
|
padding: 0 16px; display: grid;
|
|
|
|
|
|
grid-template-columns: 1fr 1fr 1fr; gap: 8px; font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-info-bar.expanded + .user-detail-panel {
|
|
|
|
|
|
max-height: 320px; padding: 12px 16px; border-bottom-width: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.detail-card { background: var(--bg-tertiary); border-radius: var(--radius); padding: 8px 10px; border: 1px solid var(--border); }
|
|
|
|
|
|
.detail-card .dc-label { font-size: 10px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 3px; }
|
|
|
|
|
|
.detail-card .dc-value { font-size: 12px; font-weight: 500; color: var(--text-primary); }
|
|
|
|
|
|
.detail-card .dc-value.warn { color: var(--warning); }
|
|
|
|
|
|
|
|
|
|
|
|
/* Chat messages */
|
|
|
|
|
|
.chat-messages {
|
|
|
|
|
|
flex: 1; overflow-y: auto; padding: 16px 20px;
|
|
|
|
|
|
display: flex; flex-direction: column; gap: 10px;
|
|
|
|
|
|
min-height: 0; /* allow shrink */
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-messages::-webkit-scrollbar { width: 4px; }
|
|
|
|
|
|
.chat-messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
|
|
|
|
|
.msg-bubble {
|
|
|
|
|
|
max-width: 72%; padding: 10px 14px; border-radius: var(--radius-lg);
|
|
|
|
|
|
font-size: 13px; line-height: 1.6; word-break: break-word;
|
|
|
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
|
|
}
|
|
|
|
|
|
.msg-user {
|
|
|
|
|
|
align-self: flex-start; background: var(--bg-secondary);
|
|
|
|
|
|
border: 1px solid var(--border); color: var(--text-primary);
|
|
|
|
|
|
border-bottom-left-radius: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.msg-agent {
|
|
|
|
|
|
align-self: flex-end; background: var(--accent); color: #fff;
|
|
|
|
|
|
border-bottom-right-radius: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
[data-theme="dark"] .msg-agent { background: #1e5a9e; }
|
|
|
|
|
|
.msg-system {
|
|
|
|
|
|
align-self: center; font-size: 11px; color: var(--text-muted);
|
|
|
|
|
|
padding: 3px 12px; background: var(--bg-tertiary); border-radius: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* AI recommend inline */
|
|
|
|
|
|
.ai-recommend-inline {
|
|
|
|
|
|
align-self: stretch; background: var(--accent-soft);
|
|
|
|
|
|
border: 1px dashed var(--accent); border-radius: var(--radius-lg);
|
|
|
|
|
|
padding: 10px 14px; margin: 4px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
[data-theme="dark"] .ai-recommend-inline { background: rgba(77,166,255,0.06); border-color: rgba(77,166,255,0.3); }
|
|
|
|
|
|
.ai-recommend-inline .ari-label {
|
|
|
|
|
|
font-size: 10px; color: var(--accent); text-transform: uppercase;
|
|
|
|
|
|
letter-spacing: 1px; margin-bottom: 6px; display: flex; align-items: center; gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ari-options { display: flex; gap: 8px; }
|
|
|
|
|
|
.ari-opt {
|
|
|
|
|
|
flex: 1; padding: 8px 12px; background: var(--bg-secondary);
|
|
|
|
|
|
border: 1px solid var(--border-light); border-radius: var(--radius);
|
|
|
|
|
|
font-size: 12px; color: var(--text-primary); cursor: pointer;
|
|
|
|
|
|
transition: var(--transition); text-align: left; line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ari-opt:hover { border-color: var(--accent); background: var(--bg-hover); }
|
|
|
|
|
|
.ari-opt .ari-shortcut { font-size: 10px; color: var(--text-muted); float: right; margin-left: 8px; background: var(--bg-tertiary); padding: 1px 5px; border-radius: 3px; }
|
|
|
|
|
|
|
|
|
|
|
|
/* Chat input — v5.4: 上边框可拖拽调整高度 */
|
|
|
|
|
|
.chat-input-area {
|
|
|
|
|
|
padding: 0 12px 8px 12px;
|
|
|
|
|
|
background: var(--bg-primary);
|
|
|
|
|
|
border-top: none;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
min-height: 50px;
|
|
|
|
|
|
display: flex; flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 输入框上方的拖拽手柄 */
|
|
|
|
|
|
.chat-input-area .input-resize-handle {
|
|
|
|
|
|
position: absolute; top: 0; left: 0; right: 0;
|
|
|
|
|
|
height: 4px; cursor: row-resize;
|
|
|
|
|
|
background: var(--border);
|
|
|
|
|
|
transition: background 0.2s;
|
|
|
|
|
|
z-index: 5;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-input-area .input-resize-handle:hover,
|
|
|
|
|
|
.chat-input-area .input-resize-handle.dragging {
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-input-area .input-resize-handle::after {
|
|
|
|
|
|
content: '···';
|
|
|
|
|
|
position: absolute; top: 50%; left: 50%;
|
|
|
|
|
|
transform: translate(-50%, -50%);
|
|
|
|
|
|
font-size: 10px; letter-spacing: 2px;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
opacity: 0; transition: opacity 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-input-area .input-resize-handle:hover::after,
|
|
|
|
|
|
.chat-input-area .input-resize-handle.dragging::after {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 快捷工具栏 — 整合圆角卡片风格 */
|
|
|
|
|
|
.chat-toolbar {
|
|
|
|
|
|
display: flex; align-items: center; gap: 1px;
|
|
|
|
|
|
padding: 8px 6px 4px 6px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-toolbar .tb-btn {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
width: 32px; height: 28px;
|
|
|
|
|
|
border: none; background: transparent;
|
|
|
|
|
|
border-radius: var(--radius); cursor: pointer;
|
|
|
|
|
|
font-size: 14px; color: var(--text-muted);
|
|
|
|
|
|
transition: all var(--transition);
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-toolbar .tb-btn:hover {
|
|
|
|
|
|
background: var(--accent-soft);
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-toolbar .tb-btn:active {
|
|
|
|
|
|
transform: scale(0.92);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-toolbar .tb-btn .tb-tip {
|
|
|
|
|
|
display: none; position: absolute; bottom: 100%; left: 50%;
|
|
|
|
|
|
transform: translateX(-50%); margin-bottom: 6px;
|
|
|
|
|
|
background: var(--text-primary); color: var(--bg-secondary);
|
|
|
|
|
|
font-size: 10px; padding: 3px 8px; border-radius: 4px;
|
|
|
|
|
|
white-space: nowrap; pointer-events: none;
|
|
|
|
|
|
box-shadow: var(--shadow);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-toolbar .tb-btn .tb-tip::after {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute; top: 100%; left: 50%;
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
border: 4px solid transparent;
|
|
|
|
|
|
border-top-color: var(--text-primary);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-toolbar .tb-btn:hover .tb-tip { display: block; }
|
|
|
|
|
|
.chat-toolbar .tb-sep {
|
|
|
|
|
|
width: 1px; height: 14px; background: var(--border);
|
|
|
|
|
|
margin: 0 6px; flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 输入行 — 整合为圆角卡片 */
|
|
|
|
|
|
.chat-input-row {
|
|
|
|
|
|
display: flex; gap: 8px; align-items: stretch; flex: 1; min-height: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 输入框容器(含textarea + 发送按钮,统一圆角卡片) */
|
|
|
|
|
|
.chat-input-card {
|
|
|
|
|
|
flex: 1; display: flex; align-items: flex-end;
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: var(--radius-lg);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
transition: border-color var(--transition), box-shadow var(--transition);
|
|
|
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-input-card:focus-within {
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
box-shadow: 0 0 0 2px var(--accent-soft);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-input {
|
|
|
|
|
|
flex: 1; background: transparent; border: none;
|
|
|
|
|
|
padding: 10px 0 10px 14px;
|
|
|
|
|
|
color: var(--text-primary); font-size: 13px; font-family: inherit;
|
|
|
|
|
|
resize: none; min-height: 60px; max-height: 300px; outline: none;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.chat-input:focus { outline: none; }
|
|
|
|
|
|
.chat-input::placeholder { color: var(--text-muted); }
|
|
|
|
|
|
/* 发送按钮 — 内嵌于卡片右侧 */
|
|
|
|
|
|
.btn-send {
|
|
|
|
|
|
padding: 8px 18px; margin: 4px 6px 4px 0;
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
color: #fff; border: none; border-radius: var(--radius);
|
|
|
|
|
|
font-size: 12px; font-weight: 600; cursor: pointer;
|
|
|
|
|
|
transition: all var(--transition); flex-shrink: 0;
|
|
|
|
|
|
letter-spacing: 0.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.btn-send:hover {
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(59,130,246,0.3);
|
|
|
|
|
|
}
|
|
|
|
|
|
.btn-send:active {
|
|
|
|
|
|
transform: scale(0.95);
|
|
|
|
|
|
}
|
|
|
|
|
|
[data-theme="dark"] .btn-send {
|
|
|
|
|
|
background: linear-gradient(135deg, var(--accent), var(--purple));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== TROUBLESHOOT BAR (always visible, flowchart collapsible) ========== */
|
|
|
|
|
|
.troubleshoot-bar {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
border-top: 1px solid var(--border);
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
display: flex; flex-direction: column;
|
|
|
|
|
|
transition: var(--transition);
|
|
|
|
|
|
max-height: 400px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* Bar is ALWAYS expanded — no .collapsed class used for the bar itself */
|
|
|
|
|
|
|
|
|
|
|
|
.ts-header {
|
|
|
|
|
|
display: flex; align-items: center; gap: 0;
|
|
|
|
|
|
padding: 6px 12px; flex-shrink: 0;
|
|
|
|
|
|
min-height: 36px;
|
|
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
cursor: default;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ts-header:hover { background: var(--bg-hover); }
|
|
|
|
|
|
.ts-title {
|
|
|
|
|
|
font-size: 13px; font-weight: 600;
|
|
|
|
|
|
display: flex; align-items: center; gap: 6px;
|
|
|
|
|
|
flex-shrink: 0; margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* Inline path steps inside header */
|
|
|
|
|
|
.ts-path-inline {
|
|
|
|
|
|
display: flex; align-items: center; gap: 0;
|
|
|
|
|
|
flex: 1; overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.path-step {
|
|
|
|
|
|
padding: 2px 7px;
|
|
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
border: 1px solid var(--border-light);
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
font-size: 11px; color: var(--text-secondary);
|
|
|
|
|
|
white-space: nowrap; flex-shrink: 0;
|
|
|
|
|
|
cursor: pointer; transition: var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.path-step:hover { border-color: var(--accent); color: var(--accent); }
|
|
|
|
|
|
.path-step.done { background: var(--success-soft); border-color: var(--success); color: var(--success); }
|
|
|
|
|
|
.path-step.current { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); font-weight: 600; }
|
|
|
|
|
|
.path-arrow-inline { display: flex; align-items: center; color: var(--text-muted); font-size: 10px; padding: 0 3px; flex-shrink: 0; }
|
|
|
|
|
|
/* Flowchart toggle — triangle icon only */
|
|
|
|
|
|
.ts-flowchart-toggle {
|
|
|
|
|
|
font-size: 12px; color: var(--accent);
|
|
|
|
|
|
cursor: pointer; padding: 4px 6px;
|
|
|
|
|
|
border-radius: 3px; transition: var(--transition);
|
|
|
|
|
|
user-select: none; flex-shrink: 0; line-height: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ts-flowchart-toggle:hover { background: var(--accent-soft); }
|
|
|
|
|
|
|
|
|
|
|
|
/* Full flowchart (collapsed by default — toggled via .show-flow on bar) */
|
|
|
|
|
|
.ts-flowchart {
|
|
|
|
|
|
padding: 10px 16px 14px;
|
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
max-height: 0;
|
|
|
|
|
|
transition: max-height 0.35s ease, padding 0.35s ease;
|
|
|
|
|
|
padding-top: 0;
|
|
|
|
|
|
padding-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.troubleshoot-bar.show-flow .ts-flowchart {
|
|
|
|
|
|
max-height: 300px;
|
|
|
|
|
|
padding: 10px 16px 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.flow-step {
|
|
|
|
|
|
display: flex; align-items: flex-start; gap: 10px;
|
|
|
|
|
|
margin-bottom: 4px; position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
.flow-step:last-child { margin-bottom: 0; }
|
|
|
|
|
|
.flow-step-connector {
|
|
|
|
|
|
position: absolute; left: 10px; top: 26px; bottom: -12px;
|
|
|
|
|
|
width: 2px; background: var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
.flow-step:last-child .flow-step-connector { display: none; }
|
|
|
|
|
|
.flow-node {
|
|
|
|
|
|
width: 22px; height: 22px; border-radius: 50%;
|
|
|
|
|
|
background: var(--accent-soft); color: var(--accent);
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 10px; font-weight: 600; flex-shrink: 0;
|
|
|
|
|
|
z-index: 1; border: 1px solid var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.flow-node.done { background: var(--success-soft); color: var(--success); border-color: var(--success); }
|
|
|
|
|
|
.flow-node.judge {
|
|
|
|
|
|
width: auto; height: auto; border-radius: var(--radius);
|
|
|
|
|
|
padding: 3px 8px; font-size: 10px; font-weight: 500;
|
|
|
|
|
|
background: var(--warning-soft); color: var(--warning); border-color: var(--warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
.flow-content { flex: 1; }
|
|
|
|
|
|
.flow-title { font-size: 12px; font-weight: 500; color: var(--text-primary); margin-bottom: 2px; }
|
|
|
|
|
|
.flow-desc { font-size: 11px; color: var(--text-secondary); line-height: 1.4; }
|
|
|
|
|
|
.flow-branch {
|
|
|
|
|
|
margin-left: 20px; margin-top: 4px;
|
|
|
|
|
|
padding-left: 10px;
|
|
|
|
|
|
border-left: 2px dashed var(--border-light);
|
|
|
|
|
|
}
|
|
|
|
|
|
.flow-branch-item {
|
|
|
|
|
|
font-size: 11px; color: var(--text-muted);
|
|
|
|
|
|
padding: 2px 0;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.flow-branch-item:hover { color: var(--accent); }
|
|
|
|
|
|
.flow-branch-item.active { color: var(--success); font-weight: 500; }
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== TASK DETAIL VIEW ========== */
|
|
|
|
|
|
.task-detail-view {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.task-detail-view.active { display: flex; }
|
|
|
|
|
|
.task-detail-header {
|
|
|
|
|
|
padding: 10px 16px; background: var(--bg-secondary);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
display: flex; align-items: center; gap: 10px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
|
|
}
|
|
|
|
|
|
.btn-back {
|
|
|
|
|
|
padding: 4px 10px; background: var(--bg-tertiary);
|
|
|
|
|
|
border: 1px solid var(--border); border-radius: var(--radius);
|
|
|
|
|
|
cursor: pointer; font-size: 12px; color: var(--text-secondary);
|
|
|
|
|
|
transition: var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.btn-back:hover { background: var(--bg-hover); color: var(--text-primary); }
|
|
|
|
|
|
.task-detail-header .task-title { font-size: 14px; font-weight: 600; flex: 1; }
|
|
|
|
|
|
.task-detail-header .task-type-badge {
|
|
|
|
|
|
font-size: 10px; padding: 2px 8px; border-radius: 10px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.task-detail-body {
|
|
|
|
|
|
flex: 1; overflow-y: auto; padding: 16px;
|
|
|
|
|
|
display: flex; flex-direction: column; gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.task-detail-body::-webkit-scrollbar { width: 4px; }
|
|
|
|
|
|
.task-detail-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
|
|
|
|
|
|
|
|
|
|
|
.task-info-card {
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: var(--radius-lg);
|
|
|
|
|
|
padding: 14px 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.task-info-card .tic-title { font-size: 13px; font-weight: 600; margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
|
|
|
|
|
|
.task-info-card .tic-row { display: flex; gap: 12px; margin-bottom: 4px; font-size: 12px; }
|
|
|
|
|
|
.task-info-card .tic-label { color: var(--text-muted); min-width: 70px; }
|
|
|
|
|
|
.task-info-card .tic-value { color: var(--text-primary); font-weight: 500; }
|
|
|
|
|
|
.task-info-card .tic-desc {
|
|
|
|
|
|
margin-top: 8px; padding-top: 8px;
|
|
|
|
|
|
border-top: 1px solid var(--border);
|
|
|
|
|
|
font-size: 12px; color: var(--text-secondary); line-height: 1.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.task-actions {
|
|
|
|
|
|
display: flex; gap: 8px; flex-shrink: 0;
|
|
|
|
|
|
padding: 10px 16px; background: var(--bg-secondary);
|
|
|
|
|
|
border-top: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
.btn-action {
|
|
|
|
|
|
padding: 8px 18px; border-radius: var(--radius);
|
|
|
|
|
|
font-size: 12px; font-weight: 500; cursor: pointer;
|
|
|
|
|
|
transition: var(--transition); border: 1px solid transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
.btn-action.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
|
|
|
|
|
|
.btn-action.primary:hover { opacity: 0.9; }
|
|
|
|
|
|
.btn-action.success { background: var(--success); color: #fff; border-color: var(--success); }
|
|
|
|
|
|
.btn-action.success:hover { opacity: 0.9; }
|
|
|
|
|
|
.btn-action.warning { background: var(--warning); color: #fff; border-color: var(--warning); }
|
|
|
|
|
|
.btn-action.warning:hover { opacity: 0.9; }
|
|
|
|
|
|
.btn-action.danger { background: var(--danger); color: #fff; border-color: var(--danger); }
|
|
|
|
|
|
.btn-action.danger:hover { opacity: 0.9; }
|
|
|
|
|
|
.btn-action.default { background: var(--bg-tertiary); color: var(--text-secondary); border-color: var(--border); }
|
|
|
|
|
|
.btn-action.default:hover { background: var(--bg-hover); color: var(--text-primary); }
|
|
|
|
|
|
|
|
|
|
|
|
/* Approval comment */
|
|
|
|
|
|
.approval-section {
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: var(--radius-lg);
|
|
|
|
|
|
padding: 14px 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.approval-section .as-title { font-size: 12px; font-weight: 600; margin-bottom: 8px; }
|
|
|
|
|
|
.approval-textarea {
|
|
|
|
|
|
width: 100%; min-height: 80px; resize: vertical;
|
|
|
|
|
|
background: var(--bg-tertiary); border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: var(--radius); padding: 8px 10px;
|
|
|
|
|
|
color: var(--text-primary); font-size: 12px; font-family: inherit;
|
|
|
|
|
|
outline: none; transition: border-color var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.approval-textarea:focus { border-color: var(--accent); }
|
|
|
|
|
|
.approval-textarea::placeholder { color: var(--text-muted); }
|
|
|
|
|
|
|
|
|
|
|
|
.device-status-grid {
|
|
|
|
|
|
display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.device-status-item {
|
|
|
|
|
|
background: var(--bg-tertiary); border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: var(--radius); padding: 8px 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.device-status-item .dsi-label { font-size: 10px; color: var(--text-muted); margin-bottom: 2px; }
|
|
|
|
|
|
.device-status-item .dsi-value { font-size: 12px; font-weight: 500; }
|
|
|
|
|
|
.dsi-value.normal { color: var(--success); }
|
|
|
|
|
|
.dsi-value.warning { color: var(--warning); }
|
|
|
|
|
|
.dsi-value.danger { color: var(--danger); }
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== RIGHT SIDEBAR ========== */
|
|
|
|
|
|
.sidebar-right {
|
|
|
|
|
|
width: 320px; min-width: 220px;
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border-left: none;
|
|
|
|
|
|
display: flex; flex-direction: column;
|
|
|
|
|
|
overflow: hidden; transition: var(--transition);
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* AI Recommend */
|
|
|
|
|
|
.ai-recommend-section { flex-shrink: 0; padding: 10px 12px; border-bottom: 1px solid var(--border); }
|
|
|
|
|
|
.ai-recommend-section .ars-title {
|
|
|
|
|
|
font-size: 12px; font-weight: 600; color: var(--accent);
|
|
|
|
|
|
margin-bottom: 8px; display: flex; align-items: center; gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ai-recommend-section .ars-title::before {
|
|
|
|
|
|
content: ''; width: 3px; height: 12px;
|
|
|
|
|
|
background: var(--accent); border-radius: 2px; display: inline-block;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ars-card {
|
|
|
|
|
|
background: var(--bg-tertiary); border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: var(--radius); padding: 8px 10px;
|
|
|
|
|
|
margin-bottom: 5px; cursor: pointer; transition: var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.ars-card:hover { border-color: var(--accent); background: var(--bg-hover); }
|
|
|
|
|
|
.ars-card .ars-card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 3px; }
|
|
|
|
|
|
.ars-card .ars-confidence { font-size: 10px; padding: 1px 6px; border-radius: 8px; background: var(--accent-soft); color: var(--accent); }
|
|
|
|
|
|
.ars-card .ars-card-text { font-size: 11px; color: var(--text-secondary); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
|
|
|
|
.ars-card .ars-shortcut-hint { font-size: 10px; color: var(--text-muted); margin-top: 3px; display: flex; align-items: center; gap: 4px; }
|
|
|
|
|
|
.key-badge {
|
|
|
|
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
|
|
|
|
font-size: 10px; padding: 1px 5px; background: var(--bg-hover);
|
|
|
|
|
|
border: 1px solid var(--border); border-radius: 3px;
|
|
|
|
|
|
color: var(--text-muted); min-width: 18px; font-family: monospace;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Quick Reply — 三层渐进式导航 */
|
|
|
|
|
|
.quick-reply-section { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 搜索栏 */
|
|
|
|
|
|
.qr-search { padding: 8px 12px; flex-shrink: 0; position: relative; }
|
|
|
|
|
|
.qr-search-input {
|
|
|
|
|
|
width: 100%; background: var(--bg-tertiary); border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: var(--radius); padding: 7px 10px 7px 28px;
|
|
|
|
|
|
color: var(--text-primary); font-size: 12px; font-family: inherit;
|
|
|
|
|
|
outline: none; transition: border-color var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-search-input:focus { border-color: var(--accent); }
|
|
|
|
|
|
.qr-search-input::placeholder { color: var(--text-muted); font-size: 11px; }
|
|
|
|
|
|
.qr-search-icon { position: absolute; left: 22px; top: 50%; transform: translateY(-50%); color: var(--text-muted); font-size: 12px; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 面包屑导航:显示当前路径 L1 > L2 */
|
|
|
|
|
|
.qr-breadcrumb {
|
|
|
|
|
|
padding: 6px 12px; flex-shrink: 0;
|
|
|
|
|
|
font-size: 11px; color: var(--text-secondary);
|
|
|
|
|
|
display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
min-height: 28px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-breadcrumb .bc-back {
|
|
|
|
|
|
cursor: pointer; color: var(--accent); font-weight: 500;
|
|
|
|
|
|
padding: 1px 6px; border-radius: 3px;
|
|
|
|
|
|
transition: var(--transition);
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-breadcrumb .bc-back:hover { background: var(--accent-soft); }
|
|
|
|
|
|
.qr-breadcrumb .bc-sep { color: var(--text-muted); }
|
|
|
|
|
|
.qr-breadcrumb .bc-current { font-weight: 600; color: var(--text-primary); }
|
|
|
|
|
|
.qr-breadcrumb .bc-hint {
|
|
|
|
|
|
margin-left: auto; font-size: 10px; color: var(--text-muted);
|
|
|
|
|
|
display: flex; align-items: center; gap: 3px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== L1 一级目录:7列网格,强制一行,按钮内上下排列 ===== */
|
|
|
|
|
|
.qr-l1-grid {
|
|
|
|
|
|
padding: 4px 6px 6px; flex-shrink: 0;
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(7, 1fr);
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l1-grid.hidden { display: none; }
|
|
|
|
|
|
.qr-l1-btn {
|
|
|
|
|
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
|
|
|
|
gap: 2px;
|
|
|
|
|
|
padding: 5px 2px;
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
cursor: pointer; transition: var(--transition);
|
|
|
|
|
|
font-size: 10px; color: var(--text-secondary);
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
min-width: 0; overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l1-btn:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--border-light); }
|
|
|
|
|
|
.qr-l1-btn.active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); font-weight: 600; }
|
|
|
|
|
|
/* L1 按钮颜色 — 7个主类(nth-child) */
|
|
|
|
|
|
.qr-l1-btn:nth-child(1).active { background: #dbeafe; color: #1e40af; border-color: #3b82f6; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(1).active .l1-num { background: #3b82f6; color: #fff; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(2).active { background: #dcfce7; color: #166534; border-color: #22c55e; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(2).active .l1-num { background: #22c55e; color: #fff; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(3).active { background: #fff7ed; color: #9a3412; border-color: #f97316; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(3).active .l1-num { background: #f97316; color: #fff; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(4).active { background: #ede9fe; color: #5b21b6; border-color: #8b5cf6; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(4).active .l1-num { background: #8b5cf6; color: #fff; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(5).active { background: #fee2e2; color: #991b1b; border-color: #ef4444; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(5).active .l1-num { background: #ef4444; color: #fff; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(6).active { background: #f0fdfa; color: #115e59; border-color: #0ea5e9; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(6).active .l1-num { background: #0ea5e9; color: #fff; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(7).active { background: #f3f4f6; color: #374151; border-color: #6b7280; }
|
|
|
|
|
|
.qr-l1-btn:nth-child(7).active .l1-num { background: #6b7280; color: #fff; }
|
|
|
|
|
|
.qr-l1-btn .l1-num {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
width: 18px; height: 18px; border-radius: 4px;
|
|
|
|
|
|
background: var(--bg-tertiary); color: var(--text-muted);
|
|
|
|
|
|
font-size: 10px; font-weight: 700; flex-shrink: 0;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l1-btn .l1-name {
|
|
|
|
|
|
font-size: 10px; line-height: 1.2;
|
|
|
|
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l1-btn.active .l1-num { background: var(--accent); color: #fff; border-color: var(--accent); }
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== L2 二级目录:横向流式,1-2行 ===== */
|
|
|
|
|
|
.qr-l2-row {
|
|
|
|
|
|
padding: 6px 10px; flex-shrink: 0;
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
display: flex; flex-wrap: wrap; gap: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l2-row.hidden { display: none; }
|
|
|
|
|
|
.qr-l2-chip {
|
|
|
|
|
|
display: flex; align-items: center; gap: 4px;
|
|
|
|
|
|
padding: 4px 10px; border-radius: 12px;
|
|
|
|
|
|
cursor: pointer; transition: var(--transition);
|
|
|
|
|
|
font-size: 11px; color: var(--text-secondary);
|
|
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l2-chip:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--border-light); }
|
|
|
|
|
|
.qr-l2-chip.selected { background: var(--qr-active-light, var(--accent-soft)); color: var(--qr-active-color, var(--accent)); border-color: var(--qr-active-color, var(--accent)); font-weight: 600; }
|
|
|
|
|
|
.qr-l2-chip .l2-num {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
width: 16px; height: 16px; border-radius: 50%;
|
|
|
|
|
|
background: var(--bg-hover); color: var(--text-muted);
|
|
|
|
|
|
font-size: 9px; font-weight: 700; flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l2-chip.selected .l2-num { background: var(--qr-active-color, var(--accent)); color: #fff; }
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== L3 回复列表 ===== */
|
|
|
|
|
|
.qr-l3-list {
|
|
|
|
|
|
flex: 1; overflow-y: auto; padding: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l3-list::-webkit-scrollbar { width: 4px; }
|
|
|
|
|
|
.qr-l3-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
|
|
|
|
|
.qr-l3-item {
|
|
|
|
|
|
display: flex; align-items: flex-start; gap: 8px;
|
|
|
|
|
|
padding: 8px 10px; margin: 2px 4px;
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
cursor: pointer; transition: var(--transition);
|
|
|
|
|
|
font-size: 12px; color: var(--text-secondary);
|
|
|
|
|
|
border: 1px solid transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l3-item:hover { background: var(--bg-hover); color: var(--text-primary); }
|
|
|
|
|
|
.qr-l3-item.selected { background: var(--qr-active-light, var(--accent-soft)); border-color: var(--qr-active-color, var(--accent)); color: var(--text-primary); }
|
|
|
|
|
|
.qr-l3-item .l3-num {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
width: 20px; height: 20px; border-radius: 4px;
|
|
|
|
|
|
background: var(--bg-tertiary); color: var(--text-muted);
|
|
|
|
|
|
font-size: 10px; font-weight: 700; flex-shrink: 0;
|
|
|
|
|
|
border: 1px solid var(--border); margin-top: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l3-item.selected .l3-num { background: var(--qr-active-color, var(--accent)); color: #fff; border-color: var(--qr-active-color, var(--accent)); }
|
|
|
|
|
|
.qr-l3-item .l3-content { flex: 1; line-height: 1.5; }
|
|
|
|
|
|
.qr-l3-item .l3-title { font-weight: 500; color: var(--text-primary); margin-bottom: 2px; }
|
|
|
|
|
|
.qr-l3-item .l3-preview { font-size: 11px; color: var(--text-muted); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
|
|
|
|
.qr-l3-empty {
|
|
|
|
|
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
|
|
|
|
height: 100%; color: var(--text-muted); font-size: 12px;
|
|
|
|
|
|
gap: 6px; padding: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-l3-empty .empty-icon { font-size: 28px; opacity: 0.4; }
|
|
|
|
|
|
.qr-l3-empty .empty-hint { font-size: 11px; text-align: center; line-height: 1.6; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 已选中的回复预览条 */
|
|
|
|
|
|
.qr-selected-bar {
|
|
|
|
|
|
padding: 6px 12px; flex-shrink: 0;
|
|
|
|
|
|
border-top: 1px solid var(--border);
|
|
|
|
|
|
background: var(--success-soft);
|
|
|
|
|
|
font-size: 11px; color: var(--success);
|
|
|
|
|
|
display: flex; align-items: center; gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.qr-selected-bar.hidden { display: none; }
|
|
|
|
|
|
.qr-selected-bar .sel-text { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
|
|
|
.qr-selected-bar .sel-hint { font-size: 10px; color: var(--text-muted); flex-shrink: 0; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 键盘指南 */
|
|
|
|
|
|
.keyboard-guide { padding: 6px 12px; border-top: 1px solid var(--border); font-size: 10px; color: var(--text-muted); display: flex; gap: 8px; flex-wrap: wrap; flex-shrink: 0; }
|
|
|
|
|
|
.keyboard-guide span { display: flex; align-items: center; gap: 3px; }
|
|
|
|
|
|
</style>
|
|
|
|
|
|
<script>
|
|
|
|
|
|
// Auto-generated from IT支持知识库2026-4-24.docx
|
|
|
|
|
|
// 7大类 28子类 180条快速回复模板
|
|
|
|
|
|
const qrData = [{"name": "电脑", "subs": [{"name": "硬件设备", "items": [{"title": "笔记本电脑电池续航异常", "content": "健康评估标准:剩余容量<70%或循环次数>500次。\n获取报告步骤::\nWindows:cmd中输入 powercfg /batteryreport,查看报告中的“CYCLE COUNT”。\nMac:按住Option键点击苹果菜单→系统信息→电源→查看“循环计数”。\n将报告留言分享,等待人工坐席进一步评估。"}, {"title": "办公电脑常见问题处理(黑屏、警报)", "content": "排查步骤\n1. 观察电源指示灯:确认电脑的电源指示灯是否亮起或闪烁。\n2. 强制关机重启:长按电源键约15-20秒,直到电源指示灯完全熄灭,等待几秒钟后,再次按下电源键尝试开机。"}, {"title": "办公电脑常见问题处理(死机、卡顿)", "content": "排查步骤:\n1. 检查系统资源:按Ctrl+Shift+Esc打开任务管理器,结束占用高的非必要进程。\n2. 强制重启:长按电源键15-20秒至指示灯熄灭,等待后重新开机。"}]}, {"name": "Windows系统", "items": [{"title": "Windows本地账户密码修改", "content": "路径:设置→帐户→登录选项→密码→更改,按提示完成。"}, {"title": "办公电脑功能异常(无声音、屏幕显示、键盘热键)", "content": "排查步骤:\n1. 检查驱动:设备管理器查看是否有异常设备(黄色/红色标志)。\n2. 重装驱动:联想电脑使用官方工具;其他品牌从官网下载最新驱动。"}, {"title": "办公电脑麦克风无声音", "content": "排查步骤:\n1. 设置默认设备:右键任务栏扬声器图标→声音设置,确保麦克风设为默认输入设备。\n2. 授予权限:在Windows搜索“麦克风隐私设置”,开启麦克风访问权限及对应应用(如企业微信、小鱼)的权限。\n3. 调整属性:在设备属性中调整音量和麦克风增强,禁用独占模式。"}, {"title": "Windows电脑和Office许可证过期|激活|即将到期", "content": "适用场景:激活过期/失败/即将到期。\n操作步骤:\n1. 下载工具:https://drive.weixin.qq.com/s?k=AAoA1wcYAAcmKeQnWG\n2. 运行工具,按需取消选项(如不需激活Office)。\n3. 点击“开始”处理。"}, {"title": "电脑C盘空间不足", "content": "操作步骤:\n1. 打开企业微信,进入【设置】→【文档/文件管理】→【文件储存位置】。\n2. 点击【更改】,选择其他盘符的目录作为新存储路径。"}, {"title": "U盘、移动硬盘无法弹出报错“弹出USB大容量存储设备时出问题”", "content": "故障现象:\n弹出U盘提示“该设备正在使用中、请关闭可能使用该设备的所有程序或窗口,然后重试”\n解决方法:\n将电脑关机后再拔出硬盘"}, {"title": "办公电脑系统初始密码", "content": "总部新电脑:Windows系统无密码(直接回车)\n电脑开机密码是独立的,不与内部统一员工账密一致。"}, {"title": "电脑开机密码重置", "content": "重置电脑开机需使用专用工具由IT支持人员进行现场处理,总部员工请携带设备前往121室,区域同事请联系本地兼职网络协助处理"}]}, {"name": "鸿蒙系统", "items": [{"title": "公司办公IT环境不支持鸿蒙系统的软硬件清单", "content": "软件功能类:\n火绒安全、税友安全助手、企业微信-同事吧(发帖、回复)"}]}]}, {"name": "软件", "subs": [{"name": "常用工具", "items": [{"title": "常用办公软件下载地址", "content": "常用办公软件下载地址:https://drive.weixin.qq.com/s?k=AAoA1wcYAAcVScZYR4"}, {"title": "压缩工具", "content": "7-Zip是一款免费开源高压缩比的压缩软件,支持7z、ZIP、RAR、CAB、GZIP、BZIP2和TAR等格式。此软件压缩的压缩比要比普通ZIP文件高30-50%。\n7-Zip 客户端下载地址:https://sparanoid.com/lab/7z/download.html"}]}, {"name": "企业微信", "items": [{"title": "企业微信综合信息", "content
|
|
|
|
|
|
</script>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body data-theme="light">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Top bar -->
|
|
|
|
|
|
<div class="theme-toggle-bar">
|
|
|
|
|
|
<div class="bar-left">
|
|
|
|
|
|
<div class="logo-sm">IT</div>
|
|
|
|
|
|
<span class="sys-name">IT智能服务台</span>
|
|
|
|
|
|
<span class="sys-tagline">· 坐席工作台 — AI驱动 · 多系统对接 · 一站式处理</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="bar-right">
|
|
|
|
|
|
<div class="theme-switch" onclick="toggleTheme()">
|
|
|
|
|
|
<span class="switch-icon">☀️</span>
|
|
|
|
|
|
<div class="switch-track"><div class="switch-thumb"></div></div>
|
|
|
|
|
|
<span class="switch-icon">🌙</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="bar-user-info">
|
|
|
|
|
|
<span>坐席: 陈思远</span>
|
|
|
|
|
|
<div class="bar-user-avatar">陈</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="workspace">
|
|
|
|
|
|
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<!-- ===== LEFT: Conversation List ===== -->
|
2026-06-14 16:49:18 +08:00
|
|
|
|
<div class="sidebar-left">
|
|
|
|
|
|
<div class="conv-search">
|
|
|
|
|
|
<div class="conv-search-input-wrap">
|
|
|
|
|
|
<span class="conv-search-icon">🔍</span>
|
|
|
|
|
|
<input class="conv-search-input" placeholder="搜索用户、关键词..." />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-search-tabs">
|
|
|
|
|
|
<span class="conv-search-tab active">全部</span>
|
|
|
|
|
|
<span class="conv-search-tab">待处理</span>
|
|
|
|
|
|
<span class="conv-search-tab">进行中</span>
|
|
|
|
|
|
<span class="conv-search-tab">已完成</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="conv-sections">
|
|
|
|
|
|
<!-- My conversations -->
|
|
|
|
|
|
<div class="conv-section-body" style="max-height:500px;">
|
|
|
|
|
|
<!-- 张伟 — 有新消息(紧急红色圆点)+ 处理对象缩略头像 -->
|
|
|
|
|
|
<div class="conv-item active">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-blue">张</div>
|
|
|
|
|
|
<span class="new-msg-dot dot-urgent" title="有新消息"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">张伟</span>
|
|
|
|
|
|
<span class="priority-icons">
|
|
|
|
|
|
<span class="pi-icon pi-blocked" title="⛔ 问题阻断性:无法工作">⛔</span>
|
|
|
|
|
|
<span class="pi-icon pi-impact high" title="📊 影响范围:12人">👥12</span>
|
|
|
|
|
|
<span class="pi-icon pi-role" title="👑 角色等级:核心研发">👑</span>
|
|
|
|
|
|
<span class="pi-icon pi-repeat" title="🔁 7天内重复3次">🔁</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="conv-time">10:25</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">VPN 连接失败,无法访问内网系统...</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span class="conv-waiting">待回复</span>
|
|
|
|
|
|
<div class="conv-target-avatar ta-blue" title="张伟">张</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 陈芳 — 有新消息(普通蓝色圆点)+ 处理对象缩略头像 -->
|
|
|
|
|
|
<div class="conv-item">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-purple">陈</div>
|
|
|
|
|
|
<span class="new-msg-dot dot-normal" title="有新消息"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">陈芳</span>
|
|
|
|
|
|
<span class="priority-icons">
|
|
|
|
|
|
<span class="pi-icon pi-impact" title="📊 影响范围:3人">👥3</span>
|
|
|
|
|
|
<span class="pi-icon pi-role" title="👑 角色等级:部门经理">👑👑</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="conv-time">09:42</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">系统卡顿严重影响工作...</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span class="conv-waiting">待回复</span>
|
|
|
|
|
|
<div class="conv-target-avatar ta-purple" title="陈芳">陈</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 李娜 — 无新消息(无圆点)+ 处理对象缩略头像 -->
|
|
|
|
|
|
<div class="conv-item">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-green">李</div>
|
|
|
|
|
|
<!-- 无新消息,无圆点 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">李娜</span>
|
|
|
|
|
|
<span class="priority-icons">
|
|
|
|
|
|
<span class="pi-icon pi-role" title="👤 角色等级:普通员工">👤</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="conv-time">10:18</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">邮箱签名设置问题</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-target-avatar ta-green" title="李娜">李</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- === 新增:不同状态会话展示 === -->
|
|
|
|
|
|
<!-- 王磊 — 有新消息(紧急红色圆点)+ 举手标签 + 处理对象缩略头像 -->
|
|
|
|
|
|
<div class="conv-item" data-conv="conv-004" style="border-left:2px solid #f59e0b">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-orange">王</div>
|
|
|
|
|
|
<span class="new-msg-dot dot-urgent" title="有新消息"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">王磊</span>
|
|
|
|
|
|
<span class="conv-tag-warn">需介入</span>
|
|
|
|
|
|
<span class="conv-tag-urgent">举手</span>
|
|
|
|
|
|
<span class="priority-icons">
|
|
|
|
|
|
<span class="pi-icon pi-block" title="🚫 阻断">🚫</span>
|
|
|
|
|
|
<span class="pi-impact">8人</span>
|
|
|
|
|
|
<span class="pi-icon pi-role" title="👤 部门主管">👤</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="conv-time">10:25</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">税控系统还是登录不上,下午3点前要报税</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-target-avatar ta-orange" title="王磊">王</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 孙丽 — 无新消息(无圆点)+ 处理对象缩略头像 -->
|
|
|
|
|
|
<div class="conv-item" data-conv="conv-005" style="opacity:0.7; border-left:2px solid var(--border)">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-teal">孙</div>
|
|
|
|
|
|
<!-- 无新消息,无圆点 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">孙丽</span>
|
|
|
|
|
|
<span class="conv-tag-new">新</span>
|
|
|
|
|
|
<span class="priority-icons">
|
|
|
|
|
|
<span class="pi-icon pi-confused" title="😕 困惑">😕</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="conv-time">10:10</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">合同管理系统看不到审批列表,不知道怎么操作</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-target-avatar ta-teal" title="孙丽">孙</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 刘洋 — 有新消息(紧急红色圆点)+ 举手标签 + VIP + 置顶 + 处理对象缩略头像 -->
|
|
|
|
|
|
<div class="conv-item active" data-conv="conv-006" style="border-left:2px solid #ef4444; background:var(--accent-light)">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-red">刘</div>
|
|
|
|
|
|
<span class="new-msg-dot dot-urgent" title="有新消息"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-pin-badge">📌 置顶</span>
|
|
|
|
|
|
<span class="conv-name">刘洋</span>
|
|
|
|
|
|
<span class="conv-tag-vip">VIP</span>
|
|
|
|
|
|
<span class="conv-tag-urgent">举手</span>
|
|
|
|
|
|
<span class="priority-icons">
|
|
|
|
|
|
<span class="pi-icon pi-block" title="🚫 阻断">🚫</span>
|
|
|
|
|
|
<span class="pi-impact">20人</span>
|
|
|
|
|
|
<span class="pi-icon pi-angry" title="😡 愤怒">😡</span>
|
|
|
|
|
|
<span class="pi-icon pi-repeat" title="🔄 重复">🔄</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="conv-time">10:27</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">这个问题已经拖了三天了,请尽快解决!</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-target-avatar ta-red" title="刘洋">刘</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Colleague sessions (always expanded) -->
|
|
|
|
|
|
<div class="conv-section-body" style="max-height:300px;">
|
|
|
|
|
|
<!-- 赵敏 — 有新消息(普通蓝色圆点)+ 坐席刘明缩略头像 -->
|
|
|
|
|
|
<div class="conv-item">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-pink">赵</div>
|
|
|
|
|
|
<span class="new-msg-dot dot-normal" title="有新消息"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">赵敏</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">OA 审批流程报错</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-target-avatar ta-blue" title="坐席:刘明">刘</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 周芳 — 无新消息(无圆点)+ 坐席缩略头像 -->
|
|
|
|
|
|
<div class="conv-item">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-green">周</div>
|
|
|
|
|
|
<!-- 无新消息 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">周芳</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">打印机无法连接</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-target-avatar ta-green" title="坐席:王强">王</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 吴明 — 有新消息(低优先灰色圆点)+ 坐席缩略头像 -->
|
|
|
|
|
|
<div class="conv-item">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-orange">吴</div>
|
|
|
|
|
|
<span class="new-msg-dot dot-muted" title="低优先新消息"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">吴明</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">新电脑开机配置</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-target-avatar ta-purple" title="坐席:李静">李</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- History (always expanded) -->
|
|
|
|
|
|
<div class="conv-section-body" style="max-height:400px;">
|
|
|
|
|
|
<!-- 历史会话 — 无新消息(无圆点),无处理对象缩略头像 -->
|
|
|
|
|
|
<div class="conv-item">
|
|
|
|
|
|
<div class="conv-avatar-wrap">
|
|
|
|
|
|
<div class="conv-avatar av-teal">周</div>
|
|
|
|
|
|
<!-- 历史会话,无新消息圆点 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-content">
|
|
|
|
|
|
<div class="conv-top">
|
|
|
|
|
|
<span class="conv-name-row">
|
|
|
|
|
|
<span class="conv-name">周杰</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="conv-time">昨日</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="conv-preview">VPN 证书过期 — 已解决</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 拖拽手柄:左栏↔中间栏 -->
|
|
|
|
|
|
<div class="resize-handle" id="resizeLeft" title="拖拽调整左栏宽度"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== CENTER: Chat View (default) + Task Detail View ===== -->
|
|
|
|
|
|
<div class="center-column">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== Chat View (default) ===== -->
|
|
|
|
|
|
<div class="chat-view" id="chatView">
|
|
|
|
|
|
<!-- User info bar -->
|
|
|
|
|
|
<div class="user-info-bar" id="userInfoBar" onclick="toggleUserDetail()">
|
|
|
|
|
|
<div class="user-avatar">张</div>
|
|
|
|
|
|
<div class="user-name-section">
|
|
|
|
|
|
<span class="user-name">
|
|
|
|
|
|
张伟 · 研发一部 高级工程师
|
|
|
|
|
|
<span class="it-level-badge gold" title="IT技能等级:黄金 — 熟练使用,高级操作需指导">
|
|
|
|
|
|
🥇 黄金
|
|
|
|
|
|
<span class="level-num">Lv.3</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="info-chips">
|
|
|
|
|
|
<span class="info-chip emotion">😟 焦虑</span>
|
|
|
|
|
|
<span class="info-chip default">⏱ 8分32秒</span>
|
|
|
|
|
|
<span class="info-chip default">💬 6轮</span>
|
|
|
|
|
|
<span class="info-chip repeat">🔁 重复</span>
|
|
|
|
|
|
<span class="info-chip remark">📝 备注</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Device status icons -->
|
|
|
|
|
|
<div class="device-status-row">
|
|
|
|
|
|
<!-- OS Type: Windows (online) -->
|
|
|
|
|
|
<div class="dev-icon online" title="Windows 11 · 在线">
|
|
|
|
|
|
<span>🪟</span>
|
|
|
|
|
|
<span class="dev-badge green"></span>
|
|
|
|
|
|
<span class="dev-tooltip">Windows 11 · 在线联网</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- Antivirus: Huorong installed & up-to-date -->
|
|
|
|
|
|
<div class="dev-icon safe" title="火绒 · 已安装 · 病毒库最新">
|
|
|
|
|
|
<span>🛡️</span>
|
|
|
|
|
|
<span class="dev-badge green"></span>
|
|
|
|
|
|
<span class="dev-tooltip">火绒杀毒 · 已安装 · 病毒库最新</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- Adobe: Certified/Licensed -->
|
|
|
|
|
|
<div class="dev-icon certified" title="Adobe · 已授权">
|
|
|
|
|
|
<span style="font-size:11px;font-weight:700;letter-spacing:-0.5px;">Ai</span>
|
|
|
|
|
|
<span class="dev-badge green"></span>
|
|
|
|
|
|
<span class="dev-tooltip">Adobe Illustrator · ✅ 已授权</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- Office: Certified -->
|
|
|
|
|
|
<div class="dev-icon certified" title="Office 365 · 已授权">
|
|
|
|
|
|
<span style="font-size:11px;font-weight:700;">O</span>
|
|
|
|
|
|
<span class="dev-badge green"></span>
|
|
|
|
|
|
<span class="dev-tooltip">Microsoft 365 · ✅ 已授权</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- Patch: Warning - 2 pending -->
|
|
|
|
|
|
<div class="dev-icon warn" title="系统补丁 · 2个待更新">
|
|
|
|
|
|
<span>🔄</span>
|
|
|
|
|
|
<span class="dev-badge yellow"></span>
|
|
|
|
|
|
<span class="dev-tooltip">系统补丁 · ⚠️ 2个待更新</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<!-- 2026-07-24 优化:接单按钮(用户信息栏右侧操作区) -->
|
|
|
|
|
|
<div style="display:flex;align-items:center;gap:6px;margin-left:auto;">
|
|
|
|
|
|
<!-- 待接单状态 -->
|
|
|
|
|
|
<button class="btn-action primary" style="font-size:12px;padding:4px 10px;" onclick="this.outerHTML='<button class=\'btn-action primary\' disabled style=\'opacity:0.5;cursor:not-allowed;background:#9ca3af;border-color:#9ca3af;font-size:12px;padding:4px 10px;\'>📥 已接单</button>'">📥 接单</button>
|
|
|
|
|
|
<!-- 已接单状态(点击后变为):<button class="btn-action primary" disabled style="opacity:0.5;cursor:not-allowed;background:#9ca3af;border-color:#9ca3af;">📥 已接单</button> -->
|
|
|
|
|
|
<button class="btn-action warning" style="font-size:12px;padding:4px 10px;">📌 置顶</button>
|
|
|
|
|
|
<button class="btn-action default" style="font-size:12px;padding:4px 10px;">📋 代办</button>
|
|
|
|
|
|
<button class="btn-action default" style="font-size:12px;padding:4px 10px;">🔄 转接</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-06-14 16:49:18 +08:00
|
|
|
|
<span class="expand-icon">▶</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<!-- 2026-07-24 更新:根据线上实际情况,右侧详情栏6个卡片 -->
|
|
|
|
|
|
<div class="user-detail-panel" style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;padding:12px 16px;">
|
|
|
|
|
|
<!-- 卡片1:情绪状态 -->
|
|
|
|
|
|
<div class="detail-card" style="background:var(--bg-tertiary);border-radius:8px;padding:12px;">
|
|
|
|
|
|
<div class="dc-label" style="font-size:11px;color:var(--text-secondary);margin-bottom:6px;">情绪状态</div>
|
|
|
|
|
|
<div class="dc-value" style="font-size:13px;">😟 担忧</div>
|
|
|
|
|
|
<div style="font-size:11px;color:var(--text-muted);margin-top:4px;">语气急促,连续追问进度</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 卡片2:会话详情 -->
|
|
|
|
|
|
<div class="detail-card" style="background:var(--bg-tertiary);border-radius:8px;padding:12px;">
|
|
|
|
|
|
<div class="dc-label" style="font-size:11px;color:var(--text-secondary);margin-bottom:6px;">会话详情</div>
|
|
|
|
|
|
<div class="dc-value" style="font-size:13px;">⏱ 等待时长:<strong>8分钟</strong></div>
|
|
|
|
|
|
<div class="dc-value" style="font-size:13px;margin-top:4px;">💬 对话轮次:<strong>6轮</strong></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 卡片3:问题分析 -->
|
|
|
|
|
|
<div class="detail-card" style="background:var(--bg-tertiary);border-radius:8px;padding:12px;">
|
|
|
|
|
|
<div class="dc-label" style="font-size:11px;color:var(--text-secondary);margin-bottom:6px;">问题分析</div>
|
|
|
|
|
|
<div class="dc-value" style="font-size:13px;">🔁 重复问题</div>
|
|
|
|
|
|
<div style="font-size:11px;color:var(--text-muted);margin-top:4px;">7天内反馈:<strong>3次</strong></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 卡片4:IT技能等级 -->
|
|
|
|
|
|
<div class="detail-card" style="background:var(--bg-tertiary);border-radius:8px;padding:12px;">
|
|
|
|
|
|
<div class="dc-label" style="font-size:11px;color:var(--text-secondary);margin-bottom:6px;">IT技能等级</div>
|
|
|
|
|
|
<div style="display:flex;align-items:center;gap:6px;">
|
2026-06-14 16:49:18 +08:00
|
|
|
|
<span class="it-level-badge gold">🥇 黄金 Lv.3</span>
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<span style="font-size:12px;font-weight:600;">黄金</span>
|
2026-06-14 16:49:18 +08:00
|
|
|
|
</div>
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<div style="font-size:11px;color:var(--text-muted);margin-top:4px;">熟悉常见操作,可独立解决一般问题</div>
|
2026-06-14 16:49:18 +08:00
|
|
|
|
</div>
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<!-- 卡片5:历史工单 -->
|
|
|
|
|
|
<div class="detail-card" style="background:var(--bg-tertiary);border-radius:8px;padding:12px;">
|
|
|
|
|
|
<div class="dc-label" style="font-size:11px;color:var(--text-secondary);margin-bottom:6px;">历史工单</div>
|
|
|
|
|
|
<div style="font-size:13px;">30天内工单:<strong>3次</strong></div>
|
|
|
|
|
|
<div style="font-size:11px;color:var(--text-muted);margin-top:4px;">类型分布:VPN(2次) 邮箱(1次)</div>
|
2026-06-14 16:49:18 +08:00
|
|
|
|
</div>
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<!-- 卡片6:其他备注 -->
|
|
|
|
|
|
<div class="detail-card" style="background:var(--bg-tertiary);border-radius:8px;padding:12px;">
|
|
|
|
|
|
<div class="dc-label" style="font-size:11px;color:var(--text-secondary);margin-bottom:6px;">其他备注</div>
|
|
|
|
|
|
<div style="font-size:12px;color:var(--text-secondary);">暂无备注</div>
|
2026-06-14 16:49:18 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== Troubleshoot bar (ALWAYS visible, flowchart collapsible) ===== -->
|
|
|
|
|
|
<div class="troubleshoot-bar" id="tsBar">
|
|
|
|
|
|
<div class="ts-header">
|
|
|
|
|
|
<span class="ts-title">🔧 排查步骤</span>
|
|
|
|
|
|
<div class="ts-path-inline" id="tsPathView">
|
|
|
|
|
|
<span class="path-step done">① 确认版本</span>
|
|
|
|
|
|
<span class="path-arrow-inline">→</span>
|
|
|
|
|
|
<span class="path-step done">② 清除缓存</span>
|
|
|
|
|
|
<span class="path-arrow-inline">→</span>
|
|
|
|
|
|
<span class="path-step current">③ 远程排查</span>
|
|
|
|
|
|
<span class="path-arrow-inline">→</span>
|
|
|
|
|
|
<span class="path-step">④ 升级客户端</span>
|
|
|
|
|
|
<span class="path-arrow-inline">→</span>
|
|
|
|
|
|
<span class="path-step">⑤ 回访确认</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span class="ts-flowchart-toggle" id="tsFlowBtn" onclick="toggleFlowchart()" title="展开全流程图">▶</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Full flowchart with decision nodes (collapsed by default) -->
|
|
|
|
|
|
<div class="ts-flowchart" id="tsFlowchart">
|
|
|
|
|
|
<div style="font-size:11px;color:var(--text-muted);margin-bottom:8px;">
|
|
|
|
|
|
🔀 VPN 连接失败 — 完整排查决策树
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Step 1 -->
|
|
|
|
|
|
<div class="flow-step">
|
|
|
|
|
|
<div class="flow-node done">1</div>
|
|
|
|
|
|
<div class="flow-step-connector"></div>
|
|
|
|
|
|
<div class="flow-content">
|
|
|
|
|
|
<div class="flow-title">确认 VPN 客户端版本</div>
|
|
|
|
|
|
<div class="flow-desc">询问用户使用 AnyConnect 或 SSL VPN,记录版本号</div>
|
|
|
|
|
|
<div class="flow-branch">
|
|
|
|
|
|
<div class="flow-branch-item active">→ AnyConnect 4.10 及以下:进入兼容性问题分支</div>
|
|
|
|
|
|
<div class="flow-branch-item">→ SSL VPN 网页版:进入浏览器兼容分支</div>
|
|
|
|
|
|
<div class="flow-branch-item">→ 其他版本:进入通用排查</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Judge node 1 -->
|
|
|
|
|
|
<div class="flow-step">
|
|
|
|
|
|
<div class="flow-node judge">❓ 判断</div>
|
|
|
|
|
|
<div class="flow-step-connector"></div>
|
|
|
|
|
|
<div class="flow-content">
|
|
|
|
|
|
<div class="flow-title">版本 < 4.14?</div>
|
|
|
|
|
|
<div class="flow-desc">AnyConnect 4.10 及更早版本存在已知兼容性问题</div>
|
|
|
|
|
|
<div class="flow-branch">
|
|
|
|
|
|
<div class="flow-branch-item active">是 → 执行步骤②清除缓存,若仍失败直接进入步骤④升级</div>
|
|
|
|
|
|
<div class="flow-branch-item">否 → 进入网络配置排查分支</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Step 2 -->
|
|
|
|
|
|
<div class="flow-step">
|
|
|
|
|
|
<div class="flow-node done">2</div>
|
|
|
|
|
|
<div class="flow-step-connector"></div>
|
|
|
|
|
|
<div class="flow-content">
|
|
|
|
|
|
<div class="flow-title">清除缓存配置文件</div>
|
|
|
|
|
|
<div class="flow-desc">指导用户删除 C:\ProgramData\Cisco\ 下 XML 文件,重启客户端</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Judge node 2 -->
|
|
|
|
|
|
<div class="flow-step">
|
|
|
|
|
|
<div class="flow-node judge">❓ 判断</div>
|
|
|
|
|
|
<div class="flow-step-connector"></div>
|
|
|
|
|
|
<div class="flow-content">
|
|
|
|
|
|
<div class="flow-title">清除缓存后能否连接?</div>
|
|
|
|
|
|
<div class="flow-branch">
|
|
|
|
|
|
<div class="flow-branch-item active">能 → 标记为"已解决",进入步骤⑤回访</div>
|
|
|
|
|
|
<div class="flow-branch-item">不能 → 进入步骤③远程排查</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Step 3 -->
|
|
|
|
|
|
<div class="flow-step">
|
|
|
|
|
|
<div class="flow-node current">3</div>
|
|
|
|
|
|
<div class="flow-step-connector"></div>
|
|
|
|
|
|
<div class="flow-content">
|
|
|
|
|
|
<div class="flow-title">远程桌面排查</div>
|
|
|
|
|
|
<div class="flow-desc">通过内网远程桌面连接用户电脑,检查网络适配器、防火墙、hosts 文件</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Step 4 -->
|
|
|
|
|
|
<div class="flow-step">
|
|
|
|
|
|
<div class="flow-node">4</div>
|
|
|
|
|
|
<div class="flow-step-connector"></div>
|
|
|
|
|
|
<div class="flow-content">
|
|
|
|
|
|
<div class="flow-title">升级客户端至 4.14</div>
|
|
|
|
|
|
<div class="flow-desc">发送下载链接,指导用户卸载旧版并安装新版,重新配置连接</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Step 5 -->
|
|
|
|
|
|
<div class="flow-step">
|
|
|
|
|
|
<div class="flow-node">5</div>
|
|
|
|
|
|
<div class="flow-content">
|
|
|
|
|
|
<div class="flow-title">24H 后回访确认</div>
|
|
|
|
|
|
<div class="flow-desc">创建提醒任务,24小时后通过企业微信确认 VPN 使用正常</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Chat -->
|
|
|
|
|
|
<div class="chat-messages">
|
|
|
|
|
|
<div class="msg-system">—— 2026年6月6日 10:25 ——</div>
|
|
|
|
|
|
<div class="msg-bubble msg-user">VPN 连接一直失败,提示"无法建立安全连接",重启了好几次都不行,急需访问内网代码仓库…</div>
|
|
|
|
|
|
<div class="msg-bubble msg-agent">张工您好,先帮您排查一下:请问您是使用的 AnyConnect 客户端还是 SSL VPN 网页版?</div>
|
|
|
|
|
|
<div class="msg-bubble msg-user">AnyConnect 客户端,版本是 4.10。刚才又试了一次,还是同样的错误。</div>
|
|
|
|
|
|
<div class="msg-bubble msg-agent">收到。建议您先清除缓存配置:1)退出客户端;2)删除 XML 文件;3)重新连接。如果还不行,可以远程协助。</div>
|
|
|
|
|
|
<div class="msg-bubble msg-user">按你说的试了,还是不行。能远程看下吗?</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Chat input -->
|
|
|
|
|
|
<div class="chat-input-area" id="chatInputArea">
|
|
|
|
|
|
<div class="input-resize-handle" id="inputResizeHandle" title="拖拽调整输入框高度"></div>
|
|
|
|
|
|
<!-- 快捷工具栏 -->
|
|
|
|
|
|
<div class="chat-toolbar">
|
|
|
|
|
|
<button class="tb-btn" title="表情"><span class="tb-tip">表情</span>😊</button>
|
|
|
|
|
|
<button class="tb-btn" title="图片"><span class="tb-tip">图片</span>🖼</button>
|
|
|
|
|
|
<button class="tb-btn" title="截图"><span class="tb-tip">截图</span>✂</button>
|
|
|
|
|
|
<button class="tb-btn" title="文件"><span class="tb-tip">文件</span>📎</button>
|
|
|
|
|
|
<button class="tb-btn" title="语音"><span class="tb-tip">语音</span>🎤</button>
|
|
|
|
|
|
<div class="tb-sep"></div>
|
|
|
|
|
|
<button class="tb-btn" title="远程协助"><span class="tb-tip">远程协助</span>🖥</button>
|
|
|
|
|
|
<button class="tb-btn" title="快速回复"><span class="tb-tip">快速回复</span>⚡</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="chat-input-row">
|
|
|
|
|
|
<div class="chat-input-card">
|
|
|
|
|
|
<textarea class="chat-input" id="chatInput" placeholder="输入回复内容... (Enter 发送,Shift+Enter 换行)" rows="3"></textarea>
|
|
|
|
|
|
<button class="btn-send">发 送</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== Task Detail View (hidden by default) ===== -->
|
|
|
|
|
|
<div class="task-detail-view" id="taskDetailView">
|
|
|
|
|
|
<div class="task-detail-header">
|
|
|
|
|
|
<button class="btn-back" onclick="showChatView()">← 返回会话</button>
|
|
|
|
|
|
<span class="task-title" id="taskDetailTitle">工单详情</span>
|
|
|
|
|
|
<span class="task-type-badge" id="taskTypeBadge">工单</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="task-detail-body" id="taskDetailBody">
|
|
|
|
|
|
<!-- Dynamic content inserted by JS -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="task-actions" id="taskActions">
|
|
|
|
|
|
<!-- Dynamic buttons inserted by JS -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 拖拽手柄:中间栏↔右栏 -->
|
|
|
|
|
|
<div class="resize-handle" id="resizeRight" title="拖拽调整右栏宽度"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== RIGHT SIDEBAR ===== -->
|
|
|
|
|
|
<div class="sidebar-right">
|
|
|
|
|
|
<!-- AI Recommend -->
|
|
|
|
|
|
<div class="ai-recommend-section">
|
|
|
|
|
|
<div class="ars-title">🤖 AI 智能推荐</div>
|
|
|
|
|
|
<div class="ars-card" onclick="fillInput(this)">
|
|
|
|
|
|
<div class="ars-card-header"><span style="font-size:10px;color:var(--text-secondary);">远程协助方案</span><span class="ars-confidence">92%</span></div>
|
|
|
|
|
|
<div class="ars-card-text">可以远程,请先安装 TeamViewer 或允许内网远程桌面。您的电脑名是什么?</div>
|
|
|
|
|
|
<div class="ars-shortcut-hint"><span class="key-badge">Ctrl</span>+<span class="key-badge">1</span></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="ars-card" onclick="fillInput(this)">
|
|
|
|
|
|
<div class="ars-card-header"><span style="font-size:10px;color:var(--text-secondary);">备用方案</span><span class="ars-confidence">85%</span></div>
|
|
|
|
|
|
<div class="ars-card-text">临时使用 SSL VPN 网页版:https://sslvpn.servyou-it.com 企业微信扫码登录</div>
|
|
|
|
|
|
<div class="ars-shortcut-hint"><span class="key-badge">Ctrl</span>+<span class="key-badge">2</span></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Quick Reply — 三层渐进式导航 -->
|
|
|
|
|
|
<div class="quick-reply-section" id="qrSection">
|
|
|
|
|
|
<!-- 搜索栏 -->
|
|
|
|
|
|
<div class="qr-search">
|
|
|
|
|
|
<span class="qr-search-icon">🔍</span>
|
|
|
|
|
|
<input class="qr-search-input" id="qrSearchInput" placeholder="搜索快速回复 / Alt+目录数字" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 面包屑导航 -->
|
|
|
|
|
|
<div class="qr-breadcrumb" id="qrBreadcrumb">
|
|
|
|
|
|
<span class="bc-back hidden" id="qrBackBtn" onclick="qrGoBack()">← 返回上级</span>
|
|
|
|
|
|
<span class="bc-current" id="qrPathLabel">请选择分类</span>
|
|
|
|
|
|
<span class="bc-hint hidden" id="qrPathHint">
|
|
|
|
|
|
<span class="key-badge">Alt</span>+数字切换一级
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- L1 一级目录:网格 2 列 × 4 行 -->
|
|
|
|
|
|
<div class="qr-l1-grid" id="qrL1Grid"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- L2 二级目录:流式 chip -->
|
|
|
|
|
|
<div class="qr-l2-row hidden" id="qrL2Row"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- L3 回复列表 -->
|
|
|
|
|
|
<div class="qr-l3-list" id="qrL3List">
|
|
|
|
|
|
<div class="qr-l3-empty">
|
|
|
|
|
|
<span class="empty-icon">💬</span>
|
|
|
|
|
|
<span class="empty-hint">按 <span class="key-badge">Alt</span>+数字 选择一级分类<br>进入后按数字键逐层筛选<br>选中回复后按 <span class="key-badge">Enter</span> 填入输入框</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 已选中回复预览条 -->
|
|
|
|
|
|
<div class="qr-selected-bar hidden" id="qrSelectedBar">
|
|
|
|
|
|
<span>✅</span>
|
|
|
|
|
|
<span class="sel-text" id="qrSelectedText"></span>
|
|
|
|
|
|
<span class="sel-hint">Enter 填入</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 键盘指南 -->
|
|
|
|
|
|
<div class="keyboard-guide" id="qrKeyboardGuide">
|
|
|
|
|
|
<span><span class="key-badge">Alt</span>+<span class="key-badge">1-7</span> 一级分类</span>
|
|
|
|
|
|
<span><span class="key-badge">数字</span> 选子项</span>
|
|
|
|
|
|
<span><span class="key-badge">Enter</span> 填入</span>
|
|
|
|
|
|
<span><span class="key-badge">←</span> 返回</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-08-07 22:31:32 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- ===== 待办事项(已移至右栏底部) ===== -->
|
|
|
|
|
|
<div class="kanban">
|
|
|
|
|
|
<div class="kanban-title">待办事项 <span class="count">6</span></div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="kanban-item active" onclick="showTaskDetail('ticket')">
|
|
|
|
|
|
<span class="ki-priority urgent"></span>
|
|
|
|
|
|
<span class="ki-text">CEO办公室 - 投屏设备故障</span>
|
|
|
|
|
|
<span class="ki-type ticket">工单</span>
|
|
|
|
|
|
<span class="ki-time">5m</span>
|
|
|
|
|
|
<div class="ki-avatar ka-red" title="王莉">王</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="kanban-item" onclick="showTaskDetail('ticket')">
|
|
|
|
|
|
<span class="ki-priority urgent"></span>
|
|
|
|
|
|
<span class="ki-text">财务部 - 税控系统无法登录</span>
|
|
|
|
|
|
<span class="ki-type ticket">工单</span>
|
|
|
|
|
|
<span class="ki-time">12m</span>
|
|
|
|
|
|
<div class="ki-avatar ka-orange" title="王磊">王</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="kanban-item" onclick="showTaskDetail('approval')">
|
|
|
|
|
|
<span class="ki-priority high"></span>
|
|
|
|
|
|
<span class="ki-text">IT采购申请 - 研发部笔记本电脑</span>
|
|
|
|
|
|
<span class="ki-type approval">审批</span>
|
|
|
|
|
|
<span class="ki-time">28m</span>
|
|
|
|
|
|
<div class="ki-avatar ka-blue" title="李研发">李</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="kanban-item" onclick="showTaskDetail('device')">
|
|
|
|
|
|
<span class="ki-priority high"></span>
|
|
|
|
|
|
<span class="ki-text">会议室 A - 投影仪离线</span>
|
|
|
|
|
|
<span class="ki-type device">设备</span>
|
|
|
|
|
|
<span class="ki-time">45m</span>
|
|
|
|
|
|
<div class="ki-avatar ka-green" title="行政部">行</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="kanban-item" onclick="showTaskDetail('approval')">
|
|
|
|
|
|
<span class="ki-priority normal"></span>
|
|
|
|
|
|
<span class="ki-text">新员工入职 - 设备申领审批</span>
|
|
|
|
|
|
<span class="ki-type approval">审批</span>
|
|
|
|
|
|
<span class="ki-time">32m</span>
|
|
|
|
|
|
<div class="ki-avatar ka-purple" title="HR部">H</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="kanban-item resolved" onclick="showTaskDetail('ticket')">
|
|
|
|
|
|
<span class="ki-priority done"></span>
|
|
|
|
|
|
<span class="ki-text">客服部 - 耳机无声(驱动重装)</span>
|
|
|
|
|
|
<span class="ki-type ticket">工单</span>
|
|
|
|
|
|
<span class="ki-time">1h</span>
|
|
|
|
|
|
<div class="ki-avatar ka-blue" title="客服部">客</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="kanban-stats"><span><span class="dot dot-online"></span> 在线 4</span><span><span class="dot dot-busy"></span> 忙碌 2</span><span><span class="dot dot-offline"></span> 离线 1</span></div>
|
|
|
|
|
|
</div>
|
2026-06-14 16:49:18 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
/* ========== 主题切换 ========== */
|
|
|
|
|
|
function toggleTheme() {
|
|
|
|
|
|
const body = document.body;
|
|
|
|
|
|
body.setAttribute('data-theme', body.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
|
|
|
|
|
|
}
|
|
|
|
|
|
function toggleUserDetail() {
|
|
|
|
|
|
document.getElementById('userInfoBar').classList.toggle('expanded');
|
|
|
|
|
|
}
|
|
|
|
|
|
function toggleSection(header) {
|
|
|
|
|
|
header.classList.toggle('collapsed');
|
|
|
|
|
|
header.nextElementSibling.classList.toggle('collapsed');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== FLOWCHART TOGGLE ===== */
|
|
|
|
|
|
function toggleFlowchart() {
|
|
|
|
|
|
const bar = document.getElementById('tsBar');
|
|
|
|
|
|
const btn = document.getElementById('tsFlowBtn');
|
|
|
|
|
|
bar.classList.toggle('show-flow');
|
|
|
|
|
|
if (bar.classList.contains('show-flow')) {
|
|
|
|
|
|
btn.textContent = '▼';
|
|
|
|
|
|
btn.title = '收起全流程图';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
btn.textContent = '▶';
|
|
|
|
|
|
btn.title = '展开全流程图';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function fillInput(el) {
|
|
|
|
|
|
const text = el.textContent.replace(/Ctrl\s*\+\s*\d/g, '').replace(/快速填入|执行操作/g, '').trim();
|
|
|
|
|
|
document.getElementById('chatInput').value = text;
|
|
|
|
|
|
autoResize(document.getElementById('chatInput'));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 输入框自动高度(最小3行约60px,最大300px) */
|
|
|
|
|
|
function autoResize(textarea) {
|
|
|
|
|
|
textarea.style.height = 'auto';
|
|
|
|
|
|
textarea.style.height = Math.max(60, Math.min(textarea.scrollHeight, 300)) + 'px';
|
|
|
|
|
|
}
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
var chatInput = document.getElementById('chatInput');
|
|
|
|
|
|
if (chatInput) {
|
|
|
|
|
|
chatInput.addEventListener('input', function() { autoResize(this); });
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== Task Detail View Logic ========== */
|
|
|
|
|
|
function showTaskDetail(type) {
|
|
|
|
|
|
document.getElementById('chatView').classList.add('hidden');
|
|
|
|
|
|
const detailView = document.getElementById('taskDetailView');
|
|
|
|
|
|
detailView.classList.add('active');
|
|
|
|
|
|
|
|
|
|
|
|
const titleEl = document.getElementById('taskDetailTitle');
|
|
|
|
|
|
const badgeEl = document.getElementById('taskTypeBadge');
|
|
|
|
|
|
const bodyEl = document.getElementById('taskDetailBody');
|
|
|
|
|
|
const actionsEl = document.getElementById('taskActions');
|
|
|
|
|
|
|
|
|
|
|
|
if (type === 'ticket') {
|
|
|
|
|
|
titleEl.textContent = '工单 #20240606001';
|
|
|
|
|
|
badgeEl.textContent = '运维工单';
|
|
|
|
|
|
badgeEl.style.background = 'var(--accent-soft)';
|
|
|
|
|
|
badgeEl.style.color = 'var(--accent)';
|
|
|
|
|
|
badgeEl.style.border = '1px solid var(--accent)';
|
|
|
|
|
|
|
|
|
|
|
|
bodyEl.innerHTML = `
|
|
|
|
|
|
<div class="task-info-card">
|
|
|
|
|
|
<div class="tic-title">📋 工单描述</div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">标题</span><span class="tic-value">CEO办公室 - 投屏设备故障</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">类型</span><span class="tic-value">硬件故障</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">优先级</span><span class="tic-value" style="color:var(--danger);">🔴 紧急</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">上报人</span><span class="tic-value">张总秘书 · 王莉</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">上报时间</span><span class="tic-value">2026-06-06 10:20</span></div>
|
|
|
|
|
|
<div class="tic-desc">CEO 办公室无线投屏设备(型号:Microsoft Wireless Display Adapter v2)无法连接,会议即将开始(10:40),急需处理。已尝试重启设备和更换 HDMI 端口,问题依旧。</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="task-info-card">
|
|
|
|
|
|
<div class="tic-title">📍 处理进度</div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">状态</span><span class="tic-value" style="color:var(--warning);">⏳ 待接单</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">接单人</span><span class="tic-value" style="color:var(--text-muted);">未分配</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">SLA</span><span class="tic-value" style="color:var(--danger);">⏰ 剩余 12 分钟</span></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
2026-08-07 22:31:32 +08:00
|
|
|
|
// 2026-07-24 优化:按钮持续显示,已接单时显示"已接单"(禁用状态)
|
|
|
|
|
|
// 待接单:绿色可点击
|
|
|
|
|
|
// 已接单:灰色禁用
|
2026-06-14 16:49:18 +08:00
|
|
|
|
actionsEl.innerHTML = `
|
2026-08-07 22:31:32 +08:00
|
|
|
|
<button class="btn-action primary" onclick="this.outerHTML='<button class=\\'btn-action primary\\' disabled style=\\'opacity:0.5;cursor:not-allowed;background:#9ca3af;border-color:#9ca3af;\\'>📥 已接单</button>'">📥 接单</button>
|
2026-06-14 16:49:18 +08:00
|
|
|
|
<button class="btn-action warning" onclick="alert('开始处理')">🔧 开始处理</button>
|
|
|
|
|
|
<button class="btn-action success" onclick="alert('工单已结单')">✅ 结单</button>
|
|
|
|
|
|
<button class="btn-action default" onclick="alert('已转派')">🔄 转派</button>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
} else if (type === 'approval') {
|
|
|
|
|
|
titleEl.textContent = '审批 #APP-20240606003';
|
|
|
|
|
|
badgeEl.textContent = '审批单';
|
|
|
|
|
|
badgeEl.style.background = 'var(--purple-soft)';
|
|
|
|
|
|
badgeEl.style.color = 'var(--purple)';
|
|
|
|
|
|
badgeEl.style.border = '1px solid var(--purple)';
|
|
|
|
|
|
|
|
|
|
|
|
bodyEl.innerHTML = `
|
|
|
|
|
|
<div class="task-info-card">
|
|
|
|
|
|
<div class="tic-title">📝 审批内容</div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">申请人</span><span class="tic-value">李研发经理 · 研发一部</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">审批类型</span><span class="tic-value">IT设备采购</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">申请时间</span><span class="tic-value">2026-06-05 14:30</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">预算</span><span class="tic-value">¥86,400(10台 × ¥8,640)</span></div>
|
|
|
|
|
|
<div class="tic-desc">
|
|
|
|
|
|
<strong>采购明细:</strong><br>
|
|
|
|
|
|
• MacBook Pro 14" M3 Pro × 10台<br>
|
|
|
|
|
|
• 预计交付日期:2026-06-20<br>
|
|
|
|
|
|
• 用途:新员工入职配发<br>
|
|
|
|
|
|
• 附件:<a href="#" style="color:var(--accent);">采购清单.xlsx</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="approval-section">
|
|
|
|
|
|
<div class="as-title">✏️ 审批意见(可选)</div>
|
|
|
|
|
|
<textarea class="approval-textarea" placeholder="输入审批意见..."></textarea>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
actionsEl.innerHTML = `
|
|
|
|
|
|
<button class="btn-action success" onclick="alert('已审批通过')">✅ 审批通过</button>
|
|
|
|
|
|
<button class="btn-action danger" onclick="alert('已拒绝审批')">❌ 拒绝审批</button>
|
|
|
|
|
|
<button class="btn-action default" onclick="alert('已转交')">🔄 转交审批</button>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
} else if (type === 'device') {
|
|
|
|
|
|
titleEl.textContent = '设备异常 #DEV-20240606007';
|
|
|
|
|
|
badgeEl.textContent = '设备异常';
|
|
|
|
|
|
badgeEl.style.background = 'var(--orange-soft)';
|
|
|
|
|
|
badgeEl.style.color = 'var(--orange)';
|
|
|
|
|
|
badgeEl.style.border = '1px solid var(--orange)';
|
|
|
|
|
|
|
|
|
|
|
|
bodyEl.innerHTML = `
|
|
|
|
|
|
<div class="task-info-card">
|
|
|
|
|
|
<div class="tic-title">🖥 设备状态</div>
|
|
|
|
|
|
<div class="device-status-grid">
|
|
|
|
|
|
<div class="device-status-item">
|
|
|
|
|
|
<div class="dsi-label">设备名称</div>
|
|
|
|
|
|
<div class="dsi-value">会议室A-投影仪</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="device-status-item">
|
|
|
|
|
|
<div class="dsi-label">设备型号</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- === 新增 AI 推荐 === -->
|
|
|
|
|
|
<div class="recommend-item" data-ctrl="Ctrl+3">
|
|
|
|
|
|
<div class="rec-header">
|
|
|
|
|
|
<span class="rec-badge" style="background:#22c55e20;color:#22c55e;">知识库匹配</span>
|
|
|
|
|
|
<span class="rec-confidence">88%</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="rec-content" style="font-size:11px;">邮箱登录异常通常原因:密码过期(90天强制更换)、账号临时锁定、客户端配置错误。请先确认用户是否收到密码过期提醒。</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="recommend-item" data-ctrl="Ctrl+4">
|
|
|
|
|
|
<div class="rec-header">
|
|
|
|
|
|
<span class="rec-badge" style="background:#a855f720;color:#a855f7;">相似案例</span>
|
|
|
|
|
|
<span class="rec-confidence">78%</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="rec-content" style="font-size:11px;">打印驱动重装:设置→蓝牙和其他设备→打印机→删除→访问 print-server 下载最新驱动→重新添加。</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="dsi-value">Epson CB-W42</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="device-status-item">
|
|
|
|
|
|
<div class="dsi-label">在线状态</div>
|
|
|
|
|
|
<div class="dsi-value danger">🔴 离线</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="device-status-item">
|
|
|
|
|
|
<div class="dsi-label">最后在线</div>
|
|
|
|
|
|
<div class="dsi-value">2026-06-06 09:15</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="device-status-item">
|
|
|
|
|
|
<div class="dsi-label">IP 地址</div>
|
|
|
|
|
|
<div class="dsi-value">192.168.10.88</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="device-status-item">
|
|
|
|
|
|
<div class="dsi-label">告警次数</div>
|
|
|
|
|
|
<div class="dsi-value warning">3 次/今日</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tic-desc" style="margin-top:8px;">
|
|
|
|
|
|
<strong>异常描述:</strong>设备连续 3 次离线,每次恢复后约 10 分钟再次掉线。可能原因:电源接触不良 / 网络端口故障 / 设备固件异常。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="task-info-card">
|
|
|
|
|
|
<div class="tic-title">🔧 处理记录</div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">10:15</span><span class="tic-value">尝试 Ping 设备 — 超时</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">10:20</span><span class="tic-value">检查交换机端口 — 指示灯不亮</span></div>
|
|
|
|
|
|
<div class="tic-row"><span class="tic-label">10:25</span><span class="tic-value" style="color:var(--warning);">⏳ 待现场排查物理连接</span></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
actionsEl.innerHTML = `
|
|
|
|
|
|
<button class="btn-action primary" onclick="alert('一键开单')">📝 一键开单</button>
|
|
|
|
|
|
<button class="btn-action warning" onclick="alert('已派工给硬件组')">🚚 派工</button>
|
|
|
|
|
|
<button class="btn-action success" onclick="alert('设备已恢复')">✅ 标记恢复</button>
|
|
|
|
|
|
<button class="btn-action default" onclick="alert('已加入巡检计划')">📅 加入巡检</button>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function showChatView() {
|
|
|
|
|
|
document.getElementById('chatView').classList.remove('hidden');
|
|
|
|
|
|
document.getElementById('taskDetailView').classList.remove('active');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ================================================================
|
|
|
|
|
|
快速回复 — 三层渐进式导航系统
|
|
|
|
|
|
数据来源:IT支持知识库 180 条模板(2026-04-24)
|
|
|
|
|
|
L1(Alt+数字) → L2(数字) → L3(数字) → Enter 填入
|
|
|
|
|
|
================================================================ */
|
|
|
|
|
|
|
|
|
|
|
|
// 知识库数据从 qr_data.js 加载(IT支持知识库2026-4-24.docx 导出)
|
|
|
|
|
|
|
|
|
|
|
|
// 导航状态
|
|
|
|
|
|
let qrState = {
|
|
|
|
|
|
l1Index: -1, // 当前选中的一级分类索引(-1 = 未选)
|
|
|
|
|
|
l2Index: -1, // 当前选中的二级分类索引(-1 = 未选)
|
|
|
|
|
|
l3Index: -1, // 当前选中的三级回复索引(-1 = 未选)
|
|
|
|
|
|
selectedText: '', // 当前选中的回复文本
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 快速回复 L1 主类颜色(与 CSS 变量 --qr-c0 ~ --qr-c6 对应)
|
|
|
|
|
|
const qrColors = ['#3b82f6', '#22c55e', '#f97316', '#8b5cf6', '#ef4444', '#0ea5e9', '#6b7280'];
|
|
|
|
|
|
const qrLightColors = ['#dbeafe', '#dcfce7', '#fff7ed', '#ede9fe', '#fee2e2', '#f0fdfa', '#f3f4f6'];
|
|
|
|
|
|
|
|
|
|
|
|
// 判断当前焦点是否在搜索框
|
|
|
|
|
|
function isSearchFocused() {
|
|
|
|
|
|
return document.activeElement === document.getElementById('qrSearchInput');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染 L1 网格
|
|
|
|
|
|
function renderL1() {
|
|
|
|
|
|
const grid = document.getElementById('qrL1Grid');
|
|
|
|
|
|
grid.innerHTML = qrData.map((cat, i) => {
|
|
|
|
|
|
const isActive = qrState.l1Index === i;
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="qr-l1-btn${isActive ? ' active' : ''}" data-l1="${i}" onclick="selectL1(${i})">
|
|
|
|
|
|
<span class="l1-num">${i + 1}</span>
|
|
|
|
|
|
<span class="l1-name">${cat.name}</span>
|
|
|
|
|
|
</div>`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
grid.classList.remove('hidden');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染 L2 chip 行
|
|
|
|
|
|
function renderL2() {
|
|
|
|
|
|
const row = document.getElementById('qrL2Row');
|
|
|
|
|
|
const cat = qrData[qrState.l1Index];
|
|
|
|
|
|
if (!cat) { row.classList.add('hidden'); return; }
|
|
|
|
|
|
row.innerHTML = cat.subs.map((sub, i) => {
|
|
|
|
|
|
const isSelected = qrState.l2Index === i;
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="qr-l2-chip${isSelected ? ' selected' : ''}" data-l2="${i}" onclick="selectL2(${i})">
|
|
|
|
|
|
<span class="l2-num">${i + 1}</span>
|
|
|
|
|
|
<span>${sub.name}</span>
|
|
|
|
|
|
</div>`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
row.classList.remove('hidden');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染 L3 回复列表
|
|
|
|
|
|
function renderL3() {
|
|
|
|
|
|
const list = document.getElementById('qrL3List');
|
|
|
|
|
|
const cat = qrData[qrState.l1Index];
|
|
|
|
|
|
if (!cat || qrState.l2Index === -1) {
|
|
|
|
|
|
// 还没选到 L2,显示空状态
|
|
|
|
|
|
list.innerHTML = `
|
|
|
|
|
|
<div class="qr-l3-empty">
|
|
|
|
|
|
<span class="empty-icon">👆</span>
|
|
|
|
|
|
<span class="empty-hint">请先在上方选择子分类<br>或按数字键 <span class="key-badge">1</span>~<span class="key-badge">${cat ? cat.subs.length : 'N'}</span> 快速选择</span>
|
|
|
|
|
|
</div>`;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const sub = cat.subs[qrState.l2Index];
|
|
|
|
|
|
if (!sub) return;
|
|
|
|
|
|
list.innerHTML = sub.items.map((item, i) => {
|
|
|
|
|
|
const isSelected = qrState.l3Index === i;
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="qr-l3-item${isSelected ? ' selected' : ''}" data-l3="${i}" onclick="selectL3(${i})">
|
|
|
|
|
|
<span class="l3-num">${i + 1}</span>
|
|
|
|
|
|
<div class="l3-content">
|
|
|
|
|
|
<div class="l3-title">${item.title}</div>
|
|
|
|
|
|
<div class="l3-preview">${item.content}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新面包屑
|
|
|
|
|
|
function updateBreadcrumb() {
|
|
|
|
|
|
const backBtn = document.getElementById('qrBackBtn');
|
|
|
|
|
|
const pathLabel = document.getElementById('qrPathLabel');
|
|
|
|
|
|
const pathHint = document.getElementById('qrPathHint');
|
|
|
|
|
|
|
|
|
|
|
|
if (qrState.l1Index === -1) {
|
|
|
|
|
|
backBtn.classList.add('hidden');
|
|
|
|
|
|
pathLabel.textContent = '请选择分类';
|
|
|
|
|
|
pathHint.classList.remove('hidden');
|
|
|
|
|
|
pathHint.innerHTML = '<span class="key-badge">Alt</span>+数字 选择分类';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const cat = qrData[qrState.l1Index];
|
|
|
|
|
|
if (qrState.l2Index === -1) {
|
|
|
|
|
|
backBtn.classList.remove('hidden');
|
|
|
|
|
|
backBtn.textContent = '← 返回分类';
|
|
|
|
|
|
pathLabel.textContent = `${cat.name}`;
|
|
|
|
|
|
pathHint.classList.remove('hidden');
|
|
|
|
|
|
pathHint.innerHTML = `数字 <span class="key-badge">1</span>~<span class="key-badge">${cat.subs.length}</span> 选子类`;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const sub = cat.subs[qrState.l2Index];
|
|
|
|
|
|
backBtn.classList.remove('hidden');
|
|
|
|
|
|
backBtn.textContent = '← 返回子类';
|
|
|
|
|
|
pathLabel.innerHTML = `${cat.name} <span class="bc-sep">›</span> ${sub.name}`;
|
|
|
|
|
|
pathHint.classList.remove('hidden');
|
|
|
|
|
|
pathHint.innerHTML = `数字 <span class="key-badge">1</span>~<span class="key-badge">${sub.items.length}</span> 选回复 · <span class="key-badge">Enter</span> 填入`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新选中回复预览条
|
|
|
|
|
|
function updateSelectedBar() {
|
|
|
|
|
|
const bar = document.getElementById('qrSelectedBar');
|
|
|
|
|
|
const textEl = document.getElementById('qrSelectedText');
|
|
|
|
|
|
if (qrState.selectedText && qrState.l3Index !== -1) {
|
|
|
|
|
|
bar.classList.remove('hidden');
|
|
|
|
|
|
const cat = qrData[qrState.l1Index];
|
|
|
|
|
|
const sub = cat.subs[qrState.l2Index];
|
|
|
|
|
|
const item = sub.items[qrState.l3Index];
|
|
|
|
|
|
textEl.textContent = item.title + ':' + item.content.substring(0, 40) + '...';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
bar.classList.add('hidden');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 选择动作 =====
|
|
|
|
|
|
|
|
|
|
|
|
function selectL1(index) {
|
|
|
|
|
|
qrState.l1Index = index;
|
|
|
|
|
|
qrState.l2Index = -1;
|
|
|
|
|
|
qrState.l3Index = -1;
|
|
|
|
|
|
qrState.selectedText = '';
|
|
|
|
|
|
renderL1();
|
|
|
|
|
|
renderL2();
|
|
|
|
|
|
renderL3();
|
|
|
|
|
|
updateBreadcrumb();
|
|
|
|
|
|
updateSelectedBar();
|
|
|
|
|
|
// 设置 L2/L3 继承的主类颜色
|
|
|
|
|
|
const qrSection = document.getElementById('qrSection');
|
|
|
|
|
|
qrSection.style.setProperty('--qr-active-color', qrColors[index]);
|
|
|
|
|
|
qrSection.style.setProperty('--qr-active-light', qrLightColors[index]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function selectL2(index) {
|
|
|
|
|
|
qrState.l2Index = index;
|
|
|
|
|
|
qrState.l3Index = -1;
|
|
|
|
|
|
qrState.selectedText = '';
|
|
|
|
|
|
renderL2();
|
|
|
|
|
|
renderL3();
|
|
|
|
|
|
updateBreadcrumb();
|
|
|
|
|
|
updateSelectedBar();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function selectL3(index) {
|
|
|
|
|
|
qrState.l3Index = index;
|
|
|
|
|
|
const cat = qrData[qrState.l1Index];
|
|
|
|
|
|
const sub = cat.subs[qrState.l2Index];
|
|
|
|
|
|
const item = sub.items[index];
|
|
|
|
|
|
qrState.selectedText = item.content;
|
|
|
|
|
|
renderL3();
|
|
|
|
|
|
updateBreadcrumb();
|
|
|
|
|
|
updateSelectedBar();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将选中回复填入聊天输入框
|
|
|
|
|
|
function qrInsertToChat() {
|
|
|
|
|
|
if (qrState.selectedText) {
|
|
|
|
|
|
document.getElementById('chatInput').value = qrState.selectedText;
|
|
|
|
|
|
document.getElementById('chatInput').focus();
|
|
|
|
|
|
// 闪烁反馈
|
|
|
|
|
|
const bar = document.getElementById('qrSelectedBar');
|
|
|
|
|
|
bar.style.background = 'var(--accent-soft)';
|
|
|
|
|
|
bar.style.color = 'var(--accent)';
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
bar.style.background = 'var(--success-soft)';
|
|
|
|
|
|
bar.style.color = 'var(--success)';
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 返回上一级
|
|
|
|
|
|
function qrGoBack() {
|
|
|
|
|
|
if (qrState.l2Index !== -1) {
|
|
|
|
|
|
// 从 L3 回到 L2
|
|
|
|
|
|
qrState.l2Index = -1;
|
|
|
|
|
|
qrState.l3Index = -1;
|
|
|
|
|
|
qrState.selectedText = '';
|
|
|
|
|
|
} else if (qrState.l1Index !== -1) {
|
|
|
|
|
|
// 从 L2 回到 L1
|
|
|
|
|
|
qrState.l1Index = -1;
|
|
|
|
|
|
qrState.l2Index = -1;
|
|
|
|
|
|
qrState.l3Index = -1;
|
|
|
|
|
|
qrState.selectedText = '';
|
|
|
|
|
|
document.getElementById('qrL2Row').classList.add('hidden');
|
|
|
|
|
|
// 清除 L2/L3 继承的主类颜色
|
|
|
|
|
|
const qrSection = document.getElementById('qrSection');
|
|
|
|
|
|
qrSection.style.removeProperty('--qr-active-color');
|
|
|
|
|
|
qrSection.style.removeProperty('--qr-active-light');
|
|
|
|
|
|
}
|
|
|
|
|
|
renderL1();
|
|
|
|
|
|
renderL2();
|
|
|
|
|
|
renderL3();
|
|
|
|
|
|
updateBreadcrumb();
|
|
|
|
|
|
updateSelectedBar();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 键盘事件 =====
|
|
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
|
|
|
|
// 状态判断
|
|
|
|
|
|
const chatFocused = document.activeElement === document.getElementById('chatInput');
|
|
|
|
|
|
|
|
|
|
|
|
// "/" 聚焦搜索框(非输入状态)
|
|
|
|
|
|
if (e.key === '/' && !chatFocused && !isSearchFocused()) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
document.getElementById('qrSearchInput').focus();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Alt+数字:选择 L1 一级分类(全局有效,除聊天输入框外)
|
|
|
|
|
|
if (e.altKey && e.key >= '1' && e.key <= '7') {
|
|
|
|
|
|
if (chatFocused) return; // 聊天输入框中不拦截 Alt+数字
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
const idx = parseInt(e.key) - 1;
|
|
|
|
|
|
if (idx < qrData.length) {
|
|
|
|
|
|
selectL1(idx);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 在搜索框内时不处理数字导航
|
|
|
|
|
|
if (isSearchFocused()) return;
|
|
|
|
|
|
// 聊天输入框内不处理快速回复导航
|
|
|
|
|
|
if (chatFocused) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 数字键:逐层选择 L2 或 L3
|
|
|
|
|
|
if (e.key >= '0' && e.key <= '9' && !e.altKey && !e.ctrlKey && !e.metaKey) {
|
|
|
|
|
|
const num = parseInt(e.key);
|
|
|
|
|
|
if (num === 0) return; // 0 不参与导航
|
|
|
|
|
|
|
|
|
|
|
|
if (qrState.l1Index !== -1 && qrState.l2Index === -1) {
|
|
|
|
|
|
// 已选中 L1,数字选择 L2
|
|
|
|
|
|
const cat = qrData[qrState.l1Index];
|
|
|
|
|
|
if (num <= cat.subs.length) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
selectL2(num - 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (qrState.l1Index !== -1 && qrState.l2Index !== -1) {
|
|
|
|
|
|
// 已选中 L2,数字选择 L3
|
|
|
|
|
|
const cat = qrData[qrState.l1Index];
|
|
|
|
|
|
const sub = cat.subs[qrState.l2Index];
|
|
|
|
|
|
if (num <= sub.items.length) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
selectL3(num - 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Enter:将选中的回复填入聊天输入框
|
|
|
|
|
|
if (e.key === 'Enter' && qrState.selectedText) {
|
|
|
|
|
|
if (chatFocused) return; // 聊天输入框中 Enter 用于发送
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
qrInsertToChat();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Backspace/Escape:返回上一级
|
|
|
|
|
|
if ((e.key === 'Backspace' || e.key === 'Escape') && (qrState.l1Index !== -1)) {
|
|
|
|
|
|
if (chatFocused) return;
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
qrGoBack();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 初始渲染 — 默认展示第一分类第二层目录效果(方便原型评审)
|
|
|
|
|
|
selectL1(0);
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== v5.4: 拖拽调整中间栏左右边框 ===== */
|
|
|
|
|
|
(function initResizeHandles() {
|
|
|
|
|
|
const leftSidebar = document.querySelector('.sidebar-left');
|
|
|
|
|
|
const rightSidebar = document.querySelector('.sidebar-right');
|
|
|
|
|
|
const handleLeft = document.getElementById('resizeLeft');
|
|
|
|
|
|
const handleRight = document.getElementById('resizeRight');
|
|
|
|
|
|
|
|
|
|
|
|
if (!handleLeft || !handleRight) return;
|
|
|
|
|
|
|
|
|
|
|
|
let dragging = null; // 'left' 或 'right'
|
|
|
|
|
|
let startX = 0;
|
|
|
|
|
|
let startWidth = 0;
|
|
|
|
|
|
|
|
|
|
|
|
function onMouseDown(e, side) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dragging = side;
|
|
|
|
|
|
startX = e.clientX;
|
|
|
|
|
|
startWidth = side === 'left'
|
|
|
|
|
|
? leftSidebar.offsetWidth
|
|
|
|
|
|
: rightSidebar.offsetWidth;
|
|
|
|
|
|
document.body.style.cursor = 'col-resize';
|
|
|
|
|
|
document.body.style.userSelect = 'none';
|
|
|
|
|
|
// 高亮当前手柄
|
|
|
|
|
|
(side === 'left' ? handleLeft : handleRight).classList.add('dragging');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onMouseMove(e) {
|
|
|
|
|
|
if (!dragging) return;
|
|
|
|
|
|
if (dragging === 'left') {
|
|
|
|
|
|
const dx = e.clientX - startX;
|
|
|
|
|
|
const newW = Math.max(200, Math.min(500, startWidth + dx));
|
|
|
|
|
|
leftSidebar.style.width = newW + 'px';
|
|
|
|
|
|
leftSidebar.style.minWidth = newW + 'px';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const dx = startX - e.clientX;
|
|
|
|
|
|
const newW = Math.max(220, Math.min(500, startWidth + dx));
|
|
|
|
|
|
rightSidebar.style.width = newW + 'px';
|
|
|
|
|
|
rightSidebar.style.minWidth = newW + 'px';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onMouseUp() {
|
|
|
|
|
|
if (!dragging) return;
|
|
|
|
|
|
document.body.style.cursor = '';
|
|
|
|
|
|
document.body.style.userSelect = '';
|
|
|
|
|
|
handleLeft.classList.remove('dragging');
|
|
|
|
|
|
handleRight.classList.remove('dragging');
|
|
|
|
|
|
dragging = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
handleLeft.addEventListener('mousedown', function(e) { onMouseDown(e, 'left'); });
|
|
|
|
|
|
handleRight.addEventListener('mousedown', function(e) { onMouseDown(e, 'right'); });
|
|
|
|
|
|
document.addEventListener('mousemove', onMouseMove);
|
|
|
|
|
|
document.addEventListener('mouseup', onMouseUp);
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== v5.4: 输入框上方拖拽手柄(调整输入框高度,textarea 同步伸缩) ===== */
|
|
|
|
|
|
(function initInputResize() {
|
|
|
|
|
|
const inputArea = document.getElementById('chatInputArea');
|
|
|
|
|
|
const handle = document.getElementById('inputResizeHandle');
|
|
|
|
|
|
const chatInput = document.getElementById('chatInput');
|
|
|
|
|
|
if (!inputArea || !handle) return;
|
|
|
|
|
|
|
|
|
|
|
|
let dragging = false;
|
|
|
|
|
|
let startY = 0;
|
|
|
|
|
|
let startHeight = 0;
|
|
|
|
|
|
let startInputHeight = 0;
|
|
|
|
|
|
|
|
|
|
|
|
handle.addEventListener('mousedown', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dragging = true;
|
|
|
|
|
|
startY = e.clientY;
|
|
|
|
|
|
startHeight = inputArea.offsetHeight;
|
|
|
|
|
|
startInputHeight = chatInput ? chatInput.offsetHeight : 40;
|
|
|
|
|
|
document.body.style.cursor = 'row-resize';
|
|
|
|
|
|
document.body.style.userSelect = 'none';
|
|
|
|
|
|
handle.classList.add('dragging');
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('mousemove', function(e) {
|
|
|
|
|
|
if (!dragging) return;
|
|
|
|
|
|
// 向上拖 → 整个区域变高,向下拖 → 变矮
|
|
|
|
|
|
const dy = startY - e.clientY;
|
|
|
|
|
|
const newH = Math.max(80, Math.min(400, startHeight + dy));
|
|
|
|
|
|
inputArea.style.height = newH + 'px';
|
|
|
|
|
|
// textarea 同步伸缩
|
|
|
|
|
|
if (chatInput) {
|
|
|
|
|
|
const delta = newH - startHeight;
|
|
|
|
|
|
const newInputH = Math.max(60, Math.min(350, startInputHeight + delta));
|
|
|
|
|
|
chatInput.style.height = newInputH + 'px';
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('mouseup', function() {
|
|
|
|
|
|
if (!dragging) return;
|
|
|
|
|
|
dragging = false;
|
|
|
|
|
|
document.body.style.cursor = '';
|
|
|
|
|
|
document.body.style.userSelect = '';
|
|
|
|
|
|
handle.classList.remove('dragging');
|
|
|
|
|
|
});
|
|
|
|
|
|
})();
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
/* ===== 排查步骤交互:用户端同步逻辑 ===== */
|
|
|
|
|
|
(function() {
|
|
|
|
|
|
var pathSteps = document.querySelectorAll('.path-step-inline');
|
|
|
|
|
|
pathSteps.forEach(function(step, idx) {
|
|
|
|
|
|
step.addEventListener('click', function() {
|
|
|
|
|
|
pathSteps.forEach(function(s, i) {
|
|
|
|
|
|
s.classList.remove('path-step-inline--done', 'path-step-inline--current', 'path-step-inline--pending');
|
|
|
|
|
|
if (i < idx) s.classList.add('path-step-inline--done');
|
|
|
|
|
|
else if (i === idx) s.classList.add('path-step-inline--current');
|
|
|
|
|
|
else s.classList.add('path-step-inline--pending');
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
})();
|
|
|
|
|
|
</script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|