fix: 改进错误处理和清理测试代码
## 主要修复 ### 1. JSON 解析错误处理 - 修复所有 Agent 的 LLM 响应解析失败时返回原始内容的问题 - 当 JSON 解析失败时,返回友好的兜底消息而不是原始文本 - 影响文件: customer_service.py, order.py, product.py, aftersale.py ### 2. FAQ 快速路径修复 - 修复 customer_service.py 中变量定义顺序问题 - has_faq_query 在使用前未定义导致 NameError - 添加详细的错误日志记录 ### 3. Chatwoot 集成改进 - 添加响应内容调试日志 - 改进错误处理和日志记录 ### 4. 订单查询优化 - 将订单列表默认返回数量从 10 条改为 5 条 - 统一 MCP 工具层和 Mall Client 层的默认值 ### 5. 代码清理 - 删除所有测试代码和示例文件 - 刋试文件包括: test_*.py, test_*.html, test_*.sh - 删除测试目录: tests/, agent/tests/, agent/examples/ Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,337 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>B2B AI 助手 - 调试版本</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
.left-panel, .right-panel {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
h2 {
|
||||
color: #667eea;
|
||||
border-bottom: 2px solid #667eea;
|
||||
padding-bottom: 10px;
|
||||
margin-top: 0;
|
||||
}
|
||||
.log-container {
|
||||
background: #1e1e1e;
|
||||
color: #00ff00;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
height: 400px;
|
||||
overflow-y: auto;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
.log-entry {
|
||||
margin: 5px 0;
|
||||
padding: 3px 0;
|
||||
}
|
||||
.log-info { color: #00ff00; }
|
||||
.log-warn { color: #ffaa00; }
|
||||
.log-error { color: #ff4444; }
|
||||
.log-success { color: #44ff44; }
|
||||
.status-box {
|
||||
background: #f8f9fa;
|
||||
border-left: 4px solid #667eea;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.status-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.status-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.status-label {
|
||||
font-weight: bold;
|
||||
color: #667eea;
|
||||
}
|
||||
.status-value {
|
||||
color: #333;
|
||||
}
|
||||
.test-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.test-btn {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
.test-btn:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
.test-btn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.clear-btn {
|
||||
background: #ff4444;
|
||||
}
|
||||
.clear-btn:hover {
|
||||
background: #dd3333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🤖 B2B AI 智能客服助手 - 调试面板</h1>
|
||||
<p class="subtitle">实时监控 Widget 状态和消息流</p>
|
||||
|
||||
<div class="container">
|
||||
<div class="left-panel">
|
||||
<h2>📊 连接状态</h2>
|
||||
<div class="status-box">
|
||||
<div class="status-item">
|
||||
<span class="status-label">Chatwoot 服务:</span>
|
||||
<span class="status-value" id="chatwootStatus">检查中...</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">Widget SDK:</span>
|
||||
<span class="status-value" id="widgetStatus">未加载</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">WebSocket:</span>
|
||||
<span class="status-value" id="wsStatus">未连接</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">当前会话:</span>
|
||||
<span class="status-value" id="conversationId">无</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">Website Token:</span>
|
||||
<span class="status-value" id="websiteToken">39PNCMvbMk3NvB7uaDNucc6o</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>🧪 测试操作</h2>
|
||||
<div class="test-buttons">
|
||||
<button class="test-btn" onclick="checkChatwootService()">检查服务</button>
|
||||
<button class="test-btn" onclick="refreshWidget()">刷新 Widget</button>
|
||||
<button class="test-btn" onclick="getConversationInfo()">获取会话信息</button>
|
||||
<button class="test-btn clear-btn" onclick="clearLogs()">清除日志</button>
|
||||
</div>
|
||||
|
||||
<h2>📝 快速测试问题(点击复制到剪贴板)</h2>
|
||||
<div class="test-buttons">
|
||||
<button class="test-btn" onclick="sendTestMessage('你好')">👋 你好</button>
|
||||
<button class="test-btn" onclick="sendTestMessage('查询订单 202071324')">📦 查询订单</button>
|
||||
<button class="test-btn" onclick="sendTestMessage('如何退货?')">❓ 如何退货</button>
|
||||
<button class="test-btn" onclick="sendTestMessage('营业时间')">🕐 营业时间</button>
|
||||
</div>
|
||||
<p style="color: #666; font-size: 14px; margin-top: 10px;">
|
||||
💡 提示:点击按钮后,在右下角聊天窗口中按 Ctrl+V 粘贴并发送
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="right-panel">
|
||||
<h2>📋 实时日志</h2>
|
||||
<div class="log-container" id="logContainer">
|
||||
<div class="log-entry log-info">[系统] 日志系统已启动...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const logContainer = document.getElementById('logContainer');
|
||||
|
||||
function addLog(message, type = 'info') {
|
||||
const timestamp = new Date().toLocaleTimeString();
|
||||
const logEntry = document.createElement('div');
|
||||
logEntry.className = `log-entry log-${type}`;
|
||||
logEntry.textContent = `[${timestamp}] ${message}`;
|
||||
logContainer.appendChild(logEntry);
|
||||
logContainer.scrollTop = logContainer.scrollHeight;
|
||||
}
|
||||
|
||||
function clearLogs() {
|
||||
logContainer.innerHTML = '<div class="log-entry log-info">[系统] 日志已清除</div>';
|
||||
}
|
||||
|
||||
// 检查 Chatwoot 服务
|
||||
async function checkChatwootService() {
|
||||
addLog('检查 Chatwoot 服务状态...', 'info');
|
||||
const statusEl = document.getElementById('chatwootStatus');
|
||||
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000', { mode: 'no-cors' });
|
||||
statusEl.textContent = '✅ 运行中';
|
||||
statusEl.style.color = '#28a745';
|
||||
addLog('✅ Chatwoot 服务运行正常', 'success');
|
||||
} catch (error) {
|
||||
statusEl.textContent = '❌ 无法访问';
|
||||
statusEl.style.color = '#dc3545';
|
||||
addLog(`❌ 无法连接到 Chatwoot: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 发送测试消息 - 直接复制到剪贴板
|
||||
function sendTestMessage(message) {
|
||||
addLog(`📋 已复制消息到剪贴板: "${message}"`, 'info');
|
||||
addLog('→ 请在右下角聊天窗口中粘贴并发送', 'warn');
|
||||
|
||||
// 复制到剪贴板
|
||||
navigator.clipboard.writeText(message).then(() => {
|
||||
// 可选:自动打开 Widget
|
||||
if (window.$chatwoot && window.$chatwoot.toggle) {
|
||||
try {
|
||||
window.$chatwoot.toggle('open');
|
||||
addLog('✅ 聊天窗口已打开', 'success');
|
||||
} catch (e) {
|
||||
addLog('⚠️ 无法自动打开聊天窗口', 'warn');
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
addLog(`❌ 复制失败: ${err.message}`, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// 刷新 Widget
|
||||
function refreshWidget() {
|
||||
addLog('刷新 Widget...', 'info');
|
||||
location.reload();
|
||||
}
|
||||
|
||||
// 获取会话信息
|
||||
function getConversationInfo() {
|
||||
if (window.$chatwoot) {
|
||||
try {
|
||||
const info = window.$chatwoot.getConversationInfo();
|
||||
addLog(`会话信息: ${JSON.stringify(info)}`, 'info');
|
||||
} catch (error) {
|
||||
addLog(`无法获取会话信息: ${error.message}`, 'warn');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时检查服务
|
||||
window.addEventListener('load', function() {
|
||||
setTimeout(checkChatwootService, 1000);
|
||||
});
|
||||
|
||||
// ==================== Chatwoot Widget 配置 ====================
|
||||
|
||||
window.chatwootSettings = {
|
||||
"position": "right",
|
||||
"type": "expanded_bubble",
|
||||
"launcherTitle": "Chat with us"
|
||||
};
|
||||
|
||||
(function(d,t) {
|
||||
var BASE_URL = "http://localhost:3000";
|
||||
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
|
||||
g.src = BASE_URL + "/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
g.onload = function() {
|
||||
addLog('Chatwoot SDK 文件已加载', 'success');
|
||||
document.getElementById('widgetStatus').textContent = '✅ 已加载';
|
||||
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: '39PNCMvbMk3NvB7uaDNucc6o',
|
||||
baseUrl: BASE_URL
|
||||
});
|
||||
|
||||
addLog('Website Token: 39PNCMvbMk3NvB7uaDNucc6o', 'info');
|
||||
addLog('Base URL: ' + BASE_URL, 'info');
|
||||
|
||||
// 监听 Widget 就绪事件
|
||||
setTimeout(function() {
|
||||
if (window.$chatwoot) {
|
||||
addLog('✅ Chatwoot Widget 已初始化', 'success');
|
||||
document.getElementById('wsStatus').textContent = '✅ 已连接';
|
||||
|
||||
// 设置用户信息(可选)
|
||||
window.$chatwoot.setUser('debug_user_' + Date.now(), {
|
||||
email: 'debug@example.com',
|
||||
name: 'Debug User'
|
||||
});
|
||||
|
||||
addLog('用户信息已设置', 'info');
|
||||
} else {
|
||||
addLog('❌ Widget 初始化失败', 'error');
|
||||
document.getElementById('widgetStatus').textContent = '❌ 初始化失败';
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
g.onerror = function() {
|
||||
addLog('❌ Chatwoot SDK 加载失败', 'error');
|
||||
document.getElementById('widgetStatus').textContent = '❌ 加载失败';
|
||||
};
|
||||
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})(document, "script");
|
||||
|
||||
// 监听网络错误
|
||||
window.addEventListener('error', function(e) {
|
||||
if (e.message.includes('404')) {
|
||||
addLog(`⚠️ 404 错误: ${e.filename}`, 'warn');
|
||||
}
|
||||
});
|
||||
|
||||
// 拦截 fetch 请求
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = function(...args) {
|
||||
const url = args[0];
|
||||
|
||||
// 记录发送到 Chatwoot API 的请求
|
||||
if (typeof url === 'string' && url.includes('localhost:3000')) {
|
||||
const method = args[1]?.method || 'GET';
|
||||
addLog(`API 请求: ${method} ${url}`, 'info');
|
||||
}
|
||||
|
||||
return originalFetch.apply(this, args).then(response => {
|
||||
// 记录错误响应
|
||||
if (!response.ok && url.includes('localhost:3000')) {
|
||||
addLog(`API 响应: ${response.status} ${response.statusText} - ${url}`, 'error');
|
||||
}
|
||||
return response;
|
||||
});
|
||||
};
|
||||
|
||||
addLog('调试系统已初始化', 'success');
|
||||
</script>
|
||||
|
||||
<!-- Chatwoot Widget 会自动加载 -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,262 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>B2B AI 助手 - 测试页面</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.info-box {
|
||||
background: #f8f9fa;
|
||||
border-left: 4px solid #667eea;
|
||||
padding: 15px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.info-box h3 {
|
||||
margin-top: 0;
|
||||
color: #667eea;
|
||||
}
|
||||
.feature-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.feature-card {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
.feature-card h4 {
|
||||
color: #667eea;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.test-questions {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffc107;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.test-questions h3 {
|
||||
margin-top: 0;
|
||||
color: #856404;
|
||||
}
|
||||
.question-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
.question-list li {
|
||||
background: white;
|
||||
margin: 10px 0;
|
||||
padding: 12px 15px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.question-list li:hover {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
transform: translateX(5px);
|
||||
}
|
||||
.status {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.status.online {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
.status.testing {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🤖 B2B AI 智能客服助手</h1>
|
||||
<p class="subtitle">基于 LangGraph + MCP 的智能客服系统</p>
|
||||
|
||||
<div class="status online">
|
||||
✅ 系统状态:所有服务运行正常
|
||||
</div>
|
||||
|
||||
<div id="tokenStatus" class="status testing" style="display: none;">
|
||||
🍪 Token 状态:检测中...
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>📝 如何测试</h3>
|
||||
<ol>
|
||||
<li>点击右下角的聊天图标打开对话窗口</li>
|
||||
<li>输入你的名字开始对话</li>
|
||||
<li>尝试下面的问题测试 AI 能力</li>
|
||||
<li>查看 AI 如何理解并回答你的问题</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="test-questions">
|
||||
<h3>💬 推荐测试问题</h3>
|
||||
<p style="color: #666; margin-bottom: 15px;">点击以下问题直接复制到聊天窗口:</p>
|
||||
<ul class="question-list">
|
||||
<li onclick="copyQuestion(this.textContent)">🕐 你们的营业时间是什么?</li>
|
||||
<li onclick="copyQuestion(this.textContent)">📦 我的订单 202071324 怎么样了?</li>
|
||||
<li onclick="copyQuestion(this.textContent)">🔍 查询订单 202071324</li>
|
||||
<li onclick="copyQuestion(this.textContent)">📞 如何联系客服?</li>
|
||||
<li onclick="copyQuestion(this.textContent)">🛍️ 我想退换货</li>
|
||||
<li onclick="copyQuestion(this.textContent)">📦 订单 202071324 的物流信息</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="feature-list">
|
||||
<div class="feature-card">
|
||||
<h4>🎯 智能意图识别</h4>
|
||||
<p>自动识别客户需求并分类</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h4>📚 知识库查询</h4>
|
||||
<p>快速检索 FAQ 和政策文档</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h4>📦 订单管理</h4>
|
||||
<p>查询订单、售后等服务</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h4>🔄 多轮对话</h4>
|
||||
<p>支持上下文理解的连续对话</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>🔧 技术栈</h3>
|
||||
<ul>
|
||||
<li><strong>前端:</strong>Chatwoot 客户支持平台</li>
|
||||
<li><strong>AI 引擎:</strong>LangGraph + 智谱 AI (GLM-4.5)</li>
|
||||
<li><strong>知识库:</strong>Strapi CMS + MCP</li>
|
||||
<li><strong>业务系统:</strong>Hyperf PHP API</li>
|
||||
<li><strong>缓存:</strong>Redis</li>
|
||||
<li><strong>容器:</strong>Docker Compose</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function copyQuestion(text) {
|
||||
// 移除表情符号
|
||||
const cleanText = text.replace(/^[^\s]+\s*/, '');
|
||||
navigator.clipboard.writeText(cleanText).then(() => {
|
||||
alert('问题已复制!请粘贴到聊天窗口中发送。');
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Cookie Token 读取 ====================
|
||||
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkToken() {
|
||||
const token = getCookie('token');
|
||||
const statusDiv = document.getElementById('tokenStatus');
|
||||
|
||||
if (token) {
|
||||
statusDiv.style.display = 'block';
|
||||
statusDiv.className = 'status online';
|
||||
statusDiv.innerHTML = `✅ Token 已找到 | 长度: ${token.length} 字符 | 前缀: ${token.substring(0, 20)}...`;
|
||||
// 存储到 window 供后续使用
|
||||
window._chatwootUserToken = token;
|
||||
console.log('✅ Token 已从 Cookie 读取');
|
||||
} else {
|
||||
statusDiv.style.display = 'block';
|
||||
statusDiv.className = 'status testing';
|
||||
statusDiv.innerHTML = '⚠️ 未找到 Token | 请确保已登录商城 | Cookie 名称: token';
|
||||
console.warn('⚠️ 未找到 Token,订单查询功能可能无法使用');
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时检查 Token
|
||||
window.addEventListener('load', function() {
|
||||
setTimeout(checkToken, 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Chatwoot Widget - 官方集成方式 -->
|
||||
<script>
|
||||
(function(d,t) {
|
||||
var BASE_URL="http://localhost:3000";
|
||||
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=BASE_URL+"/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g,s);
|
||||
g.onload=function(){
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: '39PNCMvbMk3NvB7uaDNucc6o',
|
||||
baseUrl: BASE_URL,
|
||||
locale: 'zh_CN',
|
||||
userIdentifier: getCookie('token') || 'web_user_' + Date.now()
|
||||
});
|
||||
|
||||
const userToken = getCookie('token');
|
||||
console.log('✅ Chatwoot Widget 已加载 (官方集成方式)');
|
||||
console.log('Base URL:', BASE_URL);
|
||||
console.log('Website Token: 39PNCMvbMk3NvB7uaDNucc6o');
|
||||
console.log('Locale: zh_CN');
|
||||
console.log('User Identifier:', userToken || 'web_user_' + Date.now());
|
||||
|
||||
// 设置用户信息(可选)
|
||||
setTimeout(function() {
|
||||
const token = getCookie('token');
|
||||
if (token && window.$chatwoot) {
|
||||
window.$chatwoot.setUser('user_' + Date.now(), {
|
||||
email: 'user@example.com',
|
||||
name: 'Website User',
|
||||
phone_number: ''
|
||||
});
|
||||
|
||||
console.log('✅ 用户信息已设置');
|
||||
} else if (!token) {
|
||||
console.warn('⚠️ 未找到 Token');
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
g.onerror=function(){
|
||||
console.error('❌ Chatwoot SDK 加载失败');
|
||||
console.error('请确保 Chatwoot 运行在: ' + BASE_URL);
|
||||
}
|
||||
})(document,"script");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,425 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>会话 ID 检查工具</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
.info-box {
|
||||
background: #e7f3ff;
|
||||
border-left: 4px solid #2196F3;
|
||||
padding: 15px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.info-box h3 {
|
||||
margin-top: 0;
|
||||
color: #2196F3;
|
||||
}
|
||||
.data-display {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
}
|
||||
.data-label {
|
||||
font-weight: bold;
|
||||
color: #495057;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.data-value {
|
||||
color: #212529;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
word-break: break-all;
|
||||
}
|
||||
button {
|
||||
background: #2196F3;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin: 5px;
|
||||
}
|
||||
button:hover {
|
||||
background: #0b7dda;
|
||||
}
|
||||
button.danger {
|
||||
background: #dc3545;
|
||||
}
|
||||
button.danger:hover {
|
||||
background: #c82333;
|
||||
}
|
||||
.instructions {
|
||||
background: #fff3cd;
|
||||
border-left: 4px solid #ffc107;
|
||||
padding: 15px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.instructions ol {
|
||||
margin: 10px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.instructions li {
|
||||
margin: 8px 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔍 Chatwoot 会话 ID 检查工具</h1>
|
||||
|
||||
<div class="instructions">
|
||||
<h3>📝 使用说明</h3>
|
||||
<ol>
|
||||
<li>打开浏览器开发者工具(按 F12)</li>
|
||||
<li>切换到 Console(控制台)标签</li>
|
||||
<li>点击下面的"显示会话信息"按钮</li>
|
||||
<li>在 Console 中查看当前的 conversation_id</li>
|
||||
<li>将这个 ID 与 Agent 日志中的 conversation_id 对比</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>🎯 操作按钮</h3>
|
||||
<button onclick="showConversationInfo()">显示会话信息</button>
|
||||
<button onclick="checkWidgetStatus()">检查 Widget 状态</button>
|
||||
<button onclick="checkToken()">检查 Token</button>
|
||||
<button onclick="testOrderAPI()">测试订单 API</button>
|
||||
<button onclick="clearLocalStorage()" class="danger">清除本地存储(重新开始)</button>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>📊 信息显示</h3>
|
||||
<div class="data-display">
|
||||
<div class="data-label">Widget SDK 状态:</div>
|
||||
<div class="data-value" id="widgetStatus">未初始化</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">当前会话 ID:</div>
|
||||
<div class="data-value" id="conversationId">未知</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">Token 状态:</div>
|
||||
<div class="data-value" id="tokenStatus">未检查</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">订单 API 测试结果:</div>
|
||||
<div class="data-value" id="orderApiResult">未测试</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">本地存储数据:</div>
|
||||
<div class="data-value" id="localStorageData">无</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="instructions">
|
||||
<h3>💡 问题排查</h3>
|
||||
<p><strong>如果看不到 AI 回复:</strong></p>
|
||||
<ol>
|
||||
<li>点击"清除本地存储"按钮</li>
|
||||
<li>刷新页面(Ctrl+Shift+R)</li>
|
||||
<li>在右下角聊天窗口重新发送消息</li>
|
||||
<li>查看 Agent 日志: <code>docker logs ai_agent --tail 50</code></li>
|
||||
<li>对比 Console 中的 conversation_id 与日志中的是否一致</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 获取 Cookie 中的 token
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查 Token
|
||||
function checkToken() {
|
||||
console.log('======================================');
|
||||
console.log('Token 检查');
|
||||
console.log('======================================');
|
||||
|
||||
const token = getCookie('token');
|
||||
const tokenStatusDiv = document.getElementById('tokenStatus');
|
||||
|
||||
if (token) {
|
||||
console.log('✅ Token 已找到');
|
||||
console.log('Token 长度:', token.length);
|
||||
console.log('Token 前缀:', token.substring(0, 50) + '...');
|
||||
tokenStatusDiv.textContent = `✅ 已找到 | 长度: ${token.length} | 前缀: ${token.substring(0, 30)}...`;
|
||||
tokenStatusDiv.style.color = '#28a745';
|
||||
} else {
|
||||
console.log('❌ 未找到 Token');
|
||||
console.log('Cookie 名称: token');
|
||||
tokenStatusDiv.textContent = '❌ 未找到 | Cookie 名称: token';
|
||||
tokenStatusDiv.style.color = '#dc3545';
|
||||
}
|
||||
|
||||
console.log('所有 Cookie:', document.cookie);
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
// 测试订单 API
|
||||
async function testOrderAPI() {
|
||||
console.log('======================================');
|
||||
console.log('测试订单 API');
|
||||
console.log('======================================');
|
||||
|
||||
const token = getCookie('token');
|
||||
const resultDiv = document.getElementById('orderApiResult');
|
||||
|
||||
if (!token) {
|
||||
console.error('❌ 未找到 Token,无法调用 API');
|
||||
resultDiv.textContent = '❌ 未找到 Token';
|
||||
resultDiv.style.color = '#dc3545';
|
||||
alert('❌ 未找到 Token,请先确保已登录商城');
|
||||
return;
|
||||
}
|
||||
|
||||
const orderId = '202071324';
|
||||
const apiUrl = `https://apicn.qa1.gaia888.com/mall/api/order/show?orderId=${orderId}`;
|
||||
|
||||
console.log('API URL:', apiUrl);
|
||||
console.log('Authorization:', `Bearer ${token.substring(0, 30)}...`);
|
||||
|
||||
resultDiv.textContent = '🔄 请求中...';
|
||||
resultDiv.style.color = '#ffc107';
|
||||
|
||||
try {
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9',
|
||||
'authorization': `Bearer ${token}`,
|
||||
'currency-code': 'EUR',
|
||||
'device-type': 'pc',
|
||||
'language-id': '1',
|
||||
'origin': 'https://www.qa1.gaia888.com',
|
||||
'referer': 'https://www.qa1.gaia888.com/',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-site',
|
||||
'source': 'us.qa1.gaia888.com',
|
||||
'tenant-id': '2'
|
||||
}
|
||||
});
|
||||
|
||||
console.log('响应状态:', response.status);
|
||||
console.log('响应头:', Object.fromEntries(response.headers.entries()));
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('✅ API 调用成功');
|
||||
console.log('响应数据:', data);
|
||||
|
||||
resultDiv.textContent = `✅ 成功 (HTTP ${response.status}) | 订单 ${orderId}`;
|
||||
resultDiv.style.color = '#28a745';
|
||||
|
||||
alert(`✅ 订单 API 调用成功!\n\n订单 ID: ${orderId}\n状态码: ${response.status}\n\n详细数据请查看控制台`);
|
||||
} else {
|
||||
const errorText = await response.text();
|
||||
console.error('❌ API 调用失败');
|
||||
console.error('状态码:', response.status);
|
||||
console.error('响应内容:', errorText);
|
||||
|
||||
resultDiv.textContent = `❌ 失败 (HTTP ${response.status})`;
|
||||
resultDiv.style.color = '#dc3545';
|
||||
|
||||
alert(`❌ 订单 API 调用失败\n\n状态码: ${response.status}\n错误: ${errorText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 网络错误:', error);
|
||||
resultDiv.textContent = `❌ 网络错误: ${error.message}`;
|
||||
resultDiv.style.color = '#dc3545';
|
||||
alert(`❌ 网络错误\n\n${error.message}`);
|
||||
}
|
||||
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
function showConversationInfo() {
|
||||
console.log('======================================');
|
||||
console.log('Chatwoot Widget 会话信息');
|
||||
console.log('======================================');
|
||||
|
||||
if (window.$chatwoot) {
|
||||
try {
|
||||
// 尝试获取会话信息
|
||||
const info = window.$chatwoot.getConversationInfo();
|
||||
console.log('✅ 会话信息:', info);
|
||||
document.getElementById('conversationId').textContent =
|
||||
info && info.conversationId ? info.conversationId : '无法获取';
|
||||
} catch (e) {
|
||||
console.log('⚠️ 无法获取会话信息:', e.message);
|
||||
document.getElementById('conversationId').textContent = '无法获取';
|
||||
}
|
||||
} else {
|
||||
console.log('❌ Widget 未初始化');
|
||||
document.getElementById('conversationId').textContent = 'Widget 未初始化';
|
||||
}
|
||||
|
||||
// 显示本地存储
|
||||
const storage = {};
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key.includes('chatwoot') || key.includes('widget')) {
|
||||
storage[key] = localStorage.getItem(key);
|
||||
}
|
||||
}
|
||||
console.log('本地存储 (Chatwoot 相关):', storage);
|
||||
document.getElementById('localStorageData').textContent =
|
||||
Object.keys(storage).length > 0 ? JSON.stringify(storage, null, 2) : '无';
|
||||
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
function checkWidgetStatus() {
|
||||
console.log('======================================');
|
||||
console.log('Widget 状态检查');
|
||||
console.log('======================================');
|
||||
console.log('window.$chatwoot:', window.$chatwoot);
|
||||
console.log('window.chatwootSDK:', window.chatwootSDK);
|
||||
|
||||
if (window.$chatwoot) {
|
||||
console.log('✅ Widget 已加载');
|
||||
console.log('可用方法:', Object.getOwnPropertyNames(window.$chatwoot));
|
||||
document.getElementById('widgetStatus').textContent = '✅ 已加载';
|
||||
document.getElementById('widgetStatus').style.color = '#28a745';
|
||||
} else {
|
||||
console.log('❌ Widget 未加载');
|
||||
document.getElementById('widgetStatus').textContent = '❌ 未加载';
|
||||
document.getElementById('widgetStatus').style.color = '#dc3545';
|
||||
}
|
||||
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
function clearLocalStorage() {
|
||||
if (confirm('确定要清除所有本地存储吗?这将重置会话。')) {
|
||||
// 清除 Chatwoot 相关的本地存储
|
||||
const keysToRemove = [];
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key.includes('chatwoot') || key.includes('widget')) {
|
||||
keysToRemove.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
keysToRemove.forEach(key => localStorage.removeItem(key));
|
||||
|
||||
console.log(`✅ 已清除 ${keysToRemove.length} 个本地存储项`);
|
||||
console.log('清除的键:', keysToRemove);
|
||||
|
||||
alert(`✅ 已清除 ${keysToRemove.length} 个本地存储项\n\n页面将重新加载以创建新的会话。`);
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时显示本地存储和检查 Token
|
||||
window.addEventListener('load', function() {
|
||||
// 显示本地存储
|
||||
const storage = {};
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key.includes('chatwoot') || key.includes('widget')) {
|
||||
storage[key] = localStorage.getItem(key);
|
||||
}
|
||||
}
|
||||
if (Object.keys(storage).length > 0) {
|
||||
document.getElementById('localStorageData').textContent = JSON.stringify(storage, null, 2);
|
||||
}
|
||||
|
||||
// 自动检查 Token
|
||||
setTimeout(checkToken, 500);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Chatwoot Widget -->
|
||||
<script>
|
||||
(function(d,t) {
|
||||
var BASE_URL="http://localhost:3000";
|
||||
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=BASE_URL+"/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g,s);
|
||||
g.onload=function(){
|
||||
// 获取 token 函数
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
||||
return null;
|
||||
}
|
||||
|
||||
const token = getCookie('token');
|
||||
|
||||
// 初始化配置
|
||||
const widgetConfig = {
|
||||
websiteToken: '39PNCMvbMk3NvB7uaDNucc6o',
|
||||
baseUrl: BASE_URL,
|
||||
locale: 'zh_CN',
|
||||
userIdentifier: token || 'web_user_' + Date.now()
|
||||
};
|
||||
|
||||
window.chatwootSDK.run(widgetConfig);
|
||||
|
||||
// 等待 widget 加载完成后设置用户属性
|
||||
setTimeout(() => {
|
||||
if (token && window.chatwootSDK.setUser) {
|
||||
window.chatwootSDK.setUser(
|
||||
token || 'web_user_' + Date.now(),
|
||||
{
|
||||
jwt_token: token,
|
||||
mall_token: token
|
||||
}
|
||||
);
|
||||
console.log('✅ 已通过 setUser 设置用户属性');
|
||||
} else if (token && window.$chatwoot) {
|
||||
// 备用方案:使用 $chatwoot.setCustomAttributes
|
||||
window.$chatwoot.setCustomAttributes({
|
||||
jwt_token: token,
|
||||
mall_token: token
|
||||
});
|
||||
console.log('✅ 已通过 $chatwoot.setCustomAttributes 设置用户属性');
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
console.log('✅ Chatwoot Widget 已加载');
|
||||
console.log('Locale: zh_CN');
|
||||
console.log('User Identifier:', token || 'web_user_' + Date.now());
|
||||
|
||||
document.getElementById('widgetStatus').textContent = '✅ 已加载';
|
||||
document.getElementById('widgetStatus').style.color = '#28a745';
|
||||
}
|
||||
})(document,"script");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,261 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>B2B AI 助手 - 简化测试</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.info-box {
|
||||
background: #f8f9fa;
|
||||
border-left: 4px solid #667eea;
|
||||
padding: 15px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.info-box h3 {
|
||||
margin-top: 0;
|
||||
color: #667eea;
|
||||
}
|
||||
.test-questions {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffc107;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.test-questions h3 {
|
||||
margin-top: 0;
|
||||
color: #856404;
|
||||
}
|
||||
.question-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
.question-list li {
|
||||
background: white;
|
||||
margin: 10px 0;
|
||||
padding: 12px 15px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.question-list li:hover {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
transform: translateX(5px);
|
||||
}
|
||||
.status {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.status.online {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
.instructions {
|
||||
background: #e7f3ff;
|
||||
border-left: 4px solid #2196F3;
|
||||
padding: 15px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.instructions ol {
|
||||
margin: 10px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.instructions li {
|
||||
margin: 8px 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.feature-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.feature-card {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
.feature-card h4 {
|
||||
color: #667eea;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🤖 B2B AI 智能客服助手</h1>
|
||||
<p class="subtitle">简化测试页面 - Chatwoot 官方集成方式</p>
|
||||
|
||||
<div class="status online">
|
||||
✅ 系统状态:使用官方标准集成
|
||||
</div>
|
||||
|
||||
<div class="instructions">
|
||||
<h3>📝 使用说明</h3>
|
||||
<ol>
|
||||
<li><strong>点击右下角的聊天图标</strong>打开 Chatwoot 对话窗口</li>
|
||||
<li><strong>输入消息</strong>开始与 AI 对话</li>
|
||||
<li><strong>或者</strong>点击下面的测试问题,复制后在聊天窗口粘贴发送</li>
|
||||
<li><strong>查看 AI 如何理解和回答</strong>你的问题</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="test-questions">
|
||||
<h3>💬 推荐测试问题</h3>
|
||||
<p style="color: #666; margin-bottom: 15px;">点击以下问题复制到剪贴板,然后在聊天窗口粘贴(Ctrl+V)并发送:</p>
|
||||
<ul class="question-list">
|
||||
<li onclick="copyQuestion(this.textContent)">🕐 你们的营业时间是什么?</li>
|
||||
<li onclick="copyQuestion(this.textContent)">📦 我的订单 202071324 怎么样了?</li>
|
||||
<li onclick="copyQuestion(this.textContent)">🔍 查询订单 202071324</li>
|
||||
<li onclick="copyQuestion(this.textContent)">📞 如何联系客服?</li>
|
||||
<li onclick="copyQuestion(this.textContent)">🛍️ 我想退换货</li>
|
||||
<li onclick="copyQuestion(this.textContent)">📦 订单 202071324 的物流信息</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>🔧 技术栈</h3>
|
||||
<ul>
|
||||
<li><strong>前端:</strong>Chatwoot 客户支持平台(官方 Widget SDK)</li>
|
||||
<li><strong>AI 引擎:</strong>LangGraph + 智谱 AI (GLM-4.5)</li>
|
||||
<li><strong>知识库:</strong>Strapi CMS + MCP</li>
|
||||
<li><strong>业务系统:</strong>Hyperf PHP API</li>
|
||||
<li><strong>缓存:</strong>Redis</li>
|
||||
<li><strong>容器:</strong>Docker Compose</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="feature-list">
|
||||
<div class="feature-card">
|
||||
<h4>🎯 智能意图识别</h4>
|
||||
<p>自动识别客户需求并分类</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h4>📚 知识库查询</h4>
|
||||
<p>快速检索 FAQ 和政策文档</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h4>📦 订单管理</h4>
|
||||
<p>查询订单、售后等服务</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h4>🔄 多轮对话</h4>
|
||||
<p>支持上下文理解的连续对话</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>📊 系统信息</h3>
|
||||
<p><strong>Chatwoot 服务:</strong>http://localhost:3000</p>
|
||||
<p><strong>Website Token:</strong>39PNCMvbMk3NvB7uaDNucc6o</p>
|
||||
<p><strong>集成方式:</strong>Chatwoot 官方 SDK</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function copyQuestion(text) {
|
||||
// 移除表情符号
|
||||
const cleanText = text.replace(/^[^\s]+\s*/, '');
|
||||
navigator.clipboard.writeText(cleanText).then(() => {
|
||||
alert('✅ 问题已复制到剪贴板!\n\n请在聊天窗口中按 Ctrl+V 粘贴并发送。');
|
||||
}).catch(err => {
|
||||
console.error('复制失败:', err);
|
||||
alert('❌ 复制失败,请手动复制问题文本。');
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Cookie Token 读取 ====================
|
||||
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 页面加载时检查 Token
|
||||
window.addEventListener('load', function() {
|
||||
const token = getCookie('token');
|
||||
if (token) {
|
||||
console.log('✅ Token 已从 Cookie 读取');
|
||||
console.log('Token 长度:', token.length);
|
||||
} else {
|
||||
console.warn('⚠️ 未找到 Token,订单查询功能可能无法使用');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Chatwoot Widget - 官方集成方式 -->
|
||||
<script>
|
||||
(function(d,t) {
|
||||
var BASE_URL="http://localhost:3000";
|
||||
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=BASE_URL+"/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g,s);
|
||||
g.onload=function(){
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: '39PNCMvbMk3NvB7uaDNucc6o',
|
||||
baseUrl: BASE_URL
|
||||
});
|
||||
|
||||
console.log('✅ Chatwoot Widget 已加载 (官方集成方式)');
|
||||
console.log('Base URL:', BASE_URL);
|
||||
console.log('Website Token: 39PNCMvbMk3NvB7uaDNucc6o');
|
||||
|
||||
// 设置用户信息(可选)
|
||||
setTimeout(function() {
|
||||
const token = getCookie('token');
|
||||
if (token && window.$chatwoot) {
|
||||
window.$chatwoot.setUser('user_' + Date.now(), {
|
||||
email: 'user@example.com',
|
||||
name: 'Website User',
|
||||
phone_number: ''
|
||||
});
|
||||
|
||||
console.log('✅ 用户信息已设置');
|
||||
} else if (!token) {
|
||||
console.warn('⚠️ 未找到 Token');
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
g.onerror=function(){
|
||||
console.error('❌ Chatwoot SDK 加载失败');
|
||||
console.error('请确保 Chatwoot 运行在: ' + BASE_URL);
|
||||
}
|
||||
})(document,"script");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user