diff --git a/assets/css/routes/user-center/credits.css b/assets/css/routes/user-center/credits.css index 8f5cf45a..701b5325 100644 --- a/assets/css/routes/user-center/credits.css +++ b/assets/css/routes/user-center/credits.css @@ -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; } diff --git a/assets/js/credits.js b/assets/js/credits.js index 8e15442a..3f86bd4e 100644 --- a/assets/js/credits.js +++ b/assets/js/credits.js @@ -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'); }); }); }); diff --git a/inc/helpers/user-center-renderers/credits-wallet.php b/inc/helpers/user-center-renderers/credits-wallet.php index 125024e4..7c48543e 100644 --- a/inc/helpers/user-center-renderers/credits-wallet.php +++ b/inc/helpers/user-center-renderers/credits-wallet.php @@ -125,7 +125,6 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元'); -
diff --git a/tests/widget-system/card-pass-universal-redeem.test.cjs b/tests/widget-system/card-pass-universal-redeem.test.cjs index 28b0322d..c04617bd 100644 --- a/tests/widget-system/card-pass-universal-redeem.test.cjs +++ b/tests/widget-system/card-pass-universal-redeem.test.cjs @@ -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 缓存失效按后端识别类型', () => { diff --git a/tests/widget-system/toast-contract.test.cjs b/tests/widget-system/toast-contract.test.cjs index 01c348dc..c8572570 100644 --- a/tests/widget-system/toast-contract.test.cjs +++ b/tests/widget-system/toast-contract.test.cjs @@ -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', () => {