From 196438b02c34bb81a0fdc7bd36e34b3024ed7f2c Mon Sep 17 00:00:00 2001 From: zhx Date: Tue, 26 May 2026 21:02:42 +0800 Subject: [PATCH] support wrapped recharge reward slots --- h5/activity/recharge/index.html | 141 +++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 12 deletions(-) diff --git a/h5/activity/recharge/index.html b/h5/activity/recharge/index.html index c0dea65..93b7ee5 100644 --- a/h5/activity/recharge/index.html +++ b/h5/activity/recharge/index.html @@ -765,6 +765,13 @@ var LEVEL_GAP = 814; var LEVEL_PANEL_HEIGHT = 618; var LEVEL_BOTTOM_PADDING = 57; + var REWARD_COLUMNS = 3; + var REWARD_ROW_GAP = 330; + var REWARD_FRAME_LEFTS = { + 1: [420], + 2: [269, 571], + 3: [118, 420, 722], + }; var query = buildPageQueryParams(); var countdownTimer = null; var countdownEndsAt = 0; @@ -1024,22 +1031,68 @@ }); } - function setCanvasHeight(levelCount) { - var count = Math.max(0, Number(levelCount) || 0); - var height = count > 0 - ? LEVEL_PANEL_TOP + ((count - 1) * LEVEL_GAP) + LEVEL_PANEL_HEIGHT + LEVEL_BOTTOM_PADDING + function layoutPanel(panel, panelHeight) { + if (!panel) return; + panel.style.height = panelHeight + "px"; + var middleHeight = Math.max(0, panelHeight - 382); + var middles = Array.prototype.slice.call(panel.querySelectorAll(".panel-middle")); + var middle = middles[0]; + if (middle) { + middle.classList.remove("is-hidden"); + middle.style.top = "191px"; + middle.style.height = middleHeight + "px"; + } + middles.slice(1).forEach(function (node) { + node.classList.add("is-hidden"); + }); + var bottom = panel.querySelector(".panel-edge.bottom"); + if (bottom) bottom.style.top = (panelHeight - 191) + "px"; + } + + function rewardRowCount(level) { + var rewardCount = levelRewards(level).length; + return Math.max(1, Math.ceil(rewardCount / REWARD_COLUMNS)); + } + + function rewardExtraHeight(rowCount) { + return Math.max(0, Number(rowCount || 1) - 1) * REWARD_ROW_GAP; + } + + function buildLevelLayouts(levels) { + var offset = 0; + return levels.map(function (level) { + var rowCount = rewardRowCount(level); + var layout = { + offset: offset, + rowCount: rowCount, + panelHeight: LEVEL_PANEL_HEIGHT + rewardExtraHeight(rowCount), + }; + offset += LEVEL_GAP + rewardExtraHeight(rowCount); + return layout; + }); + } + + function setCanvasHeight(layouts) { + var count = Array.isArray(layouts) ? layouts.length : 0; + var last = count > 0 ? layouts[count - 1] : null; + var height = last + ? LEVEL_PANEL_TOP + last.offset + last.panelHeight + LEVEL_BOTTOM_PADDING : LEVEL_BASE_HEIGHT; document.documentElement.style.setProperty("--canvas-height", height + "px"); } - function layoutLevelSection(section, index) { + function layoutLevelSection(section, index, layout) { if (!section) return; - var offset = index * LEVEL_GAP; + var offset = layout ? layout.offset : index * LEVEL_GAP; + var panelHeight = layout ? layout.panelHeight : LEVEL_PANEL_HEIGHT; + var rowCount = layout ? layout.rowCount : 1; section.setAttribute("data-level-section", String(index)); + section.setAttribute("data-level-offset", String(offset)); + section.setAttribute("data-level-row-count", String(rowCount)); section.setAttribute("aria-label", "Recharge level " + (index + 1)); var panel = firstLevelPanel(section); setTop(panel, LEVEL_PANEL_TOP + offset); - if (panel) panel.style.height = LEVEL_PANEL_HEIGHT + "px"; + layoutPanel(panel, panelHeight); setTop(section.querySelector(".section-badge"), LEVEL_BADGE_TOP + offset); setTop(section.querySelector("[data-level-title]"), LEVEL_TITLE_TOP + offset); Array.prototype.slice.call(section.querySelectorAll("[data-level-frame]")).forEach(function (node) { @@ -1053,8 +1106,9 @@ }); } - function ensureLevelSections(levelCount) { - var targetCount = Math.max(0, Number(levelCount) || 0); + function ensureLevelSections(levels) { + var targetCount = Array.isArray(levels) ? levels.length : Math.max(0, Number(levels) || 0); + var layouts = Array.isArray(levels) ? buildLevelLayouts(levels) : []; var sections = Array.prototype.slice.call(document.querySelectorAll("[data-level-section]")); var template = sections[0]; if (!template) return []; @@ -1064,14 +1118,71 @@ sections.push(next); } sections.forEach(function (section, index) { - layoutLevelSection(section, index); + layoutLevelSection(section, index, layouts[index]); section.classList.toggle("is-hidden", index >= targetCount); }); - setCanvasHeight(targetCount); + setCanvasHeight(layouts); els.sections = sections; return sections; } + function ensureRewardSlots(section, rewardCount) { + var targetCount = Math.max(0, Number(rewardCount) || 0); + var frames = Array.prototype.slice.call(section.querySelectorAll("[data-level-frame]")); + var images = Array.prototype.slice.call(section.querySelectorAll("[data-reward-image]")); + var prices = Array.prototype.slice.call(section.querySelectorAll(".reward-price")); + var frameTemplate = frames[0]; + var imageTemplate = images[0]; + var priceTemplate = prices[0]; + + while (frames.length < targetCount && frameTemplate) { + var frame = frameTemplate.cloneNode(true); + frame.setAttribute("data-level-frame", String(frames.length)); + section.appendChild(frame); + frames.push(frame); + } + while (images.length < targetCount && imageTemplate) { + var image = imageTemplate.cloneNode(true); + image.setAttribute("data-reward-image", String(images.length)); + section.appendChild(image); + images.push(image); + } + while (prices.length < targetCount && priceTemplate) { + var price = priceTemplate.cloneNode(true); + var label = price.querySelector("[data-reward-label]"); + if (label) label.setAttribute("data-reward-label", String(prices.length)); + section.appendChild(price); + prices.push(price); + } + } + + function rewardFrameLeft(rowSize, slotIndex) { + var positions = REWARD_FRAME_LEFTS[Math.max(1, Math.min(REWARD_COLUMNS, rowSize))] || REWARD_FRAME_LEFTS[3]; + return positions[Math.max(0, Math.min(slotIndex, positions.length - 1))]; + } + + function positionRewardNodes(section, index, totalRewards, nodes) { + var offset = Number(section.getAttribute("data-level-offset") || 0); + var rowIndex = Math.floor(index / REWARD_COLUMNS); + var rowStart = rowIndex * REWARD_COLUMNS; + var rowSize = Math.min(REWARD_COLUMNS, totalRewards - rowStart); + var slotIndex = index - rowStart; + var frameLeft = rewardFrameLeft(rowSize, slotIndex); + var rowOffset = rowIndex * REWARD_ROW_GAP; + if (nodes.frame) { + nodes.frame.style.left = frameLeft + "px"; + setTop(nodes.frame, LEVEL_FRAME_TOP + offset + rowOffset); + } + if (nodes.image) { + nodes.image.style.left = (frameLeft + 20) + "px"; + setTop(nodes.image, LEVEL_ICON_TOP + offset + rowOffset); + } + if (nodes.price) { + nodes.price.style.left = (frameLeft - 22) + "px"; + setTop(nodes.price, LEVEL_PRICE_TOP + offset + rowOffset); + } + } + function renderLevel(section, level) { if (!section) return; if (!level) { @@ -1082,6 +1193,7 @@ var title = section.querySelector("[data-level-title]"); if (title) title.textContent = "Recharge $" + formatAmountCents(centsValue(level)); var rewards = levelRewards(level); + ensureRewardSlots(section, rewards.length); 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]")); @@ -1093,6 +1205,11 @@ if (node) node.classList.toggle("is-hidden", !reward); }); if (!reward) continue; + positionRewardNodes(section, i, rewards.length, { + frame: frames[i], + image: images[i], + price: prices[i], + }); setImage(images[i], reward.cover, DEFAULT_REWARD_ICON); if (labels[i]) labels[i].textContent = rewardLabel(reward); } @@ -1111,7 +1228,7 @@ startCountdown(body.countdownMillis); var levels = normalizeLevels(body.levelConfigs); if (Array.isArray(body.levelConfigs)) { - ensureLevelSections(levels.length).forEach(function (section, index) { + ensureLevelSections(levels).forEach(function (section, index) { renderLevel(section, levels[index]); }); }