const icon=n=>``; if (/\bQt/i.test(navigator.userAgent) || window.qtBridge || typeof qt !== "undefined") { document.documentElement.classList.add("embedded"); } window.STATE = window.STATE || { view: "auto", demo: false, ready: false, listening: false }; function esc(value){ return String(value ?? "").replace(/[&<>"']/g, ch => ({ "&":"&","<":"<",">":">",'"':""","'":"'" }[ch])); } function bridge(){ return window.qtBridge || null; } function callBridge(name, ...args){ const api = bridge(); if (!api || typeof api[name] !== "function") return false; api[name](...args); return true; } function fieldNum(id, fallback){ const el = document.getElementById(id); if (!el || el.value === "" || el.value == null) return fallback; const n = Number(el.value); return Number.isFinite(n) ? n : fallback; } function collectAiPayload(extra){ const ai = STATE.ai || {}; const rawLength = fieldNum("ai-length", [10,55,90][Number(ai.replyLengthIndex ?? 1)] || 55); const replyLength = rawLength <= 33 ? 0 : (rawLength < 75 ? 1 : 2); const payload = { name: (document.getElementById("ai-name") || {}).value || ai.name || "", temperature: fieldNum("ai-temp", Math.round(Number(ai.temperature || 0.35) * 100)) / 100, context: fieldNum("ai-context", fieldNum("auto-context", Number(ai.context || 8))), maxTokens: fieldNum("ai-tokens", Number(ai.maxTokens || 500)), mcpRounds: fieldNum("ai-mcp-rounds", Number(ai.mcpRounds || 5)), replyLength: replyLength, }; return JSON.stringify(Object.assign(payload, extra || {})); } function markAiDirty(){ const status = document.querySelector("[data-config-status]"); if (status) status.innerHTML = '有未保存更改'; } function collectAutomationPayload(){ const a = STATE.automation || {}; return JSON.stringify({ poll: fieldNum("auto-poll", Number(a.poll || 2)), batch: fieldNum("auto-batch", Number(a.batch || 20)), delay: fieldNum("auto-delay", Number(a.delay || 1)), idle: fieldNum("auto-idle", Number(a.idle || 5)), context: fieldNum("auto-context", Number(a.context || 8)), }); } function collectSystemPayload(){ const s = STATE.system || {}; return JSON.stringify({ language: (document.getElementById("sys-language") || {}).value || s.language || "简体中文", scale: (document.getElementById("sys-scale") || {}).value || s.scale || "自动", retention: fieldNum("sys-retention", Number(s.retention || 90)), }); } function sortLabel(mode){ return ({queue:"入队顺序", wait:"等待时长", name:"客户名称"})[mode] || "入队顺序"; } var people=[["高","高瑞@微信","处理中","00:00:12",""],["小","一个小迷糊@微信","等待中","00:01:45","green"],["李","李先生@微信","等待中","00:02:10",""] ,["陈","陈女士@微信","待重试","—","violet"],["张","张小明@微信","等待中","00:03:22","cyan"]]; var listening=false; var head=(title,sub,actions)=>`

${title}

${sub}

${actions}
`; var connected=(extra="",primary="")=>`企业微信已连接AI 服务正常${extra}`; var ribbon=items=>`
${items.map(x=>`
${icon(x[2])}
${x[0]}${x[1]}
`).join("")}
`; var queueList=(archive=false)=>`
${people.map((p,i)=>`
${p[0]}
${p[1]}${archive?(i===0?"请问你们的灵芝孢子粉怎么服用…":i===1?"每天吃几次比较合适?":i===2?"有不良反应吗?":"会话已归档"):`${p[2]}`}
${archive?["16:31","16:18","15:42","14:20","13:35"][i]:p[3]}${archive?`${i===2?"已转人工":"AI 已回复"}`:`${icon("message")} ${i===3?1:0}`}
`).join("")}
`; var activities=(more="查看完整日志")=>`
${[["16:33:27","扫描未读","检测到客户未读消息","activity","成功",""],["16:33:28","提取聊天记录","已提取最近 6 条聊天记录","log","成功",""],["16:33:29","AI 服务","正在请求 AI 生成回复","brain","进行中","blue"],["16:33:31","人工保护","检测到人工鼠标操作,暂停 5 秒","user","警告","orange"]].map(x=>`
${icon(x[3])}
${x[1]}

${x[2]}

● ${x[4]}
`).join("")}
`; var journey=()=>`
${[["扫描未读","已完成","0.3s"],["提取聊天记录","已完成","1.2s"],["合并连续消息","已完成","0.4s"],["发送至 AI","已完成","0.6s"],["生成回复","进行中","2.4s"],["回填企业微信","等待","—"],["自动发送与归档","等待","—"]].map((x,i)=>`
4?"wait":""}">
${i<4?"✓":i+1}
${x[0]}${x[1]}
${x[2]}
`).join("")}
`; var statusCells=items=>`
${items.map(x=>`
${icon(x[0])}
${x[1]}${x[2]}
`).join("")}
`; function autoView(){return `
${head("桌面自动化控制台","监听企业微信未读消息,并由 AI 自动生成与发送回复",connected(`${icon("send")}自动发送`,"danger"))}${ribbon([["监听状态","运行中","activity","green"],["排队","3","users"],["今日回复","128","message"],["失败","1","alert","red"]])}

任务队列

3${icon("filter")}${icon("sort")}
${queueList()}

当前处理任务

${icon("user")}高瑞@微信已读取 6 条消息AI 生成中
复制的聊天内容
请问你们的灵芝孢子粉怎么服用?
每天吃几次比较合适?
有什么注意事项吗?
AI 回复预览
您好!灵芝孢子粉建议每日 1–2 次,每次 2–3 克,温水冲服,饭前半小时或睡前服用效果更佳。
如有特殊体质或正在服药,建议咨询专业医生后再服用哦。
${icon("shield")}置信度 96%${icon("clock")}模型耗时 2.4s

自动化执行状态

总耗时 5.01s
${journey()}

企业微信窗口状态

${[["folder","窗口","已识别"],["message","当前会话","高瑞@微信"],["monitor","DPI","200%"],["shield","人工保护","5 秒"],["refresh","最小化恢复","已开启"]].map(x=>`
${icon(x[0])}${x[1]}${x[2]}
`).join("")}

实时事件

${activities()}
`} function queueView(){return `
${head("任务队列","查看排队、处理中与待重试的自动回复任务",connected(`${icon("send")}自动发送`,"danger"))}${ribbon([["处理中","1","check","","blue"],["等待中","3","clock"],["待重试","1","refresh","orange"],["平均等待","12s","clock","green"]])}

全部任务

${queueList()}

任务详情

客户高瑞@微信
会话 ID7bc26546… ${icon("copy")}
已等待12 秒
重试0 次
来源消息
请问你们的灵芝孢子粉怎么服用?
✦ AI 生成回复中
${[["入队","16:32:11"],["读取消息","16:32:11"],["请求 AI","16:32:12"],["生成回复","进行中"],["回填发送","等待中"],["完成","等待中"]].map((x,i)=>`
${i<3?"✓":i+1}
${x[0]}${x[1]}
`).join("")}

调度信息

优先级普通
${icon("clock")}
预计完成3 秒
${icon("shield")}
人工保护已开启
${icon("refresh")}
下次重试

任务执行记录

${activities()}
`} function archiveView(){return `
${head("会话归档","保存客户上下文、自动回复与回访线索",`企业微信已连接AI 服务正常`)}

最近会话

${queueList(true)}

会话记录

${icon("user")}高瑞@微信6 条消息AI 已回复${icon("clock")}16:31 更新
${icon("user")}
请问你们的灵芝孢子粉怎么服用?
${icon("bot")}
每天吃几次比较合适?
${icon("user")}
有什么注意事项吗?
${icon("bot")}
温水冲服,饭前半小时或睡前服用效果更佳。
如有特殊体质或正在服药,建议咨询专业医生后再服用哦。
${icon("user")}
好的,谢谢!
${icon("bot")}
不客气!如有其他问题,随时为您服务~

客户记忆

饮食控制体重管理长期回访
客户关注灵芝孢子粉的服用方法与注意事项,希望优化服用时间与剂量,同时注重产品安全性与体质适配。
◔ 上下文 8 轮

业务沉淀

挂号登记已登记潜在客户
1 次 ✓
回访线索创建回访计划
1 条 ✓
${icon("user")}
人工跟进未分配客服
0 次 ·

最近更新

${activities("复制全部记录")}
`} function aiView(){return `
${head("AI 设置","配置模型、客服人格、知识库与工具能力",`配置已同步`)}

客服人格

AI
服务风格:温和专业简洁
✧ 实时预览

您好!我是甄养堂贴心管家,
很高兴为您服务 😊

请问有什么可以帮您的吗?

✣ 模型引擎

▰ 企业知识库

1,284个知识片段
● 刚刚同步✓ 已连接

◇ MCP 工具

单次最多调用 5 个工具 ⓘ
挂号登记
已启用
客户查询
已启用
回访记录
已启用

${icon("shield")} 安全边界

🛡 不做医疗诊断
💊 不修改用药方案
♙ 高风险转人工
当前模式:${icon("shield")}严格模式

配置状态

${statusCells([["cloud","云端模型正常","最后检查:刚刚"],["folder","知识库已同步","1,284 个知识片段"],["folder","3 个工具可用","全部运行正常"],["shield","安全策略已生效","严格模式"]])}
`} function automationView(){return `
${head("自动化设置","配置企业微信监听、消息合并与自动发送规则",`企业微信已识别规则已生效`)}

监听与发送策略

${icon("activity")} ● 规则运行中
${[["activity","扫描未读"],["log","提取消息"],["folder","合并消息"],["brain","请求 AI"],["send","回填发送"]].map(x=>`
${icon(x[0])}
${x[1]}
`).join("")}
${icon("clock")}扫描间隔 2 秒
⌛ 连续消息等待 20 秒
${icon("clock")}发送前等待 1 秒

企业微信窗口

▣ 主窗口:● 已识别
${icon("user")} 当前账号:甄养堂客服
◎ DPI:200%
${icon("monitor")} 最小化恢复:● 已开启

人机共存

启用人工操作保护
鼠标静止 5 秒 后恢复
${icon("bot")}
AI 运行中

检测到人工操作
AI 暂停

消息处理

✓ 同一客户连续消息自动合并
✓ 保留最近 8 轮上下文8 轮
✓ 一次只处理 1 个会话1 个

异常与兜底

${icon("clock")}AI 超时:重试 2 次2 次
${icon("alert")}发送失败:自动重试已开启
${icon("message")}固定回复:在的,请稍等编辑

高风险转人工

● 已开启
⚕ 诊断◇ 用药调整¥ 投诉退款

启动前检查

${statusCells([["check","企业微信已登录","检查完成"],["cloud","AI 服务正常","检查完成"],["activity","窗口坐标已校准","检查完成"],["shield","规则配置有效","检查完成"]])}
`} function logsView(){return `
${head("运行日志","实时追踪连接、消息识别、AI 调用与自动发送事件",`监控中`)}${ribbon([["企业微信","99.9%","message","green"],["AI 成功率","98.6%","brain","","blue"],["平均响应","2.4s","clock","","blue"],["警告","1","alert","red"]])}

实时事件流

${[["16:33:27","未读扫描","检测到客户未读消息","activity","成功","green"],["16:33:28","提取聊天记录","已读取最近 6 条消息","message","成功","green"],["16:33:29","AI 服务","正在生成回复","brain","进行中",""],["16:33:31","人工保护","检测到鼠标操作,暂停 5 秒","user","警告","orange"],["16:33:36","自动发送","回复发送成功","send","成功","green"]].map(x=>`
${icon(x[3])}
${x[1]}${x[2]}
${x[4]}
`).join("")}

系统健康

${[["企业微信连接","正常"],["AI 服务","正常"],["窗口识别","正常"]].map(x=>`
${icon("check")}
${x[0]}${x[1]}
`).join("")}
${icon("clock")}运行时长 02:18:46

当前回复链路

${[["activity","扫描未读","0.3s"],["message","读取消息","1.2s"],["brain","请求 AI","2.4s"],["send","回填发送","0.6s"]].map(x=>`
${icon(x[0])}
${x[1]}${x[2]}
`).join("")}

事件详情

${icon("user")}
人工保护

检测到人工鼠标操作,自动回复暂停 5 秒

模块:人机共存会话:高瑞@微信已自动恢复

异常追踪

${icon("alert")}
发送失败1
${icon("clock")}
模型超时0
${icon("monitor")}
窗口丢失0

最近活动

${activities("查看完整记录")}
`} function systemView(){return `
${head("系统设置","管理软件启动、数据存储、通知与系统维护",`当前版本 v2.0 ⓘ`)}

基础设置

${icon("power")}开机自动启动
${icon("activity")}启动后自动监听
最小化到系统托盘
${icon("log")}关闭窗口时保持后台运行
界面语言: 简体中文
${icon("monitor")}缩放比例: 自动

数据与存储

286MB 已使用
● 会话归档128 MB
● 运行日志86 MB
● 缓存数据72 MB
数据保留90 天 ⌄

通知提醒

${icon("send")}发送失败提醒
模型超时提醒
${icon("user")}需要人工跟进
企业微信连接中断
发送失败提醒消息发送失败,已加入重试队列

安全与隐私

${icon("shield")}敏感信息脱敏:已开启 ●
${icon("lock")}本地数据加密:已开启 ●
${icon("lock")}日志隐藏聊天正文:已开启 ●
${icon("log")}退出时清理剪贴板:已开启 ●

网络与服务

${icon("cloud")}云端 AI:已连接 ●
${icon("folder")}企业知识库:已连接 ●
网络延迟:28ms ●

维护与诊断

${icon("refresh")}
检查更新已是最新版本
导出诊断导出系统诊断报告
恢复默认设置重置所有设置项
${icon("shield")}
查看许可信息查看软件许可详情

系统状态

${statusCells([["shield","配置已保存","所有设置已生效"],["cloud","数据已备份","最近备份:16:33:28"],["shield","安全策略正常","所有安全策略已启用"],["monitor","后台服务运行中","系统运行状态良好"]])}
`} var views={auto:autoView,queue:queueView,archive:archiveView,ai:aiView,automation:automationView,logs:logsView,system:systemView}; var glyphIcons=[["✦","sparkles"],["✧","sparkles"],["✣","brain"],["⚑","flag"],["▣","clipboard"],["☎","phone"],["⌕","search"],["▤","clipboard"],["◇","package"],["🛡","shield"],["💊","pill"],["♙","users"],["⌛","hourglass"],["◎","globe"],["⚕","shield"],["¥","coins"],["⌁","wifi"],["♟","bell"],["▰","tray"],["▷","play"],["↻","refresh"],["➤","cursor"],["Ⅱ","pause"],["◔","clock"],["ⓘ","info"],["⌄","chevron"]]; function polishedIcons(html){return glyphIcons.reduce((value,[glyph,name])=>value.replaceAll(glyph,icon(name)),html)} function render(name){ if(!views[name])name="auto"; document.querySelectorAll("[data-view]").forEach(b=>b.classList.toggle("active",b.dataset.view===name)); document.getElementById("main").innerHTML=polishedIcons(views[name]()); const listen=document.querySelector('[data-action="toggle-listen"]'); if(listen)listen.innerHTML=listening?`${icon("pause")}暂停监听`:`${icon("play")}恢复监听`; location.hash=name; } function toast(msg="操作已完成"){const t=document.getElementById("toast");t.textContent=msg;t.classList.add("show");clearTimeout(window.__toast);window.__toast=setTimeout(()=>t.classList.remove("show"),1600)} document.addEventListener("click",e=>{if(window.STATE&&window.STATE.ready&&!window.STATE.demo&&bridge())return;const nav=e.target.closest("[data-view]");if(nav){render(nav.dataset.view);return}const action=e.target.closest("[data-action]");if(action){const a=action.dataset.action;if(a==="toggle-listen"){listening=!listening;document.getElementById("orb").classList.toggle("paused",!listening);document.getElementById("orb-label").textContent=listening?"监听中":"已暂停";render(location.hash.slice(1));toast(listening?"已恢复监听":"监听已暂停")}else if(a==="logs")render("logs");else if(a==="clear-logs"){const list=document.getElementById("log-list");if(list)list.innerHTML='
日志已清空
';toast("日志已清空")}else toast()}const sw=e.target.closest(".switch");if(sw)sw.classList.toggle("on");const pill=e.target.closest(".filter-pill,.tab");if(pill){[...pill.parentElement.children].forEach(x=>x.classList.remove("active"));pill.classList.add("active")}}); function fit(){const s=Math.min(innerWidth/1630,innerHeight/965);document.getElementById("stage").style.setProperty("--scale",String(s))} const _queueList = queueList; const _activities = activities; const _connected = connected; const _journey = journey; connected = function(extra="", primary=""){ const wecom = STATE.wecomLabel || (STATE.wecomConnected ? "企业微信已连接" : "企业微信未连接"); const ai = STATE.aiLabel || (STATE.aiOk === false ? "AI 服务异常" : "AI 服务正常"); const listenLabel = STATE.listening ? `${icon("pause")}暂停监听` : `${icon("play")}恢复监听`; const wecomLed = STATE.wecomConnected ? "" : "off"; const aiLed = STATE.aiOk === false ? "off" : ""; return `${esc(wecom)}${esc(ai)}${extra}`; }; queueList = function(archive=false){ if (STATE.demo) return _queueList(archive); const rows = archive ? (STATE.archives || []) : (STATE.people || []); if (!rows.length){ const title = archive ? "暂无会话档案" : "当前没有待处理任务"; const hint = archive ? "新的客户会话会自动出现在这里" : "所有客户消息均已完成"; return `
${icon("check")}
${title}${hint}
`; } return `
${rows.map((p,i)=>{ const selectedKey = archive ? STATE.selectedArchive : STATE.selectedKey; const active = p.active || p.key === selectedKey || (!selectedKey && i===0); const preview = archive ? (p.preview || "会话已归档") : `${esc(p.status || "")}`; const meta = archive ? `${esc(p.time || "")}${esc(p.badge || "AI 已回复")}` : `${esc(p.wait || "")}${icon("message")} ${p.bubbles || 0}`; return `
${esc(p.avatar || "客")}
${esc(p.name || "")}${preview}
${meta}
`; }).join("")}
`; }; activities = function(more="查看完整日志"){ const items = STATE.demo ? null : (STATE.activities || []); if (STATE.demo || !items) return _activities(more); const cards = items.length ? items.map(x=>{ const tone = x.tone || ""; const color = tone==="orange"?"var(--orange)":tone==="blue"?"var(--blue)":"var(--green)"; return `
${icon(x.icon || "activity")}
${esc(x.title || "")}

${esc(x.detail || "")}

● ${esc(x.state || "")}
`; }).join("") : `
暂无执行记录
`; const action = more === "复制全部记录" ? "copy-archive" : (more === "查看完整记录" ? "full-log" : "logs"); return `
${cards}
`; }; journey = function(){ if (STATE.demo) return _journey(); const items = STATE.journey || []; if (!items.length){ return `
等待新的自动回复任务
`; } return `
${STATE.journey.map((x,i)=>{ const mode = x.mode || (x.active ? "active" : x.wait ? "wait" : ""); const token = x.done ? "✓" : String(i+1); return `
${token}
${esc(x.title)}${esc(x.status)}
${esc(x.time)}
`; }).join("")}
`; }; const _autoView = autoView; const _queueView = queueView; const _archiveView = archiveView; const _aiView = aiView; const _automationView = automationView; const _logsView = logsView; const _systemView = systemView; function liveRibbonAuto(){ const m = STATE.metrics || {}; return ribbon([ ["监听状态", m.listen || (STATE.listening ? "运行中" : "已停止"), "activity", STATE.listening ? "green" : "", "", "listen"], ["排队", m.queue || "0", "users", "", "", "queue"], ["今日回复", m.today || "0", "message", "", "", "today"], ["失败", m.failed || "0", "alert", Number(m.failed) > 0 ? "red" : "", "", "failed"], ]); } function liveRibbonQueue(){ const m = STATE.metrics || {}; return ribbon([ ["处理中", m.processing || "0", "check", "", "blue", "processing"], ["等待中", m.waiting || "0", "clock", "", "", "waiting"], ["待重试", m.retry || "0", "refresh", "orange", "", "retry"], ["平均等待", m.avgWait || "0s", "clock", "green", "", "avgWait"], ]); } function liveRibbonLogs(){ const m = STATE.metrics || {}; return ribbon([ ["企业微信", m.wecomHealth || "待连接", "message", STATE.wecomConnected ? "green" : "", "", "wecomHealth"], ["AI 成功率", m.aiRate || "—", "brain", "", "blue", "aiRate"], ["平均响应", m.avgResp || "—", "clock", "", "blue", "avgResp"], ["警告", m.warnings || "0", "alert", Number(m.warnings) > 0 ? "red" : "", "", "warnings"], ]); } function currentTaskCard(){ const task = STATE.task; if (!task){ return `

当前处理任务

暂无处理中的任务新的客户消息入队后会显示在这里
`; } const messages = (task.messages || []).map(x=>`
${esc(x.text || "")}
`).join("") || `
等待读取客户消息
`; const answer = task.answer ? `
${esc(task.answer).replace(/\n/g,"
")}
` : `
尚未生成回复
`; return `

当前处理任务

${icon("user")}${esc(task.name || "")}${esc(task.messageCount || "已读取消息")}${esc(task.action || "")}
复制的聊天内容
${messages}
AI 回复预览
${answer}
${icon("shield")}置信度 ${esc(task.confidence || "—")}${icon("clock")}模型耗时 ${esc(task.latency || "—")}
`; } function windowStatusCard(){ const stats = STATE.windowStats || [["folder","窗口", STATE.wecomConnected ? "已识别" : "未识别"],["message","当前会话", (STATE.task && STATE.task.name) || "—"],["monitor","DPI", STATE.dpi || "—"],["shield","人工保护", STATE.idleLabel || "—"],["refresh","最小化恢复", "已开启"]]; return `

企业微信窗口状态

${stats.map(x=>`
${icon(x[0])}${esc(x[1])}${esc(x[2])}
`).join("")}
`; } function queueDetailPanel(){ const task = STATE.task; if (!task){ return `

任务详情

暂无选中任务选择左侧任务后查看来源消息与处理进度
`; } const steps = task.steps || [["入队","等待中"],["读取消息","等待中"],["请求 AI","等待中"],["生成回复","等待中"],["回填发送","等待中"],["完成","等待中"]]; const active = Number(task.stepIndex ?? -1); const process = steps.map((x,i)=>`
${i${esc(x[0])}${esc(x[1])}
`).join(""); const message = (task.messages && task.messages[0]) || {time:"", text:"队列为空时,选择任务后会在这里显示来源消息。"}; return `

任务详情

客户${esc(task.name || "暂无选中任务")}
会话 ID${esc(task.sessionDisplay || task.sessionId || "--")} ${icon("copy")}
已等待${esc(task.wait || "--")}
重试${esc(task.retries || "0 次")}
来源消息
${esc(message.text || "")}
${icon("sparkles")} ${esc(task.action || "等待新任务")}
${process}
`; } function schedulePanel(){ const s = (STATE.task && STATE.task.schedule) || {priority:"—", eta:"—", protect:"—", retry:"—"}; return `

调度信息

${icon("flag")}
优先级${esc(s.priority)}
${icon("clock")}
预计完成${esc(s.eta)}
${icon("shield")}
人工保护${esc(s.protect)}
${icon("refresh")}
下次重试${esc(s.retry)}
`; } autoView = function(){ if (STATE.demo) return _autoView(); const count = (STATE.people || []).length; const waiting = (STATE.metrics && STATE.metrics.waiting) || "0"; return `
${head("桌面自动化控制台","监听企业微信未读消息,并由 AI 自动生成与发送回复",connected(``,"danger"))}${liveRibbonAuto()}

任务队列

${esc(waiting)}${icon("filter")}${icon("sort")}
${queueList()}
${currentTaskCard()}

自动化执行状态

${esc(STATE.journeyTotal || "")}
${journey()}
${windowStatusCard()}

实时事件

${activities()}
`; }; queueView = function(){ if (STATE.demo) return _queueView(); const count = (STATE.people || []).length; const filter = STATE.queueFilter || "全部"; const pills = ["全部","处理中","等待中","待重试"].map(name=>``).join(""); return `
${head("任务队列","查看排队、处理中与待重试的自动回复任务",connected(``,"danger"))}${liveRibbonQueue()}

全部任务

${pills}
${queueList()}
${queueDetailPanel()}${schedulePanel()}

任务执行记录

${activities()}
`; }; archiveView = function(){ if (STATE.demo) return _archiveView(); const rows = STATE.archives || []; const chat = STATE.chat || []; const selected = rows.find(x=>x.key===STATE.selectedArchive) || rows[0] || {}; const chatHtml = chat.length ? chat.map(x=>`
${icon(x.role==="assistant"?"bot":"user")}
${esc(x.text || "")}
`).join("") : `
选择会话后显示聊天记录
`; const tags = (STATE.memory && STATE.memory.tags || []).map((t,i)=>`${esc(t)}`).join("") || `暂无标签`; const settle = (STATE.settle || []).map(x=>`
${x.iconHtml || icon("clipboard")}
${esc(x.title)}${esc(x.hint)}
${esc(x.value)}
`).join(""); const filter = STATE.archiveFilter || "全部会话"; const dateValue = STATE.archiveDate || ""; return `
${head("会话归档","保存客户上下文、自动回复与回访线索",`${esc(STATE.wecomLabel || "企业微信")}${esc(STATE.aiLabel || "AI 服务")}`)}
${["全部会话","今日","AI 已回复","已转人工"].map(name=>``).join("")}

最近会话

${queueList(true)}

会话记录

${icon("user")}${esc(selected.name || "未选择")}${esc(selected.count || "0")} 条消息${esc(selected.badge || "")}${icon("clock")}${esc(selected.time || "")}
${chatHtml}

客户记忆

${tags}
${esc((STATE.memory && STATE.memory.text) || "选择会话后显示长期上下文。")}
${icon("clock")} 上下文 ${esc((STATE.memory && STATE.memory.rounds) || 0)} 轮

业务沉淀

${settle || "
暂无业务沉淀
"}

最近更新

${activities("复制全部记录")}
`; }; aiView = function(){ if (STATE.demo) return _aiView(); const ai = STATE.ai || {}; const toolsOn = ai.tools || [true, true, true]; const names = ["挂号登记","客户查询","回访记录"]; const toolIcons = ["clipboard","search","clipboard"]; const tab = STATE.aiTab || "基础设置"; const tabs = ["基础设置","知识与工具","安全策略"].map(n=>``).join(""); const lengthIndex = Number(ai.replyLengthIndex ?? 1); const lengthLabel = ai.replyLength || ["短","中等","长"][lengthIndex] || "中等"; const tempVal = Number(ai.temperature || 0.35); return `
${head("AI 设置","配置模型、客服人格、知识库与工具能力",`配置已同步`)}
${tabs}

客服人格

AI
服务风格:温和专业简洁
${icon("sparkles")} 实时预览

您好!我是甄养堂${esc(ai.name || "贴心管家")},
很高兴为您服务 😊

请问有什么可以帮您的吗?

${icon("brain")} 模型引擎

tokens

${icon("tray")} 企业知识库

${esc(ai.knowledge || "0")}个 MCP 服务
● ${esc(ai.syncAt || "尚未同步")}✓ ${Number(ai.knowledge||0)?"已连接":"未配置"}

${icon("package")} MCP 工具

单次最多调用 个工具
${names.map((n,i)=>`
${icon(toolIcons[i])}
${n}
${toolsOn[i]?"已启用":"未启用"}
`).join("")}

${icon("link")} MCP 配置

服务数量${esc(ai.knowledge || "0")}
工具开关${toolsOn.filter(Boolean).length ? "已启用" : "未启用"}

${icon("shield")} 安全边界

${icon("shield")} 不做医疗诊断
${icon("pill")} 不修改用药方案
${icon("users")} 高风险转人工

转人工规则

${icon("shield")} 诊断${icon("package")} 用药调整${icon("coins")} 投诉退款

当前模式

${icon("shield")}严格模式

配置状态

${statusCells([["cloud", STATE.aiOk ? "云端模型正常" : "AI 服务异常", `最后同步:${esc(ai.syncAt || "尚未同步")}`],["folder","MCP 工具配置",`${esc(ai.knowledge || "0")} 个服务`],["folder",`${esc(ai.toolCount || 0)} 个工具可用`, toolsOn.filter(Boolean).length ? "已启用" : "未启用"],["shield","安全策略已生效","严格模式"]])}
`; }; // Keep the live WebChannel pages on the exact HTML reference structure. Data // and actions are dynamic, but no extra cards or alternate tab layouts are // introduced here. archiveView = function(){ if (STATE.demo) return wireDemoArchive(_archiveView()); const rows = STATE.archives || []; const chat = STATE.chat || []; const selected = rows.find(x=>x.key===STATE.selectedArchive) || rows[0] || {}; const chatHtml = chat.length ? chat.map(x=>`
${icon(x.role==="assistant"?"bot":"user")}
${esc(x.text || "").replace(/\n/g,"
")}
`).join("") : `
选择会话后显示聊天记录
`; const tags = (STATE.memory && STATE.memory.tags || []).map((tag,index)=>`${esc(tag)}`).join("") || `暂无标签`; const settleTokens = ["▣","☎",icon("user")]; const settleStyles = ["","background:linear-gradient(145deg,#9d7cff,#6e5be5)","background:linear-gradient(145deg,#ffc65a,#ff941f)"]; const settle = (STATE.settle || []).map((item,index)=>`
${settleTokens[index] || icon("clipboard")}
${esc(item.title)}${esc(item.hint)}
${esc(item.value)}
`).join(""); const filter = STATE.archiveFilter || "全部会话"; const now = new Date(); const currentDate = `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,"0")}-${String(now.getDate()).padStart(2,"0")}`; const dateLabel = STATE.archiveDate || currentDate; const filterButtons = ["全部会话","今日","AI 已回复","已转人工"].map(name=>``).join(""); return `
${head("会话归档","保存客户上下文、自动回复与回访线索",`${esc(STATE.wecomLabel || "企业微信")}${esc(STATE.aiLabel || "AI 服务")}`)}
${filterButtons}

最近会话

${queueList(true)}

会话记录

${icon("user")}${esc(selected.name || "未选择")}${esc(selected.count || "0")} 条消息${esc(selected.badge || "")}${icon("clock")}${esc(selected.time || "")} 更新
${chatHtml}

客户记忆

${tags}
${esc((STATE.memory && STATE.memory.text) || "选择会话后显示长期上下文。").replace(/\n/g,"
")}
◔ 上下文 ${esc((STATE.memory && STATE.memory.rounds) || 0)} 轮

业务沉淀

${settle || "
暂无业务沉淀
"}

最近更新

${activities("复制全部记录")}
`; }; aiView = function(){ if (STATE.demo) return wireDemoAi(_aiView()); const ai = STATE.ai || {}; const toolsOn = ai.tools || [true,true,true]; const names = ["挂号登记","客户查询","回访记录"]; const toolTokens = ["▣","⌕","▤"]; const tab = STATE.aiTab || "基础设置"; const tabs = ["基础设置","知识与工具","安全策略"].map(name=>``).join(""); const contextValue = Math.max(1,Number(ai.context || 8)); const contextValues = [...new Set([4,8,12,16,20,contextValue])].sort((a,b)=>a-b); const contextOptions = contextValues.map(value=>``).join(""); const tokenValue = Math.max(50,Number(ai.maxTokens || 500)); const tokenValues = [...new Set([300,500,1000,tokenValue])].sort((a,b)=>a-b); const tokenOptions = tokenValues.map(value=>``).join(""); const lengthIndex = Math.max(0,Math.min(2,Number(ai.replyLengthIndex ?? 1))); const lengthLabel = ["短","中等","长"][lengthIndex]; const lengthValue = [10,55,90][lengthIndex]; const temperature = Math.max(0,Math.min(1,Number(ai.temperature || 0.35))); const knowledgeCount = ai.knowledgeCount || ai.knowledge || "0"; const connectedKnowledge = ai.knowledgeConnected !== undefined ? Boolean(ai.knowledgeConnected) : Number(ai.knowledge || 0) > 0; const syncLabel = ai.syncLabel || ai.syncAt || "尚未同步"; const toolCount = Number(ai.toolCount ?? toolsOn.filter(Boolean).length); const configLabel = ai.synced === false ? "配置未同步" : "配置已同步"; const knowledgeStatus = connectedKnowledge ? "知识库已同步" : "知识库未连接"; const toolStatus = toolCount === 3 ? "全部运行正常" : `${toolCount} 个已启用`; return `
${head("AI 设置","配置模型、客服人格、知识库与工具能力",`${configLabel}`)}
${tabs}

客服人格

AI
服务风格:温和专业简洁
✧ 实时预览

您好!我是甄养堂${esc(ai.name || "贴心管家")},
很高兴为您服务 😊

请问有什么可以帮您的吗?

✣ 模型引擎

▰ 企业知识库

${esc(knowledgeCount)}个知识片段
● ${esc(syncLabel)}✓ ${connectedKnowledge?"已连接":"未连接"}

◇ MCP 工具

单次最多调用 ${esc(ai.mcpRounds || 5)} 个工具 ⓘ
${names.map((name,index)=>`
${toolTokens[index]}
${name}
${toolsOn[index]?"已启用":"未启用"}
`).join("")}

${icon("shield")} 安全边界

🛡 不做医疗诊断
💊 不修改用药方案
♙ 高风险转人工
当前模式:${icon("shield")}严格模式

配置状态

${statusCells([["cloud",STATE.aiOk===false?"AI 服务异常":"云端模型正常","最后检查:刚刚"],["folder",knowledgeStatus,`${esc(knowledgeCount)} 个知识片段`],["folder",`${toolCount} 个工具可用`,toolStatus],["shield","安全策略已生效","严格模式"]])}
`; }; automationView = function(){ if (STATE.demo) return _automationView(); const a = STATE.automation || {}; const autoOn = (STATE.sendMode || "auto") === "auto"; return `
${head("自动化设置","配置企业微信监听、消息合并与自动发送规则",`${esc(a.wecom || "企业微信未识别")}规则已生效`)}

监听与发送策略

${icon("activity")} ● 规则运行中
${[["activity","扫描未读"],["log","提取消息"],["folder","合并消息"],["brain","请求 AI"],["send","回填发送"]].map(x=>`
${icon(x[0])}
${x[1]}
`).join("")}
${icon("clock")}扫描间隔 
${icon("hourglass")} 连续消息等待 
${icon("clock")}发送前等待 

企业微信窗口

${icon("clipboard")} 主窗口:● ${esc(a.wecom || "未识别")}
${icon("user")} 当前账号:${esc(a.account || "—")}
${icon("globe")} DPI:${esc(STATE.dpi || "—")}
${icon("monitor")} 最小化恢复:● 已开启

人机共存

启用人工操作保护
鼠标静止  秒 后恢复
${icon("bot")}
AI 运行中
${icon("cursor")}
${icon("pause")}
检测到人工操作
AI 暂停

消息处理

✓ 同一客户连续消息自动合并
✓ 保留最近 轮上下文${esc(a.context || 8)} 轮
✓ 一次只处理 1 个会话1 个

异常与兜底

${icon("clock")}AI 超时:${esc(a.timeout || 120)} 秒后重试2 次
${icon("alert")}发送失败:自动重试已开启
${icon("message")}固定回复:${esc(a.reply || "在的,请稍等")}

高风险转人工

● 已开启
${icon("shield")} 诊断${icon("package")} 用药调整${icon("coins")} 投诉退款

启动前检查

${statusCells([["check","企业微信已登录", STATE.wecomConnected ? "检查完成" : "等待连接"],["cloud","AI 服务正常","检查完成"],["activity","窗口坐标已校准", STATE.wecomConnected ? "检查完成" : "待校准"],["shield","规则配置有效","检查完成"]])}
`; }; logsView = function(){ if (STATE.demo) return _logsView(); const events = STATE.logs || []; const list = events.length ? events.map(x=>`
${icon(x.icon || "activity")}
${esc(x.title)}${esc(x.detail)}
${esc(x.state || "")}
`).join("") : `
当前没有运行记录
`; const ex = STATE.exceptions || {}; const detail = STATE.logDetail || {title:"等待事件", text:"开始监听后,这里会显示最近一条运行事件。", tags:[]}; const chain = (STATE.chain && STATE.chain.length ? STATE.chain : [{icon:"activity",title:"扫描未读",time:""},{icon:"message",title:"读取消息",time:""},{icon:"brain",title:"请求 AI",time:""},{icon:"send",title:"回填发送",time:""}]); return `
${head("运行日志","实时追踪连接、消息识别、AI 调用与自动发送事件",`${esc(STATE.statusLabel || "监控中")}`)}${liveRibbonLogs()}

实时事件流

${["全部","连接","识别","AI","发送","警告"].map(n=>``).join("")}
${list}

系统健康

${[["企业微信连接", STATE.wecomConnected ? "正常" : "待连接"],["AI 服务", STATE.aiOk ? "正常" : "异常"],["窗口识别", STATE.wecomConnected ? "正常" : "待监听"]].map(x=>`
${icon("check")}
${x[0]}${x[1]}
`).join("")}
${icon("clock")}运行时长 ${esc(STATE.runtime || "00:00:00")}

当前回复链路

${chain.map((x,i)=>`
${icon(x.icon || "activity")}
${esc(x.title)}${esc(x.time || "")}
`).join("")}

事件详情

${icon("user")}
${esc(detail.title)}

${esc(detail.text)}

${(detail.tags||[]).map(t=>`${esc(t)}`).join("")}

异常追踪

${icon("alert")}
发送失败${esc(ex.sendFail || 0)}
${icon("clock")}
模型超时${esc(ex.timeout || 0)}
${icon("monitor")}
窗口丢失${esc(ex.windowLost || 0)}

最近活动

${activities("查看完整记录")}
`; }; systemView = function(){ if (STATE.demo) return _systemView(); const s = STATE.system || {}; const on = k => s[k] ? "on" : ""; return `
${head("系统设置","管理软件启动、数据存储、通知与系统维护",`当前版本 v${esc(s.version || "2.0")} ${icon("info")}`)}

基础设置

${icon("power")}开机自动启动
${icon("activity")}启动后自动监听
${icon("tray")}最小化到系统托盘
${icon("log")}关闭窗口时保持后台运行
${icon("globe")}界面语言
${icon("monitor")}缩放比例

数据与存储

${esc(s.storage || "—")}已使用
● 会话归档${esc(s.archiveSize || "—")}
● 运行日志${esc(s.logSize || "—")}
● 缓存数据${esc(s.cacheSize || "—")}
数据保留

通知提醒

${icon("send")}发送失败提醒
${icon("hourglass")}模型超时提醒
${icon("user")}需要人工跟进
${icon("wifi")}企业微信连接中断
${icon("bell")}
发送失败提醒消息发送失败,已加入重试队列

安全与隐私

${icon("shield")}敏感信息脱敏
${icon("lock")}本地数据加密
${icon("lock")}日志隐藏聊天正文
${icon("log")}退出时清理剪贴板

网络与服务

${icon("cloud")}云端 AI:${esc(s.cloudAi || "未检测")}
${icon("folder")}企业知识库:${esc(s.knowledgeNet || "未检测")}
${icon("wifi")}网络延迟:${esc(s.latency || "—")}

维护与诊断

${icon("refresh")}
检查更新${esc(s.updateLabel || "已是最新版本")}
${icon("clipboard")}
导出诊断导出系统诊断报告
${icon("refresh")}
恢复默认设置重置所有设置项
${icon("shield")}
查看许可信息查看软件许可详情

系统状态

${statusCells([["shield","配置已保存","所有设置已生效"],["cloud","最近备份", esc(s.lastBackup || "尚未备份")],["shield","安全策略正常","所有安全策略已启用"],["monitor","后台服务", STATE.listening ? "运行中" : "已停止"]])}
`; }; views = {auto:autoView,queue:queueView,archive:archiveView,ai:aiView,automation:automationView,logs:logsView,system:systemView}; function syncOrb(){ const orb = document.getElementById("orb"); const label = document.getElementById("orb-label"); if (orb) orb.classList.toggle("paused", !STATE.listening); if (label) label.textContent = STATE.statusLabel || (STATE.listening ? "监听中" : "已停止"); } function coreFingerprint(state){ const sys = state.system || {}; const ai = state.ai || {}; const auto = state.automation || {}; const metrics = state.metrics || {}; const view = state.view || "auto"; const common = { view: state.view, demo: state.demo, listening: state.listening, wecomConnected: state.wecomConnected, aiOk: state.aiOk, wecomLabel: state.wecomLabel, aiLabel: state.aiLabel, }; const people = (state.people || []).map(p => [ p.key, p.name, p.status, p.bubbles, p.avatar, p.tone, p.dot ]); const task = state.task ? { key: state.task.key, name: state.task.name, sessionId: state.task.sessionId, sessionDisplay: state.task.sessionDisplay, action: state.task.action, stepIndex: state.task.stepIndex, answer: state.task.answer, messageCount: state.task.messageCount, confidence: state.task.confidence, messages: (state.task.messages || []).map(message => [message.time, message.text]), steps: (state.task.steps || []).map(step => [step[0], step[1]]), } : null; const metricModes = [Number(metrics.failed) > 0, Number(metrics.warnings) > 0]; let page; if (view === "auto") { page = { selectedKey: state.selectedKey, queueFilter: state.queueFilter, queueSort: state.queueSort, people, task, journey: (state.journey || []).map(j => [j.title, j.status, j.mode, j.done, j.active]), windowStats: state.windowStats, metricModes, }; } else if (view === "queue") { page = { selectedKey: state.selectedKey, queueFilter: state.queueFilter, queueSort: state.queueSort, people, task, metricModes, }; } else if (view === "archive") { page = { archiveFilter: state.archiveFilter, archiveQuery: state.archiveQuery, archiveDate: state.archiveDate, selectedArchive: state.selectedArchive, archives: (state.archives || []).map(a => [ a.key, a.badge, a.count, a.name, a.time, a.preview, a.avatar, a.tone ]), chat: (state.chat || []).map(message => [message.role, message.time, message.text]), memory: state.memory, settle: state.settle, }; } else if (view === "ai") { page = {aiTab: state.aiTab, ai}; } else if (view === "automation") { page = {sendMode: state.sendMode, dpi: state.dpi, auto, tray: sys.tray}; } else if (view === "logs") { page = { statusLabel: state.statusLabel, eventFilter: state.eventFilter, eventQuery: state.eventQuery, exceptions: state.exceptions, logDetail: state.logDetail, chain: (state.chain || []).map(item => [item.icon, item.title]), metricModes, }; } else { const { storage: _storage, archiveSize: _archiveSize, logSize: _logSize, cacheSize: _cacheSize, noticeTime: _noticeTime, ...systemStructure } = sys; page = {system: systemStructure}; } return JSON.stringify({common, page}); } function logsFingerprint(state){ return JSON.stringify((state.logs || []).map(x => [x.time, x.title, x.detail, x.state])); } function logRowsHtml(events){ events = (events || []).slice(-5); if (!events.length){ return `
当前没有运行记录
`; } return events.map(x=>`
${icon(x.icon || "activity")}
${esc(x.title)}${esc(x.detail)}
${esc(x.state || "")}
`).join(""); } function wireDemoArchive(html){ let rowIndex = 0; return html .replace('data-action="toast">' + icon("download") + '导出记录', 'data-action="export-archive">' + icon("download") + '导出记录') .replace('', '') .replace('', '') .replace('', '') .replace('', '') .replace('', '') .replace('', '') .replace(/
/g, (_match, classes) => `
`) .replace('', '') .replace('data-action="logs">复制全部记录', 'data-action="copy-archive">复制全部记录'); } function wireDemoAi(html){ const activeTab = STATE.aiTab || "基础设置"; let toolIndex = 0; return html .replace('配置已同步', '配置已同步') .replace('', '') .replace('', '') .replace('
', `
${["基础设置","知识与工具","安全策略"].map(name=>``).join("")}
`) .replace('', '') .replace('