const API_BASE_URL = "https://jvapi.haiyihy.com"; const DEFAULT_AVATAR = "/assets/defaultAvatar-CdxWBK1k.png"; const icons = { policy: "./icons/policy.svg", exchange: "./icons/exchange.svg", transfer: "./icons/transfer.svg", withdraw: "./icons/withdraw.svg", bank: "./icons/bank.svg", money: "./icons/money.svg", back: "./icons/back.svg", arrow: "./icons/arrow.svg" }; let commonHeaders = { authorization: "Bearer undefined", "req-app-intel": "version=1.0.0;build=1;model=SM-G9550;sysVersion=9;channel=Google", "req-client": "Android", "req-imei": "8fa54d728ab449e04f9292329ed44bda", "req-lang": "id-ID", "req-sys-origin": "origin=ATYOU;originChild=ATYOU", "req-version": "V2", "req-zone": "Asia/Shanghai" }; const i18n = { en: { host_center: "Host Center", my_agency: "My agency", user_id_prefix: "ID:", leave: "Leave", my_available_salary: "My available salary", my_salary_details: "My salary details", todays_task: "Today's task", anchor_type: "Anchor type", minutes: "Minutes", gift_task: "Gift Task", platform_policy: "Platform policy", exchange_coins: "Exchange coins", transfer: "Transfer", cash_withdraw: "Cash withdraw", bank_accounts: "Bank accounts", prompt: "Prompt", tips: "Tips", fill_info_tips: "Please complete your information first.", card_issue_tips: "Please make sure your bank card and KYC information are available.", to_improve: "To improve", leave_agent_tips: "Are you sure you want to leave?", cancel: "Cancel", confirm: "Confirm", failed_to_load_balance: "Failed to load balance. Please try again.", something_went_wrong: "Something went wrong." }, ar: { host_center: "مركز المضيف", my_agency: "وكالتي", user_id_prefix: "ID:", leave: "مغادرة", my_available_salary: "راتبي المتاح", my_salary_details: "تفاصيل الراتب", todays_task: "مهمة اليوم", anchor_type: "نوع المضيف", minutes: "الدقائق", gift_task: "مهمة الهدايا", platform_policy: "سياسة المنصة", exchange_coins: "استبدال العملات", transfer: "تحويل", cash_withdraw: "سحب نقدي", bank_accounts: "الحسابات البنكية", prompt: "تنبيه", tips: "نصائح", fill_info_tips: "يرجى إكمال معلوماتك أولا.", card_issue_tips: "يرجى التأكد من توفر البطاقة البنكية ومعلومات KYC.", to_improve: "إكمال", leave_agent_tips: "هل أنت متأكد أنك تريد المغادرة؟", cancel: "إلغاء", confirm: "تأكيد", failed_to_load_balance: "فشل تحميل الرصيد. يرجى المحاولة مرة أخرى.", something_went_wrong: "حدث خطأ ما." }, tr: { host_center: "Host Merkezi", my_agency: "Ajansım", user_id_prefix: "ID:", leave: "Ayrıl", my_available_salary: "Kullanılabilir maaşım", my_salary_details: "Maaş detayları", todays_task: "Bugünkü görev", anchor_type: "Host türü", minutes: "Dakika", gift_task: "Hediye görevi", platform_policy: "Platform politikası", exchange_coins: "Coin değiştir", transfer: "Transfer", cash_withdraw: "Para çek", bank_accounts: "Banka hesapları", prompt: "Uyarı", tips: "İpuçları", fill_info_tips: "Lütfen önce bilgilerinizi tamamlayın.", card_issue_tips: "Lütfen banka kartı ve KYC bilgilerinizin mevcut olduğundan emin olun.", to_improve: "Tamamla", leave_agent_tips: "Ayrılmak istediğinizden emin misiniz?", cancel: "İptal", confirm: "Onayla", failed_to_load_balance: "Bakiye yüklenemedi. Lütfen tekrar deneyin.", something_went_wrong: "Bir şeyler ters gitti." }, bn: { host_center: "হোস্ট সেন্টার", my_agency: "আমার এজেন্সি", user_id_prefix: "ID:", leave: "ছাড়ুন", my_available_salary: "আমার উপলভ্য বেতন", my_salary_details: "বেতনের বিবরণ", todays_task: "আজকের কাজ", anchor_type: "হোস্ট ধরন", minutes: "মিনিট", gift_task: "গিফট টাস্ক", platform_policy: "প্ল্যাটফর্ম নীতি", exchange_coins: "কয়েন এক্সচেঞ্জ", transfer: "ট্রান্সফার", cash_withdraw: "ক্যাশ উত্তোলন", bank_accounts: "ব্যাংক অ্যাকাউন্ট", prompt: "প্রম্পট", tips: "টিপস", fill_info_tips: "প্রথমে আপনার তথ্য সম্পূর্ণ করুন।", card_issue_tips: "আপনার ব্যাংক কার্ড এবং KYC তথ্য আছে কিনা নিশ্চিত করুন।", to_improve: "সম্পূর্ণ করুন", leave_agent_tips: "আপনি কি নিশ্চিত যে আপনি ছাড়তে চান?", cancel: "বাতিল", confirm: "নিশ্চিত", failed_to_load_balance: "ব্যালেন্স লোড করতে ব্যর্থ। আবার চেষ্টা করুন।", something_went_wrong: "কিছু ভুল হয়েছে।" } }; const state = { lang: resolveLanguage(), profile: {}, teamInfo: null, identityInfo: null, agency: {}, salaryInfo: { currentSalary: "0" }, taskInfo: { anchorType: "Chat", minutesProgress: 0, minutesTotal: 120, giftTask: 0 }, bankCards: [], activeBankCard: null, withdrawInfo: null, withdrawEnabled: false }; const $ = (selector) => document.querySelector(selector); const $$ = (selector) => Array.from(document.querySelectorAll(selector)); const t = (key) => (i18n[state.lang] && i18n[state.lang][key]) || i18n.en[key] || key; function resolveLanguage() { const params = new URLSearchParams(window.location.search); const hashQuery = window.location.hash.includes("?") ? window.location.hash.split("?")[1] : ""; const hashParams = new URLSearchParams(hashQuery); const lang = params.get("lang") || hashParams.get("lang") || navigator.language || "en"; if (lang.startsWith("ar")) return "ar"; if (lang.startsWith("tr")) return "tr"; if (lang.startsWith("bn")) return "bn"; return "en"; } function splitHeaderPairs(value) { const result = {}; if (!value) return result; value.split(";").forEach((item) => { const index = item.indexOf("="); if (index > -1) result[item.slice(0, index)] = item.slice(index + 1); }); return result; } function parseAccessOrigin(raw) { const data = JSON.parse(raw); const appIntel = splitHeaderPairs(data["Req-App-Intel"]); const sysOrigin = splitHeaderPairs(data["Req-Sys-Origin"]); return { reqLang: data["Req-Lang"], authorization: data.Authorization, buildVersion: appIntel.build, appVersion: appIntel.version, appChannel: appIntel.channel, reqImei: appIntel["Req-Imei"], sysOrigin: sysOrigin.origin, sysOriginChild: sysOrigin.child }; } function setHeadersFromApp(headers) { const next = {}; if (headers.authorization) next.authorization = headers.authorization; if (headers.reqLang) next["req-lang"] = headers.reqLang; if (headers.appVersion || headers.buildVersion || headers.appChannel) { const intel = []; if (headers.appVersion) intel.push(`version=${headers.appVersion}`); if (headers.buildVersion) intel.push(`build=${headers.buildVersion}`); if (headers.appChannel) intel.push(`channel=${headers.appChannel}`); next["req-app-intel"] = intel.join(";"); } if (headers.reqImei) next["req-imei"] = headers.reqImei; if (headers.sysOrigin) { const origin = [`origin=${headers.sysOrigin}`]; if (headers.sysOriginChild) origin.push(`child=${headers.sysOriginChild}`); next["req-sys-origin"] = origin.join(";"); } commonHeaders = { ...commonHeaders, ...next }; } function connectToApp() { return new Promise((resolve) => { window.renderData = resolve; window.getIosAccessOriginParam = resolve; if (!(window.app || window.webkit || window.FlutterPageControl)) { resolve({ success: true, environment: "browser" }); return; } let attempt = 0; const poll = () => { attempt += 1; if (window.app && typeof window.app.getAccessOrigin === "function") { try { const raw = window.app.getAccessOrigin(); if (raw) setHeadersFromApp(parseAccessOrigin(raw)); } catch (error) { console.error("Failed to parse access origin:", error); } resolve({ success: true, environment: "app" }); return; } if (attempt < 50) { window.setTimeout(poll, 100); return; } if (window.FlutterApp && typeof window.FlutterApp.postMessage === "function") { window.FlutterApp.postMessage("requestAccessOrigin"); } resolve({ success: true, environment: "app" }); }; poll(); }).then((result) => { if (typeof result === "string") { setHeadersFromApp(parseAccessOrigin(result)); return { success: true, environment: "app" }; } return result; }); } async function apiGet(path) { const response = await fetch(`${API_BASE_URL}${path}`, { method: "GET", headers: commonHeaders }); return parseApiResponse(response); } async function apiPost(path, body) { const response = await fetch(`${API_BASE_URL}${path}`, { method: "POST", headers: { ...commonHeaders, "content-type": "application/json" }, body: JSON.stringify(body || {}) }); return parseApiResponse(response); } async function parseApiResponse(response) { 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; } function formatMoney(value) { if (value === null || value === undefined || value === "") return "0"; const number = Number(value); if (Number.isNaN(number)) return String(value); return number.toFixed(2); } function getMemberId() { return state.profile.id || state.profile.userId || state.profile.account || null; } function getTeamId() { if (state.teamInfo && state.teamInfo.id) return state.teamInfo.id; const cached = localStorage.getItem("teamInfo"); if (cached) { try { const data = JSON.parse(cached); if (data && data.id) return data.id; } catch (error) { console.error("Failed to parse teamInfo:", error); } } return state.agency.teamId || state.agency.id || null; } async function fetchUserProfile() { const cached = localStorage.getItem("userProfile"); if (cached) { try { state.profile = JSON.parse(cached) || {}; } catch (error) { console.error("Failed to parse userProfile:", error); } } const result = await apiGet("/team/member/profile"); if (result.status && result.body) { state.profile = result.body; localStorage.setItem("userProfile", JSON.stringify(result.body)); } } async function fetchAgencyProfile() { const result = await apiGet("/team/team-own/profile"); if (result.status && result.body) state.agency = result.body; } async function fetchTeamEntry() { const cached = localStorage.getItem("teamInfo"); if (cached) { try { state.teamInfo = JSON.parse(cached); } catch (error) { console.error("Failed to parse teamInfo:", error); } } const result = await apiGet("/team/entry"); if (result.status && result.body) { state.teamInfo = result.body.teamProfile || result.body; localStorage.setItem("teamInfo", JSON.stringify(state.teamInfo)); } } async function fetchBankBalance() { const result = await apiGet("/wallet/bank/balance"); if (result.status && typeof result.body === "number") { state.salaryInfo.currentSalary = result.body.toFixed(2); } else if (result.status && result.body) { state.salaryInfo.currentSalary = formatMoney(result.body.currentSalary ?? result.body.availableBalance ?? result.body.balance ?? 0); } else { state.salaryInfo.currentSalary = "0"; } } async function fetchWorkStatistics() { const memberId = getMemberId(); if (!memberId) { console.warn("No user ID available"); return; } const result = await apiGet(`/team/member/work/statistics-now?dataType=DAILY&memberId=${encodeURIComponent(memberId)}`); if (result.status && result.body) { const ownTime = Number(result.body.ownTime) || 0; const otherTime = Number(result.body.otherTime) || 0; const total = ownTime + otherTime; state.taskInfo.anchorType = "Chat"; state.taskInfo.minutesProgress = total >= state.taskInfo.minutesTotal ? state.taskInfo.minutesTotal : total; state.taskInfo.giftTask = result.body.acceptGiftValue || 0; } } async function fetchMemberWork() { const memberId = getMemberId(); if (!memberId) return; const result = await apiGet(`/team/member-work?userId=${encodeURIComponent(memberId)}`); if (result.status && result.body) console.debug("member work data:", result.body); } async function fetchBankCards() { const result = await apiGet("/wallet/bank-card/list"); if (result.status && result.body) { state.bankCards = result.body; state.activeBankCard = state.bankCards.find((item) => item.use) || null; } } async function fetchWithdrawInfo() { const result = await apiGet("/wallet/withdraw-info/list"); if (result.status && result.body && result.body.length > 0) { const first = result.body[0]; let previewUrls = []; try { previewUrls = JSON.parse(first.passportFrontUrl || "[]").map((item) => item); } catch (error) { console.error("Failed to parse passportFrontUrl:", error); } state.withdrawInfo = { previewUrls, ...first }; } } async function fetchWithdrawEnabled() { const result = await apiGet("/wallet/bank/host-salary/withdraw/enabled"); if (result.status) state.withdrawEnabled = Boolean(result.body); } function calculateRoles(identity) { if (!identity) return ["guest"]; const roles = []; if (identity.freightAgent) roles.push("freightAgent"); if (identity.agent) roles.push("agent"); if (identity.bdLeader) roles.push("bdLeader"); if (identity.bd) roles.push("bd"); if (identity.anchor) roles.push("anchor"); if (identity.yumi_manager || identity.yumiManager) roles.push("yumiManager"); if (identity.admin) roles.push("admin"); return roles.length ? roles : ["guest"]; } function getPrimaryRole(roles) { const weight = { guest: 0, anchor: 1, agent: 2, bd: 3, bdLeader: 4, freightAgent: 5, yumiManager: 6, admin: 7 }; return roles.reduce((current, role) => (weight[role] > weight[current] ? role : current), "guest"); } function getDefaultPage(role) { return { admin: "/admin-center", yumiManager: "/admin-center", freightAgent: "/coin-seller", agent: "/agency-center", bdLeader: "/bd-leader-center", bd: "/bd-center", anchor: "/host-center", guest: "/apply" }[role] || "/apply"; } async function checkIdentityAndRedirect() { const memberId = getMemberId(); if (!memberId) { navigateTo("/apply"); return; } const result = await apiGet("/app/h5/identity"); if (!result.status || !result.body) return; state.identityInfo = result.body; const roles = calculateRoles(result.body); const primaryRole = getPrimaryRole(roles); if (!roles.includes("anchor")) { const defaultPage = getDefaultPage(primaryRole); if (defaultPage !== "/host-center") navigateTo(defaultPage); } } async function leaveAgency() { await apiPost("/team/user/apply", { reason: "QUIT", teamId: getTeamId() }); } async function runTask(task, label) { try { await task(); } catch (error) { console.error(`${label} failed:`, error); if (label === "bank balance") showToast(t("failed_to_load_balance")); if (label === "withdraw info" || label === "withdraw enabled") showToast(error.response?.errorMsg || error.message || t("something_went_wrong")); } } function normalizeRoute(target) { const url = new URL(target, window.location.origin); const currentLang = new URLSearchParams(window.location.search).get("lang"); if (currentLang && !url.searchParams.has("lang")) url.searchParams.set("lang", currentLang); return `${url.pathname}${url.search}${url.hash}`; } function navigateTo(target) { window.location.href = normalizeRoute(target); } function closePage() { if (window.app && typeof window.app.closePage === "function") { window.app.closePage(); return; } if (window.FlutterPageControl && typeof window.FlutterPageControl.postMessage === "function") { window.FlutterPageControl.postMessage("close_page"); return; } if (window.history.length > 1) { window.history.back(); } } function showToast(message) { const toast = $("#toast"); toast.textContent = message; toast.hidden = false; window.clearTimeout(showToast.timer); showToast.timer = window.setTimeout(() => { toast.hidden = true; }, 2500); } function showModal(id) { const modal = $(`#${id}`); if (modal) modal.hidden = false; } function hideModal(id) { const modal = $(`#${id}`); if (modal) modal.hidden = true; } function renderI18n() { document.documentElement.lang = state.lang; document.documentElement.dir = state.lang === "ar" ? "rtl" : "ltr"; $("[data-action='language']").textContent = state.lang.toUpperCase(); $$("[data-i18n]").forEach((node) => { node.textContent = t(node.dataset.i18n); }); } function renderIcons() { $("#policyIcon").src = icons.policy; $("#exchangeIcon").src = icons.exchange; $("#transferIcon").src = icons.transfer; $("#withdrawIcon").src = icons.withdraw; $("#bankIcon").src = icons.bank; $("#moneyIcon").src = icons.money; $("#backIcon").src = icons.back; ["#arrowIcon1", "#arrowIcon2", "#arrowIcon3", "#arrowIcon4", "#arrowIcon5"].forEach((selector) => { $(selector).src = icons.arrow; }); } function renderAgency() { const avatar = $("#agencyAvatar"); const fallback = $("#avatarFallback"); const displayName = state.agency.userNickname || state.agency.name || "-"; const account = state.agency.ownSpecialId?.account || state.agency.account || "-"; $("#agencyName").textContent = displayName; $("#agencyId").textContent = account; fallback.textContent = (displayName || "U").slice(0, 1).toUpperCase(); avatar.alt = displayName; avatar.src = state.agency.userAvatar || ""; avatar.hidden = !state.agency.userAvatar; } function renderData() { $("#currentSalary").textContent = state.salaryInfo.currentSalary; $("#anchorType").textContent = state.taskInfo.anchorType; $("#minutesProgress").textContent = state.taskInfo.minutesProgress; $("#minutesTotal").textContent = state.taskInfo.minutesTotal; $("#giftTask").textContent = state.taskInfo.giftTask; $("#cashWithdrawRow").hidden = !state.withdrawEnabled; $("#cashDivider").hidden = !state.withdrawEnabled; } function render() { renderI18n(); renderIcons(); renderAgency(); renderData(); } function bindEvents() { $("[data-action='back']").addEventListener("click", closePage); $("[data-action='language']").addEventListener("click", () => navigateTo("/language")); $("[data-action='leave']").addEventListener("click", () => showModal("leaveModal")); $$("[data-route]").forEach((node) => { node.addEventListener("click", () => navigateTo(node.dataset.route)); }); $("[data-action='cash-withdraw']").addEventListener("click", () => { if (!state.withdrawInfo || !state.activeBankCard) { showModal("infoMissingModal"); return; } navigateTo("/cash-withdraw"); }); $("#agencyAvatar").addEventListener("error", (event) => { event.target.onerror = null; event.target.src = DEFAULT_AVATAR; event.target.hidden = false; }); $("#infoMissingModal").addEventListener("click", () => hideModal("infoMissingModal")); $("#leaveModal").addEventListener("click", () => hideModal("leaveModal")); $$(".modal-card").forEach((node) => node.addEventListener("click", (event) => event.stopPropagation())); $("[data-action='improve']").addEventListener("click", () => navigateTo("/host-setting")); $("[data-action='cancel-leave']").addEventListener("click", () => hideModal("leaveModal")); $("[data-action='confirm-leave']").addEventListener("click", async () => { try { await leaveAgency(); } catch (error) { showToast(error.response?.errorMsg || error.errorMsg || t("something_went_wrong")); } finally { hideModal("leaveModal"); } }); } async function init() { localStorage.setItem("identity", JSON.stringify({ identity: "HOST" })); localStorage.removeItem("payee"); bindEvents(); render(); try { await connectToApp(); await fetchUserProfile(); await Promise.all([ runTask(fetchTeamEntry, "team entry"), runTask(fetchAgencyProfile, "agency profile"), runTask(fetchBankBalance, "bank balance"), runTask(fetchWorkStatistics, "work statistics"), runTask(fetchBankCards, "bank cards"), runTask(fetchWithdrawInfo, "withdraw info"), runTask(fetchWithdrawEnabled, "withdraw enabled") ]); await checkIdentityAndRedirect(); runTask(fetchMemberWork, "member work"); } catch (error) { console.error("Host center data request failed:", error); showToast(error.response?.errorMsg || error.message || t("failed_to_load_balance")); } finally { render(); } } init();