# Chatwoot Widget 初始化流程说明 ## 🔍 当前的初始化流程 ### 1. 页面首次加载(游客模式) **服务器端 (Ruby ERB):** ```erb <% token_present = cookies[:token].present? # false test_user_id = nil # 没有用户 ID test_user_hash = nil %> ``` **前端 JavaScript:** ```javascript // 服务器端渲染后 const TEST_USER = { userId: '', // 空字符串 userHash: '', // 空字符串 ... }; const token = getCookie('token'); // null if (token) { // 不执行 } const widgetConfig = { websiteToken: 'xxx', baseUrl: '', locale: 'zh_CN', useBrowserLanguage: false // 没有 userIdentifier }; window.chatwootSDK.run(widgetConfig); // ✅ Widget 初始化成功(游客模式) ``` ### 2. 点击登录(不刷新) ```javascript function simulateLogin() { setCookie('token', TEST_TOKEN); // 设置 cookie isLoggedIn = true; currentUser = TEST_USER; // 调用 setUser 设置用户信息 window.$chatwoot.setUser(currentUser.userId, { identifier_hash: currentUser.userHash, email: currentUser.email, name: currentUser.name, ... }); // ✅ 用户信息已设置 // ⚠️ 但 widget 仍然是游客模式初始化的! } ``` ### 3. 刷新页面(登录后) **服务器端 (Ruby ERB):** ```erb <% token_present = cookies[:token].present? # ✅ true test_user_id = '211845' # ✅ 有用户 ID test_user_hash = OpenSSL::HMAC.hexdigest(...) %> ``` **前端 JavaScript:** ```javascript // 服务器端渲染后 const TEST_USER = { userId: '211845', # ✅ 正确的用户 ID userHash: 'xxx...', # ✅ 正确的 hash ... }; const token = getCookie('token'); // ✅ 存在 if (token) { const widgetConfig = { websiteToken: 'xxx', baseUrl: '', locale: 'zh_CN', useBrowserLanguage: false, userIdentifier: '211845' # ✅ 设置用户标识 }; window.chatwootSDK.run(widgetConfig); // ❌ 问题:window.$chatwoot 已经存在! // ❌ SDK 内部会 return,不会重新初始化! } ``` ## ⚠️ 核心问题 **Chatwoot SDK 只能初始化一次!** ```javascript // app/javascript/entrypoints/sdk.js:21-24 runSDK({ baseUrl, websiteToken }) { if (window.$chatwoot) { return; // ❌ 已经初始化过,直接返回 } // ... 初始化代码 } ``` ## 💡 解决方案 ### 方案 1:登录时强制刷新(推荐) ```javascript function simulateLogin() { setCookie('token', TEST_TOKEN); isLoggedIn = true; currentUser = TEST_USER; // 立即刷新页面,让 SDK 正确初始化 addLog('💡 即将刷新页面以应用登录状态...'); setTimeout(() => { location.reload(); }, 500); } ``` **优点:** - 简单可靠 - SDK 会正确初始化 - userIdentifier 在初始化时就设置 **缺点:** - 需要刷新页面 - 用户体验略差 ### 方案 2:在登录前先 reset ```javascript function simulateLogin() { // 先清除旧的 SDK 实例 if (window.$chatwoot && window.$chatwoot.reset) { window.$chatwoot.reset(); } // 等待 reset 完成 setTimeout(() => { setCookie('token', TEST_TOKEN); isLoggedIn = true; currentUser = TEST_USER; // 重新初始化 const widgetConfig = { websiteToken: '<%= @web_widget.website_token %>', baseUrl: '', locale: 'zh_CN', useBrowserLanguage: false, userIdentifier: currentUser.userId }; window.chatwootSDK.run(widgetConfig); // ... }, 100); } ``` **问题:** - SDK 已经初始化检查在 `run()` 函数内部 - 无法绕过这个检查 ### 方案 3:使用 iframe 的方式(不推荐) 每次都创建新的 iframe,但这样会失去状态同步。 ## ✅ 推荐的实现 **登录时自动刷新页面:** ```javascript function simulateLogin() { addLog('🔐 开始模拟用户登录...'); // 设置 token cookie setCookie('token', TEST_TOKEN); // 验证设置成功 const tokenCheck = getCookie('token'); if (tokenCheck) { addLog('✅ Token 已设置'); addLog('⏳ 即将刷新页面以完成登录...'); // 显示倒计时 let countdown = 2; const countdownInterval = setInterval(() => { countdown--; if (countdown <= 0) { clearInterval(countdownInterval); location.reload(); } }, 1000); } else { addLog('❌ Token 设置失败'); } } ``` ## 📊 完整流程 ### 游客 → 登录: ``` 1. 游客模式访问 2. 点击登录 3. 设置 token 4. 自动刷新(2秒倒计时) 5. Ruby 检测到 token,设置 user_id = '211845' 6. SDK 初始化(带 userIdentifier) 7. ✅ 登录成功 ``` ### 登录 → 退出: ``` 1. 点击退出 2. 删除 token 3. 调用 reset() 清除所有数据 4. ✅ 立即切换到游客模式 ``` ### 退出 → 登录: ``` 1. 游客模式 2. 点击登录 3. 设置 token 4. 自动刷新 5. ✅ 恢复登录状态(新会话) ``` ## 🎯 总结 **Chatwoot SDK 的设计限制:** - SDK 只能初始化一次 - 初始化后无法动态更改 userIdentifier - 必须刷新页面才能重新初始化 **最佳实践:** - **登录/退出时都刷新页面** - 服务器端检查 token 来决定初始状态 - 确保每次刷新都能正确初始化