2026-04-28 20:57:04 +08:00

566 lines
18 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: "Join Agency",
page_label: "Join Agency",
back: "Back",
title: "Join Agency",
language_button_aria: "Change language",
agency_id: "Agency ID",
enter_agent_id: "Enter agency ID",
search: "Search",
searching: "Searching...",
apply: "Apply",
applying: "Applying...",
agency: "Agency",
uid_prefix: "UID:",
account_not_found: "Account not found or not an agency",
missing_token: "Missing token",
found: "Agency found",
application_submitted: "Application submitted",
application_failed: "Application failed",
application_records: "Application Records",
pending: "Pending",
cancel: "Cancel",
cancelling: "Cancelling...",
cancellation_failed: "Cancellation failed",
application_cancelled: "Application cancelled",
network_error: "Network error"
},
ar: {
document_title: "الانضمام إلى وكالة",
page_label: "الانضمام إلى وكالة",
back: "رجوع",
title: "الانضمام إلى وكالة",
language_button_aria: "تغيير اللغة",
agency_id: "معرّف الوكالة",
enter_agent_id: "أدخل معرّف الوكالة",
search: "بحث",
searching: "جار البحث...",
apply: "تقديم",
applying: "جار التقديم...",
agency: "الوكالة",
uid_prefix: "UID:",
account_not_found: "لم يتم العثور على وكالة",
missing_token: "رمز الدخول مفقود",
found: "تم العثور على الوكالة",
application_submitted: "تم إرسال الطلب",
application_failed: "فشل الطلب",
application_records: "سجلات الطلب",
pending: "قيد الانتظار",
cancel: "إلغاء",
cancelling: "جار الإلغاء...",
cancellation_failed: "فشل الإلغاء",
application_cancelled: "تم إلغاء الطلب",
network_error: "خطأ في الشبكة"
},
tr: {
document_title: "Ajansa Katıl",
page_label: "Ajansa Katıl",
back: "Geri",
title: "Ajansa Katıl",
language_button_aria: "Dili değiştir",
agency_id: "Ajans ID",
enter_agent_id: "Ajans ID gir",
search: "Ara",
searching: "Aranıyor...",
apply: "Başvur",
applying: "Başvuruluyor...",
agency: "Ajans",
uid_prefix: "UID:",
account_not_found: "Hesap bulunamadı veya ajans değil",
missing_token: "Token eksik",
found: "Ajans bulundu",
application_submitted: "Başvuru gönderildi",
application_failed: "Başvuru başarısız",
application_records: "Başvuru Kayıtları",
pending: "Beklemede",
cancel: "İptal",
cancelling: "İptal ediliyor...",
cancellation_failed: "İptal başarısız",
application_cancelled: "Başvuru iptal edildi",
network_error: "Ağ hatası"
},
id: {
document_title: "Gabung Agensi",
page_label: "Gabung Agensi",
back: "Kembali",
title: "Gabung Agensi",
language_button_aria: "Ubah bahasa",
agency_id: "ID Agensi",
enter_agent_id: "Masukkan ID agensi",
search: "Cari",
searching: "Mencari...",
apply: "Ajukan",
applying: "Mengajukan...",
agency: "Agensi",
uid_prefix: "UID:",
account_not_found: "Akun tidak ditemukan atau bukan agensi",
missing_token: "Token tidak ditemukan",
found: "Agensi ditemukan",
application_submitted: "Pengajuan dikirim",
application_failed: "Pengajuan gagal",
application_records: "Riwayat Pengajuan",
pending: "Menunggu",
cancel: "Batal",
cancelling: "Membatalkan...",
cancellation_failed: "Gagal membatalkan",
application_cancelled: "Pengajuan dibatalkan",
network_error: "Kesalahan jaringan"
}
};
const params = readURLParams();
let currentLang = normalizeLanguage(params.get("lang"));
let currentMessages = fallbackMessages[currentLang] || fallbackMessages.en;
let foundAgency = null;
let pendingRecord = null;
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";
}
function t(key) {
return currentMessages[key] || fallbackMessages.en[key] || key;
}
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"
};
}
async function apiRequest(path, options = {}) {
const token = readRawParam("token");
if (!token) throw new Error(t("missing_token"));
const method = options.method || "GET";
const headers = authHeadersFromToken(token);
const request = {
method,
cache: "no-store",
headers
};
if (options.body) {
headers["Content-Type"] = "application/json";
request.body = JSON.stringify(options.body);
}
const response = await fetch(new URL(path, `${apiBaseURL()}/`).toString(), request);
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 ?? null;
}
async function loadMessages(lang) {
return fallbackMessages[normalizeLanguage(lang)] || fallbackMessages.en;
}
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);
});
document.querySelectorAll("[data-i18n-placeholder]").forEach((node) => {
const value = messages[node.dataset.i18nPlaceholder];
if (value) node.setAttribute("placeholder", value);
});
}
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.document_title || "Join Agency";
renderMessages(messages);
renderLanguageControls(messages);
renderFoundAgency(foundAgency);
renderPendingRecord(pendingRecord);
}
function showMessage(message, type = "") {
const node = document.querySelector("#statusMessage");
if (!node) return;
node.textContent = message || "";
node.hidden = !message;
node.classList.toggle("is-error", type === "error");
node.classList.toggle("is-success", type === "success");
}
function pickProfile(body) {
return body?.ownUserProfile || body?.userProfile || body?.teamProfile || body || null;
}
function pickSpecialAccount(profile) {
return profile?.ownSpecialId?.account ||
profile?.specialId?.account ||
profile?.specialAccount ||
profile?.shortAccount ||
profile?.shortId ||
"";
}
function pickSearchAgency(body) {
const teamProfile = body?.teamProfile || null;
const userProfile = body?.ownUserProfile || body?.userProfile || teamProfile?.ownUserProfile || teamProfile?.userProfile || null;
if (!teamProfile?.id) return null;
const specialAccount = pickSpecialAccount(userProfile) || pickSpecialAccount(teamProfile);
return {
...(teamProfile || {}),
...(userProfile || {}),
id: teamProfile.id,
teamId: teamProfile.id,
teamName: teamProfile.teamName || userProfile?.teamName || "",
userNickname: userProfile?.userNickname || teamProfile.userNickname || teamProfile.name || teamProfile.teamName || "",
name: userProfile?.name || teamProfile.name || teamProfile.teamName || "",
userAvatar: userProfile?.userAvatar || teamProfile.userAvatar || userProfile?.avatar || teamProfile.avatar || "",
avatar: userProfile?.avatar || teamProfile.avatar || userProfile?.userAvatar || teamProfile.userAvatar || "",
displayAccount: specialAccount || userProfile?.account || teamProfile.account || "",
account: userProfile?.account || teamProfile.account || "",
ownSpecialId: userProfile?.ownSpecialId || teamProfile.ownSpecialId || (specialAccount ? { account: specialAccount } : null),
specialId: userProfile?.specialId || teamProfile.specialId || null,
specialAccount,
shortAccount: userProfile?.shortAccount || teamProfile.shortAccount || "",
shortId: userProfile?.shortId || teamProfile.shortId || ""
};
}
function pickName(profile) {
return profile?.userNickname || profile?.name || profile?.teamName || "-";
}
function pickAccount(profile) {
return pickSpecialAccount(profile) || profile?.displayAccount || profile?.account || profile?.id || "-";
}
function initials(name) {
const value = String(name || "A").trim();
return value ? value.slice(0, 1).toUpperCase() : "A";
}
function renderAvatar(profile, imageSelector, fallbackSelector) {
const image = document.querySelector(imageSelector);
const fallback = document.querySelector(fallbackSelector);
if (!image || !fallback) return;
const name = pickName(profile);
const avatar = profile?.userAvatar || profile?.avatar || "";
fallback.textContent = initials(name);
image.alt = name;
if (!avatar) {
image.hidden = true;
image.removeAttribute("src");
fallback.hidden = false;
return;
}
fallback.hidden = true;
image.hidden = false;
image.onerror = () => {
image.hidden = true;
image.removeAttribute("src");
fallback.hidden = false;
};
image.src = avatar;
}
function syncApplyAvailability() {
const button = document.querySelector("#applyButton");
if (button) button.hidden = Boolean(pendingRecord);
}
function renderFoundAgency(profile) {
const card = document.querySelector("#resultCard");
if (!card) return;
if (!profile) {
card.hidden = true;
syncApplyAvailability();
return;
}
card.hidden = false;
document.querySelector("#agencyName").textContent = pickName(profile);
document.querySelector("#agencyAccountText").textContent = `${t("uid_prefix")} ${pickAccount(profile)}`.trim();
renderAvatar(profile, "#agencyAvatar", "#agencyAvatarFallback");
syncApplyAvailability();
}
function renderPendingRecord(record) {
const card = document.querySelector("#pendingCard");
if (!card) return;
if (!record) {
card.hidden = true;
syncApplyAvailability();
return;
}
const profile = pickProfile(record);
card.hidden = false;
document.querySelector("#pendingName").textContent = pickName(profile);
document.querySelector("#pendingAccount").textContent = `${t("uid_prefix")} ${pickAccount(profile)}`.trim();
renderAvatar(profile, "#pendingAvatar", "#pendingAvatarFallback");
syncApplyAvailability();
}
function errorMessage(error, fallbackKey) {
return error?.response?.errorMsg || error?.response?.message || error?.message || t(fallbackKey);
}
async function searchAgency() {
const input = document.querySelector("#agencyAccount");
const button = document.querySelector("#searchButton");
const account = input?.value.trim() || "";
if (!account) {
showMessage(t("enter_agent_id"), "error");
return;
}
button.disabled = true;
button.textContent = t("searching");
showMessage("");
try {
const body = await apiRequest(`/team/search-account?account=${encodeURIComponent(account)}`);
const profile = pickSearchAgency(body);
if (!profile?.id) {
foundAgency = null;
renderFoundAgency(null);
showMessage(t("account_not_found"), "error");
return;
}
foundAgency = profile;
renderFoundAgency(foundAgency);
showMessage(t("found"), "success");
} catch (error) {
foundAgency = null;
renderFoundAgency(null);
showMessage(errorMessage(error, "network_error"), "error");
} finally {
button.disabled = false;
button.textContent = t("search");
}
}
async function fetchPendingRecord() {
try {
pendingRecord = await apiRequest("/team/wait-apply/profile");
renderPendingRecord(pendingRecord);
} catch (error) {
pendingRecord = null;
renderPendingRecord(null);
if (error.message === t("missing_token")) showMessage(error.message, "error");
}
}
async function applyToAgency() {
if (pendingRecord) return;
if (!foundAgency?.id) return;
const button = document.querySelector("#applyButton");
button.disabled = true;
button.textContent = t("applying");
showMessage("");
try {
await apiRequest("/team/user/apply", {
method: "POST",
body: {
teamId: foundAgency.id,
reason: "JOIN"
}
});
foundAgency = null;
renderFoundAgency(null);
showMessage(t("application_submitted"), "success");
await fetchPendingRecord();
} catch (error) {
showMessage(errorMessage(error, "application_failed"), "error");
} finally {
button.disabled = false;
button.textContent = t("apply");
}
}
async function cancelApplication() {
const id = pendingRecord?.messageId || pendingRecord?.id;
if (!id) return;
const button = document.querySelector("#cancelButton");
button.disabled = true;
button.textContent = t("cancelling");
showMessage("");
try {
await apiRequest("/team/user/join-apply-cancel", {
method: "POST",
body: { id }
});
pendingRecord = null;
renderPendingRecord(null);
showMessage(t("application_cancelled"), "success");
} catch (error) {
showMessage(errorMessage(error, "cancellation_failed"), "error");
} finally {
button.disabled = false;
button.textContent = t("cancel");
}
}
function buildPageURL(path) {
const url = new URL(path, window.location.href);
const nextParams = new URLSearchParams(params);
const token = readRawParam("token");
if (token) nextParams.set("token", token);
if (currentLang) nextParams.set("lang", currentLang);
url.search = nextParams.toString();
return url.toString();
}
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);
});
document.querySelector(".back-button")?.addEventListener("click", () => {
if (window.history.length > 1) {
window.history.back();
return;
}
window.location.href = buildPageURL("../host-center/index.html");
});
document.querySelector("#searchForm")?.addEventListener("submit", (event) => {
event.preventDefault();
searchAgency();
});
document.querySelector("#applyButton")?.addEventListener("click", applyToAgency);
document.querySelector("#cancelButton")?.addEventListener("click", cancelApplication);
applyLanguage(currentLang).then(fetchPendingRecord);
})();