chatapp-h5/h5/center-static/center-static.js
2026-04-24 20:42:36 +08:00

298 lines
10 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 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 fallbackConfig = {
title: "Center",
identity: "USER",
heroTitle: "Available salary",
heroLink: "Details",
heroRoute: "/history-salary",
balanceType: "",
summaries: [],
sections: []
};
const config = { ...fallbackConfig, ...(window.CENTER_PAGE || {}) };
const state = {
lang: resolveLanguage(),
heroValue: "0",
summaries: [...(config.summaries || [])]
};
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 formatMoney(value) {
if (value === null || value === undefined || value === "") return "0";
const number = Number(value);
if (Number.isNaN(number)) return String(value);
return Number.isInteger(number) ? String(number) : number.toFixed(2);
}
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 requestAccessOrigin() {
return new Promise((resolve) => {
window.renderData = resolve;
window.getIosAccessOriginParam = resolve;
if (!(window.app || window.webkit || window.FlutterPageControl)) {
setHeadersFromApp({
authorization: "",
reqLang: state.lang,
appVersion: "1.0.0",
buildVersion: "1",
appChannel: "Web",
reqImei: "H5-STATIC",
sysOrigin: "LIKEI",
sysOriginChild: "LIKEI"
});
resolve(null);
return;
}
let attempt = 0;
const poll = () => {
attempt += 1;
if (window.app && typeof window.app.getAccessOrigin === "function") {
resolve(window.app.getAccessOrigin());
return;
}
if (attempt < 50) {
window.setTimeout(poll, 100);
return;
}
if (window.FlutterApp && typeof window.FlutterApp.postMessage === "function") {
window.FlutterApp.postMessage("requestAccessOrigin");
}
};
poll();
});
}
async function connectToApp() {
const raw = await requestAccessOrigin();
if (raw) setHeadersFromApp(parseAccessOrigin(raw));
}
async function apiGet(path) {
const response = await fetch(`${API_BASE_URL}${path}`, {
method: "GET",
headers: commonHeaders
});
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;
}
async function fetchHeroValue() {
if (config.balanceType) {
const result = await apiGet(`/wallet/salary-account/balance?salaryType=${config.balanceType}`);
if (result.status && result.body) state.heroValue = formatMoney(result.body.availableBalance || 0);
return;
}
if (config.balanceEndpoint) {
const result = await apiGet(config.balanceEndpoint);
const body = result.body || {};
state.heroValue = formatMoney(body.currentSalary ?? body.availableBalance ?? body.balance ?? 0);
}
}
function showToast(message) {
const toast = document.getElementById("toast");
toast.textContent = message;
toast.hidden = false;
window.clearTimeout(showToast.timer);
showToast.timer = window.setTimeout(() => {
toast.hidden = true;
}, 2500);
}
function normalizeRoute(target) {
const alias = {
"/invite-agency": "/invite-agency/",
"/invite-bd": "/invite-bd/",
"/invite-bd-leader": "/invite-bd-leader/",
"/invite-recharge-agency": "/invite-recharge-agency/"
};
const url = new URL(alias[target] || 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 menuIcon(text) {
return (text || "?").trim().slice(0, 1).toUpperCase();
}
function render() {
document.documentElement.lang = state.lang;
document.documentElement.dir = state.lang === "ar" ? "rtl" : "ltr";
document.getElementById("pageTitle").textContent = config.title;
document.querySelector("[data-action='language']").textContent = state.lang.toUpperCase();
document.getElementById("heroTitle").textContent = config.heroTitle;
document.getElementById("heroLink").textContent = config.heroLink || "Details";
document.getElementById("heroValue").textContent = `$${state.heroValue}`;
const summaryRoot = document.getElementById("summaryGrid");
summaryRoot.innerHTML = "";
state.summaries.forEach((item) => {
const node = document.createElement("div");
node.className = "summary-item";
node.innerHTML = `<div class="summary-label"></div><div class="summary-value"></div>`;
node.querySelector(".summary-label").textContent = item.label;
node.querySelector(".summary-value").textContent = item.value;
summaryRoot.appendChild(node);
});
summaryRoot.hidden = !state.summaries.length;
const oldTask = document.getElementById("taskCard");
if (oldTask) oldTask.remove();
if (config.task) {
const taskCard = document.createElement("section");
taskCard.className = "surface-card task-card";
taskCard.id = "taskCard";
taskCard.innerHTML = `<div class="task-title"></div><div class="task-grid"></div>`;
taskCard.querySelector(".task-title").textContent = config.task.title || "";
const taskGrid = taskCard.querySelector(".task-grid");
(config.task.items || []).forEach((item) => {
const node = document.createElement("div");
node.innerHTML = `<div class="task-label"></div><div class="task-value"></div>`;
node.querySelector(".task-label").textContent = item.label;
node.querySelector(".task-value").textContent = item.value;
taskGrid.appendChild(node);
});
const sections = document.getElementById("sections");
sections.parentNode.insertBefore(taskCard, sections);
}
const sectionRoot = document.getElementById("sections");
sectionRoot.innerHTML = "";
(config.sections || []).forEach((section) => {
const card = document.createElement("section");
card.className = "surface-card menu-card";
const title = document.createElement("div");
title.className = "section-title";
title.textContent = section.title || "";
card.appendChild(title);
(section.items || []).forEach((item) => {
const row = document.createElement("button");
row.type = "button";
row.className = "menu-row";
row.dataset.route = item.route;
row.innerHTML = `<div class="menu-label"><span class="menu-icon"></span><span class="menu-text"></span></div><span class="arrow"></span>`;
row.querySelector(".menu-icon").textContent = item.icon || menuIcon(item.label);
row.querySelector(".menu-text").textContent = item.label;
row.addEventListener("click", () => navigateTo(item.route));
card.appendChild(row);
});
sectionRoot.appendChild(card);
});
}
function bindEvents() {
document.querySelector("[data-action='back']").addEventListener("click", () => {
if (window.history.length > 1) {
window.history.back();
return;
}
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");
}
});
document.querySelector("[data-action='language']").addEventListener("click", () => navigateTo("/language"));
document.getElementById("heroLink").addEventListener("click", () => navigateTo(config.heroRoute || "/history-salary"));
}
async function init() {
localStorage.setItem("identity", JSON.stringify({ identity: config.identity }));
render();
bindEvents();
try {
await connectToApp();
await fetchHeroValue();
} catch (error) {
console.warn(`${config.title} data request failed:`, error);
showToast(error.response?.errorMsg || error.message || "Failed to load data.");
} finally {
render();
}
}
init();