最初版本
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
{% 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
|
||||
});
|
||||
};
|
||||
|
||||
script.onerror = function () {
|
||||
console.error(
|
||||
"Chatwoot SDK load failed:",
|
||||
script.src
|
||||
);
|
||||
};
|
||||
|
||||
firstScript.parentNode.insertBefore(
|
||||
script,
|
||||
firstScript
|
||||
);
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}{{ app_name }}{% endblock %}</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body class="{% block body_class %}{% endblock %}">
|
||||
{% block body %}{% endblock %}
|
||||
{% block integrations %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,67 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}客服中心|{{ app_name }}{% endblock %}
|
||||
{% block body %}
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<div class="site-title">客服測試入口</div>
|
||||
<div class="site-subtitle">目前用戶:{{ username }}</div>
|
||||
</div>
|
||||
<a class="back-link" href="{{ url_for('home') }}">返回首頁</a>
|
||||
</header>
|
||||
|
||||
<main class="page narrow">
|
||||
<section class="support-panel">
|
||||
<div class="support-avatar">🎧</div>
|
||||
<h1>會員資料查詢</h1>
|
||||
{% if error %}
|
||||
<div class="alert alert-error">{{ error }}</div>
|
||||
{% else %}
|
||||
{% if account.status == "locked" %}
|
||||
<div class="alert alert-warning">
|
||||
帳戶已凍結{% if account.locked_reason %}|{{ account.locked_reason }}{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2>未完成提款</h2>
|
||||
{% if not withdrawals %}
|
||||
<div class="empty-state">目前沒有查到未完成提款資料。</div>
|
||||
{% else %}
|
||||
<div class="order-list">
|
||||
{% for order in withdrawals %}
|
||||
<article class="order-card">
|
||||
<strong>{{ order.status or "狀態未知" }}</strong>
|
||||
<span>來源:{{ order.source }}</span>
|
||||
<span>訂單:{{ order.order_id or "NA" }}</span>
|
||||
<span>金額:{{ order.amount }}</span>
|
||||
<span>時間:{{ order.create_time or "NA" }}</span>
|
||||
{% if order.fail_reason %}<span>備註:{{ order.fail_reason }}</span>{% endif %}
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2 class="section-gap">最近充值</h2>
|
||||
{% if not deposits %}
|
||||
<div class="empty-state">目前沒有查到充值資料。</div>
|
||||
{% else %}
|
||||
<div class="order-list">
|
||||
{% for order in deposits %}
|
||||
<article class="order-card">
|
||||
<strong>{{ order.status or "狀態未知" }}</strong>
|
||||
<span>訂單:{{ order.thirdparty_order_id or "NA" }}</span>
|
||||
<span>充值金額:{{ order.amount }}</span>
|
||||
<span>實際到帳:{{ order.actual_arrival_amount }}</span>
|
||||
<span>充值時間:{{ order.created_at or "NA" }}</span>
|
||||
<span>到帳時間:{{ order.arrival_time or "NA" }}</span>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</section>
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
{% block integrations %}
|
||||
{% include "_chatwoot.html" %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ title }}|{{ app_name }}{% endblock %}
|
||||
{% block body_class %}login-body{% endblock %}
|
||||
{% block body %}
|
||||
<main class="login-card">
|
||||
<div class="brand-mark">!</div>
|
||||
<h1>{{ title }}</h1>
|
||||
<div class="alert alert-error">{{ message }}</div>
|
||||
<a class="primary-link" href="{{ url_for('root') }}">返回系統</a>
|
||||
</main>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,38 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}游客客服|{{ app_name }}{% endblock %}
|
||||
{% block body_class %}guest-page{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<div class="site-title">游客客服中心</div>
|
||||
<div class="site-subtitle">Guest Customer Service</div>
|
||||
</div>
|
||||
<a class="back-link" href="{{ url_for('login') }}">返回登录页</a>
|
||||
</header>
|
||||
|
||||
<main class="page narrow">
|
||||
<section class="support-panel guest-support-panel">
|
||||
<div class="support-avatar">🎧</div>
|
||||
<span class="guest-badge">游客模式</span>
|
||||
<h1>欢迎使用在线客服</h1>
|
||||
<p>您目前以游客身份进入,可咨询注册、登录、活动与平台操作问题。</p>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
游客模式不会识别会员身份,也不能查询充值、提款、余额或其他会员资料。
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="primary-button guest-open-chat"
|
||||
onclick="if (window.openGuestChatNewConversation) { window.openGuestChatNewConversation(); }"
|
||||
>
|
||||
开启在线客服
|
||||
</button>
|
||||
</section>
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
{% block integrations %}
|
||||
{% include "_chatwoot.html" %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,74 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}遊戲首頁|{{ app_name }}{% endblock %}
|
||||
{% block body %}
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<div class="site-title">YD GAME DEMO</div>
|
||||
<div class="site-subtitle">Python 唯讀 API 測試站點</div>
|
||||
</div>
|
||||
<div class="member-area">
|
||||
<span>用戶:<strong>{{ account.raw_username or username }}</strong></span>
|
||||
<span class="status-badge {{ account.status }}">
|
||||
{{ "已凍結" if account.status == "locked" else "正常" }}
|
||||
</span>
|
||||
<form
|
||||
method="post"
|
||||
action="{{ url_for('logout') }}"
|
||||
onsubmit="return window.resetChatwootBeforeLogout ? window.resetChatwootBeforeLogout(this) : true;"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="logout-button" type="submit">登出</button>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="page">
|
||||
{% if warning %}
|
||||
<div class="alert alert-error">帳戶資料讀取失敗:{{ warning }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if account.status == "locked" %}
|
||||
<div class="alert alert-warning">
|
||||
<strong>帳戶已凍結</strong>
|
||||
{% if account.locked_reason %}|凍結原因:{{ account.locked_reason }}{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<section class="hero">
|
||||
<div>
|
||||
<span class="eyebrow">PYTHON TEST ENVIRONMENT</span>
|
||||
<h1>歡迎進入遊戲站點模擬首頁</h1>
|
||||
<p>登入會員:{{ account.username_clean or username }}。本頁只用於驗證會員資料、充值、提款與客服 API。</p>
|
||||
</div>
|
||||
<a class="service-entry" href="{{ url_for('customer_service') }}">
|
||||
<span class="service-icon">🎧</span>
|
||||
<span><strong>在線客服</strong><small>查詢充值與提款資料</small></span>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section class="account-grid">
|
||||
<div class="metric-card"><span>UID</span><strong>{{ account.uid or "NA" }}</strong></div>
|
||||
<div class="metric-card"><span>VIP 等級</span><strong>{{ account.vip_level or "NA" }}</strong></div>
|
||||
<div class="metric-card"><span>會員餘額</span><strong>{{ account.balance or "0.0000" }}</strong></div>
|
||||
<div class="metric-card"><span>凍結餘額</span><strong>{{ account.frozen_balance or "0.0000" }}</strong></div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-heading"><h2>熱門遊戲</h2><span>畫面模擬,不執行真實投注</span></div>
|
||||
<div class="game-grid">
|
||||
{% for game in games %}
|
||||
<article class="game-card">
|
||||
<div class="game-icon">{{ game.icon }}</div>
|
||||
<div><h3>{{ game.name }}</h3><p>{{ game.category }}</p></div>
|
||||
<button type="button" disabled>模擬遊戲</button>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<a class="floating-service" href="{{ url_for('customer_service') }}">🎧 客服</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block integrations %}
|
||||
{% include "_chatwoot.html" %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,40 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}登录|{{ app_name }}{% endblock %}
|
||||
{% block body_class %}login-body{% endblock %}
|
||||
{% block body %}
|
||||
<main class="login-card">
|
||||
<div class="brand-mark">YD</div>
|
||||
<h1>游戏站点模拟</h1>
|
||||
<p class="muted">仅使用 members 表内存在的用户名登录,不需要密码。</p>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
|
||||
<form method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<label for="username">用户名</label>
|
||||
<input id="username" name="username" type="text" maxlength="191"
|
||||
value="{{ username }}" placeholder="输入 username 或 username_clean"
|
||||
required autofocus>
|
||||
<button type="submit" class="primary-button">登录测试站点</button>
|
||||
</form>
|
||||
|
||||
<div class="login-divider"><span>或</span></div>
|
||||
|
||||
<a
|
||||
class="guest-service-button"
|
||||
href="{{ url_for('guest_customer_service') }}"
|
||||
>
|
||||
🎧 游客进入客服
|
||||
</a>
|
||||
|
||||
<p class="guest-service-note">
|
||||
游客只能进行一般咨询,不能查询会员充值、提款或账户资料。
|
||||
</p>
|
||||
|
||||
<p class="security-note">【测试限定】此登录方式不具备正式身份验证能力。</p>
|
||||
</main>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user