chatapp-h5/h5/host-center/host-center.js
2026-05-12 20:08:48 +08:00

647 lines
21 KiB
JavaScript
Raw Permalink 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.

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();