454 lines
12 KiB
HTML
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 %}
|