fix(revenue): match reference poster modal UI 1:1
The 推广海报 modal on the revenue page used a bespoke .uc-modal card — white panel, 12px radius, heavy shadow, title bar, corner × button and a full-width 保存海报 button — plus a light-gray plate with its own border-radius around the poster canvas. None of that exists in the reference theme, so the popup read as bordered and off-spec. Rebuild the modal on the reference poster-share structure: a borderless 360px .modal-dialog.poster-share centred by .modal.flex.jc, a .loading-mask overlay while the canvas renders, and the download/close buttons moved onto a .abs-center.hover-show-con layer that only fades in on hover. initAffiliatePoster() now drives Bootstrap 3 modal semantics (.in toggle, .modal-backdrop, body.modal-open, ESC and backdrop-click to close), mirroring the existing openChargeModal/closeChargeModal pair, and animates .modal-content from the 220px placeholder to the poster's real height before clearing the inline styles. No CSS added — every rule the reference modal needs was already ported. Drop the now-dead .uc-affiliate-poster rules; the shared .uc-modal shell and openModal/closeModal stay for the withdraw and transfer modals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a120f61e13
commit
de0e5cd481
4 files changed
+135
-30
No files matched your search
@@ -214,9 +214,3 @@
|
||||
.uc-content .uc-revenue-summary-row--explain { grid-template-columns: 1fr; }
|
||||
.uc-content .uc-revenue-summary-row--explain .uc-reward-richtext { grid-column: 1; }
|
||||
}
|
||||
|
||||
/* 推广海报预览弹窗:舞台居中,canvas 自适应弹窗宽度。 */
|
||||
.uc-content .uc-affiliate-poster { display: grid; place-items: center; min-height: 120px; }
|
||||
.uc-content .uc-affiliate-poster img,
|
||||
.uc-content .uc-affiliate-poster canvas { display: block; max-width: 100%; height: auto; margin: 0 auto; border-radius: 12px; background: var(--surface-2, #f7f8fa); }
|
||||
.uc-content .uc-affiliate-poster p { margin: 0; text-align: center; }
|
||||
+82
-12
@@ -150,19 +150,62 @@
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Referral poster (canvas preview modal: hero image + copy + QR + link) =====
|
||||
// ===== Referral poster =====
|
||||
// 弹窗形态 1:1 复刻参考主题 poster-share.js:Bootstrap 语义(.in 显隐 +
|
||||
// .modal-backdrop + body.modal-open + ESC),与下方充值弹窗同构,不复依赖
|
||||
// jQuery/Bootstrap 运行时。壳上带 .flex.jc,故打开态用 flex 而非 block。
|
||||
function initAffiliatePoster(root, url, poster, siteName) {
|
||||
var button = root.querySelector('[data-affiliate-poster]');
|
||||
var modal = document.querySelector('[data-aksrt-affiliate-poster-modal]');
|
||||
var stage = document.querySelector('[data-affiliate-poster-stage]');
|
||||
var download = document.querySelector('[data-affiliate-poster-download]');
|
||||
var stage = modal ? modal.querySelector('[data-affiliate-poster-stage]') : null;
|
||||
var loading = modal ? modal.querySelector('[data-affiliate-poster-loading]') : null;
|
||||
var content = modal ? modal.querySelector('.modal-content') : null;
|
||||
var download = modal ? modal.querySelector('[data-affiliate-poster-download]') : null;
|
||||
if (!button || !modal) return;
|
||||
if (!url || !poster || poster.enabled !== true) return;
|
||||
button.hidden = false;
|
||||
[].forEach.call(modal.querySelectorAll('[data-affiliate-poster-close]'), function (closer) {
|
||||
closer.addEventListener('click', function () { closeModal(modal); });
|
||||
});
|
||||
|
||||
var backdrop = null;
|
||||
var canvas = null;
|
||||
|
||||
function openPosterModal() {
|
||||
if (modal.classList.contains('in')) return;
|
||||
modal.style.display = 'flex';
|
||||
void modal.offsetWidth; // 强制 reflow,让 .fade 过渡从 scale(0.9) 起手
|
||||
modal.classList.add('in');
|
||||
modal.setAttribute('aria-hidden', 'false');
|
||||
if (!backdrop) {
|
||||
backdrop = document.createElement('div');
|
||||
backdrop.className = 'modal-backdrop fade in';
|
||||
backdrop.setAttribute('data-affiliate-poster-backdrop', '1');
|
||||
document.body.appendChild(backdrop);
|
||||
}
|
||||
document.body.classList.add('modal-open');
|
||||
}
|
||||
|
||||
function closePosterModal() {
|
||||
if (!modal.classList.contains('in')) return;
|
||||
modal.classList.remove('in');
|
||||
modal.setAttribute('aria-hidden', 'true');
|
||||
document.body.classList.remove('modal-open');
|
||||
if (backdrop && backdrop.parentNode) backdrop.parentNode.removeChild(backdrop);
|
||||
backdrop = null;
|
||||
// 等过渡结束再撤 display,复刻 Bootstrap 的 fade-out 收尾
|
||||
window.setTimeout(function () {
|
||||
if (!modal.classList.contains('in')) modal.style.display = '';
|
||||
}, 300);
|
||||
}
|
||||
|
||||
modal.addEventListener('click', function (event) {
|
||||
// 点遮罩层(.modal 自身)或关闭按钮(data-dismiss="modal")
|
||||
if (event.target === modal || (event.target.closest && event.target.closest('[data-dismiss="modal"]'))) {
|
||||
closePosterModal();
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Escape' && modal.classList.contains('in')) closePosterModal();
|
||||
});
|
||||
|
||||
if (download) {
|
||||
download.addEventListener('click', function () {
|
||||
if (!canvas) return;
|
||||
@@ -178,20 +221,47 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
button.addEventListener('click', function () {
|
||||
if (typeof window.qrcode !== 'function') {
|
||||
if (stage) { stage.innerHTML = '<p class="muted-2-color em09">' + '二维码组件未加载。' + '</p>'; }
|
||||
openModal(modal);
|
||||
openPosterModal();
|
||||
return;
|
||||
}
|
||||
if (stage) { stage.innerHTML = '<p class="muted-2-color em09">' + '正在生成海报…' + '</p>'; }
|
||||
if (download) download.hidden = true;
|
||||
openModal(modal);
|
||||
if (stage) { stage.innerHTML = ''; stage.classList.remove('loaded'); }
|
||||
if (loading) loading.style.display = '';
|
||||
if (download) download.classList.add('hide');
|
||||
openPosterModal();
|
||||
button.disabled = true;
|
||||
buildPosterCanvas(url, poster, siteName).then(function (built) {
|
||||
canvas = built;
|
||||
if (stage) { stage.innerHTML = ''; stage.appendChild(built); }
|
||||
if (download) download.hidden = false;
|
||||
if (!stage) return;
|
||||
// 参考主题:img.loaded-img 直接进 .poster-imgbox,遮罩淡出,
|
||||
// 内容块高度从 220px 过渡到海报实际高度后清掉内联样式。
|
||||
var img = document.createElement('img');
|
||||
img.src = canvas.toDataURL('image/png');
|
||||
img.alt = '推广海报';
|
||||
img.className = 'loaded-img';
|
||||
// 参考主题按 0.7 比例预设尺寸;.poster-imgbox > img 的 max-width:360px
|
||||
// 会在窄屏把它压回弹窗宽度,height:100% 让 offsetHeight 反映真实渲染高度。
|
||||
img.width = 768 * 0.7;
|
||||
img.height = 1168 * 0.7;
|
||||
stage.appendChild(img);
|
||||
stage.classList.add('loaded');
|
||||
if (download) {
|
||||
download.href = img.src;
|
||||
download.classList.remove('hide');
|
||||
}
|
||||
if (loading) loading.style.display = 'none';
|
||||
if (content) {
|
||||
content.style.height = stage.offsetHeight + 'px';
|
||||
content.style.transition = '.2s';
|
||||
window.setTimeout(function () {
|
||||
content.style.height = '';
|
||||
content.style.overflow = '';
|
||||
content.style.transition = '';
|
||||
}, 200);
|
||||
}
|
||||
}).catch(function () {
|
||||
if (stage) { stage.innerHTML = '<p class="muted-2-color em09">' + '海报生成失败,请重试。' + '</p>'; }
|
||||
}).finally(function () {
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
/**
|
||||
* Affiliate poster preview modal.
|
||||
*
|
||||
* The 推广海报 button lives in the revenue detail link row; the QR code is no
|
||||
* longer rendered on its own — it exists only inside the generated poster.
|
||||
* 1:1 replica of the reference theme's poster-share modal (zibll js/poster-share.js
|
||||
* + css/main.css `.poster-share` block): a borderless 360px Bootstrap-style dialog
|
||||
* centred by `.modal.flex.jc`, a `.loading-mask` overlay while the canvas renders,
|
||||
* and circular download/close buttons on a `.hover-show-con` layer that only fades
|
||||
* in on hover. The 推广海报 button lives in the revenue detail link row; the QR code
|
||||
* is no longer rendered on its own — it exists only inside the generated poster.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
@@ -15,14 +19,18 @@ if (!empty($GLOBALS['aksrt_affiliate_poster_modal_rendered'])) {
|
||||
}
|
||||
$GLOBALS['aksrt_affiliate_poster_modal_rendered'] = true;
|
||||
?>
|
||||
<div class="uc-modal" id="aksrt-affiliate-poster-modal" hidden data-aksrt-affiliate-poster-modal>
|
||||
<div class="uc-modal__overlay" data-affiliate-poster-close></div>
|
||||
<div class="uc-modal__dialog" role="dialog" aria-modal="true">
|
||||
<button type="button" class="uc-modal__close" data-affiliate-poster-close aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>"><i class="fa fas fa-times" aria-hidden="true"></i></button>
|
||||
<h3 class="uc-modal__title"><?php esc_html_e('推广海报', 'aksrt'); ?></h3>
|
||||
<div class="uc-affiliate-poster" data-affiliate-poster-stage>
|
||||
<p class="muted-2-color em09"><?php esc_html_e('正在生成海报…', 'aksrt'); ?></p>
|
||||
<div class="modal fade flex jc" id="aksrt-affiliate-poster-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog poster-share hover-show" role="document">
|
||||
<div class="modal-content" style="height:220px;overflow:hidden">
|
||||
<div class="poster-imgbox hover-show" data-affiliate-poster-stage></div>
|
||||
<div class="flex jc loading-mask absolute main-bg radius8" data-affiliate-poster-loading>
|
||||
<div class="loading zts fa-2x"></div>
|
||||
<div class="muted-2-color box-body"><?php esc_html_e('正在生成图片,请稍候...', 'aksrt'); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="padding-6 abs-center hover-show-con text-center" style="top:auto">
|
||||
<a href="javascript:;" class="but cir jb-blue poster-download hide" data-affiliate-poster-download aria-label="<?php esc_attr_e('保存海报', 'aksrt'); ?>"><i class="fas fa-download" aria-hidden="true"></i></a>
|
||||
<button type="button" data-dismiss="modal" class="but cir jb-yellow ml10" aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>"><svg aria-hidden="true" class="icon em12"><use xlink:href="#icon-close"></use></svg></button>
|
||||
</div>
|
||||
<button type="button" class="but jb-blue btn-block mt10" data-affiliate-poster-download hidden><?php esc_html_e('保存海报', 'aksrt'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,11 +47,19 @@ test('revenue detail card is a four-row info list with no standalone QR block',
|
||||
assert.doesNotMatch(script, /function renderAffiliateQr/)
|
||||
assert.doesNotMatch(script, /renderAffiliateQr\(/)
|
||||
assert.doesNotMatch(script, /data-affiliate-qr/)
|
||||
// 海报弹窗:舞台 + 保存按钮 + 复用 openModal/closeModal。
|
||||
// 海报弹窗:参考主题 poster-share 形态 —— Bootstrap 语义 + .poster-imgbox 舞台。
|
||||
assert.match(script, /data-affiliate-poster-stage/)
|
||||
assert.match(script, /data-affiliate-poster-download/)
|
||||
assert.match(script, /openModal\(modal\)/)
|
||||
assert.match(script, /modal-backdrop/)
|
||||
assert.match(script, /classList\.add\('in'\)/)
|
||||
assert.match(script, /poster-imgbox/)
|
||||
assert.match(script, /classList\.add\('hide'\)/)
|
||||
assert.match(script, /link\.download = 'referral-poster\.png'/)
|
||||
// 弹窗开关不再走 uc-modal 的 openModal/closeModal(那套留给提现/转账弹窗)。
|
||||
const posterInit = script.slice(script.indexOf('function initAffiliatePoster'), script.indexOf('function buildPosterCanvas'))
|
||||
assert.doesNotMatch(posterInit, /openModal\(modal\)/)
|
||||
assert.doesNotMatch(posterInit, /closeModal\(modal\)/)
|
||||
assert.doesNotMatch(posterInit, /data-affiliate-poster-close/)
|
||||
// 链接由 PHP 直出:复制按钮立即可用,REST 只负责海报配置与佣金比例。
|
||||
assert.match(script, /var url = input \? input\.value : '';/)
|
||||
assert.match(script, /if \(copy\) copy\.disabled = !url;/)
|
||||
@@ -93,6 +101,31 @@ test('poster canvas is built from admin-configured copy and gated on the poster
|
||||
assert.match(script, /image\.crossOrigin = 'anonymous'/)
|
||||
})
|
||||
|
||||
test('poster modal markup is a 1:1 replica of the reference poster-share dialog', () => {
|
||||
const modal = read('inc', 'helpers', 'user-center-renderers', 'affiliate-poster-modal.php')
|
||||
// 参考主题骨架:Bootstrap 模态壳 + 360px 无边框对话框 + hover 浮钮层。
|
||||
assert.match(modal, /class="modal fade flex jc"/)
|
||||
assert.match(modal, /class="modal-dialog poster-share hover-show"/)
|
||||
assert.match(modal, /class="modal-content" style="height:220px;overflow:hidden"/)
|
||||
assert.match(modal, /class="poster-imgbox hover-show" data-affiliate-poster-stage/)
|
||||
assert.match(modal, /class="flex jc loading-mask absolute main-bg radius8"/)
|
||||
assert.match(modal, /class="but cir jb-blue poster-download hide"/)
|
||||
assert.match(modal, /class="but cir jb-yellow ml10"/)
|
||||
assert.match(modal, /#icon-close/)
|
||||
assert.match(modal, /data-dismiss="modal"/)
|
||||
// 自研 uc-modal 卡片形态(白底 + 标题栏 + 整宽保存钮 + 浅灰画框)已退役。
|
||||
assert.doesNotMatch(modal, /uc-modal__dialog/)
|
||||
assert.doesNotMatch(modal, /uc-modal__title/)
|
||||
assert.doesNotMatch(modal, /uc-modal__close/)
|
||||
assert.doesNotMatch(modal, /uc-modal__overlay/)
|
||||
assert.doesNotMatch(modal, /uc-affiliate-poster/)
|
||||
assert.doesNotMatch(modal, /btn-block/)
|
||||
|
||||
// 配套的 .uc-affiliate-poster 画框规则已从样式表删除。
|
||||
const css = read('assets', 'css', 'routes', 'user-center', 'revenue-earnings.css')
|
||||
assert.doesNotMatch(css, /uc-affiliate-poster/)
|
||||
})
|
||||
|
||||
test('invite-code input verifies live against the public REST endpoint', () => {
|
||||
const template = read('templates', 'parts', 'auth-content.php')
|
||||
assert.match(template, /data-invite-verify/)
|
||||
|
||||
Reference in new issue
Block a user