fix: connect recharge reward page API

This commit is contained in:
ZuoZuo 2026-05-01 15:30:34 +08:00
parent 187c935de3
commit 7b98d4bccb

View File

@ -345,6 +345,13 @@
object-fit: cover;
}
.avatar-crop img[data-profile-avatar] {
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.avatar-frame {
left: 389px;
top: 1319px;
@ -387,6 +394,8 @@
font-weight: 500;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.section-title {
@ -450,6 +459,9 @@
position: relative;
z-index: 1;
padding-top: 2px;
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
}
.reward-price .price-fill,
@ -482,6 +494,13 @@
height: 1px;
background: rgba(255, 234, 181, 0.75);
}
.reward-section.is-hidden,
.reward-slot-frame.is-hidden,
.reward-icon.is-hidden,
.reward-price.is-hidden {
display: none;
}
</style>
</head>
@ -503,22 +522,22 @@
<div class="countdown-item" style="left: 185px; top: 926px;" data-node-id="5:748">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-value" data-countdown="days">01</div>
<div class="countdown-label">Days</div>
</div>
<div class="countdown-item" style="left: 387px; top: 926px;" data-node-id="5:752">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-value" data-countdown="hours">01</div>
<div class="countdown-label">Hours</div>
</div>
<div class="countdown-item" style="left: 588px; top: 926px;" data-node-id="5:756">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-value" data-countdown="minutes">01</div>
<div class="countdown-label">Minutes</div>
</div>
<div class="countdown-item" style="left: 787px; top: 926px;" data-node-id="5:760">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-value" data-countdown="seconds">01</div>
<div class="countdown-label">Seconds</div>
</div>
@ -534,7 +553,7 @@
</section>
<div class="avatar-crop" data-node-id="5:703">
<img src="../../assets/recharge/avatar-photo.png" alt="" />
<img src="../../assets/recharge/avatar-photo.png" alt="" data-profile-avatar />
</div>
<div class="ornate-square avatar-frame" aria-hidden="true" data-node-id="5:706">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
@ -546,11 +565,11 @@
<img class="center-gem bottom" src="../../assets/recharge/reward-frame-center.png" alt="" />
</div>
<div class="figure-text profile-name" data-node-id="5:707">nanfangjian</div>
<div class="figure-text profile-id" data-node-id="5:709">ID12345678</div>
<div class="figure-text profile-total" data-node-id="5:708">Accumlated Recharge:5998</div>
<div class="figure-text profile-name" data-node-id="5:707" data-profile-name>nanfangjian</div>
<div class="figure-text profile-id" data-node-id="5:709" data-profile-id>ID12345678</div>
<div class="figure-text profile-total" data-node-id="5:708" data-profile-total>Accumlated Recharge:5998</div>
<section aria-label="Recharge 100 two rewards" data-node-id="5:710">
<section class="reward-section" aria-label="Recharge 100 two rewards" data-node-id="5:710" data-level-section="0">
<div class="panel" style="top: 1937px; height: 758px;" aria-hidden="true">
<img class="panel-edge" style="top: 0;" src="../../assets/recharge/panel-edge.png" alt="" />
<img class="panel-middle" style="top: 191px;" src="../../assets/recharge/panel-middle.png" alt="" />
@ -559,42 +578,42 @@
<img class="panel-edge bottom" style="top: 567px;" src="../../assets/recharge/panel-edge.png" alt="" />
</div>
<img class="asset section-badge" style="left: 370px; top: 1891px;" src="../../assets/recharge/section-badge.png" alt="" />
<div class="section-title" style="left: 370px; top: 1960px;" data-node-id="5:718">Recharge $100</div>
<div class="section-title" style="left: 370px; top: 1960px;" data-node-id="5:718" data-level-title>Recharge $100</div>
<div class="ornate-square reward-frame-lg" style="left: 118px; top: 2088px;" aria-hidden="true">
<div class="ornate-square reward-frame-lg reward-slot-frame" style="left: 118px; top: 2088px;" aria-hidden="true" data-level-frame="0">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<div class="ornate-square reward-frame-lg" style="left: 602px; top: 2088px;" aria-hidden="true">
<div class="ornate-square reward-frame-lg reward-slot-frame" style="left: 602px; top: 2088px;" aria-hidden="true" data-level-frame="1">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<img class="reward-icon" style="left: 148px; top: 2118px; width: 300px; height: 300px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 632px; top: 2118px; width: 300px; height: 300px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 148px; top: 2118px; width: 300px; height: 300px;" src="../../assets/recharge/reward-icon.png" alt="" data-reward-image="0" />
<img class="reward-icon" style="left: 632px; top: 2118px; width: 300px; height: 300px;" src="../../assets/recharge/reward-icon.png" alt="" data-reward-image="1" />
<div class="reward-price" style="left: 156px; top: 2458px;" data-node-id="5:725">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
<span data-reward-label="0">$100</span>
</div>
<div class="reward-price" style="left: 640px; top: 2458px;" data-node-id="5:726">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
<span data-reward-label="1">$100</span>
</div>
</section>
<section aria-label="Recharge 100 three rewards" data-node-id="5:727">
<section class="reward-section" aria-label="Recharge 100 three rewards" data-node-id="5:727" data-level-section="1">
<div class="panel" style="top: 2751px; height: 618px;" aria-hidden="true">
<img class="panel-edge" style="top: 0;" src="../../assets/recharge/panel-edge.png" alt="" />
<img class="panel-middle" style="top: 191px;" src="../../assets/recharge/panel-middle.png" alt="" />
@ -602,53 +621,53 @@
<img class="panel-edge bottom" style="top: 427px;" src="../../assets/recharge/panel-edge.png" alt="" />
</div>
<img class="asset section-badge" style="left: 370px; top: 2705px;" src="../../assets/recharge/section-badge.png" alt="" />
<div class="section-title" style="left: 370px; top: 2774px;" data-node-id="5:734">Recharge $100</div>
<div class="section-title" style="left: 370px; top: 2774px;" data-node-id="5:734" data-level-title>Recharge $100</div>
<div class="ornate-square reward-frame-sm" style="left: 118px; top: 2902px;" aria-hidden="true">
<div class="ornate-square reward-frame-sm reward-slot-frame" style="left: 118px; top: 2902px;" aria-hidden="true" data-level-frame="0">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<div class="ornate-square reward-frame-sm" style="left: 420px; top: 2902px;" aria-hidden="true">
<div class="ornate-square reward-frame-sm reward-slot-frame" style="left: 420px; top: 2902px;" aria-hidden="true" data-level-frame="1">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<div class="ornate-square reward-frame-sm" style="left: 722px; top: 2902px;" aria-hidden="true">
<div class="ornate-square reward-frame-sm reward-slot-frame" style="left: 722px; top: 2902px;" aria-hidden="true" data-level-frame="2">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<img class="reward-icon" style="left: 138px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 440px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 742px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 138px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" data-reward-image="0" />
<img class="reward-icon" style="left: 440px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" data-reward-image="1" />
<img class="reward-icon" style="left: 742px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" data-reward-image="2" />
<div class="reward-price" style="left: 96px; top: 3152px;" data-node-id="5:744">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
<span data-reward-label="0">$100</span>
</div>
<div class="reward-price" style="left: 398px; top: 3152px;" data-node-id="5:745">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
<span data-reward-label="1">$100</span>
</div>
<div class="reward-price" style="left: 700px; top: 3152px;" data-node-id="5:746">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
<span data-reward-label="2">$100</span>
</div>
</section>
</div>
@ -657,6 +676,301 @@
<script>
window.__H5_ROUTE_PATH__ = "/activity/recharge";
(function () {
var DEFAULT_API_BASE = "https://jvapi.haiyihy.com/";
var DEFAULT_API_PREFIX = "/go";
var HOME_ENDPOINT = "/app/h5/recharge-reward/home";
var DEFAULT_AVATAR = "../../assets/defaultAvatar-CdxWBK1k.png";
var DEFAULT_REWARD_ICON = "../../assets/recharge/reward-icon.png";
var query = buildPageQueryParams();
var countdownTimer = null;
var countdownEndsAt = 0;
var els = {
avatar: document.querySelector("[data-profile-avatar]"),
name: document.querySelector("[data-profile-name]"),
id: document.querySelector("[data-profile-id]"),
total: document.querySelector("[data-profile-total]"),
days: document.querySelector("[data-countdown='days']"),
hours: document.querySelector("[data-countdown='hours']"),
minutes: document.querySelector("[data-countdown='minutes']"),
seconds: document.querySelector("[data-countdown='seconds']"),
sections: Array.prototype.slice.call(document.querySelectorAll("[data-level-section]")),
};
function trimValue(value) {
return value == null ? "" : String(value).trim();
}
function buildPageQueryParams() {
var params = new URLSearchParams(window.location.search || "");
var hash = window.location.hash || "";
var queryIndex = hash.indexOf("?");
if (queryIndex >= 0) {
var hashParams = new URLSearchParams(hash.slice(queryIndex + 1).split("#")[0]);
hashParams.forEach(function (value, key) {
if (!params.has(key)) params.append(key, value);
});
}
return params;
}
function readParam(names) {
for (var i = 0; i < names.length; i += 1) {
var value = trimValue(query.get(names[i]));
if (value) return value;
}
return "";
}
function normalizeBaseURL(base) {
var value = trimValue(base) || DEFAULT_API_BASE;
return value.endsWith("/") ? value : value + "/";
}
function resolveAPIBase() {
var override = readParam(["apiBase", "api_base"]);
if (override) return normalizeBaseURL(override);
if (typeof window.__RECHARGE_REWARD_API_BASE__ === "string") {
return normalizeBaseURL(window.__RECHARGE_REWARD_API_BASE__);
}
return normalizeBaseURL(DEFAULT_API_BASE);
}
function resolveAPIPrefix(apiBase) {
var override = readParam(["apiPrefix", "api_prefix"]);
if (override) return override;
if (typeof window.__RECHARGE_REWARD_API_PREFIX__ === "string") {
return trimValue(window.__RECHARGE_REWARD_API_PREFIX__);
}
try {
return new URL(apiBase).origin === new URL(DEFAULT_API_BASE).origin ? DEFAULT_API_PREFIX : "";
} catch (_) {
return "";
}
}
function joinPath() {
return "/" + Array.prototype.slice.call(arguments)
.map(function (part) { return trimValue(part).replace(/^\/+|\/+$/g, ""); })
.filter(Boolean)
.join("/");
}
function buildURL(path) {
var apiBase = resolveAPIBase();
var apiPrefix = resolveAPIPrefix(apiBase);
return new URL(joinPath(apiPrefix, path).replace(/^\/+/, ""), apiBase);
}
function normalizeAuthorization(value) {
var token = trimValue(value);
if (!token) return "";
if (/^bearer\s+/i.test(token)) {
return "Bearer " + token.replace(/^bearer\s+/i, "").replace(/ /g, "+");
}
return "Bearer " + token.replace(/ /g, "+");
}
function readAuthorization() {
var direct = readParam(["Authorization", "authorization"]);
if (direct) return normalizeAuthorization(direct);
var token = readParam(["token", "accessToken", "access_token"]);
if (token) return normalizeAuthorization(token);
if (typeof window.__RECHARGE_REWARD_AUTHORIZATION__ === "string") {
return normalizeAuthorization(window.__RECHARGE_REWARD_AUTHORIZATION__);
}
try {
return normalizeAuthorization(
window.localStorage.getItem("Authorization") ||
window.localStorage.getItem("authorization") ||
window.localStorage.getItem("token") ||
window.localStorage.getItem("accessToken")
);
} catch (_) {
return "";
}
}
function numberValue(value) {
var number = Number(trimValue(value).replace(/,/g, ""));
return Number.isFinite(number) ? number : 0;
}
function centsValue(item) {
var cents = numberValue(item && item.rechargeAmountCents);
if (cents > 0) return cents;
var amount = numberValue(item && item.rechargeAmount);
return Math.round(amount * 100);
}
function formatAmountCents(cents) {
var safeCents = Math.max(0, Math.trunc(Number(cents) || 0));
var dollars = Math.floor(safeCents / 100);
var remainder = String(safeCents % 100).padStart(2, "0");
return remainder === "00" ? String(dollars) : dollars + "." + remainder;
}
function trimDecimal(value) {
return Number(value.toFixed(1)).toString();
}
function formatCompact(value) {
var number = Number(value || 0);
if (!Number.isFinite(number)) return "0";
var absolute = Math.abs(number);
if (absolute >= 1000000) return trimDecimal(number / 1000000) + "M";
if (absolute >= 1000) return trimDecimal(number / 1000) + "K";
return new Intl.NumberFormat("en-US").format(Math.trunc(number));
}
function pad2(value) {
return String(Math.max(0, Math.trunc(value))).padStart(2, "0");
}
function renderCountdown() {
if (!countdownEndsAt) return;
var remaining = Math.max(0, countdownEndsAt - Date.now());
var totalSeconds = Math.floor(remaining / 1000);
var days = Math.floor(totalSeconds / 86400);
var hours = Math.floor((totalSeconds % 86400) / 3600);
var minutes = Math.floor((totalSeconds % 3600) / 60);
var seconds = totalSeconds % 60;
if (els.days) els.days.textContent = pad2(days);
if (els.hours) els.hours.textContent = pad2(hours);
if (els.minutes) els.minutes.textContent = pad2(minutes);
if (els.seconds) els.seconds.textContent = pad2(seconds);
}
function startCountdown(milliseconds) {
var value = Number(milliseconds || 0);
if (!Number.isFinite(value) || value <= 0) return;
countdownEndsAt = Date.now() + value;
renderCountdown();
if (countdownTimer) window.clearInterval(countdownTimer);
countdownTimer = window.setInterval(renderCountdown, 1000);
}
function setImage(img, src, fallback) {
if (!img) return;
img.onerror = function () {
if (fallback && img.src.indexOf(fallback) === -1) {
img.src = fallback;
}
};
img.src = trimValue(src) || fallback || "";
}
function rewardLabel(item) {
if (!item) return "";
if (item.kind === "gold") return formatCompact(item.amount || 0);
var name = trimValue(item.name) || trimValue(item.content) || trimValue(item.type);
var quantity = Number(item.quantity || 0);
if (name && quantity > 1) return name + " x" + formatCompact(quantity);
if (name) return name;
return quantity > 0 ? "x" + formatCompact(quantity) : "";
}
function levelRewards(level) {
var result = [];
var rewardGold = Number(level && level.rewardGold || 0);
if (Number.isFinite(rewardGold) && rewardGold > 0) {
result.push({ kind: "gold", amount: rewardGold, cover: DEFAULT_REWARD_ICON });
}
var items = Array.isArray(level && level.rewardItems) ? level.rewardItems : [];
items.forEach(function (item) {
result.push({
kind: "item",
cover: trimValue(item && item.cover) || DEFAULT_REWARD_ICON,
name: item && item.name,
content: item && item.content,
type: item && item.type,
quantity: item && item.quantity,
});
});
return result;
}
function normalizeLevels(levels) {
if (!Array.isArray(levels)) return [];
return levels
.filter(function (level) { return level && level.enabled !== false && centsValue(level) > 0; })
.sort(function (a, b) {
var byAmount = centsValue(a) - centsValue(b);
return byAmount || Number(a.level || 0) - Number(b.level || 0);
});
}
function renderLevel(section, level) {
if (!section) return;
if (!level) {
section.classList.add("is-hidden");
return;
}
section.classList.remove("is-hidden");
var title = section.querySelector("[data-level-title]");
if (title) title.textContent = "Recharge $" + formatAmountCents(centsValue(level));
var rewards = levelRewards(level);
var images = Array.prototype.slice.call(section.querySelectorAll("[data-reward-image]"));
var labels = Array.prototype.slice.call(section.querySelectorAll("[data-reward-label]"));
var frames = Array.prototype.slice.call(section.querySelectorAll("[data-level-frame]"));
var prices = Array.prototype.slice.call(section.querySelectorAll(".reward-price"));
var count = Math.max(images.length, labels.length, frames.length, prices.length);
for (var i = 0; i < count; i += 1) {
var reward = rewards[i];
[images[i], labels[i], frames[i], prices[i]].forEach(function (node) {
if (node) node.classList.toggle("is-hidden", !reward);
});
if (!reward) continue;
setImage(images[i], reward.cover, DEFAULT_REWARD_ICON);
if (labels[i]) labels[i].textContent = rewardLabel(reward);
}
}
function applyHomeData(body) {
if (!body || typeof body !== "object") return;
if (els.name) els.name.textContent = trimValue(body.userNickname) || trimValue(body.userAccount) || els.name.textContent;
if (els.id) els.id.textContent = "ID:" + (trimValue(body.userAccount) || trimValue(body.userId) || "");
if (els.total) {
var totalCents = numberValue(body.accumulatedRechargeAmountCents);
if (totalCents <= 0) totalCents = Math.round(numberValue(body.accumulatedRechargeAmount) * 100);
els.total.textContent = "Accumlated Recharge:" + formatAmountCents(totalCents);
}
setImage(els.avatar, body.userAvatar, DEFAULT_AVATAR);
startCountdown(body.countdownMillis);
var levels = normalizeLevels(body.levelConfigs);
if (Array.isArray(body.levelConfigs)) {
els.sections.forEach(function (section, index) {
renderLevel(section, levels[index]);
});
}
}
async function fetchHomeData() {
var authorization = readAuthorization();
if (!authorization) return;
try {
var response = await fetch(buildURL(HOME_ENDPOINT).toString(), {
cache: "no-store",
headers: {
Accept: "application/json",
Authorization: authorization,
"req-client": "H5",
},
});
var json = await response.json().catch(function () { return {}; });
if (!response.ok || json.status === false) {
throw new Error(json.errorMsg || json.message || "request_failed");
}
applyHomeData(json && (json.body || json.data || json));
} catch (error) {
console.warn("[RechargeReward] load failed", error);
}
}
fetchHomeData();
})();
(function () {
var root = document.documentElement;
var maxWidth = 432;