663 lines
29 KiB
JavaScript
663 lines
29 KiB
JavaScript
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}¤cyType=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();
|