2026-04-24 20:42:36 +08:00

663 lines
29 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.

const API_BASE_URL = "https://jvapi.haiyihy.com";
let headers = {
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 cfg = window.PAGE_CONFIG || {};
const $ = (selector, root = document) => root.querySelector(selector);
const money = (v) => {
const n = Number(v || 0);
return Number.isFinite(n) ? n.toFixed(2).replace(/\.00$/, "") : String(v || 0);
};
function lang() {
const value = new URLSearchParams(location.search).get("lang") || navigator.language || "en";
if (value.startsWith("ar")) return "AR";
if (value.startsWith("tr")) return "TR";
if (value.startsWith("bn")) return "BN";
return "EN";
}
function splitPairs(value) {
const result = {};
String(value || "").split(";").forEach((item) => {
const index = item.indexOf("=");
if (index > -1) result[item.slice(0, index)] = item.slice(index + 1);
});
return result;
}
function setAppHeaders(raw) {
if (!raw) return;
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
const appIntel = splitPairs(data["Req-App-Intel"]);
const sysOrigin = splitPairs(data["Req-Sys-Origin"]);
headers = {
...headers,
authorization: data.Authorization || headers.authorization,
"req-lang": data["Req-Lang"] || headers["req-lang"],
"req-app-intel": [`version=${appIntel.version || "1.0.0"}`, `build=${appIntel.build || "1"}`, `channel=${appIntel.channel || "Web"}`].join(";"),
"req-imei": appIntel["Req-Imei"] || headers["req-imei"],
"req-sys-origin": [`origin=${sysOrigin.origin || "LIKEI"}`, `child=${sysOrigin.child || "LIKEI"}`].join(";")
};
}
async function connectApp() {
if (!(window.app || window.webkit || window.FlutterPageControl)) {
headers["req-lang"] = lang().toLowerCase();
return;
}
const raw = await new Promise((resolve) => {
window.renderData = resolve;
window.getIosAccessOriginParam = resolve;
let attempt = 0;
const poll = () => {
attempt += 1;
if (window.app && typeof window.app.getAccessOrigin === "function") return resolve(window.app.getAccessOrigin());
if (attempt < 50) return setTimeout(poll, 100);
if (window.FlutterApp && typeof window.FlutterApp.postMessage === "function") window.FlutterApp.postMessage("requestAccessOrigin");
resolve(null);
};
poll();
});
if (raw) setAppHeaders(raw);
}
async function request(method, path, body) {
const response = await fetch(`${API_BASE_URL}${path}`, {
method,
headers: { ...headers, "content-type": "application/json" },
body: body === undefined ? undefined : JSON.stringify(body)
});
const data = await response.json().catch(() => ({}));
if (!response.ok || data.status === false) {
const error = new Error(data.errorMsg || data.message || `HTTP ${response.status}`);
error.response = data;
throw error;
}
return data;
}
const get = (path) => request("GET", path);
const post = (path, body) => request("POST", path, body);
function getTeamId() {
const keys = ["teamId", "TEAM_ID", "team_id"];
for (const key of keys) {
const value = localStorage.getItem(key);
if (value) return value.replace(/^"|"$/g, "");
}
for (const key of ["teamInfo", "userInfo", "identity"]) {
try {
const item = JSON.parse(localStorage.getItem(key) || "{}");
if (item.teamId || item.id) return item.teamId || item.id;
} catch {}
}
return "";
}
function getIdentity() {
try {
const value = JSON.parse(localStorage.getItem("identity") || "{}");
return value.identity || value.role || "BD";
} catch {
return "BD";
}
}
function toast(message) {
const node = $("#toast");
node.textContent = message || "Request failed";
node.hidden = false;
clearTimeout(toast.timer);
toast.timer = setTimeout(() => (node.hidden = true), 2500);
}
function setLoading(text = "Loading...") {
$("#app").innerHTML = `<div class="loading">${text}</div>`;
}
function row({ avatar, title, sub, side, tag, onClick }) {
const node = document.createElement("button");
node.type = "button";
node.className = "row";
node.innerHTML = `${avatar !== undefined ? `<img class="avatar" src="${avatar || ""}" alt="">` : ""}<div class="main"><div class="title"></div><div class="sub"></div></div><div class="side"></div>${tag ? `<span class="tag"></span>` : ""}`;
$(".title", node).textContent = title || "-";
$(".sub", node).textContent = sub || "";
$(".side", node).textContent = side || "";
if (tag) $(".tag", node).textContent = tag;
if (onClick) node.addEventListener("click", onClick);
return node;
}
function metrics(items) {
return `<section class="metric-grid">${items.map((item) => `<div class="metric"><div class="label">${item.label}</div><div class="value">${item.value}</div></div>`).join("")}</section>`;
}
function showModal(title, content, center = false) {
const mask = $("#modalMask");
mask.innerHTML = `<div class="modal ${center ? "center" : ""}"><div class="modal-title"></div><div class="modal-body"></div></div>`;
$(".modal-title", mask).textContent = title || "";
$(".modal-body", mask).append(content);
mask.classList.add("show");
}
function closeModal() {
$("#modalMask").classList.remove("show");
}
function navigate(route) {
const url = new URL(route, location.origin);
const langParam = new URLSearchParams(location.search).get("lang");
if (langParam && !url.searchParams.has("lang")) url.searchParams.set("lang", langParam);
location.href = `${url.pathname}${url.search}${url.hash}`;
}
function renderShell() {
document.title = cfg.title || "Yumi H5";
document.body.innerHTML = `
<div class="page">
<header class="header">
<button class="back" type="button" data-back aria-label="Back"><span></span></button>
<h1>${cfg.title || "Yumi H5"}</h1>
<button class="lang" type="button">${lang()}</button>
</header>
<main class="content" id="app"></main>
<div class="modal-mask" id="modalMask"></div>
<div class="toast" id="toast" hidden></div>
</div>`;
$("[data-back]").addEventListener("click", () => history.length > 1 ? history.back() : window.app?.closePage?.());
$("#modalMask").addEventListener("click", (event) => {
if (event.target.id === "modalMask") closeModal();
});
}
async function renderTeamHistory() {
setLoading();
const [listRes, historyRes] = await Promise.allSettled([get(cfg.listEndpoint), get(cfg.historyEndpoint)]);
const bill = listRes.value?.body || {};
const history = historyRes.value?.body || {};
$("#app").innerHTML = `
${metrics([
{ label: cfg.countLabel, value: bill.memberCount || 0 },
{ label: cfg.totalLabel, value: `$${money(bill.totalSalary || bill.teamSalary || bill.totalRecharge || 0)}` }
])}
<section class="card">
<div class="row">
<div class="main"><div class="title">${bill.billTitle || cfg.title}</div><div class="sub">${cfg.totalLabel}: $${money(bill.totalSalary || 0)}</div></div>
<button class="primary" id="historyBtn" type="button">History</button>
</div>
<div id="list"></div>
</section>`;
const list = $("#list");
(bill.memberBillList || []).forEach((item) => {
list.appendChild(row({
avatar: item.agentAvatar || item.userAvatar,
title: item.agentName || item.userName,
sub: `ID: ${item.agentAccount || item.account || "-"}`,
side: `${cfg.memberSide1}: $${money(item.teamSalaryAmount || item.salary || 0)}\n${cfg.memberSide2}: ${item.teamMemberCount || item.hostCount || item.agencyCount || 0}`
}));
});
if (!list.children.length) list.innerHTML = `<div class="empty">No data</div>`;
$("#historyBtn").addEventListener("click", () => {
const body = document.createElement("div");
body.innerHTML = metrics([
{ label: "Total income", value: `$${money(history.totalIncome || 0)}` },
{ label: "Previous period", value: `$${money(history.previousPeriodIncome || 0)}` }
]);
const wrap = document.createElement("div");
wrap.className = "card";
(history.incomeDetails || []).forEach((item) => {
wrap.appendChild(row({
title: item.billTitle || item.settlementPeriod,
sub: `${cfg.countLabel}: ${item.agencyNumber || item.bdNumber || item.memberCount || 0}`,
side: `$${money(item.teamSalaryAmount || item.teamTotalIncome || item.settlementSalary || 0)}`,
tag: item.statusText || item.status,
onClick: async () => {
if (!cfg.moreEndpoint || !item.billBelong) return;
try {
const more = await get(`${cfg.moreEndpoint}${item.billBelong}`);
const detail = document.createElement("div");
const card = document.createElement("div");
card.className = "card";
(more.body?.memberDetails || more.body?.members || []).forEach((member) => {
card.appendChild(row({
avatar: member.userAvatar || member.bdUserAvatar || member.avatar,
title: member.userName || member.bdUserName || member.account,
sub: `ID: ${member.account || "-"}`,
side: `$${money(member.salary || member.income || 0)}`
}));
});
detail.appendChild(card);
showModal(more.body?.period || item.billTitle, detail);
} catch (error) {
toast(error.message);
}
}
}));
});
if (!wrap.children.length) wrap.innerHTML = `<div class="empty">No data</div>`;
body.appendChild(wrap);
showModal("History", body);
});
}
async function renderAdminTeam() {
setLoading();
const res = await post("/bd/team/overview", { type: cfg.teamType });
const data = res.body || {};
$("#app").innerHTML = `
${metrics([
{ label: "Total income", value: `$${money(data.totalIncome || 0)}` },
{ label: "Previous period", value: `$${money(data.previousPeriodIncome || 0)}` },
{ label: cfg.memberTitle, value: data.memberCount || 0 },
{ label: "Team total income", value: `$${money(data.teamTotalIncome || 0)}` }
])}
<section class="card" id="members"></section>`;
const members = $("#members");
(data.members || []).forEach((item) => {
members.appendChild(row({
avatar: item.avatar,
title: item.userName || "-",
sub: `ID: ${item.account || "-"}`,
side: `${cfg.subMemberLabel}: ${item.subMemberCount || 0}\n$${money(item.totalIncome || 0)}`,
tag: "More",
onClick: () => showAdminTeamDetail(item)
}));
});
if (!members.children.length) members.innerHTML = `<div class="empty">No data</div>`;
}
async function showAdminTeamDetail(item) {
try {
const res = await post("/bd/team/member/detail", { targetId: item.userId, type: cfg.detailType || cfg.teamType });
const data = res.body || {};
const body = document.createElement("div");
body.innerHTML = metrics([
{ label: "Total income", value: `$${money(data.totalIncome || 0)}` },
{ label: "Previous period", value: `$${money(data.previousPeriodIncome || 0)}` }
]);
const card = document.createElement("div");
card.className = "card";
(data.incomeDetails || []).forEach((detail) => {
card.appendChild(row({
title: detail.settlementPeriod,
sub: `${cfg.subMemberLabel}: ${detail.memberCount || 0}`,
side: `$${money(detail.teamTotalIncome || 0)}`,
tag: detail.status || "More",
onClick: () => {
const detailBody = document.createElement("div");
const detailCard = document.createElement("div");
detailCard.className = "card";
(detail.members || []).forEach((member) => detailCard.appendChild(row({
avatar: member.avatar,
title: member.userName,
sub: `ID: ${member.account || "-"}`,
side: `$${money(member.income || 0)}`
})));
detailBody.appendChild(detailCard);
showModal(detail.settlementPeriod, detailBody);
}
}));
});
if (!card.children.length) card.innerHTML = `<div class="empty">No data</div>`;
body.appendChild(card);
showModal(`${cfg.memberTitle} ${item.account || ""}`, body);
} catch (error) {
toast(error.message);
}
}
async function renderRechargeAgency() {
setLoading();
const [summary, list] = await Promise.allSettled([
get("/app/h5/recharge-summary"),
get("/app/h5/recharge-page?cursor=1&limit=20")
]);
const data = summary.value?.body || {};
const records = list.value?.body?.records || [];
$("#app").innerHTML = `${metrics([
{ label: "My total income", value: `$${money(data.totalIncome || 0)}` },
{ label: "This period recharge", value: `$${money(data.currentMonthRecharge || 0)}` }
])}<div class="section-title">Recharge agency list</div><section class="card" id="records"></section>`;
const root = $("#records");
records.forEach((item) => root.appendChild(row({
avatar: item.userAvatar,
title: item.userNickname,
sub: `ID: ${item.account || "-"}`,
side: `This: $${money(item.thisMonth || 0)}\nLast: $${money(item.lastMonth || 0)}`
})));
if (!root.children.length) root.innerHTML = `<div class="empty">No data</div>`;
}
async function renderMessage() {
const teamId = getTeamId();
setLoading();
const res = await get(`/team/user/apply/record?teamId=${teamId}&status=WAIT`);
const records = (res.body || []).map((item) => ({
id: item.id,
account: item.createUserProfile?.account,
name: item.createUserProfile?.userNickname,
avatar: item.createUserProfile?.userAvatar
}));
$("#app").innerHTML = `<section class="card" id="messages"></section>`;
const root = $("#messages");
records.forEach((item) => {
const node = row({ avatar: item.avatar, title: item.name || "Unknown user", sub: `ID: ${item.account || "-"}` });
const actions = document.createElement("div");
actions.className = "toolbar";
actions.innerHTML = `<button class="primary" type="button">Agree</button><button class="ghost" type="button">Refuse</button>`;
actions.children[0].addEventListener("click", async () => updateApply(item.id, "AGREE", node));
actions.children[1].addEventListener("click", async () => updateApply(item.id, "REJECT", node));
node.appendChild(actions);
root.appendChild(node);
});
if (!root.children.length) root.innerHTML = `<div class="empty">No data</div>`;
}
async function updateApply(id, status, node) {
try {
await post("/team/user/apply/record/update", { id, status });
node.remove();
toast(status === "AGREE" ? "Approved" : "Rejected");
} catch (error) {
toast(error.message);
}
}
async function renderTeamMembers() {
const teamId = getTeamId();
setLoading();
const res = await get(`/team/members?id=${teamId}`);
const records = res.body || [];
$("#app").innerHTML = `
<div class="toolbar"><input id="search" placeholder="Enter host ID"><button class="primary" id="searchBtn">Search</button><button class="ghost" id="cancelBtn">Cancel</button></div>
<section class="card" id="members"></section>`;
const root = $("#members");
const draw = (items) => {
root.innerHTML = "";
items.forEach((member, index) => root.appendChild(row({
avatar: member.userProfile?.userAvatar,
title: `${index + 1}. ${member.userProfile?.userNickname || "-"}`,
sub: `ID: ${member.userProfile?.ownSpecialId?.account || member.userProfile?.account || "-"}`,
side: `${member.targetFormat || "-"}\n${member.timeHours || "-"}`
})));
if (!root.children.length) root.innerHTML = `<div class="empty">No data</div>`;
};
draw(records);
$("#searchBtn").addEventListener("click", async () => {
const account = $("#search").value.trim();
if (!account) return draw(records);
try {
const searched = await get(`/team/search-members?account=${account}`);
draw(searched.body || []);
} catch (error) {
toast(error.message);
}
});
$("#cancelBtn").addEventListener("click", () => {
$("#search").value = "";
draw(records);
});
}
async function renderTeamBill() {
const teamId = getTeamId();
setLoading();
const res = await get(`/team/bill?id=${teamId}`);
const records = res.body || [];
let total = 0;
records.forEach((item) => {
if (item.status === "SETTLED") total += Number(item.settleResult?.totalSalary || 0);
});
$("#app").innerHTML = `${metrics([{ label: "History team income", value: `$${money(total)}` }])}<div class="section-title">Work report</div><section class="card" id="bills"></section>`;
const root = $("#bills");
records.forEach((item) => root.appendChild(row({
title: item.billTitle,
sub: `Host salary: $${money(item.settleResult?.memberSalary || 0)} | Agent salary: $${money(item.settleResult?.ownSalary || 0)}`,
side: `$${money(item.settleResult?.totalSalary || 0)}`,
tag: ({ SETTLED: "Completed", UNPAID: "In Progress", HANG_UP: "Out of account", PAY_OUT: "Completed" })[item.status] || item.status,
onClick: async () => {
try {
const detail = await get(`/team/bill/work-members?id=${item.id}`);
const body = document.createElement("div");
const card = document.createElement("div");
card.className = "card";
(detail.body || []).forEach((member) => card.appendChild(row({
avatar: member.memberProfile?.userAvatar,
title: member.memberProfile?.userNickname,
sub: `ID: ${member.memberProfile?.account || "-"}`,
side: `Target: ${member.target?.acceptGiftValue || 0}\nDays: ${member.target?.effectiveDay || 0}`
})));
body.appendChild(card);
showModal(item.billTitle, body);
} catch (error) {
toast(error.message);
}
}
})));
if (!root.children.length) root.innerHTML = `<div class="empty">No data</div>`;
}
function renderInviteProcess() {
$("#app").innerHTML = `<section class="card card-pad">
<div class="row"><div class="tag">1</div><div class="main"><div class="title">Invite users to download the app.</div></div></div>
<div class="row"><div class="tag">2</div><div class="main"><div class="title">Invited users log in.</div></div></div>
<div class="row"><div class="tag">3</div><div class="main"><div class="title">Users join your team.</div></div></div>
<div class="row"><div class="tag">4</div><div class="main"><div class="title">Enter team ID when joining.</div></div></div>
</section>`;
}
async function renderBankCards() {
setLoading();
const [cards, kyc] = await Promise.allSettled([get("/wallet/bank-card/list"), get("/wallet/withdraw-info/list")]);
const current = (cards.value?.body || []).find((item) => item.use);
const info = kyc.value?.body?.[0];
$("#app").innerHTML = `
<div class="section-title">Bank card</div>
<section class="card" id="cardBox"></section>
<div class="section-title">KYC</div>
<section class="card" id="kycBox"></section>`;
$("#cardBox").appendChild(current ? row({ title: current.cardType, sub: `Card: ${current.cardNo}`, side: current.payee }) : row({ title: "Add payment method", sub: "No bank cards in use", tag: "Add", onClick: () => navigate("/bank-card") }));
$("#kycBox").appendChild(info ? row({ title: `Status: ${info.status}`, sub: `Contact: ${info.contactNumber || "-"}`, side: info.otherDescription || "", tag: "KYC", onClick: () => navigate("/KYC") }) : row({ title: "Complete information", sub: "No KYC info", tag: "KYC", onClick: () => navigate("/KYC") }));
}
async function renderWalletAction() {
setLoading();
const action = new URLSearchParams(location.search).get("activeAction") || cfg.action || "Exchange";
const balanceEndpoint = cfg.salaryType ? `/wallet/salary-account/balance?salaryType=${cfg.salaryType}` : "/wallet/bank/balance";
const balanceRes = await get(balanceEndpoint).catch(() => ({ body: 0 }));
const balance = typeof balanceRes.body === "number" ? balanceRes.body : balanceRes.body?.availableBalance || balanceRes.body?.balance || 0;
const amounts = [1, 5, 10, 50, 100, 200];
$("#app").innerHTML = `
${metrics([{ label: "Available salaries", value: `$${money(balance)}` }])}
<div class="tabs">
<button class="${action === "Exchange" ? "active" : ""}" data-act="Exchange">Exchange</button>
<button class="${action === "Transfer" ? "active" : ""}" data-act="Transfer">Transfer</button>
<button class="${action === "Cash out" ? "active" : ""}" data-act="Cash out">Cash out</button>
</div>
<section class="card card-pad" id="walletPanel"></section>`;
document.querySelectorAll("[data-act]").forEach((btn) => btn.addEventListener("click", () => navigate(`${location.pathname}?activeAction=${encodeURIComponent(btn.dataset.act)}&lang=${lang().toLowerCase()}`)));
const panel = $("#walletPanel");
if (action === "Cash out") return renderCashOutPanel(panel);
if (action === "Transfer") return renderTransferPanel(panel, amounts);
renderExchangePanel(panel, amounts);
}
function renderExchangePanel(panel, amounts) {
panel.innerHTML = `<div class="grid three">${amounts.map((amount) => `<button class="tile" data-amount="${amount}">$${amount}</button>`).join("")}</div><button class="primary" id="submit">Exchange</button>`;
let selected = null;
panel.querySelectorAll("[data-amount]").forEach((node) => node.addEventListener("click", () => {
selected = Number(node.dataset.amount);
panel.querySelectorAll(".tile").forEach((tile) => tile.classList.remove("selected"));
node.classList.add("selected");
}));
$("#submit").addEventListener("click", async () => {
if (!selected) return toast("Please select amount");
try {
const path = cfg.salaryType ? "/wallet/salary-account/exchange/gold" : "/wallet/bank/exchange/gold";
await post(path, cfg.salaryType ? { amount: selected, salaryType: cfg.salaryType } : { amount: selected });
toast("Exchange success");
} catch (error) {
toast(error.message);
}
});
}
function renderTransferPanel(panel, amounts) {
panel.innerHTML = `<div class="form-row"><input id="payee" placeholder="Enter user ID"><button class="primary" id="findPayee">Search</button></div><div id="payeeInfo"></div><div class="grid three">${amounts.map((amount) => `<button class="tile" data-amount="${amount}">$${amount}</button>`).join("")}</div><button class="primary" id="submit">Transfer</button>`;
let payee = null;
let selected = null;
$("#findPayee").addEventListener("click", async () => {
try {
const res = await get(`/user/user-profile/open-search?account=${encodeURIComponent($("#payee").value.trim())}`);
payee = res.body;
$("#payeeInfo").innerHTML = "";
$("#payeeInfo").appendChild(row({ avatar: payee.userAvatar, title: payee.userNickname || payee.name, sub: `ID: ${payee.account}`, side: "" }));
} catch (error) {
toast(error.message);
}
});
panel.querySelectorAll("[data-amount]").forEach((node) => node.addEventListener("click", () => {
selected = Number(node.dataset.amount);
panel.querySelectorAll(".tile").forEach((tile) => tile.classList.remove("selected"));
node.classList.add("selected");
}));
$("#submit").addEventListener("click", async () => {
if (!selected || !payee?.id) return toast("Please select amount and payee");
try {
const path = cfg.salaryType ? "/wallet/salary-account/transferGold" : "/wallet/bank/transferGold";
await post(path, cfg.salaryType ? { amount: selected, acceptUserId: payee.id, salaryType: cfg.salaryType } : { amount: selected, acceptUserId: payee.id, acceptMethod: "BANK_TRANSFER" });
toast("Transfer success");
} catch (error) {
toast(error.message);
}
});
}
async function renderCashOutPanel(panel) {
const [cards, kyc] = await Promise.allSettled([get("/wallet/bank-card/list"), get("/wallet/withdraw-info/list")]);
const card = (cards.value?.body || []).find((item) => item.use);
const info = kyc.value?.body?.[0];
panel.innerHTML = `<div class="form-row"><input id="amount" placeholder="50" inputmode="decimal"></div><div id="card"></div><div id="kyc"></div><button class="primary" id="submit">Cash out</button>`;
$("#card").appendChild(card ? row({ title: card.cardType, sub: `Card: ${card.cardNo}`, side: card.payee }) : row({ title: "No bank cards in use", sub: "Add bank card", tag: "Add", onClick: () => navigate("/bank-card") }));
$("#kyc").appendChild(info ? row({ title: `KYC: ${info.status}`, sub: `Contact: ${info.contactNumber || "-"}`, tag: "KYC" }) : row({ title: "Complete KYC", sub: "No KYC information", tag: "KYC", onClick: () => navigate("/KYC") }));
$("#submit").addEventListener("click", async () => {
const amount = Number($("#amount").value);
if (!card?.id || !amount || amount < 50) return toast("Please complete information and enter at least 50");
try {
await post("/wallet/bank/withdraw", { amount, acceptBankCardId: card.id, salaryType: cfg.salaryType || (getIdentity() === "HOST" ? "HOST_SALARY" : "BD_SALARY") });
toast("Cash withdrawal submitted");
} catch (error) {
toast(error.message);
}
});
}
async function renderItemDistribution() {
setLoading();
const permissionEndpoint = cfg.admin ? "/app/h5/own-permission?propsType=NOBLE_VIP" : "/sys/bd/list-permission";
const propsBase = cfg.admin ? "/sys/manager/props" : "/sys/bd/props";
const sendEndpoint = cfg.admin ? "/sys/manager/send" : "/sys/bd/send";
let tabs = cfg.admin ? [{ name: "frames", type: "AVATAR_FRAME" }, { name: "vehicles", type: "RIDE" }, { name: "vip", type: "NOBLE_VIP" }] : [];
if (!cfg.admin) {
const res = await get(permissionEndpoint);
const body = res.body || [];
if (body.includes("AVATAR_FRAME")) tabs.push({ name: "frames", type: "AVATAR_FRAME" });
if (body.includes("RIDE")) tabs.push({ name: "vehicles", type: "RIDE" });
if (body.some((x) => String(x).startsWith("NOBLE_VIP"))) tabs.push({ name: "vip", type: "NOBLE_VIP" });
}
if (!tabs.length) tabs = [{ name: "frames", type: "AVATAR_FRAME" }];
$("#app").innerHTML = `<div class="tabs">${tabs.map((tab, index) => `<button data-tab="${index}" class="${index === 0 ? "active" : ""}">${tab.name}</button>`).join("")}</div><section class="grid" id="props"></section>`;
const load = async (tab) => {
const res = await get(`${propsBase}?propsType=${tab.type}&currencyType=GOLD`);
const root = $("#props");
root.innerHTML = "";
(res.body || []).forEach((item) => {
const tile = document.createElement("button");
tile.type = "button";
tile.className = "tile";
tile.innerHTML = `<img src="${item.cover || ""}" alt=""><span>${item.name || "Item"}</span><span class="tag">Send</span>`;
tile.addEventListener("click", () => openSendProps(item, sendEndpoint));
root.appendChild(tile);
});
if (!root.children.length) root.innerHTML = `<div class="empty">No data</div>`;
};
document.querySelectorAll("[data-tab]").forEach((btn) => btn.addEventListener("click", () => {
document.querySelectorAll("[data-tab]").forEach((b) => b.classList.remove("active"));
btn.classList.add("active");
load(tabs[Number(btn.dataset.tab)]);
}));
await load(tabs[0]);
}
function openSendProps(item, endpoint) {
const body = document.createElement("div");
body.innerHTML = `<div class="form-row"><input id="targetUser" placeholder="Enter user ID"><button class="primary" id="confirmSend">Confirm</button></div>`;
$("#confirmSend", body).addEventListener("click", async () => {
try {
const user = await get(`/user/user-profile/open-search?account=${encodeURIComponent($("#targetUser", body).value.trim())}`);
await post(endpoint, { propsId: item.id, acceptUserId: user.body.id });
closeModal();
toast("Gift delivery successful");
} catch (error) {
toast(error.message);
}
});
showModal(item.name || "Send", body, true);
}
function renderPolicy() {
$("#app").innerHTML = "";
}
async function renderPlatformPolicy() {
const teamId = getTeamId();
setLoading();
const res = await get(`/team/release/policy?id=${teamId}`);
const policies = res.body?.policy || [];
$("#app").innerHTML = `<section class="card" id="policyList"></section>`;
const root = $("#policyList");
policies.forEach((item) => root.appendChild(row({
title: `Lv.${item.level}`,
sub: `Time: ${item.onlineTime || 0}h | Target: ${item.target || 0}`,
side: `Host: $${money(item.memberSalary || 0)}\nAgent: $${money(item.ownSalary || 0)}`
})));
if (!root.children.length) root.innerHTML = `<div class="empty">No policy data available</div>`;
}
async function init() {
renderShell();
try {
await connectApp();
const handlers = {
teamHistory: renderTeamHistory,
adminTeam: renderAdminTeam,
rechargeAgency: renderRechargeAgency,
message: renderMessage,
teamMembers: renderTeamMembers,
teamBill: renderTeamBill,
inviteProcess: renderInviteProcess,
bankCards: renderBankCards,
walletAction: renderWalletAction,
itemDistribution: renderItemDistribution,
platformPolicy: renderPlatformPolicy,
policy: renderPolicy
};
await (handlers[cfg.mode] || renderPolicy)();
} catch (error) {
console.error(error);
$("#app").innerHTML = `<div class="empty">${error.message || "Failed to load data"}</div>`;
}
}
init();