fix(frontend): 卡密兑换通知接入全局 notyf Toast 固定 id 流
- credits.js initCardPass 从 setTip 内联提示迁移为固定 id 三态 notyf 流 (aksrt-card-pass-toast:load → success/danger 原位更新), 成功后延迟 800ms 刷新以保证成功 Toast 可见,对齐其余资产操作。 - credits-wallet.php 删除 data-aksrt-card-tip 死元素;credits.css 删除 .uc-card-pass__tip 死样式。 - 契约:toast-contract 将卡密兑换纳入固定 id 流清单并禁止 tip 回潮; card-pass-universal-redeem 新增 Toast 流断言(27/27 通过)。 - 验证:容器内真实抓取 /user/balance/ 确认弹窗正常渲染且无 tip 残留。
This commit is contained in:
@@ -849,13 +849,6 @@ body.uc-modal-open {
|
||||
justify-content: flex-end;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.uc-card-pass__tip {
|
||||
margin: 8px 0 0;
|
||||
font-size: 12px;
|
||||
color: #059669;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
.uc-card-pass__tip.is-error { color: #b91c1c; }
|
||||
|
||||
|
||||
|
||||
|
||||
+6
-13
@@ -286,16 +286,9 @@
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(roots, function (root) {
|
||||
var tip = root.querySelector('[data-aksrt-card-tip]');
|
||||
var busy = false;
|
||||
resetOperationKeyOnChange(root);
|
||||
|
||||
function setTip(text, isError) {
|
||||
if (!tip) return;
|
||||
tip.textContent = text || '';
|
||||
tip.classList.toggle('is-error', !!isError);
|
||||
}
|
||||
|
||||
var btn = root.querySelector('[data-aksrt-card-redeem]');
|
||||
if (!btn) return;
|
||||
|
||||
@@ -308,14 +301,14 @@
|
||||
var card = cardInput ? String(cardInput.value || '').trim() : '';
|
||||
// 卡号为选填:是否需要卡号由后端按卡密类型判定并返回错误提示。
|
||||
if (!password) {
|
||||
setTip('请输入卡密', true);
|
||||
notyf('请输入卡密', 'danger');
|
||||
if (pwInput) pwInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
busy = true;
|
||||
btn.disabled = true;
|
||||
setTip('正在兑换…');
|
||||
notyf('正在兑换…', 'load', '', 'aksrt-card-pass-toast');
|
||||
|
||||
var body = { password: password, type: type };
|
||||
if (card) body.card = card;
|
||||
@@ -328,7 +321,7 @@
|
||||
busy = false;
|
||||
btn.disabled = false;
|
||||
if (!r.ok || (r.json && r.json.code && !r.json.success)) {
|
||||
setTip((r.json && r.json.message) || '兑换失败', true);
|
||||
notyf((r.json && r.json.message) || '兑换失败', 'danger', 5, 'aksrt-card-pass-toast');
|
||||
return;
|
||||
}
|
||||
var data = (r.json && r.json.data) ? r.json.data : r.json;
|
||||
@@ -338,12 +331,12 @@
|
||||
if (redeemedType === 'vip' && window.AksrtModalRuntime && typeof window.AksrtModalRuntime.invalidate === 'function') {
|
||||
window.AksrtModalRuntime.invalidate(['vip', 'orders']);
|
||||
}
|
||||
setTip((data && data.message) || '兑换成功,正在刷新…');
|
||||
window.location.reload();
|
||||
notyf((data && data.message) || '兑换成功,正在刷新…', 'success', 5, 'aksrt-card-pass-toast');
|
||||
window.setTimeout(function () { window.location.reload(); }, 800);
|
||||
}).catch(function () {
|
||||
busy = false;
|
||||
btn.disabled = false;
|
||||
setTip('网络错误,请重试', true);
|
||||
notyf('网络错误,请重试', 'danger', 5, 'aksrt-card-pass-toast');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,7 +125,6 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元');
|
||||
<?php esc_html_e('立即兑换', 'aksrt'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<p class="uc-card-pass__tip" data-aksrt-card-tip></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -69,9 +69,25 @@ test('前台唯一兑换入口:页内联块与死文件已删除,JS 不再
|
||||
assert.doesNotMatch(usersSchemaJs, /asset_points_card_/);
|
||||
assert.doesNotMatch(chargeCard, /asset_points_card_/);
|
||||
assert.doesNotMatch(chargeCard, /'pass_charge_desc'/);
|
||||
// 失去宿主的内联块样式不回潮(弹窗仍在用 __input/__btn/__tip 子元素样式)。
|
||||
// 失去宿主的内联块样式不回潮(弹窗仍在用 __input/__btn 子元素样式;
|
||||
// 通知走全局 notyf Toast,__tip 内联提示样式已随迁移删除)。
|
||||
assert.doesNotMatch(creditsCss, /^\.uc-card-pass\s*\{/m);
|
||||
assert.doesNotMatch(creditsCss, /uc-card-pass__title|uc-card-pass__desc|\.uc-assets-col > \.uc-card-pass/);
|
||||
assert.doesNotMatch(creditsCss, /uc-card-pass__title|uc-card-pass__desc|uc-card-pass__tip|\.uc-assets-col > \.uc-card-pass/);
|
||||
});
|
||||
|
||||
test('兑换通知走全局 notyf Toast 固定 id 流,无内联 tip 残留', () => {
|
||||
assert.match(creditsJs, /notyf\('正在兑换…', 'load', '', 'aksrt-card-pass-toast'\)/);
|
||||
assert.match(creditsJs, /notyf\([^;]+?'danger', 5, 'aksrt-card-pass-toast'\)/);
|
||||
assert.match(creditsJs, /notyf\([^;]+?'success', 5, 'aksrt-card-pass-toast'\)/);
|
||||
// 初始化函数内不得再有 setTip 与 tip 元素查询(initCardPass 段)。
|
||||
const from = creditsJs.indexOf('function initCardPass(');
|
||||
const to = creditsJs.indexOf('function initBalanceCharge(', from + 1);
|
||||
const slice = creditsJs.slice(from, to);
|
||||
assert.ok(from !== -1 && to !== -1);
|
||||
assert.doesNotMatch(slice, /setTip|data-aksrt-card-tip/);
|
||||
assert.doesNotMatch(wallet, /data-aksrt-card-tip/);
|
||||
// 成功后延迟刷新,保证成功 Toast 可见(与其余资产操作一致)。
|
||||
assert.match(slice, /notyf\([^;]+?'success', 5, 'aksrt-card-pass-toast'\);[\s\S]{0,120}window\.setTimeout\(function \(\) \{ window\.location\.reload\(\); \}, 800\)/);
|
||||
});
|
||||
|
||||
test('前端:VIP 缓存失效按后端识别类型', () => {
|
||||
|
||||
@@ -223,6 +223,7 @@ test('balance center actions use direct fixed-id notyf flows', () => {
|
||||
|
||||
const flows = [
|
||||
[signinController, 'aksrt-balance-signin-toast'],
|
||||
[section('initCardPass', 'initBalanceCharge'), 'aksrt-card-pass-toast'],
|
||||
[section('initBalanceCharge', 'initTransfer'), 'aksrt-balance-charge-toast'],
|
||||
[section('initTransfer', 'initPointsExchange'), 'aksrt-balance-transfer-toast'],
|
||||
[section('initPointsExchange', 'initWithdraw'), 'aksrt-balance-points-toast'],
|
||||
@@ -233,7 +234,7 @@ test('balance center actions use direct fixed-id notyf flows', () => {
|
||||
assert.match(source, new RegExp("notyf\\([^;]+?'load'[^;]+?'" + id + "'\\);"));
|
||||
assert.match(source, new RegExp("notyf\\([^;]+?'danger'[^;]+?'" + id + "'\\);"));
|
||||
assert.match(source, new RegExp("notyf\\([^;]+?'success'[^;]+?'" + id + "'\\);"));
|
||||
assert.doesNotMatch(source, /setTip|data-(?:signin|aksrt-(?:charge|transfer|points-exchange|withdraw))-tip/);
|
||||
assert.doesNotMatch(source, /setTip|data-(?:signin|aksrt-(?:card|charge|transfer|points-exchange|withdraw))-tip/);
|
||||
});
|
||||
|
||||
assert.match(credits, /notyf\('等待支付结果…', 'load', '', 'aksrt-balance-charge-payment-toast'\)/);
|
||||
@@ -261,8 +262,8 @@ test('balance center actions use direct fixed-id notyf flows', () => {
|
||||
assert.match(context, /'signin_signed_today'\s*=>\s*\$signin_signed_today/);
|
||||
assert.match(shell, /\.uc-header__actions\s*\{[^}]*display:\s*flex;[^}]*gap:\s*6px;/s);
|
||||
assert.match(shell, /\.uc-header__message-btn\s*\{[^}]*position:\s*relative;/s);
|
||||
assert.doesNotMatch(renderers, /data-(?:signin|aksrt-(?:charge|transfer|points-exchange|withdraw))-tip/);
|
||||
assert.doesNotMatch(css, /\.uc-(?:modal|balance-card)__tip/);
|
||||
assert.doesNotMatch(renderers, /data-(?:signin|aksrt-(?:card|charge|transfer|points-exchange|withdraw))-tip/);
|
||||
assert.doesNotMatch(css, /\.uc-(?:card-pass|modal|balance-card)__tip/);
|
||||
});
|
||||
|
||||
test('VIP purchase and points exchange use direct fixed-id notyf flows', () => {
|
||||
|
||||
Reference in New Issue
Block a user