facc04aa65
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交 (5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。 一、docs 结构整改(整改 #14) 根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入, 随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录 树并存于 docs/,共 791 文件、双分类体系冲突。 修复动作: - b2 同名异主题文件改名迁移保全 9 个 - C 类 39 个孤立文件按主题正确归类 - A/B1 类 222 个重复文件删除(新结构已有内容副本) - 9 个旧独有空目录删除 - 270 处内部引用按 verified 映射改写 - 整改记录 #14 登记于 04-运维文档/部署运维 结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。 残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。 二、compose 双目录对齐(消除踩坑 A) - docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist 改为 src/frontend-*/dist(h5 / agent / admin / terminal) - docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/ - 效果:本地 docker compose up 不再把根目录 stale dist 挂回, 与线上一致,分叉隐患消除(已 docker compose config 校验通过) 防复发铁律: - 重构须提交;仓库修复须 git stash -u 或先 commit - 新结构须 git add 并提交,避免再次 untracked 复活 - H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
1363 lines
58 KiB
HTML
1363 lines
58 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN" data-theme="dark">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>IT智能服务台 · H5用户端原型 v1.8 — 修复桌面端截断</title>
|
|
<style>
|
|
/* ============================================================================
|
|
CSS 变量 — 浅色/深色双主题
|
|
============================================================================ */
|
|
:root {
|
|
--accent: #3b82f6;
|
|
--accent-soft: rgba(59, 130, 246, 0.12);
|
|
--bg-primary: #f5f6fa;
|
|
--bg-secondary: #ffffff;
|
|
--bg-tertiary: #eef0f5;
|
|
--text-primary: #1a1a2e;
|
|
--text-secondary: #555770;
|
|
--text-tertiary: #9ca3af;
|
|
--text-placeholder: #b0b4c0;
|
|
--border-color: #e5e7eb;
|
|
--shadow: 0 1px 4px rgba(0,0,0,0.06);
|
|
--radius: 12px;
|
|
--transition: 0.2s ease;
|
|
--color-employee-bg: #3b82f6;
|
|
--color-agent-bg: #ffffff;
|
|
--color-agent-border: #e5e7eb;
|
|
--color-ai-bg: #e8f5e9;
|
|
--color-ai-text: #1b5e20;
|
|
--color-ai-tag-text: #2e7d32;
|
|
--color-ai-tag-bg: #c8e6c9;
|
|
--color-system-text: #9ca3af;
|
|
--color-system-bg: #eef0f5;
|
|
--color-warning: #ff9800;
|
|
--color-danger: #ef4444;
|
|
--color-success: #22c55e;
|
|
--color-guide-active: #ff9800;
|
|
--ts-done: #22c55e;
|
|
--ts-current: #3b82f6;
|
|
--ts-pending-bg: #eef0f5;
|
|
--ts-yes-bg: rgba(34,197,94,0.06);
|
|
--ts-yes-border: rgba(34,197,94,0.3);
|
|
--ts-no-bg: rgba(239,68,68,0.06);
|
|
--ts-no-border: rgba(239,68,68,0.3);
|
|
--color-ts-card-bg: #ffffff;
|
|
--color-ts-card-border: #e5e7eb;
|
|
--color-ts-card-header: rgba(59,130,246,0.08);
|
|
--resize-handle-color: #cbd5e1;
|
|
--tool-btn-bg: #eef0f5;
|
|
--tool-btn-text: #555770;
|
|
}
|
|
[data-theme="dark"] {
|
|
--accent: #3b82f6;
|
|
--accent-soft: rgba(59, 130, 246, 0.18);
|
|
--bg-primary: #0f172a;
|
|
--bg-secondary: #1e293b;
|
|
--bg-tertiary: #162032;
|
|
--text-primary: #e2e8f0;
|
|
--text-secondary: #94a3b8;
|
|
--text-tertiary: #64748b;
|
|
--text-placeholder: #475569;
|
|
--border-color: #334155;
|
|
--shadow: 0 1px 4px rgba(0,0,0,0.3);
|
|
--color-employee-bg: #2563eb;
|
|
--color-agent-bg: #1e293b;
|
|
--color-agent-border: #334155;
|
|
--color-ai-bg: #0d3320;
|
|
--color-ai-text: #86efac;
|
|
--color-ai-tag-text: #86efac;
|
|
--color-ai-tag-bg: #14532d;
|
|
--color-system-text: #64748b;
|
|
--color-system-bg: #162032;
|
|
--color-warning: #f97316;
|
|
--color-danger: #ef4444;
|
|
--color-success: #22c55e;
|
|
--color-guide-active: #f97316;
|
|
--ts-done: #22c55e;
|
|
--ts-current: #3b82f6;
|
|
--ts-pending-bg: #162032;
|
|
--ts-yes-bg: rgba(34,197,94,0.08);
|
|
--ts-yes-border: rgba(34,197,94,0.3);
|
|
--ts-no-bg: rgba(239,68,68,0.08);
|
|
--ts-no-border: rgba(239,68,68,0.3);
|
|
--color-ts-card-bg: #1e293b;
|
|
--color-ts-card-border: #334155;
|
|
--color-ts-card-header: rgba(59,130,246,0.12);
|
|
--resize-handle-color: #475569;
|
|
--tool-btn-bg: #162032;
|
|
--tool-btn-text: #94a3b8;
|
|
}
|
|
|
|
/* ============================================================================
|
|
基础重置
|
|
============================================================================ */
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
html, body {
|
|
height: 100%;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
|
background: #0a0f1a;
|
|
color: var(--text-primary);
|
|
-webkit-font-smoothing: antialiased;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* ============================================================================
|
|
页面级布局 — 双视图并排
|
|
============================================================================ */
|
|
.page-wrapper {
|
|
display: flex;
|
|
gap: 32px;
|
|
padding: 24px;
|
|
min-height: 100vh;
|
|
align-items: flex-start;
|
|
justify-content: center;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* 视图标签 */
|
|
.view-label {
|
|
text-align: center;
|
|
padding: 8px 0 12px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: #94a3b8;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
}
|
|
.view-label .badge {
|
|
display: inline-block;
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
}
|
|
.badge--primary { background: rgba(59,130,246,0.2); color: #60a5fa; }
|
|
.badge--secondary { background: rgba(249,115,22,0.2); color: #fb923c; }
|
|
.badge--percent { background: rgba(34,197,94,0.2); color: #4ade80; }
|
|
.badge--new { background: rgba(239,68,68,0.2); color: #f87171; }
|
|
.badge--fix { background: rgba(168,85,247,0.2); color: #c084fc; }
|
|
|
|
/* ============================================================================
|
|
视图容器
|
|
============================================================================ */
|
|
.view-container { flex-shrink: 0; }
|
|
|
|
/* ===== 桌面端企微壳 — v1.8 拉长至940px修复截断 ===== */
|
|
.desktop-shell {
|
|
width: 720px;
|
|
height: 940px;
|
|
border-radius: 16px;
|
|
border: 2px solid #334155;
|
|
overflow: hidden;
|
|
background: var(--bg-primary);
|
|
box-shadow: 0 8px 40px rgba(0,0,0,0.4);
|
|
position: relative;
|
|
}
|
|
/* 企微顶栏模拟 */
|
|
.desktop-shell__wecom-bar {
|
|
height: 36px;
|
|
background: #2a2a3e;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 12px;
|
|
gap: 8px;
|
|
border-bottom: 1px solid #3a3a5c;
|
|
flex-shrink: 0;
|
|
}
|
|
.wecom-tab { font-size: 12px; color: #888; padding: 4px 10px; border-radius: 4px; cursor: default; }
|
|
.wecom-tab--active { color: #e2e8f0; background: rgba(59,130,246,0.15); }
|
|
.wecom-title { font-size: 13px; color: #ccc; margin-left: auto; }
|
|
|
|
/* ===== 手机壳 ===== */
|
|
.phone-shell {
|
|
width: 375px;
|
|
height: 820px;
|
|
border-radius: 36px;
|
|
border: 4px solid #334155;
|
|
overflow: hidden;
|
|
background: var(--bg-primary);
|
|
box-shadow: 0 8px 40px rgba(0,0,0,0.4);
|
|
position: relative;
|
|
}
|
|
.phone-shell__statusbar {
|
|
height: 44px;
|
|
background: var(--bg-secondary);
|
|
display: flex;
|
|
align-items: flex-end;
|
|
justify-content: center;
|
|
padding-bottom: 8px;
|
|
border-bottom: 1px solid var(--border-color);
|
|
flex-shrink: 0;
|
|
}
|
|
.phone-shell__statusbar-title {
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
|
|
/* ============================================================================
|
|
主布局
|
|
============================================================================ */
|
|
.chat-panel {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
background: var(--bg-primary);
|
|
}
|
|
|
|
/* ===== 桌面端双栏主体 ===== */
|
|
.desktop-body {
|
|
display: flex;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
/* 左侧:消息区 */
|
|
.desktop-left {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-width: 280px;
|
|
}
|
|
/* 拖拽手柄 — 左右栏之间 */
|
|
.resize-handle-v {
|
|
width: 6px;
|
|
cursor: col-resize;
|
|
background: transparent;
|
|
position: relative;
|
|
flex-shrink: 0;
|
|
z-index: 10;
|
|
transition: background 0.2s;
|
|
}
|
|
.resize-handle-v:hover,
|
|
.resize-handle-v--active {
|
|
background: var(--accent);
|
|
}
|
|
.resize-handle-v::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 2px;
|
|
height: 24px;
|
|
border-radius: 1px;
|
|
background: var(--resize-handle-color);
|
|
opacity: 0.5;
|
|
}
|
|
.resize-handle-v:hover::after,
|
|
.resize-handle-v--active::after {
|
|
opacity: 1;
|
|
background: #fff;
|
|
}
|
|
|
|
/* 右侧:三段式面板 */
|
|
.desktop-right {
|
|
width: 280px;
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
background: var(--bg-secondary);
|
|
min-width: 200px;
|
|
max-width: 400px;
|
|
}
|
|
|
|
/* ============================================================================
|
|
顶部标题栏
|
|
============================================================================ */
|
|
.chat-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 10px 16px;
|
|
background: var(--bg-secondary);
|
|
border-bottom: 1px solid var(--border-color);
|
|
flex-shrink: 0;
|
|
}
|
|
.chat-header__title {
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
.chat-header__title .logo-icon { font-size: 18px; }
|
|
.chat-header__actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
.chat-header__online {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
font-size: 11px;
|
|
color: var(--color-success);
|
|
}
|
|
.chat-header__online-dot {
|
|
width: 6px; height: 6px; border-radius: 50%;
|
|
background: var(--color-success);
|
|
animation: online-pulse 2s ease-in-out infinite;
|
|
}
|
|
.theme-switch {
|
|
display: flex; align-items: center; gap: 4px;
|
|
cursor: pointer; user-select: none;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
.switch-track {
|
|
width: 32px; height: 18px; border-radius: 9px;
|
|
background: var(--bg-tertiary); border: 1px solid var(--border-color);
|
|
position: relative; transition: background var(--transition);
|
|
}
|
|
.switch-thumb {
|
|
width: 14px; height: 14px; border-radius: 50%;
|
|
background: var(--accent); position: absolute; top: 1px; left: 1px;
|
|
transition: transform var(--transition);
|
|
}
|
|
[data-theme="dark"] .switch-thumb { transform: translateX(14px); }
|
|
|
|
/* ============================================================================
|
|
排查步骤 — 固定在消息区顶部
|
|
============================================================================ */
|
|
.ts-top-bar {
|
|
flex-shrink: 0;
|
|
background: var(--color-ts-card-bg);
|
|
border-bottom: 1px solid var(--color-ts-card-border);
|
|
overflow: hidden;
|
|
transition: max-height 0.3s ease;
|
|
z-index: 5;
|
|
}
|
|
.ts-top-bar__header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 6px 12px;
|
|
background: var(--color-ts-card-header);
|
|
border-bottom: 1px solid var(--border-color);
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
color: var(--accent);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
.ts-top-bar__header-icon { font-size: 12px; }
|
|
.ts-top-bar__header-title { flex: 1; }
|
|
.ts-top-bar__header-tag {
|
|
font-size: 9px;
|
|
padding: 1px 6px;
|
|
border-radius: 3px;
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
}
|
|
.ts-top-bar__toggle {
|
|
font-size: 10px;
|
|
color: var(--text-tertiary);
|
|
transition: transform 0.2s;
|
|
}
|
|
.ts-top-bar__toggle--collapsed { transform: rotate(180deg); }
|
|
|
|
.ts-top-bar__path {
|
|
padding: 6px 12px 4px;
|
|
border-bottom: 1px solid var(--border-color);
|
|
}
|
|
.ts-path-bar {
|
|
display: flex; align-items: center; gap: 2px;
|
|
overflow-x: auto; padding-bottom: 4px;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
.ts-path-bar::-webkit-scrollbar { height: 0; }
|
|
.ts-step { display: flex; align-items: center; gap: 4px; white-space: nowrap; flex-shrink: 0; }
|
|
.ts-dot {
|
|
width: 16px; height: 16px; border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 8px; font-weight: 700; flex-shrink: 0;
|
|
}
|
|
.ts-dot--done { background: var(--ts-done); color: #fff; }
|
|
.ts-dot--current { background: var(--ts-current); color: #fff; box-shadow: 0 0 0 2px var(--accent-soft); animation: ts-dot-pulse 2s ease-in-out infinite; }
|
|
.ts-dot--pending { background: var(--ts-pending-bg); color: var(--text-tertiary); border: 1px solid var(--border-color); }
|
|
.ts-label { font-size: 10px; color: var(--text-secondary); }
|
|
.ts-step--done .ts-label { color: var(--text-tertiary); text-decoration: line-through; }
|
|
.ts-step--current .ts-label { color: var(--accent); font-weight: 600; }
|
|
.ts-step--pending .ts-label { color: var(--text-tertiary); }
|
|
.ts-arrow { color: var(--text-tertiary); font-size: 8px; flex-shrink: 0; padding: 0 1px; }
|
|
.ts-arrow--active { color: var(--ts-done); }
|
|
|
|
.ts-top-bar__body {
|
|
padding: 8px 12px 10px;
|
|
}
|
|
|
|
/* 决策节点 */
|
|
.ts-question-header { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 8px; }
|
|
.ts-question-icon { font-size: 14px; flex-shrink: 0; margin-top: 1px; }
|
|
.ts-question-text { font-size: 13px; font-weight: 600; color: var(--text-primary); line-height: 1.5; }
|
|
.ts-options { display: flex; gap: 8px; margin-top: 2px; }
|
|
.ts-option {
|
|
flex: 1; display: flex; align-items: center; justify-content: center; gap: 4px;
|
|
padding: 8px 10px; border-radius: 8px;
|
|
border: 2px solid var(--border-color); background: var(--bg-primary);
|
|
color: var(--text-primary); font-size: 12px; font-weight: 600;
|
|
cursor: pointer; transition: all 0.2s; font-family: inherit;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
.ts-option:active { transform: scale(0.97); }
|
|
.ts-option--yes { border-color: var(--ts-yes-border); background: var(--ts-yes-bg); }
|
|
.ts-option--no { border-color: var(--ts-no-border); background: var(--ts-no-bg); }
|
|
.ts-option-icon { font-size: 12px; }
|
|
.ts-option--selected-yes { border-color: #22c55e !important; background: rgba(34,197,94,0.15) !important; box-shadow: 0 0 0 2px rgba(34,197,94,0.2); }
|
|
.ts-option--selected-no { border-color: #ef4444 !important; background: rgba(239,68,68,0.15) !important; box-shadow: 0 0 0 2px rgba(239,68,68,0.2); }
|
|
|
|
/* 步骤节点 */
|
|
.ts-instruction-header { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
|
|
.ts-instruction-icon { font-size: 12px; flex-shrink: 0; }
|
|
.ts-instruction-title { font-size: 12px; font-weight: 600; color: var(--accent); }
|
|
.ts-sub-steps { display: flex; flex-direction: column; gap: 4px; margin: 6px 0; padding-left: 2px; }
|
|
.ts-sub-step { display: flex; align-items: center; gap: 5px; font-size: 11px; }
|
|
.ts-sub-dot {
|
|
width: 16px; height: 16px; border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 8px; font-weight: 700; flex-shrink: 0;
|
|
background: var(--ts-pending-bg); color: var(--text-tertiary); border: 1px solid var(--border-color);
|
|
}
|
|
.ts-sub-step--done .ts-sub-dot { background: #22c55e; color: #fff; border-color: #22c55e; }
|
|
.ts-sub-step--done .ts-sub-label { color: var(--text-tertiary); text-decoration: line-through; }
|
|
.ts-sub-step--current .ts-sub-dot { background: var(--accent); color: #fff; border-color: var(--accent); }
|
|
.ts-sub-step--current .ts-sub-label { color: var(--accent); font-weight: 600; }
|
|
.ts-sub-label { color: var(--text-secondary); }
|
|
.ts-hint {
|
|
margin-top: 6px; padding: 4px 8px;
|
|
background: var(--accent-soft); border-radius: 6px;
|
|
font-size: 10px; color: var(--accent);
|
|
}
|
|
|
|
/* ============================================================================
|
|
消息列表
|
|
============================================================================ */
|
|
.chat-messages {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 8px 0;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
.chat-messages::-webkit-scrollbar { width: 3px; }
|
|
.chat-messages::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
|
|
|
|
/* ============================================================================
|
|
消息气泡
|
|
============================================================================ */
|
|
.msg {
|
|
display: flex; flex-direction: column;
|
|
padding: 4px 14px; max-width: 100%;
|
|
animation: bubble-in 0.3s ease-out;
|
|
}
|
|
.msg--employee { align-items: flex-end; }
|
|
.msg--agent, .msg--ai { align-items: flex-start; }
|
|
.msg--system { align-items: center; padding: 6px 14px; }
|
|
.msg--system .msg__system-text {
|
|
font-size: 11px; color: var(--color-system-text);
|
|
background: var(--color-system-bg);
|
|
padding: 3px 10px; border-radius: 10px;
|
|
text-align: center; line-height: 1.5;
|
|
}
|
|
.msg__sender { display: flex; align-items: center; gap: 4px; margin-bottom: 2px; padding-left: 4px; }
|
|
.msg__ai-tag {
|
|
font-size: 10px; color: var(--color-ai-tag-text);
|
|
background: var(--color-ai-tag-bg);
|
|
padding: 1px 5px; border-radius: 3px; font-weight: 600;
|
|
}
|
|
.msg__sender-name { font-size: 11px; color: var(--text-tertiary); }
|
|
.msg__bubble {
|
|
max-width: 75%; padding: 9px 13px; border-radius: 14px;
|
|
word-break: break-word; line-height: 1.6; font-size: 13px;
|
|
}
|
|
.msg--employee .msg__bubble { background: var(--color-employee-bg); color: #fff; border-top-right-radius: 4px; }
|
|
.msg--agent .msg__bubble { background: var(--color-agent-bg); color: var(--text-primary); border-top-left-radius: 4px; border: 1px solid var(--color-agent-border); }
|
|
.msg--ai .msg__bubble { background: var(--color-ai-bg); color: var(--color-ai-text); border-top-left-radius: 4px; }
|
|
.msg__time { font-size: 10px; color: var(--text-placeholder); margin-top: 2px; }
|
|
.msg--employee .msg__time { text-align: right; padding-right: 4px; }
|
|
.msg--agent .msg__time, .msg--ai .msg__time { text-align: left; padding-left: 4px; }
|
|
.msg__avatar {
|
|
width: 28px; height: 28px; border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 12px; flex-shrink: 0; margin-bottom: 2px;
|
|
}
|
|
.msg__avatar--agent { background: linear-gradient(135deg, #3b82f6, #6366f1); }
|
|
.msg__avatar--ai { background: linear-gradient(135deg, #22c55e, #14b8a6); }
|
|
.msg__avatar-row { display: flex; align-items: flex-end; gap: 6px; max-width: 88%; }
|
|
|
|
/* ============================================================================
|
|
输入栏 — 通用样式(桌面端+手机端共用)
|
|
============================================================================ */
|
|
.input-bar {
|
|
background: var(--bg-secondary);
|
|
border-top: 1px solid var(--border-color);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* 工具栏 — 表情/图片/文件/拍照 */
|
|
.input-toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 2px;
|
|
padding: 4px 12px 2px;
|
|
border-bottom: 1px solid var(--border-color);
|
|
}
|
|
.tool-btn {
|
|
width: 32px; height: 32px; border-radius: 8px;
|
|
border: none; background: var(--tool-btn-bg);
|
|
color: var(--tool-btn-text); font-size: 15px;
|
|
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
|
transition: all 0.15s; flex-shrink: 0;
|
|
-webkit-tap-highlight-color: transparent; outline: none;
|
|
}
|
|
.tool-btn:active { transform: scale(0.92); background: var(--accent-soft); }
|
|
.tool-btn:hover { background: var(--accent-soft); color: var(--accent); }
|
|
.tool-sep {
|
|
width: 1px; height: 18px; background: var(--border-color);
|
|
margin: 0 4px; flex-shrink: 0;
|
|
}
|
|
|
|
/* 输入行 */
|
|
.input-row {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
gap: 6px;
|
|
padding: 6px 12px;
|
|
padding-bottom: calc(6px + env(safe-area-inset-bottom, 6px));
|
|
}
|
|
|
|
/* 输入框 — 通用 */
|
|
.input-field {
|
|
flex: 1; background: var(--bg-tertiary); border-radius: 8px;
|
|
padding: 8px 10px; border: 1px solid var(--border-color);
|
|
font-size: 13px; font-family: inherit; color: var(--text-primary);
|
|
resize: none; outline: none; min-height: 54px; max-height: 120px;
|
|
line-height: 1.5; transition: border-color 0.2s;
|
|
}
|
|
.input-field:focus { border-color: var(--accent); }
|
|
.input-field::placeholder { color: var(--text-placeholder); }
|
|
|
|
/* 摇铃按钮 — 圆形(手机端输入栏 + 桌面端输入栏) */
|
|
.bell-btn {
|
|
position: relative; width: 34px; height: 34px; border-radius: 50%; border: none;
|
|
cursor: pointer; background: linear-gradient(135deg, var(--color-warning), #f97316);
|
|
display: flex; align-items: center; justify-content: center;
|
|
box-shadow: 0 2px 6px rgba(255, 152, 0, 0.25);
|
|
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
-webkit-tap-highlight-color: transparent; outline: none; flex-shrink: 0;
|
|
}
|
|
.bell-btn:active { transform: scale(0.92); }
|
|
.bell-btn__icon {
|
|
font-size: 16px; line-height: 1; display: inline-block;
|
|
animation: bell-ring 2s ease-in-out infinite;
|
|
}
|
|
.bell-btn__dot {
|
|
position: absolute; top: 1px; right: 1px;
|
|
width: 6px; height: 6px; border-radius: 50%;
|
|
background: var(--color-danger); border: 1px solid var(--bg-secondary);
|
|
}
|
|
|
|
/* 发送按钮 */
|
|
.send-btn {
|
|
flex-shrink: 0; height: 34px; width: 34px; border-radius: 50%;
|
|
border: none; background: var(--accent); color: #fff;
|
|
font-size: 14px; cursor: pointer;
|
|
transition: all 0.2s; font-family: inherit;
|
|
display: flex; align-items: center; justify-content: center;
|
|
box-shadow: 0 2px 6px rgba(59, 130, 246, 0.25);
|
|
}
|
|
.send-btn:active { transform: scale(0.92); }
|
|
.send-btn:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }
|
|
|
|
/* ============================================================================
|
|
摇铃按钮 — 标题栏胶囊样式(桌面端+手机端共用)
|
|
============================================================================ */
|
|
.bell-btn--header {
|
|
height: 28px; border-radius: 14px; border: none;
|
|
padding: 0 10px; gap: 4px;
|
|
font-size: 11px; font-weight: 600; color: #fff;
|
|
background: linear-gradient(135deg, var(--color-warning), #f97316);
|
|
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
|
box-shadow: 0 2px 6px rgba(255, 152, 0, 0.25);
|
|
transition: transform 0.2s;
|
|
-webkit-tap-highlight-color: transparent; outline: none;
|
|
}
|
|
.bell-btn--header:active { transform: scale(0.95); }
|
|
.bell-btn--header__icon {
|
|
font-size: 13px; animation: none;
|
|
display: inline-block;
|
|
}
|
|
.bell-btn--header__dot {
|
|
width: 5px; height: 5px; border-radius: 50%;
|
|
background: var(--color-danger); border: none;
|
|
display: inline-block; margin-left: 2px;
|
|
}
|
|
|
|
/* ============================================================================
|
|
桌面端右侧面板 — 三段式布局
|
|
============================================================================ */
|
|
.right-panel {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
.ai-push {
|
|
padding: 10px 12px;
|
|
border-bottom: 1px solid var(--border-color);
|
|
flex-shrink: 0;
|
|
overflow-y: auto;
|
|
}
|
|
.ai-push::-webkit-scrollbar { width: 3px; }
|
|
.ai-push::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
|
|
.ai-push__header { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
|
|
.ai-push__icon { font-size: 14px; }
|
|
.ai-push__title { font-size: 12px; font-weight: 700; color: var(--text-primary); }
|
|
.ai-push__badge { margin-left: auto; font-size: 9px; padding: 2px 6px; border-radius: 4px; background: var(--accent-soft); color: var(--accent); font-weight: 600; }
|
|
.ai-push__item {
|
|
padding: 7px 9px; border-radius: 8px; background: var(--bg-tertiary);
|
|
margin-bottom: 5px; cursor: pointer; transition: all 0.2s;
|
|
}
|
|
.ai-push__item:hover { background: var(--accent-soft); }
|
|
.ai-push__item-title { font-size: 11px; font-weight: 600; color: var(--text-primary); margin-bottom: 2px; display: flex; align-items: center; gap: 4px; }
|
|
.ai-push__item-desc { font-size: 10px; color: var(--text-secondary); line-height: 1.4; }
|
|
.ai-push__item-tag { display: inline-block; font-size: 9px; padding: 1px 4px; border-radius: 3px; background: var(--accent-soft); color: var(--accent); margin-right: 3px; }
|
|
|
|
.resources {
|
|
flex: 1; display: flex; flex-direction: column;
|
|
border-bottom: 1px solid var(--border-color); overflow: hidden;
|
|
}
|
|
.resources__tabs { display: flex; border-bottom: 1px solid var(--border-color); flex-shrink: 0; }
|
|
.resources__tab { flex: 1; text-align: center; padding: 7px 0; font-size: 11px; color: var(--text-secondary); cursor: pointer; border-bottom: 2px solid transparent; transition: all 0.2s; }
|
|
.resources__tab--active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
|
|
.resources__content { flex: 1; overflow-y: auto; padding: 8px 12px; }
|
|
.resources__content::-webkit-scrollbar { width: 3px; }
|
|
.resources__content::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
|
|
.resource-item { display: flex; align-items: center; gap: 8px; padding: 7px 9px; border-radius: 8px; margin-bottom: 4px; cursor: pointer; transition: all 0.2s; }
|
|
.resource-item:hover { background: var(--accent-soft); }
|
|
.resource-item__icon { width: 28px; height: 28px; border-radius: 6px; background: var(--bg-tertiary); display: flex; align-items: center; justify-content: center; font-size: 14px; flex-shrink: 0; }
|
|
.resource-item__info { flex: 1; min-width: 0; }
|
|
.resource-item__name { font-size: 11px; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
.resource-item__desc { font-size: 9px; color: var(--text-tertiary); margin-top: 1px; }
|
|
|
|
.fun-quiz { padding: 10px 12px; flex-shrink: 0; }
|
|
.fun-quiz__header { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
|
|
.fun-quiz__icon { font-size: 14px; }
|
|
.fun-quiz__title { font-size: 12px; font-weight: 700; color: var(--text-primary); }
|
|
.fun-quiz__score { margin-left: auto; font-size: 10px; color: var(--color-warning); font-weight: 600; }
|
|
.fun-quiz__question { font-size: 11px; color: var(--text-primary); margin-bottom: 6px; line-height: 1.5; }
|
|
.fun-quiz__options { display: flex; flex-direction: column; gap: 3px; }
|
|
.fun-quiz__option { padding: 5px 9px; border-radius: 6px; border: 1px solid var(--border-color); background: var(--bg-primary); font-size: 10px; color: var(--text-secondary); cursor: pointer; transition: all 0.2s; }
|
|
.fun-quiz__option:hover { border-color: var(--accent); color: var(--accent); }
|
|
.fun-quiz__option--correct { border-color: var(--color-success); background: rgba(34,197,94,0.1); color: var(--color-success); }
|
|
.fun-quiz__option--wrong { border-color: var(--color-danger); background: rgba(239,68,68,0.1); color: var(--color-danger); }
|
|
|
|
/* ============================================================================
|
|
呼叫坐席弹窗 — 摇铃样式
|
|
============================================================================ */
|
|
.modal-overlay {
|
|
position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 9999;
|
|
display: flex; justify-content: center; align-items: center;
|
|
opacity: 0; pointer-events: none; transition: opacity 0.25s ease;
|
|
}
|
|
.modal-overlay--visible { opacity: 1; pointer-events: auto; }
|
|
.modal-content {
|
|
background: var(--bg-secondary); border-radius: 16px;
|
|
width: 320px; max-height: 80vh; overflow-y: auto;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
|
|
transform: scale(0.8); transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
}
|
|
.modal-overlay--visible .modal-content { transform: scale(1); }
|
|
.modal-header { text-align: center; padding: 16px 14px 6px; }
|
|
.modal-header__icon { font-size: 28px; display: inline-block; animation: bell-ring 0.6s ease-in-out infinite; }
|
|
.modal-header h3 { margin: 6px 0 4px; font-size: 15px; color: var(--text-primary); }
|
|
.modal-body { padding: 10px 14px; display: flex; flex-direction: column; align-items: center; }
|
|
.modal-footer { padding: 10px 14px 16px; display: flex; justify-content: center; }
|
|
.modal-btn { border: none; border-radius: 8px; padding: 8px 20px; font-size: 13px; cursor: pointer; transition: all 0.2s; font-family: inherit; }
|
|
.modal-btn:active { transform: scale(0.96); }
|
|
.modal-btn--cancel { background: var(--bg-tertiary); color: var(--text-secondary); }
|
|
.modal-sending { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-secondary); }
|
|
.modal-dot-flashing { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: dot-flash 1s infinite; }
|
|
.modal-success { font-size: 13px; color: var(--color-success); font-weight: 600; padding: 8px 0; }
|
|
|
|
/* ============================================================================
|
|
标注区
|
|
============================================================================ */
|
|
.annotations {
|
|
position: fixed; top: 20px; right: 20px; width: 300px;
|
|
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
|
border-radius: 12px; padding: 14px; font-size: 11px; line-height: 1.5;
|
|
color: var(--text-secondary); box-shadow: 0 4px 16px rgba(0,0,0,0.2);
|
|
z-index: 100; max-height: 90vh; overflow-y: auto;
|
|
}
|
|
.annotations h3 { font-size: 13px; color: var(--text-primary); margin-bottom: 6px; }
|
|
.annotations ul { list-style: none; padding: 0; }
|
|
.annotations li { padding: 3px 0; border-bottom: 1px solid var(--border-color); }
|
|
.annotations li:last-child { border-bottom: none; }
|
|
.annotations .tag { display: inline-block; padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 600; margin-right: 3px; }
|
|
.tag--layout { background: rgba(168,85,247,0.15); color: #a855f7; }
|
|
.tag--decision { background: rgba(59,130,246,0.15); color: #3b82f6; }
|
|
.tag--sync { background: rgba(249,115,22,0.15); color: #f97316; }
|
|
.tag--diff { background: rgba(239,68,68,0.15); color: #ef4444; }
|
|
.tag--new { background: rgba(34,197,94,0.15); color: #22c55e; }
|
|
.tag--update { background: rgba(59,130,246,0.15); color: #3b82f6; }
|
|
.tag--fix { background: rgba(168,85,247,0.15); color: #a855f7; }
|
|
|
|
/* ============================================================================
|
|
动画
|
|
============================================================================ */
|
|
@keyframes online-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
@keyframes ts-dot-pulse { 0%, 100% { box-shadow: 0 0 0 2px var(--accent-soft); } 50% { box-shadow: 0 0 0 5px var(--accent-soft); } }
|
|
@keyframes bubble-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
|
|
@keyframes dot-flash { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } }
|
|
@keyframes bell-ring {
|
|
0%, 80%, 100% { transform: rotate(0); }
|
|
85% { transform: rotate(12deg); }
|
|
90% { transform: rotate(-12deg); }
|
|
95% { transform: rotate(6deg); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="page-wrapper">
|
|
|
|
<!-- ================================================================
|
|
左:桌面端视图 — v1.7 拉长至820px确保输入框完整可见
|
|
================================================================ -->
|
|
<div class="view-container">
|
|
<div class="view-label">
|
|
💻 企微桌面端 · 自建应用
|
|
<span class="badge badge--primary">主入口</span>
|
|
<span class="badge badge--percent">~70%</span>
|
|
<span class="badge badge--fix">v1.8修复截断</span>
|
|
</div>
|
|
<div class="desktop-shell">
|
|
<div class="desktop-shell__wecom-bar">
|
|
<span class="wecom-tab">消息</span>
|
|
<span class="wecom-tab wecom-tab--active">工作台</span>
|
|
<span class="wecom-tab">通讯录</span>
|
|
<span class="wecom-title">IT智能服务台</span>
|
|
</div>
|
|
<div class="desktop-body" id="desktopBody">
|
|
<!-- 左侧:消息区 -->
|
|
<div class="desktop-left" id="desktopLeft">
|
|
<!-- 标题栏 -->
|
|
<div class="chat-header">
|
|
<div class="chat-header__title">
|
|
<span class="logo-icon">🛎️</span>
|
|
<span>IT智能服务台</span>
|
|
</div>
|
|
<div class="chat-header__actions">
|
|
<div class="chat-header__online">
|
|
<span class="chat-header__online-dot"></span>
|
|
<span>坐席在线</span>
|
|
</div>
|
|
<button class="bell-btn--header" onclick="showCallModal()" title="呼叫人工坐席">
|
|
<span class="bell-btn--header__icon">🔔</span>
|
|
<span>呼叫</span>
|
|
<span class="bell-btn--header__dot"></span>
|
|
</button>
|
|
<div class="theme-switch" onclick="toggleTheme()" title="切换主题">
|
|
<div class="switch-track"><div class="switch-thumb"></div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 排查步骤固定在消息区顶部 -->
|
|
<div class="ts-top-bar" id="desktopTsBar">
|
|
<div class="ts-top-bar__header" onclick="toggleTsBar('desktop')">
|
|
<span class="ts-top-bar__header-icon">🔧</span>
|
|
<span class="ts-top-bar__header-title">排查步骤</span>
|
|
<span class="ts-top-bar__header-tag">进行中</span>
|
|
<span class="ts-top-bar__toggle" id="desktopTsToggle">▼ 收起</span>
|
|
</div>
|
|
<div id="desktopTsContent">
|
|
<div class="ts-top-bar__path">
|
|
<div class="ts-path-bar">
|
|
<div class="ts-step ts-step--done">
|
|
<span class="ts-dot ts-dot--done">✓</span>
|
|
<span class="ts-label">确认问题</span>
|
|
</div>
|
|
<span class="ts-arrow ts-arrow--active">→</span>
|
|
<div class="ts-step ts-step--current">
|
|
<span class="ts-dot ts-dot--current">2</span>
|
|
<span class="ts-label">网络适配器</span>
|
|
</div>
|
|
<span class="ts-arrow">→</span>
|
|
<div class="ts-step ts-step--pending">
|
|
<span class="ts-dot ts-dot--pending">3</span>
|
|
<span class="ts-label">驱动检查</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="ts-top-bar__body" id="desktopTsBody">
|
|
<div id="desktopTsDecision">
|
|
<div class="ts-question-header">
|
|
<span class="ts-question-icon">❓</span>
|
|
<span class="ts-question-text">WiFi适配器是否显示"已禁用"?</span>
|
|
</div>
|
|
<div class="ts-options">
|
|
<button class="ts-option ts-option--yes" onclick="selectDecision('desktop','yes')">
|
|
<span class="ts-option-icon">✅</span><span>是,已禁用</span>
|
|
</button>
|
|
<button class="ts-option ts-option--no" onclick="selectDecision('desktop','no')">
|
|
<span class="ts-option-icon">❌</span><span>否,正常</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="desktopTsInstruction" style="display:none;">
|
|
<div class="ts-instruction-header">
|
|
<span class="ts-instruction-icon">📋</span>
|
|
<span class="ts-instruction-title">正在执行:启用WiFi适配器</span>
|
|
</div>
|
|
<div class="ts-sub-steps">
|
|
<div class="ts-sub-step ts-sub-step--done">
|
|
<span class="ts-sub-dot">✓</span>
|
|
<span class="ts-sub-label">打开「设置」→「网络和Internet」</span>
|
|
</div>
|
|
<div class="ts-sub-step ts-sub-step--current">
|
|
<span class="ts-sub-dot">2</span>
|
|
<span class="ts-sub-label">点击「更改适配器选项」</span>
|
|
</div>
|
|
<div class="ts-sub-step">
|
|
<span class="ts-sub-dot">3</span>
|
|
<span class="ts-sub-label">右键WiFi适配器 → 启用</span>
|
|
</div>
|
|
</div>
|
|
<div class="ts-hint">💡 请按步骤操作,完成后坐席推进下一步</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 消息列表 -->
|
|
<div class="chat-messages" id="desktopMessages">
|
|
<div class="msg msg--system">
|
|
<span class="msg__system-text">坐席 小宋 已接入会话</span>
|
|
</div>
|
|
<div class="msg msg--ai">
|
|
<div class="msg__sender"><span class="msg__ai-tag">AI回复</span></div>
|
|
<div class="msg__avatar-row">
|
|
<div class="msg__avatar msg__avatar--ai">🤖</div>
|
|
<div>
|
|
<div class="msg__bubble">您好!我是AI助手,请问有什么可以帮您的?</div>
|
|
<div class="msg__time">10:02</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="msg msg--employee">
|
|
<div class="msg__bubble">我的电脑连不上公司WiFi了,网络图标显示黄色感叹号</div>
|
|
<div class="msg__time">10:03</div>
|
|
</div>
|
|
<div class="msg msg--agent">
|
|
<div class="msg__avatar-row">
|
|
<div class="msg__avatar msg__avatar--agent">👨💻</div>
|
|
<div>
|
|
<div class="msg__bubble">你好,我来帮你排查WiFi问题。请在上方排查步骤中选择 👆</div>
|
|
<div class="msg__time">10:05</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="msg msg--system">
|
|
<span class="msg__system-text">排查步骤已同步至坐席端</span>
|
|
</div>
|
|
<div class="msg msg--agent">
|
|
<div class="msg__avatar-row">
|
|
<div class="msg__avatar msg__avatar--agent">👨💻</div>
|
|
<div>
|
|
<div class="msg__bubble">好的,我看到你选择了"是,已禁用"。请按照上方步骤操作,启用WiFi适配器后告诉我结果。</div>
|
|
<div class="msg__time">10:06</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="msg msg--employee">
|
|
<div class="msg__bubble">已经启用了,但还是连不上</div>
|
|
<div class="msg__time">10:08</div>
|
|
</div>
|
|
<div class="msg msg--agent">
|
|
<div class="msg__avatar-row">
|
|
<div class="msg__avatar msg__avatar--agent">👨💻</div>
|
|
<div>
|
|
<div class="msg__bubble">明白,我继续帮你排查驱动问题。请稍等…</div>
|
|
<div class="msg__time">10:08</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ★ 桌面端输入栏(含工具栏+发送)— v1.7确保完整可见 -->
|
|
<div class="input-bar" id="desktopInputBar">
|
|
<div class="input-toolbar">
|
|
<button class="tool-btn" title="表情" onclick="showToolTip('😊 表情面板')">😊</button>
|
|
<button class="tool-btn" title="图片" onclick="showToolTip('🖼️ 选择图片')">🖼️</button>
|
|
<div class="tool-sep"></div>
|
|
<button class="tool-btn" title="文件" onclick="showToolTip('📎 选择文件')">📎</button>
|
|
<button class="tool-btn" title="拍照" onclick="showToolTip('📸 打开相机')">📸</button>
|
|
</div>
|
|
<div class="input-row">
|
|
<textarea class="input-field" rows="3" placeholder="请输入消息..." oninput="onInput('desktop', this)"></textarea>
|
|
<button class="bell-btn" onclick="showCallModal()" title="呼叫人工坐席">
|
|
<span class="bell-btn__icon">🔔</span>
|
|
<span class="bell-btn__dot"></span>
|
|
</button>
|
|
<button class="send-btn" id="desktopSendBtn" disabled title="发送" onclick="sendMessage('desktop')">➤</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 左右栏拖拽手柄 -->
|
|
<div class="resize-handle-v" id="resizeHandleV" title="左右拖动调整面板宽度"></div>
|
|
|
|
<!-- 右侧:三段式面板 -->
|
|
<div class="desktop-right" id="desktopRight">
|
|
<div class="right-panel">
|
|
<div class="ai-push">
|
|
<div class="ai-push__header">
|
|
<span class="ai-push__icon">🤖</span>
|
|
<span class="ai-push__title">AI智能推荐</span>
|
|
<span class="ai-push__badge">根据会话推送</span>
|
|
</div>
|
|
<div class="ai-push__item">
|
|
<div class="ai-push__item-title"><span>📖</span> WiFi连接问题处理指南</div>
|
|
<div class="ai-push__item-desc">相似问题处理方案,已解决 28 次</div>
|
|
<div><span class="ai-push__item-tag">相似问题</span><span class="ai-push__item-tag">WiFi</span></div>
|
|
</div>
|
|
<div class="ai-push__item">
|
|
<div class="ai-push__item-title"><span>📋</span> 网络连接申请流程</div>
|
|
<div class="ai-push__item-desc">新员工网络连接申请审批流程</div>
|
|
<div><span class="ai-push__item-tag">流程入口</span></div>
|
|
</div>
|
|
<div class="ai-push__item">
|
|
<div class="ai-push__item-title"><span>📥</span> 无线网卡驱动下载</div>
|
|
<div class="ai-push__item-desc">Intel/Realtek 常用无线网卡驱动</div>
|
|
<div><span class="ai-push__item-tag">软件下载</span></div>
|
|
</div>
|
|
</div>
|
|
<div class="resources">
|
|
<div class="resources__tabs">
|
|
<div class="resources__tab resources__tab--active" onclick="switchResourceTab('process', this)">申请流程</div>
|
|
<div class="resources__tab" onclick="switchResourceTab('software', this)">必装软件</div>
|
|
</div>
|
|
<div class="resources__content" id="resourceContent">
|
|
<div class="resource-item"><div class="resource-item__icon">📋</div><div class="resource-item__info"><div class="resource-item__name">IT设备申请</div><div class="resource-item__desc">电脑/显示器/外设</div></div></div>
|
|
<div class="resource-item"><div class="resource-item__icon">🔑</div><div class="resource-item__info"><div class="resource-item__name">权限申请</div><div class="resource-item__desc">文件夹/系统访问权限</div></div></div>
|
|
<div class="resource-item"><div class="resource-item__icon">📞</div><div class="resource-item__info"><div class="resource-item__name">VPN申请</div><div class="resource-item__desc">远程办公网络连接</div></div></div>
|
|
</div>
|
|
</div>
|
|
<div class="fun-quiz">
|
|
<div class="fun-quiz__header">
|
|
<span class="fun-quiz__icon">🎮</span>
|
|
<span class="fun-quiz__title">趣味问答</span>
|
|
<span class="fun-quiz__score">积分: 120</span>
|
|
</div>
|
|
<div class="fun-quiz__question">IT服务台电话分机号是?</div>
|
|
<div class="fun-quiz__options">
|
|
<div class="fun-quiz__option" onclick="selectQuizOption(this, true)">A. 8001</div>
|
|
<div class="fun-quiz__option" onclick="selectQuizOption(this, false)">B. 8002</div>
|
|
<div class="fun-quiz__option" onclick="selectQuizOption(this, false)">C. 8003</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ================================================================
|
|
右:手机端视图 — v1.7 摇铃上移至标题栏
|
|
================================================================ -->
|
|
<div class="view-container">
|
|
<div class="view-label">
|
|
📱 企微手机端 · 自建应用
|
|
<span class="badge badge--secondary">辅助入口</span>
|
|
<span class="badge badge--percent">~30%</span>
|
|
<span class="badge badge--fix">摇铃上移</span>
|
|
</div>
|
|
<div class="phone-shell">
|
|
<div class="chat-panel">
|
|
<div class="phone-shell__statusbar">
|
|
<div class="phone-shell__statusbar-title">
|
|
<span>🛎️</span> IT智能服务台
|
|
</div>
|
|
</div>
|
|
<!-- ★ v1.7:手机端标题栏 — 摇铃从输入栏移至此处,与桌面端一致 -->
|
|
<div class="chat-header">
|
|
<div class="chat-header__actions" style="width:100%;justify-content:space-between;">
|
|
<div class="chat-header__online">
|
|
<span class="chat-header__online-dot"></span>
|
|
<span>坐席在线</span>
|
|
</div>
|
|
<div style="display:flex;align-items:center;gap:8px;">
|
|
<button class="bell-btn--header" onclick="showCallModal()" title="呼叫人工坐席">
|
|
<span class="bell-btn--header__icon">🔔</span>
|
|
<span>呼叫</span>
|
|
<span class="bell-btn--header__dot"></span>
|
|
</button>
|
|
<div class="theme-switch" onclick="toggleTheme()" title="切换主题">
|
|
<div class="switch-track"><div class="switch-thumb"></div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 排查步骤固定在消息区顶部 -->
|
|
<div class="ts-top-bar" id="mobileTsBar">
|
|
<div class="ts-top-bar__header" onclick="toggleTsBar('mobile')">
|
|
<span class="ts-top-bar__header-icon">🔧</span>
|
|
<span class="ts-top-bar__header-title">排查步骤</span>
|
|
<span class="ts-top-bar__header-tag">进行中</span>
|
|
<span class="ts-top-bar__toggle" id="mobileTsToggle">▼ 收起</span>
|
|
</div>
|
|
<div id="mobileTsContent">
|
|
<div class="ts-top-bar__path">
|
|
<div class="ts-path-bar">
|
|
<div class="ts-step ts-step--done">
|
|
<span class="ts-dot ts-dot--done">✓</span>
|
|
<span class="ts-label">确认问题</span>
|
|
</div>
|
|
<span class="ts-arrow ts-arrow--active">→</span>
|
|
<div class="ts-step ts-step--current">
|
|
<span class="ts-dot ts-dot--current">2</span>
|
|
<span class="ts-label">网络适配器</span>
|
|
</div>
|
|
<span class="ts-arrow">→</span>
|
|
<div class="ts-step ts-step--pending">
|
|
<span class="ts-dot ts-dot--pending">3</span>
|
|
<span class="ts-label">驱动检查</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="ts-top-bar__body" id="mobileTsBody">
|
|
<div id="mobileTsDecision">
|
|
<div class="ts-question-header">
|
|
<span class="ts-question-icon">❓</span>
|
|
<span class="ts-question-text">WiFi适配器是否显示"已禁用"?</span>
|
|
</div>
|
|
<div class="ts-options">
|
|
<button class="ts-option ts-option--yes" onclick="selectDecision('mobile','yes')">
|
|
<span class="ts-option-icon">✅</span><span>是,已禁用</span>
|
|
</button>
|
|
<button class="ts-option ts-option--no" onclick="selectDecision('mobile','no')">
|
|
<span class="ts-option-icon">❌</span><span>否,正常</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="mobileTsInstruction" style="display:none;">
|
|
<div class="ts-instruction-header">
|
|
<span class="ts-instruction-icon">📋</span>
|
|
<span class="ts-instruction-title">正在执行:启用WiFi适配器</span>
|
|
</div>
|
|
<div class="ts-sub-steps">
|
|
<div class="ts-sub-step ts-sub-step--done">
|
|
<span class="ts-sub-dot">✓</span>
|
|
<span class="ts-sub-label">打开「设置」→「网络和Internet」</span>
|
|
</div>
|
|
<div class="ts-sub-step ts-sub-step--current">
|
|
<span class="ts-sub-dot">2</span>
|
|
<span class="ts-sub-label">点击「更改适配器选项」</span>
|
|
</div>
|
|
<div class="ts-sub-step">
|
|
<span class="ts-sub-dot">3</span>
|
|
<span class="ts-sub-label">右键WiFi适配器 → 启用</span>
|
|
</div>
|
|
</div>
|
|
<div class="ts-hint">💡 请按步骤操作,完成后坐席推进下一步</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 手机端消息列表 -->
|
|
<div class="chat-messages" id="mobileMessages">
|
|
<div class="msg msg--system">
|
|
<span class="msg__system-text">坐席 小宋 已接入会话</span>
|
|
</div>
|
|
<div class="msg msg--ai">
|
|
<div class="msg__sender"><span class="msg__ai-tag">AI回复</span></div>
|
|
<div class="msg__avatar-row">
|
|
<div class="msg__avatar msg__avatar--ai">🤖</div>
|
|
<div>
|
|
<div class="msg__bubble">您好!我是AI助手,请问有什么可以帮您的?</div>
|
|
<div class="msg__time">10:02</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="msg msg--employee">
|
|
<div class="msg__bubble">我的电脑连不上公司WiFi了</div>
|
|
<div class="msg__time">10:03</div>
|
|
</div>
|
|
<div class="msg msg--agent">
|
|
<div class="msg__avatar-row">
|
|
<div class="msg__avatar msg__avatar--agent">👨💻</div>
|
|
<div>
|
|
<div class="msg__bubble">你好,我来帮你排查。请在上方排查步骤中选择 👆</div>
|
|
<div class="msg__time">10:05</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="msg msg--system">
|
|
<span class="msg__system-text">排查步骤已同步至坐席端</span>
|
|
</div>
|
|
<div class="msg msg--agent">
|
|
<div class="msg__avatar-row">
|
|
<div class="msg__avatar msg__avatar--agent">👨💻</div>
|
|
<div>
|
|
<div class="msg__bubble">好的,我看到你选择了"是,已禁用"。请按照上方步骤操作,完成后告诉我。</div>
|
|
<div class="msg__time">10:06</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="msg msg--employee">
|
|
<div class="msg__bubble">已经启用了,但还是连不上</div>
|
|
<div class="msg__time">10:08</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ★ v1.7:手机端输入栏 — 摇铃已移至标题栏,输入栏仅保留工具栏+输入框+发送 -->
|
|
<div class="input-bar">
|
|
<div class="input-toolbar">
|
|
<button class="tool-btn" title="表情" onclick="showToolTip('😊 表情面板')">😊</button>
|
|
<button class="tool-btn" title="图片" onclick="showToolTip('🖼️ 选择图片')">🖼️</button>
|
|
<div class="tool-sep"></div>
|
|
<button class="tool-btn" title="文件" onclick="showToolTip('📎 选择文件')">📎</button>
|
|
<button class="tool-btn" title="拍照" onclick="showToolTip('📸 打开相机')">📸</button>
|
|
</div>
|
|
<div class="input-row">
|
|
<textarea class="input-field" rows="3" placeholder="请输入消息..." oninput="onInput('mobile', this)"></textarea>
|
|
<button class="send-btn" id="mobileSendBtn" disabled title="发送" onclick="sendMessage('mobile')">➤</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- 呼叫坐席弹窗 — 摇铃风格 -->
|
|
<div class="modal-overlay" id="callModal" onclick="hideCallModal(event)">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<span class="modal-header__icon">🔔</span>
|
|
<h3>正在呼叫 IT 坐席...</h3>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="modal-sending" id="modalSending">
|
|
<span class="modal-dot-flashing"></span>
|
|
<span>摇铃呼叫中,请稍候...</span>
|
|
</div>
|
|
<div class="modal-success" id="modalSuccess" style="display:none;">✅ 呼叫成功!坐席马上就来~</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="modal-btn modal-btn--cancel" onclick="hideCallModal()">取消</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 标注区 -->
|
|
<div class="annotations">
|
|
<h3>📝 H5用户端原型 v1.8</h3>
|
|
<ul>
|
|
<li>
|
|
<span class="tag tag--fix">v1.8修复</span>
|
|
<b>修复桌面端截断</b>:从820px→940px,解决输入框+趣味问答被 overflow:hidden 裁掉的问题(原内容总高~853px,820px不够)
|
|
</li>
|
|
<li>
|
|
<span class="tag tag--fix">v1.7修复</span>
|
|
<b>手机端摇铃上移</b>:从输入栏移至标题栏坐席状态右侧,与桌面端一致(🔔呼叫 胶囊按钮)
|
|
</li>
|
|
<li>
|
|
<span class="tag tag--layout">桌面端布局</span>
|
|
企微顶栏 → 标题栏(🛎️+坐席在线+🔔呼叫+主题) → 排查步骤(固定顶部) → 消息流 → 输入栏(工具栏+输入+🔔+➤) | 拖拽 | AI推送/资源/问答
|
|
</li>
|
|
<li>
|
|
<span class="tag tag--layout">手机端布局</span>
|
|
标题栏(坐席在线+🔔呼叫+主题) → 排查步骤(固定顶部) → 消息流 → 输入栏(工具栏+输入+➤)
|
|
</li>
|
|
<li>
|
|
<span class="tag tag--decision">双端差异</span>
|
|
摇铃位置统一:桌面端+手机端均在标题栏;输入栏:桌面端保留🔔+➤,手机端仅➤
|
|
</li>
|
|
<li>
|
|
<span class="tag tag--decision">规则</span>
|
|
影响显示效果的代码更新前,必须先通过原型图确认
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<script>
|
|
/** 主题切换 */
|
|
function toggleTheme() {
|
|
const html = document.documentElement;
|
|
html.setAttribute('data-theme', html.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
|
|
}
|
|
|
|
/** 排查步骤栏 收起/展开 */
|
|
function toggleTsBar(view) {
|
|
const prefix = view === 'desktop' ? 'desktop' : 'mobile';
|
|
const content = document.getElementById(prefix + 'TsContent');
|
|
const toggle = document.getElementById(prefix + 'TsToggle');
|
|
if (content.style.display === 'none') {
|
|
content.style.display = '';
|
|
toggle.textContent = '▼ 收起';
|
|
toggle.classList.remove('ts-top-bar__toggle--collapsed');
|
|
} else {
|
|
content.style.display = 'none';
|
|
toggle.textContent = '▲ 展开';
|
|
toggle.classList.add('ts-top-bar__toggle--collapsed');
|
|
}
|
|
}
|
|
|
|
/** 决策节点选择 */
|
|
function selectDecision(view, choice) {
|
|
const prefix = view === 'desktop' ? 'desktop' : 'mobile';
|
|
const decision = document.getElementById(prefix + 'TsDecision');
|
|
const instruction = document.getElementById(prefix + 'TsInstruction');
|
|
const buttons = decision.querySelectorAll('.ts-option');
|
|
buttons.forEach(btn => { btn.disabled = true; btn.style.pointerEvents = 'none'; });
|
|
if (choice === 'yes') buttons[0].classList.add('ts-option--selected-yes');
|
|
else buttons[1].classList.add('ts-option--selected-no');
|
|
setTimeout(() => { decision.style.display = 'none'; instruction.style.display = 'block'; }, 400);
|
|
}
|
|
|
|
/** 切换资源标签页 */
|
|
function switchResourceTab(tab, tabEl) {
|
|
tabEl.parentElement.querySelectorAll('.resources__tab').forEach(t => t.classList.remove('resources__tab--active'));
|
|
tabEl.classList.add('resources__tab--active');
|
|
const content = document.getElementById('resourceContent');
|
|
if (tab === 'process') {
|
|
content.innerHTML = '<div class="resource-item"><div class="resource-item__icon">📋</div><div class="resource-item__info"><div class="resource-item__name">IT设备申请</div><div class="resource-item__desc">电脑/显示器/外设</div></div></div><div class="resource-item"><div class="resource-item__icon">🔑</div><div class="resource-item__info"><div class="resource-item__name">权限申请</div><div class="resource-item__desc">文件夹/系统访问权限</div></div></div><div class="resource-item"><div class="resource-item__icon">📞</div><div class="resource-item__info"><div class="resource-item__name">VPN申请</div><div class="resource-item__desc">远程办公网络连接</div></div></div>';
|
|
} else {
|
|
content.innerHTML = '<div class="resource-item"><div class="resource-item__icon">📄</div><div class="resource-item__info"><div class="resource-item__name">Office 365</div><div class="resource-item__desc">办公套件</div></div></div><div class="resource-item"><div class="resource-item__icon">📊</div><div class="resource-item__info"><div class="resource-item__name">Adobe Acrobat</div><div class="resource-item__desc">PDF编辑工具</div></div></div><div class="resource-item"><div class="resource-item__icon">📱</div><div class="resource-item__info"><div class="resource-item__name">企业微信</div><div class="resource-item__desc">即时通讯工具</div></div></div>';
|
|
}
|
|
}
|
|
|
|
/** 趣味问答选择 */
|
|
function selectQuizOption(option, isCorrect) {
|
|
document.querySelectorAll('.fun-quiz__option').forEach(opt => { opt.style.pointerEvents = 'none'; });
|
|
if (isCorrect) {
|
|
option.classList.add('fun-quiz__option--correct');
|
|
setTimeout(() => alert('✅ 答对啦!+10积分'), 300);
|
|
} else {
|
|
option.classList.add('fun-quiz__option--wrong');
|
|
document.querySelectorAll('.fun-quiz__option')[0].classList.add('fun-quiz__option--correct');
|
|
setTimeout(() => alert('❌ 答错了!正确答案是 A. 8001'), 300);
|
|
}
|
|
}
|
|
|
|
/** 呼叫坐席弹窗 */
|
|
function showCallModal() {
|
|
document.getElementById('callModal').classList.add('modal-overlay--visible');
|
|
setTimeout(() => {
|
|
document.getElementById('modalSending').style.display = 'none';
|
|
document.getElementById('modalSuccess').style.display = 'block';
|
|
}, 2500);
|
|
}
|
|
function hideCallModal(e) {
|
|
if (e && e.target !== e.currentTarget) return;
|
|
document.getElementById('callModal').classList.remove('modal-overlay--visible');
|
|
setTimeout(() => {
|
|
document.getElementById('modalSending').style.display = 'flex';
|
|
document.getElementById('modalSuccess').style.display = 'none';
|
|
}, 300);
|
|
}
|
|
|
|
/** 输入框监听 — 统一桌面端+手机端 */
|
|
function onInput(view, field) {
|
|
const btnId = view === 'desktop' ? 'desktopSendBtn' : 'mobileSendBtn';
|
|
const btn = document.getElementById(btnId);
|
|
btn.disabled = !field.value.trim();
|
|
}
|
|
|
|
/** 发送消息 — 统一桌面端+手机端 */
|
|
function sendMessage(view) {
|
|
const messagesId = view === 'desktop' ? 'desktopMessages' : 'mobileMessages';
|
|
const messages = document.getElementById(messagesId);
|
|
const container = view === 'desktop' ? document.getElementById('desktopLeft') : messages.closest('.chat-panel');
|
|
const textarea = container.querySelector('.input-row textarea');
|
|
|
|
if (!textarea || !textarea.value.trim()) return;
|
|
|
|
const msgHtml = '<div class="msg msg--employee" style="animation: bubble-in 0.3s ease-out"><div class="msg__bubble">' + escapeHtml(textarea.value) + '</div><div class="msg__time">刚刚</div></div>';
|
|
|
|
const sysMsg = messages.querySelector('.msg--system:last-child');
|
|
if (sysMsg) {
|
|
sysMsg.insertAdjacentHTML('beforebegin', msgHtml);
|
|
} else {
|
|
messages.insertAdjacentHTML('beforeend', msgHtml);
|
|
}
|
|
|
|
textarea.value = '';
|
|
onInput(view, textarea);
|
|
messages.scrollTop = messages.scrollHeight;
|
|
}
|
|
|
|
/** HTML转义 */
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
/** 工具按钮提示 */
|
|
function showToolTip(text) {
|
|
alert(text);
|
|
}
|
|
|
|
/* ============================================================================
|
|
拖拽调整 — 左右栏宽度
|
|
============================================================================ */
|
|
(function() {
|
|
const handle = document.getElementById('resizeHandleV');
|
|
const left = document.getElementById('desktopLeft');
|
|
const right = document.getElementById('desktopRight');
|
|
const body = document.getElementById('desktopBody');
|
|
if (!handle || !body) return;
|
|
|
|
let isDragging = false;
|
|
handle.addEventListener('mousedown', startDrag);
|
|
|
|
function startDrag(e) {
|
|
isDragging = true;
|
|
handle.classList.add('resize-handle-v--active');
|
|
document.body.style.cursor = 'col-resize';
|
|
document.body.style.userSelect = 'none';
|
|
document.addEventListener('mousemove', onDrag);
|
|
document.addEventListener('mouseup', stopDrag);
|
|
e.preventDefault();
|
|
}
|
|
|
|
function onDrag(e) {
|
|
if (!isDragging) return;
|
|
const rect = body.getBoundingClientRect();
|
|
const offsetX = e.clientX - rect.left;
|
|
const totalWidth = rect.width;
|
|
const leftWidth = Math.max(280, Math.min(totalWidth - 200, offsetX));
|
|
const rightWidth = totalWidth - leftWidth - 6;
|
|
left.style.flex = 'none';
|
|
left.style.width = leftWidth + 'px';
|
|
right.style.width = rightWidth + 'px';
|
|
}
|
|
|
|
function stopDrag() {
|
|
isDragging = false;
|
|
handle.classList.remove('resize-handle-v--active');
|
|
document.body.style.cursor = '';
|
|
document.body.style.userSelect = '';
|
|
document.removeEventListener('mousemove', onDrag);
|
|
document.removeEventListener('mouseup', stopDrag);
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
</body>
|
|
</html> |