Files
2026-08-15 14:51:51 +08:00

454 lines
12 KiB
HTML

{% if chatwoot_config.enabled %}
<script>
(function () {
"use strict";
/*
* 會員身份由 Flask Session 注入,identifier 直接使用 username_clean。
* 不再接受 ?identifier=... 等網址參數,避免使用者冒充其他會員。
*/
const CHATWOOT_CONFIG = {{ chatwoot_config | tojson }};
const CHATWOOT_USER = {{ chatwoot_user | tojson }};
window.chatwootSettings = {
hideMessageBubble: false,
showUnreadMessagesDialog: false,
position: "right",
locale: "zh_TW",
useBrowserLanguage: false,
type: "standard",
darkMode: "auto",
launcherTitle: ""
};
function debugLog() {
if (!CHATWOOT_CONFIG.debug) {
return;
}
console.log.apply(console, arguments);
}
function configureChatwootIdentity() {
if (!window.$chatwoot) {
return;
}
if (!CHATWOOT_USER.is_authenticated) {
if (typeof window.$chatwoot.setCustomAttributes === "function") {
window.$chatwoot.setCustomAttributes({
visitor_type: "guest"
});
}
debugLog("Chatwoot anonymous guest ready");
return;
}
if (
typeof window.$chatwoot.setUser !== "function" ||
!CHATWOOT_USER.identifier
) {
return;
}
const userPayload = {
name: CHATWOOT_USER.name || CHATWOOT_USER.username
};
if (CHATWOOT_USER.identifier_hash) {
userPayload.identifier_hash = CHATWOOT_USER.identifier_hash;
}
window.$chatwoot.setUser(
CHATWOOT_USER.identifier,
userPayload
);
if (typeof window.$chatwoot.setCustomAttributes === "function") {
window.$chatwoot.setCustomAttributes({
visitor_type: "member",
username: CHATWOOT_USER.username || "",
member_uid: CHATWOOT_USER.uid == null
? ""
: String(CHATWOOT_USER.uid),
account_status: CHATWOOT_USER.account_status || "",
locked_reason: CHATWOOT_USER.locked_reason || "",
member_type: CHATWOOT_USER.member_type || "",
vip_level: CHATWOOT_USER.vip_level || "",
tier: CHATWOOT_USER.tier || ""
});
}
}
/*
* Flask 登出前清除 Chatwoot Session,避免下一個登入會員
* 沿用上一位會員的 Chatwoot Cookie 與對話。
*/
window.resetChatwootBeforeLogout = function (form) {
if (!form) {
return true;
}
/*
* 防止使用者重複點擊登出,造成多次提交。
*/
if (form.dataset.submitting === "true") {
return false;
}
form.dataset.submitting = "true";
const submitLogout = function () {
form.submit();
};
if (
window.$chatwoot &&
typeof window.$chatwoot.reset === "function"
) {
try {
window.$chatwoot.reset();
} catch (error) {
console.error(
"Chatwoot reset before logout failed:",
error
);
}
/*
* Chatwoot reset 沒有 Promise 回傳,因此提供短暫緩衝時間。
* 即使前端清理未完成,後端的一次性 guest reset
* 仍會在登出後首次載入匿名頁面時再次執行。
*/
window.setTimeout(
submitLogout,
300
);
return false;
}
submitLogout();
return false;
};
window.openGuestChatNewConversation = function () {
createGuestConversationAndShow({ openAfter: true });
};
window.exitGuestChatAndStartNew = function () {
// 先關掉視窗,再換成新對話並重新打開
closeGuestChat();
createGuestConversationAndShow({ openAfter: true, delayMs: 350 });
};
function createGuestConversationAndShow(options) {
var opts = options || {};
var openAfter = opts.openAfter !== false;
var delayMs = typeof opts.delayMs === "number" ? opts.delayMs : 700;
if (!CHATWOOT_CONFIG.guest_new_path) {
return;
}
fetch(CHATWOOT_CONFIG.guest_new_path, {
method: "POST",
headers: {
Accept: "application/json",
"X-CSRF-Token": CHATWOOT_CONFIG.csrf_token || ""
}
})
.then(function (response) {
return response.json().then(function (data) {
if (!response.ok) {
throw new Error((data && data.message) || "建立游客对话失败");
}
return data;
});
})
.then(function (data) {
if (!data || !data.widget_token) {
throw new Error("Chatwoot 未回傳 widget_token");
}
document.querySelectorAll("iframe[src*='widget']").forEach(
function (iframe) {
const url = new URL(iframe.src, window.location.origin);
url.searchParams.set("cw_conversation", data.widget_token);
url.hash = "/messages";
iframe.src = url.toString();
}
);
if (!openAfter) {
window.__guestWidgetOpen = false;
return;
}
window.__guestWidgetOpen = true;
window.setTimeout(function () {
if (
window.$chatwoot &&
typeof window.$chatwoot.toggle === "function"
) {
window.$chatwoot.toggle("open");
}
}, delayMs);
})
.catch(function (error) {
console.error("Chatwoot guest open failed:", error);
window.alert("客服暂时无法开启,请稍后再试。");
});
};
function isGuestChatOpen() {
var holder = document.querySelector(".woot-widget-holder");
if (holder && !holder.classList.contains("woot--hide")) {
var style = window.getComputedStyle(holder);
var rect = holder.getBoundingClientRect();
if (
style.display !== "none" &&
style.visibility !== "hidden" &&
Number(style.opacity || "1") > 0 &&
rect.width > 0 &&
rect.height > 0
) {
return true;
}
}
return !!window.__guestWidgetOpen;
}
function openGuestChatResume() {
window.__guestWidgetOpen = true;
if (window.$chatwoot && typeof window.$chatwoot.toggle === "function") {
try {
window.$chatwoot.toggle("open");
return;
} catch (error) {}
}
var holder = document.querySelector(".woot-widget-holder");
if (holder) {
holder.classList.remove("woot--hide");
}
}
function closeGuestChat() {
window.__guestWidgetOpen = false;
if (window.$chatwoot && typeof window.$chatwoot.toggle === "function") {
try {
window.$chatwoot.toggle("close");
return;
} catch (error) {}
}
var holder = document.querySelector(".woot-widget-holder");
if (holder) {
holder.classList.add("woot--hide");
}
}
function bindGuestBubbleToggle() {
if (!CHATWOOT_CONFIG.guest_new_path || window.__guestBubbleBound) {
return;
}
window.__guestBubbleBound = true;
window.addEventListener("chatwoot:opened", function () {
window.__guestWidgetOpen = true;
});
window.addEventListener("chatwoot:closed", function () {
window.__guestWidgetOpen = false;
});
document.addEventListener(
"click",
function (event) {
var target = event.target;
if (!target || typeof target.closest !== "function") {
return;
}
var bubble = target.closest(
".woot-widget-bubble, .woot--bubble-holder, button.woot-widget-bubble"
);
if (!bubble) {
return;
}
// 右下角氣泡:只收起/重開同一個對話,绝不開新單。
event.preventDefault();
event.stopPropagation();
if (isGuestChatOpen()) {
closeGuestChat();
} else {
openGuestChatResume();
}
},
true
);
}
window.addEventListener("message", function (event) {
var raw = event && event.data;
if (typeof raw !== "string" || raw.indexOf("chatwoot-widget:") !== 0) {
return;
}
try {
var payload = JSON.parse(raw.replace("chatwoot-widget:", ""));
if (payload && payload.event === "guestExitNewChat") {
if (typeof window.exitGuestChatAndStartNew === "function") {
window.exitGuestChatAndStartNew();
} else if (typeof window.openGuestChatNewConversation === "function") {
window.openGuestChatNewConversation();
}
}
} catch (error) {}
});
window.addEventListener(
"chatwoot:ready",
function () {
debugLog("chatwoot:ready", window.$chatwoot);
const guestResetRequired =
{{ chatwoot_guest_reset_required | tojson }};
/*
* 只有「剛完成會員登出」且目前未登入時,才清除舊會員身份。
* 一般遊客頁面不會每次都 reset,因此不會破壞既有匿名對話。
*/
if (
!CHATWOOT_USER.is_authenticated &&
guestResetRequired &&
window.$chatwoot &&
typeof window.$chatwoot.reset === "function"
) {
try {
window.$chatwoot.reset();
} catch (error) {
console.error(
"Chatwoot guest reset failed:",
error
);
}
/*
* reset 後稍候再設定 visitor_type=guest。
* 不執行 setUser(),因此不會向 Chatwoot 傳遞用戶名。
*/
window.setTimeout(
configureChatwootIdentity,
300
);
bindGuestBubbleToggle();
return;
}
configureChatwootIdentity();
bindGuestBubbleToggle();
}
);
window.addEventListener(
"chatwoot:error",
function (event) {
console.error(
"chatwoot:error",
event && event.detail ? event.detail : event
);
}
);
if (CHATWOOT_CONFIG.debug) {
window.addEventListener(
"chatwoot:on-message",
function (event) {
debugLog("chatwoot:on-message", event.detail);
}
);
window.addEventListener(
"chatwoot:postback",
function (event) {
debugLog("chatwoot:postback", event.detail);
}
);
window.addEventListener(
"chatwoot:opened",
function () {
debugLog("chatwoot:opened");
}
);
window.addEventListener(
"chatwoot:closed",
function () {
debugLog("chatwoot:closed");
}
);
window.addEventListener(
"chatwoot:on-start-conversation",
function (event) {
debugLog(
"chatwoot:on-start-conversation",
event.detail
);
}
);
}
const script = document.createElement("script");
const firstScript = document.getElementsByTagName("script")[0];
script.src = (
CHATWOOT_CONFIG.base_url +
"/packs/js/sdk.js"
);
script.async = true;
script.onload = function () {
if (!window.chatwootSDK) {
console.error("Chatwoot SDK object not found");
return;
}
window.chatwootSDK.run({
websiteToken: CHATWOOT_CONFIG.website_token,
baseUrl: CHATWOOT_CONFIG.base_url
});
// 父頁強制觸發 iframe 內快捷入口/宣傳圖掛載(同源 /cw)
function boostGuestUi() {
try {
var iframes = document.querySelectorAll("iframe");
for (var i = 0; i < iframes.length; i += 1) {
var iframe = iframes[i];
var src = iframe.getAttribute("src") || "";
if (src.indexOf("widget") === -1 && src.indexOf("/cw") === -1) {
continue;
}
var win = iframe.contentWindow;
if (win && typeof win.__ydEnsureGuestUI === "function") {
win.__ydEnsureGuestUI();
}
}
} catch (err) {}
}
window.setInterval(boostGuestUi, 1000);
window.setTimeout(boostGuestUi, 1500);
window.setTimeout(boostGuestUi, 3500);
};
script.onerror = function () {
console.error(
"Chatwoot SDK load failed:",
script.src
);
};
firstScript.parentNode.insertBefore(
script,
firstScript
);
})();
</script>
{% endif %}