2026-04-29 00:14:49 +08:00

468 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function () {
const supportedLanguages = ["en", "ar", "tr", "id"];
const languageLabels = {
en: "EN",
ar: "AR",
tr: "TR",
id: "ID"
};
const API_BASE_URL = "https://jvapi.haiyihy.com";
const fallbackMessages = {
en: {
document_title: "Host Policy",
back: "Back",
language_button_aria: "Change language",
anchor_policy: "Host Policy",
platform_policy: "Agency Policy",
policy_loading: "Loading policy...",
policy_empty: "No policy data",
policy_missing_token: "Missing token",
policy_missing_team: "Missing team ID",
policy_load_failed: "Failed to load policy",
policy_level: "Level",
policy_online: "Online (Hour)",
policy_effective_day: "Valid days",
policy_target: "Target",
policy_host_salary: "Host salary",
policy_agent_salary: "Agent salary",
policy_total_salary: "Total salary"
},
ar: {
document_title: "سياسة المضيف",
back: "رجوع",
language_button_aria: "تغيير اللغة",
anchor_policy: "سياسة المضيف",
platform_policy: "سياسة الوكالة",
policy_loading: "جار تحميل السياسة...",
policy_empty: "لا توجد بيانات سياسة",
policy_missing_token: "رمز الدخول مفقود",
policy_missing_team: "معرّف الفريق مفقود",
policy_load_failed: "فشل تحميل السياسة",
policy_level: "المستوى",
policy_online: "الاتصال (ساعة)",
policy_effective_day: "الأيام الصالحة",
policy_target: "الهدف",
policy_host_salary: "راتب المضيف",
policy_agent_salary: "راتب الوكيل",
policy_total_salary: "إجمالي الراتب"
},
tr: {
document_title: "Host Politikası",
back: "Geri",
language_button_aria: "Dili değiştir",
anchor_policy: "Host Politikası",
platform_policy: "Ajans Politikası",
policy_loading: "Politika yükleniyor...",
policy_empty: "Politika verisi yok",
policy_missing_token: "Token eksik",
policy_missing_team: "Takım ID eksik",
policy_load_failed: "Politika yüklenemedi",
policy_level: "Seviye",
policy_online: "Online (Saat)",
policy_effective_day: "Geçerli gün",
policy_target: "Hedef",
policy_host_salary: "Host maaşı",
policy_agent_salary: "Ajans maaşı",
policy_total_salary: "Toplam maaş"
},
id: {
document_title: "Kebijakan Host",
back: "Kembali",
language_button_aria: "Ubah bahasa",
anchor_policy: "Kebijakan Host",
platform_policy: "Kebijakan Agensi",
policy_loading: "Memuat kebijakan...",
policy_empty: "Tidak ada data kebijakan",
policy_missing_token: "Token tidak ditemukan",
policy_missing_team: "ID tim tidak ditemukan",
policy_load_failed: "Gagal memuat kebijakan",
policy_level: "Level",
policy_online: "Online (Jam)",
policy_effective_day: "Hari valid",
policy_target: "Target",
policy_host_salary: "Gaji host",
policy_agent_salary: "Gaji agensi",
policy_total_salary: "Total gaji"
}
};
const params = readURLParams();
let currentLang = normalizeLanguage(params.get("lang"));
let currentMessages = fallbackMessages[currentLang] || fallbackMessages.en;
let currentPolicy = null;
let policyStatusKey = "policy_loading";
function isAgencyPolicy() {
return params.get("from") === "agencycenter";
}
function policyTitleKey() {
return isAgencyPolicy() ? "platform_policy" : "anchor_policy";
}
function readURLParams() {
const result = new URLSearchParams(window.location.search);
const hashQuery = window.location.hash.includes("?") ? window.location.hash.split("?")[1] : "";
const hashParams = new URLSearchParams(hashQuery);
hashParams.forEach((value, key) => {
if (!result.has(key)) result.set(key, value);
});
return result;
}
function readRawParam(name) {
const queries = [window.location.search.replace(/^\?/, "")];
if (window.location.hash.includes("?")) queries.push(window.location.hash.split("?")[1]);
for (const query of queries) {
for (const part of query.split("&")) {
if (!part) continue;
const equalIndex = part.indexOf("=");
const rawKey = equalIndex >= 0 ? part.slice(0, equalIndex) : part;
const rawValue = equalIndex >= 0 ? part.slice(equalIndex + 1) : "";
let decodedKey = "";
try {
decodedKey = decodeURIComponent(rawKey);
} catch (error) {
continue;
}
if (decodedKey !== name) continue;
try {
return decodeURIComponent(rawValue.replace(/\+/g, "%2B"));
} catch (error) {
return rawValue;
}
}
}
return "";
}
function normalizeLanguage(lang) {
const value = String(lang || "en").toLowerCase();
return supportedLanguages.includes(value) ? value : "en";
}
async function loadMessages(lang) {
const normalizedLang = normalizeLanguage(lang);
if (window.location.protocol === "file:") return fallbackMessages[normalizedLang];
try {
const response = await fetch(`./locales/${normalizedLang}.json?v=20260428-2100`, { cache: "no-store" });
if (response.ok) return await response.json();
} catch (error) {
return fallbackMessages[normalizedLang];
}
return fallbackMessages[normalizedLang];
}
function message(key, fallback) {
return currentMessages[key] || fallbackMessages.en[key] || fallback || key;
}
function renderMessages(messages) {
document.querySelectorAll("[data-i18n]").forEach((node) => {
const value = messages[node.dataset.i18n];
if (value) node.textContent = value;
});
document.querySelectorAll("[data-i18n-aria]").forEach((node) => {
const value = messages[node.dataset.i18nAria];
if (value) node.setAttribute("aria-label", value);
});
const title = messages[policyTitleKey()] || messages.anchor_policy || fallbackMessages.en.anchor_policy;
document.querySelectorAll("[data-policy-title]").forEach((node) => {
node.textContent = title;
});
document.querySelector(".policy-page")?.setAttribute("aria-label", title);
}
function apiBaseURL() {
const override = window.HYAPP_API_BASE_URL || params.get("apiBase");
if (override) return String(override).replace(/\/+$/, "");
return API_BASE_URL.replace(/\/+$/, "");
}
function normalizeAuthorization(token) {
const value = String(token || "").trim();
if (!value) return "";
return /^bearer\s+/i.test(value) ? value : `Bearer ${value}`;
}
function authHeadersFromToken(token) {
return {
Authorization: normalizeAuthorization(token),
"req-lang": currentLang,
"req-client": "H5",
"req-version": "V2",
"req-zone": Intl.DateTimeFormat().resolvedOptions().timeZone || "Asia/Shanghai",
"req-app-intel": "version=1.0.0;build=1;model=H5;sysVersion=Web;channel=Web",
"req-sys-origin": "origin=ATYOU;originChild=ATYOU"
};
}
function renderPolicyStatus(key, fallback) {
policyStatusKey = key;
const status = document.querySelector("#policyStatus");
const list = document.querySelector("#policyList");
const region = document.querySelector("#policyRegion");
if (status) {
status.textContent = message(key, fallback);
status.hidden = false;
}
if (list) {
list.hidden = true;
list.replaceChildren();
}
if (region) region.textContent = "";
}
function formatPlainValue(value) {
if (value === null || value === undefined || value === "") return "0";
return String(value);
}
function formatTarget(value) {
const number = Number(value);
if (!Number.isFinite(number)) return formatPlainValue(value);
if (number >= 1000000) return `${(number / 1000000).toFixed(1)}M`;
if (number >= 1000) return `${(number / 1000).toFixed(1)}K`;
return String(number);
}
function formatSalary(value, policyType) {
const text = formatPlainValue(value);
return policyType === "SALARY_DIAMOND" ? text : `$${text}`;
}
function createPolicyCell(label, value) {
const cell = document.createElement("div");
cell.className = "policy-cell";
const labelNode = document.createElement("div");
labelNode.className = "policy-cell-label";
labelNode.textContent = label;
const valueNode = document.createElement("div");
valueNode.className = "policy-cell-value";
valueNode.textContent = value;
cell.append(labelNode, valueNode);
return cell;
}
function createPolicyRow(item, policyType) {
const row = document.createElement("article");
row.className = "policy-row";
const head = document.createElement("div");
head.className = "policy-row-head";
const level = document.createElement("div");
level.className = "policy-level";
level.textContent = `${message("policy_level")} ${formatPlainValue(item.level)}`;
const effectiveDay = document.createElement("div");
effectiveDay.className = "policy-effective-day";
effectiveDay.textContent = `${message("policy_effective_day")}: ${formatPlainValue(item.effectiveDay)}`;
head.append(level, effectiveDay);
const grid = document.createElement("div");
grid.className = "policy-grid";
grid.append(
createPolicyCell(message("policy_online"), formatPlainValue(item.onlineTime)),
createPolicyCell(message("policy_target"), formatTarget(item.target)),
createPolicyCell(message("policy_host_salary"), formatSalary(item.memberSalary, policyType)),
createPolicyCell(message("policy_agent_salary"), formatSalary(item.ownSalary, policyType)),
createPolicyCell(message("policy_total_salary"), formatSalary(item.totalSalary, policyType))
);
row.append(head, grid);
return row;
}
function pickTeamId(entry) {
return entry?.teamProfile?.id || entry?.teamId || entry?.id || "";
}
async function fetchTeamEntryId(token) {
try {
const url = new URL("/team/entry", `${apiBaseURL()}/`);
const response = await fetch(url.toString(), {
cache: "no-store",
headers: authHeadersFromToken(token)
});
const data = await response.json().catch(() => ({}));
if (!response.ok || data.status === false) {
throw new Error(data.errorMsg || data.message || `Request failed: ${response.status}`);
}
return pickTeamId(data.body || data.data || {});
} catch (error) {
console.error("Failed to resolve team ID:", error);
return "";
}
}
async function resolveTeamId(token, forceTeamEntry = false) {
const directTeamId = params.get("teamId") || params.get("team_id") || params.get("TEAM_ID");
if (directTeamId && !forceTeamEntry) return directTeamId;
return fetchTeamEntryId(token);
}
async function requestTeamPolicy(token, teamId) {
const url = new URL("/team/release/policy", `${apiBaseURL()}/`);
url.searchParams.set("id", teamId);
const response = await fetch(url.toString(), {
cache: "no-store",
headers: authHeadersFromToken(token)
});
const data = await response.json().catch(() => ({}));
if (!response.ok || data.status === false) {
const error = new Error(data.errorMsg || data.message || `Request failed: ${response.status}`);
error.response = data;
throw error;
}
return data.body || data.data || {};
}
function renderAnchorPolicy(policy) {
const rows = Array.isArray(policy?.policy) ? policy.policy : [];
const list = document.querySelector("#policyList");
const status = document.querySelector("#policyStatus");
const region = document.querySelector("#policyRegion");
if (!list || !status) return;
if (region) {
region.textContent = [policy?.regionCode || policy?.region, policy?.countryCode].filter(Boolean).join(" · ");
}
if (!rows.length || policy?.empty) {
renderPolicyStatus("policy_empty");
return;
}
status.textContent = "";
status.hidden = true;
list.hidden = false;
list.replaceChildren(...rows.map((item) => createPolicyRow(item, policy?.policyType)));
}
async function fetchAnchorPolicy() {
renderPolicyStatus("policy_loading");
const token = readRawParam("token");
if (!token) {
renderPolicyStatus("policy_missing_token");
return;
}
try {
const teamId = await resolveTeamId(token);
if (!teamId) {
renderPolicyStatus("policy_missing_team");
return;
}
try {
currentPolicy = await requestTeamPolicy(token, teamId);
} catch (error) {
const fallbackTeamId = await resolveTeamId(token, true);
if (!fallbackTeamId || fallbackTeamId === teamId) throw error;
currentPolicy = await requestTeamPolicy(token, fallbackTeamId);
}
renderAnchorPolicy(currentPolicy);
} catch (error) {
console.error("Failed to load anchor policy:", error);
currentPolicy = null;
renderPolicyStatus("policy_load_failed", error.message);
}
}
function syncBackFallback() {
const backButton = document.querySelector(".back-button");
if (!backButton) return;
backButton.addEventListener("click", () => {
if (window.history.length > 1) {
window.history.back();
return;
}
const nextParams = new URLSearchParams(params);
const token = readRawParam("token");
if (token) nextParams.set("token", token);
if (currentLang) nextParams.set("lang", currentLang);
const query = nextParams.toString();
const fallbackPath = isAgencyPolicy() ? "../agency-center/index.html" : "./index.html";
window.location.href = `${fallbackPath}${query ? `?${query}` : ""}`;
});
}
function setLanguageMenuOpen(open) {
const languageButton = document.querySelector(".language-button");
const languageMenu = document.querySelector(".language-menu");
if (!languageButton || !languageMenu) return;
languageMenu.hidden = !open;
languageButton.setAttribute("aria-expanded", String(open));
}
function renderLanguageControls(messages) {
const languageButton = document.querySelector(".language-button");
if (languageButton) {
languageButton.textContent = languageLabels[currentLang];
languageButton.setAttribute("aria-label", messages.language_button_aria || "Change language");
}
document.querySelectorAll(".language-menu [data-lang]").forEach((button) => {
const isActive = button.dataset.lang === currentLang;
button.classList.toggle("is-active", isActive);
button.setAttribute("aria-pressed", String(isActive));
});
}
async function applyLanguage(lang) {
currentLang = normalizeLanguage(lang);
const messages = await loadMessages(currentLang);
currentMessages = messages;
document.documentElement.lang = currentLang;
document.documentElement.dir = currentLang === "ar" ? "rtl" : "ltr";
document.title = messages[policyTitleKey()] || messages.anchor_policy || messages.document_title || "Host Policy";
renderMessages(messages);
renderLanguageControls(messages);
if (currentPolicy) {
renderAnchorPolicy(currentPolicy);
} else {
renderPolicyStatus(policyStatusKey);
}
}
document.querySelector(".language-button")?.addEventListener("click", (event) => {
event.stopPropagation();
const languageMenu = document.querySelector(".language-menu");
setLanguageMenuOpen(Boolean(languageMenu?.hidden));
});
document.querySelectorAll(".language-menu [data-lang]").forEach((button) => {
button.addEventListener("click", (event) => {
event.stopPropagation();
setLanguageMenuOpen(false);
applyLanguage(button.dataset.lang);
});
});
document.addEventListener("click", () => {
setLanguageMenuOpen(false);
});
syncBackFallback();
applyLanguage(currentLang).then(fetchAnchorPolicy);
})();