From b3b21df409afc7ea9b59b32bcaa3fd00f5a9fda2 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Sep 2026 13:04:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(vip):=20=E4=BC=9A=E5=91=98=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=20DOM=20=E7=BB=93=E6=9E=84=201:1=20=E5=AF=B9=E9=BD=90?= =?UTF-8?q?=20Zibll=20payvip-modal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 整体结构由自实现(aksrt-panel/aksrt-vip-tab/aksrt-modal-close)迁移到 参考主题 zibpay_get_pay_modal 原生 DOM: - 根元素 box-body payvip-modal;close 按钮改为 Zibll 原版内联 SVG (.close + ic-close 1024 viewBox path) - 用户信息 list-inline user-box(avatar-img 头像 + b.em12 + badg c-yellow vip-expdate-tag 到期标签) - 会员缩略卡 tab:vip-cardminis + vip-card vip-cardmini level-N vip-themeN + abs-center vip-baicon + v-iconbox(v-icon/v-info/ v-name/v-desc)+ abs-right active-icon 勾选图标 - pane 改为 bootstrap 原生 tab-pane fade active in(移除冗余 hidden 属性),tab 切换同步 active/in 双类 - 左侧信息盒 pay-vip-info:v-iconbox 图标 + v-name/v-desc + 管理员 配置的 v-equity 权益列表 + abs-center vip-baicon 背景图标 - 套餐卡 zib-widget vip-product product-box:价格行 mark 小号 px12 前缀 + original-price 原价 + abs-right vip-tag badg 折扣角标 + 时长 badge;label-box charge-box 盒由 bootstrap :checked 选中态驱动 - pane 内积分兑换链接与 more 说明移至套餐区(对齐 Zibll 顺序) - 清理 vip-modal.css 死样式(aksrt-vip-modal-panel、aksrt-vip-tab、 aksrt-vip-level-header、aksrt-vip-product-label、vip-product/ vip-tag/product-price 本地重复、uc-vip-shop__tip 等 -148 行), 样式统一由 main.css 复刻的 Zibll 原版段提供 --- assets/css/frontend/vip-modal.css | 148 +------------------------ assets/js/pay-vip.js | 178 +++++++++++++++++++++--------- 2 files changed, 127 insertions(+), 199 deletions(-) diff --git a/assets/css/frontend/vip-modal.css b/assets/css/frontend/vip-modal.css index 0144f7c8..5fe62f40 100644 --- a/assets/css/frontend/vip-modal.css +++ b/assets/css/frontend/vip-modal.css @@ -2,15 +2,6 @@ * VIP pay modal + hover cards (legacy payvip-modal / vip-card). */ -.aksrt-vip-modal-panel { - width: min(560px, 100%); - max-height: min(90vh, 760px); - overflow: auto; - background: var(--main-bg-color, #fff); - border-radius: 12px; - box-shadow: 0 16px 48px rgba(0, 0, 0, 0.22); -} - /* VIP now uses the shared modal runtime host. */ .aksrt-modal-runtime.aksrt-vip-modal-shell { z-index: 1200; @@ -116,47 +107,6 @@ } -.aksrt-modal-close { - position: absolute; - top: 8px; - right: 12px; - border: 0; - background: transparent; - font-size: 22px; - line-height: 1; - cursor: pointer; - color: inherit; - opacity: 0.65; -} - -.vip-cardminis { - list-style: none; - margin: 0; - padding: 0; - gap: 8px; - display: flex; -} - -.vip-cardminis > li { - flex: 1; -} - -.vip-cardminis a.aksrt-vip-tab { - display: block; - text-align: center; - padding: 10px 8px; - border-radius: 8px; - background: var(--surface-2, rgba(0, 0, 0, 0.05)); - color: inherit; - text-decoration: none; - font-weight: 600; -} - -.vip-cardminis > li.active a.aksrt-vip-tab { - background: linear-gradient(90deg, #ff6b6b, #f04494); - color: #fff; -} - .pay-vip-form-row { display: grid; gap: 12px; @@ -168,33 +118,8 @@ } } -.aksrt-vip-level-header { - display: flex; - align-items: center; - gap: 8px; - min-width: 0; -} - -.aksrt-vip-level-header .aksrt-vip-level-icon { - flex: 0 0 auto; -} - - padding: 12px; - border-radius: 10px; - background: var(--surface-2, rgba(0, 0, 0, 0.04)); -} - -.pay-vip-info.level-1 { - background: linear-gradient(135deg, rgba(255, 193, 7, 0.12), rgba(255, 152, 0, 0.08)); -} - -.pay-vip-info.level-2 { - background: linear-gradient(135deg, rgba(156, 39, 176, 0.12), rgba(63, 81, 181, 0.08)); -} - /* Modal-only equity (admin HTML; no forced bullets) */ -.payvip-modal .v-equity, -.aksrt-vip-modal-panel .v-equity { +.payvip-modal .v-equity { display: block; list-style: none; margin: 8px 0 0; @@ -202,91 +127,24 @@ font-size: 12px; line-height: 1.6; } -.payvip-modal .v-equity > li, -.aksrt-vip-modal-panel .v-equity > li { +.payvip-modal .v-equity > li { display: block; margin: 0 0 6px; padding: 0; list-style: none; } .payvip-modal .v-equity > li::before, -.payvip-modal .v-equity > li::after, -.aksrt-vip-modal-panel .v-equity > li::before, -.aksrt-vip-modal-panel .v-equity > li::after { +.payvip-modal .v-equity > li::after { content: none !important; display: none !important; } -.aksrt-vip-products { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; -} - -.aksrt-vip-product-label { - display: block; - cursor: pointer; - margin: 0; -} - -.aksrt-vip-product-label input { - position: absolute; - opacity: 0; - pointer-events: none; -} - -.vip-product { - position: relative; - padding: 12px 8px; - border-radius: 10px; - border: 1px solid rgba(0, 0, 0, 0.08); - background: var(--main-bg-color, #fff); - transition: border-color 0.15s, box-shadow 0.15s; -} - -.aksrt-vip-product-label input:checked + .vip-product { - border-color: #f04494; - box-shadow: 0 0 0 1px #f04494; -} - -.product-price { - font-size: 18px; - font-weight: 700; -} - -.vip-tag { - position: absolute; - top: 0; - right: 0; - font-size: 11px; - padding: 2px 6px; - border-radius: 0 10px 0 8px; - background: #ffc107; - color: #5c3b00; -} - -.aksrt-vip-submit { - width: 100%; - margin-top: 8px; - border: 0; - border-radius: 999px; - padding: 12px 16px; - background: linear-gradient(90deg, #ff6b6b, #f04494); - color: #fff; - font-weight: 600; - cursor: pointer; -} - .aksrt-vip-submit.is-loading, .aksrt-vip-submit:disabled { opacity: 0.7; cursor: wait; } -.uc-vip-shop__tip.is-error { - color: #e74c3c; -} - .vipbg-v2 { display: flex; align-items: center; diff --git a/assets/js/pay-vip.js b/assets/js/pay-vip.js index 4245ad6d..2e51f3b3 100644 --- a/assets/js/pay-vip.js +++ b/assets/js/pay-vip.js @@ -57,44 +57,67 @@ return ""; } - function renderEquity(parent, value) { - if (!value) return; - var equity = node("div"); - // The server sanitizes and wraps this admin-authored fragment before JSON. - equity.innerHTML = text(value); - while (equity.firstChild) parent.appendChild(equity.firstChild); + // 会员图标(Zibll zibpay_get_vip_icon:vip_N.svg 或自定义 img_icon)。 + function vipIcon(levelInfo) { + if (levelInfo && levelInfo.img_icon) { + var img = node("img", "img-icon"); + img.src = text(levelInfo.img_icon); + img.alt = text(levelInfo.name || ""); + img.decoding = "async"; + return img; + } + return node("i", "fa fas fa-gem"); } - function renderProducts(parent, items) { + // 价格行(Zibll:mark 小号 px12 前缀 + 数字;原价 original-price.relative)。 + function priceRow(mark, priceLabel, showLabel) { + var row = node("div", "flex abl gap6"); + var price = node("div", "product-price c-red"); + var label = text(priceLabel || ""); + if (mark && label.indexOf(mark) === 0) { + append(price, node("span", "px12", mark)); + append(price, node("span", "", label.slice(mark.length))); + } else { + append(price, node("span", "", label)); + } + append(row, price); + if (showLabel) { + var original = node("div", "original-price relative muted-2-color"); + var showText = text(showLabel); + if (mark && showText.indexOf(mark) === 0) { + append(original, node("span", "px12", mark)); + append(original, node("span", "", showText.slice(mark.length))); + } else { + append(original, node("span", "", showText)); + } + append(row, original); + } + return row; + } + + function renderProducts(parent, items, mark) { if (!Array.isArray(items) || !items.length) { append(parent, node("div", "muted-2-color text-center padding-10", "暂无可用套餐")); return; } - var wrap = node("div", "mb10 label-box charge-box aksrt-vip-products"); + var wrap = node("div", "mb10 label-box charge-box"); items.forEach(function (item, index) { if (!item || !item.package_id) return; - var label = node("label", "aksrt-vip-product-label"); + var label = node("label"); var input = node("input"); input.className = "hide vip-product-input"; input.type = "radio"; - input.name = "vip_product_id_" + String(item.level || "group"); - input.setAttribute("data-aksrt-vip-package", ""); + input.name = "vip_product_id"; input.value = String(item.package_id); + input.setAttribute("data-aksrt-vip-package", ""); input.checked = index === 0; - label.appendChild(input); + append(label, input); - var product = node("div", "aksrt-panel vip-product relative text-center product-box"); + // Zibll 套餐卡:zib-widget vip-product relative text-center product-box + // (右上 tag + 价格行 + 时长 badge,无标题行)。 + var product = node("div", "zib-widget vip-product relative text-center product-box"); if (item.discount_tag) append(product, node("div", "abs-right vip-tag badg jb-yellow", item.discount_tag)); - if (item.title) append(product, node("div", "em09 mb3", item.title)); - var priceRow = node("div", "flex abl gap6 jc"); - append(priceRow, node("div", "product-price c-red", item.price_label || "")); - if (item.show_price_label) { - var original = node("div", "original-price relative muted-2-color"); - var strike = node("s", "", item.show_price_label); - append(original, strike); - append(priceRow, original); - } - append(product, priceRow); + append(product, priceRow(mark, item.price_label || "", item.show_price_label || "")); if (item.days_label) append(product, node("div", "muted-2-color c-blue em09 p2-10 badg radius", item.days_label)); append(label, product); append(wrap, label); @@ -325,22 +348,35 @@ modal.setAttribute("data-aksrt-vip-modal", ""); if (view.version && view.version.catalog) modal.setAttribute("data-aksrt-vip-version", view.version.catalog); - var close = node("button", "aksrt-modal-close", "×"); + // 关闭按钮(Zibll 原版内联 SVG close 图标)。 + var close = document.createElement("button"); close.type = "button"; + close.className = "close"; close.setAttribute("data-aksrt-modal-close", ""); + close.setAttribute("aria-hidden", "true"); close.setAttribute("aria-label", "关闭"); + var closeSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + closeSvg.setAttribute("class", "ic-close"); + closeSvg.setAttribute("viewBox", "0 0 1024 1024"); + var closePath = document.createElementNS("http://www.w3.org/2000/svg", "path"); + closePath.setAttribute("d", "M573.44 512.128l237.888 237.696a43.328 43.328 0 0 1 0 59.712 43.392 43.392 0 0 1-59.712 0L513.728 571.84 265.856 819.712a44.672 44.672 0 0 1-61.568 0 44.672 44.672 0 0 1 0-61.568L452.16 510.272 214.208 272.448a43.328 43.328 0 0 1 0-59.648 43.392 43.392 0 0 1 59.712 0l237.952 237.76 246.272-246.272a44.672 44.672 0 0 1 61.568 0 44.672 44.672 0 0 1 0 61.568L573.44 512.128z"); + closeSvg.appendChild(closePath); + close.appendChild(closeSvg); append(modal, close); - var userBox = node("ul", "list-inline user-box flex ac mb10"); - var avatarItem = node("li", "avatar-img"); + // 用户信息(Zibll:list-inline user-box)。 + var userBox = node("ul", "list-inline user-box"); + var avatarItem = node("li"); + var avatarWrap = node("div", "avatar-img"); if (member.avatar_url) { var avatar = node("img"); avatar.src = text(member.avatar_url); avatar.alt = ""; avatar.width = 42; avatar.height = 42; - append(avatarItem, avatar); + append(avatarWrap, avatar); } + append(avatarItem, avatarWrap); append(userBox, avatarItem); var userInfo = node("li"); append(userInfo, node("b", "em12", member.name || "")); @@ -357,7 +393,8 @@ append(userBox, userInfo); append(modal, userBox); - var tabs = node("ul", "flex jsb mt10 mb20 vip-cardminis gutters-5 nav"); + // 会员缩略卡 tabs(Zibll vip-cardminis:vip-card.vip-cardmini + active-icon 勾)。 + var tabs = node("ul", "flex jsb mt10 mb20 vip-cardminis gutters-5"); var content = node("div", "tab-content mt10"); var activeIndex = -1; groups.forEach(function (group, index) { @@ -370,34 +407,75 @@ if (!group || !Array.isArray(group.items) || !group.items.length) return; var level = Number(group.level || 0); var action = text(group.action || "pay"); - var tabId = "tab-payvip-" + level + "-" + action; + var tabId = "tab-payvip-" + level; var active = index === activeIndex; + var levelInfo = levels[String(level)] || {}; + var tabItem = node("li", "relative" + (active ? " active" : "")); - var tab = node("a", "aksrt-vip-tab", actionLabel(action) + (group.name || "VIP" + level)); + var tab = document.createElement("a"); tab.href = "javascript:;"; tab.setAttribute("data-vip-tab", tabId); + var miniCard = node("div", "vip-card vip-cardmini level-" + level + " vip-theme" + level); + var miniBa = node("div", "abs-center vip-baicon"); + append(miniBa, vipIcon(levelInfo)); + append(miniCard, miniBa); + var miniIconbox = node("div", "v-iconbox flex ac gap10"); + var miniIcon = node("div", "v-icon flex jc"); + append(miniIcon, vipIcon(levelInfo)); + append(miniIconbox, miniIcon); + var miniInfo = node("div", "v-info"); + append(miniInfo, node("div", "v-name", actionLabel(action) + (levelInfo.name || group.name || "VIP" + level))); + append(miniInfo, node("div", "v-desc em09", levelInfo.desc || "")); + append(miniIconbox, miniInfo); + append(miniCard, miniIconbox); + append(tab, miniCard); append(tabItem, tab); + var activeIcon = node("div", "abs-right active-icon"); + append(activeIcon, node("i", "fa fa-check-circle")); + activeIcon.setAttribute("aria-hidden", "true"); + append(tabItem, activeIcon); append(tabs, tabItem); - var pane = node("div", "tab-pane aksrt-vip-pane" + (active ? " active" : "")); + // pane(Zibll tab-pane fade active in)。 + var pane = node("div", "tab-pane fade aksrt-vip-pane" + (active ? " active in" : "")); pane.id = tabId; pane.hidden = !active; + var form = document.createElement("form"); + form.setAttribute("onsubmit", "return false;"); var row = node("div", "pay-vip-form-row"); - var info = node("div", "pay-vip-info level-" + level); - var levelInfo = levels[String(level)] || {}; - var levelHeader = node("div", "aksrt-vip-level-header"); - if (levelInfo.img_icon) { - var levelIcon = imageNode(text(levelInfo.img_icon), "aksrt-vip-level-icon"); - append(levelHeader, levelIcon); + + // 左侧会员信息(Zibll zibpay_get_pay_vip_info_box)。 + var info = node("div", "text-center pay-vip-info"); + var iconbox = node("div", "v-iconbox mb10 flex jc gap10"); + var vicon = node("div", "v-icon flex jc"); + append(vicon, vipIcon(levelInfo)); + append(iconbox, vicon); + var vinfo = node("div", "v-info"); + append(vinfo, node("div", "v-name", levelInfo.name || group.name || "VIP" + level)); + append(vinfo, node("div", "v-desc em09", levelInfo.desc || "")); + append(iconbox, vinfo); + append(info, iconbox); + if (levelInfo.equity) { + var equity = document.createElement("ul"); + equity.className = "v-equity"; + equity.innerHTML = text(levelInfo.equity); + append(info, equity); } - append(levelHeader, node("div", "v-name font-bold", group.name || levelInfo.name || "VIP" + level)); - append(info, levelHeader); - if (levelInfo.desc) append(info, node("div", "muted-2-color em09 mb6", levelInfo.desc)); - renderEquity(info, levelInfo.equity); + var infoBa = node("div", "abs-center vip-baicon"); + append(infoBa, vipIcon(levelInfo)); + append(info, infoBa); append(row, info); + // 右侧:套餐盒 → 积分兑换链接 → more → 支付方式/卡密 → 立即支付。 var products = node("div", "pay-vip-products"); - renderProducts(products, group.items); + renderProducts(products, group.items, wallet.mark); + var points = catalog.points_exchange || {}; + if (allowed.points_exchange !== false && points.enabled && Array.isArray(points.packages) && points.packages.length && catalog.vip_url) { + var pointsLink = node("a", "but c-green btn-block mb10", "积分兑换会员"); + pointsLink.href = text(catalog.vip_url); + append(products, pointsLink); + } + if (catalog.more) append(products, node("div", "muted-2-color mb10 em09 muted-box padding-10 mini-radius", catalog.more)); renderMethods(products, methods, cardPass, wallet); var actionName = actionKey(action); var actionAllowed = allowed[actionName] === true; @@ -409,22 +487,14 @@ submit.setAttribute("data-vip-submit", ""); append(products, submit); append(row, products); - append(pane, row); + append(form, row); + append(pane, form); append(content, pane); }); append(modal, tabs); append(modal, content); if (catalog.help_text) append(modal, node("div", "muted-2-color em09 mb6", catalog.help_text)); - if (catalog.more) append(modal, node("div", "muted-2-color mb10 em09 muted-box padding-10 mini-radius", catalog.more)); - var points = catalog.points_exchange || {}; - if (allowed.points_exchange !== false && points.enabled && Array.isArray(points.packages) && points.packages.length && catalog.vip_url) { - var pointsWrap = node("div", "mt10"); - var pointsLink = node("a", "but c-green btn-block", "积分兑换会员"); - pointsLink.href = text(catalog.vip_url); - append(pointsWrap, pointsLink); - append(modal, pointsWrap); - } // 卡密渠道初始显隐(选中 card_pass 时隐藏套餐、显示卡密输入盒)。 modal.querySelectorAll(".aksrt-vip-pane").forEach(function (pane) { @@ -585,13 +655,13 @@ if (tab) { event.preventDefault(); var id = tab.getAttribute("data-vip-tab"); - root.querySelectorAll(".aksrt-vip-tab").forEach(function (item) { + root.querySelectorAll("[data-vip-tab]").forEach(function (item) { if (item.parentElement) item.parentElement.classList.toggle("active", item === tab); }); root.querySelectorAll(".aksrt-vip-pane").forEach(function (pane) { var active = pane.id === id; - pane.hidden = !active; pane.classList.toggle("active", active); + pane.classList.toggle("in", active); }); return; }