入口视觉强化: - 从 <a> 改为 <button>(点击先进说明弹窗,由弹窗确认后才跳转) - 内边距 p-4→py-5、图标 11→12、标题 15px→base/extrabold、箭头 8→9 - 增加呼吸光环动画 cdk-pulse(prefers-reduced-motion 下自动关闭) 跳转前说明弹窗(新增 showCdkBuyConfirm): 按用户要求提示完整流程—— 1. 在购买平台购买卡密,需填写并牢记「邮箱」与「查询密码」 2. 支付成功后,用同样的邮箱与查询密码在平台查询 CDK 3. 回到本站,在「兑换次数 / VIP」处粘贴 CDK 兑换 并提示购买平台为独立站点、兑换码勿泄露。 跳转方式:确认后在 DOM 中创建临时 <a target=_blank> 并 click(), 而非 window.open —— 手机浏览器会把程序化 window.open 当弹窗强制 当前页打开,原生链接行为更稳定。
This commit is contained in:
@@ -86,6 +86,24 @@ const vipExpireAt = ref('')
|
||||
// 「购买 CDK」入口(后台系统设置控制:跳转链接 + 是否展示;visible 且 url 非空才显示)
|
||||
const cdkBuyUrl = ref('')
|
||||
const cdkBuyVisible = ref(false)
|
||||
// 跳转购买平台前的说明弹窗:告知购买流程(需邮箱+查询密码,支付后回本站兑换)
|
||||
const showCdkBuyConfirm = ref(false)
|
||||
function onCdkBuyClick() {
|
||||
if (!cdkBuyUrl.value) return
|
||||
showCdkBuyConfirm.value = true
|
||||
}
|
||||
// 确认后在新标签打开购买平台。用真实 <a> 动态点击而非 window.open,
|
||||
// 避免手机浏览器把它当弹窗强制当前页打开。
|
||||
function confirmCdkBuy() {
|
||||
showCdkBuyConfirm.value = false
|
||||
const a = document.createElement('a')
|
||||
a.href = cdkBuyUrl.value
|
||||
a.target = '_blank'
|
||||
a.rel = 'noopener noreferrer'
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
a.remove()
|
||||
}
|
||||
// 验证码
|
||||
const captchaId = ref('')
|
||||
const captchaImage = ref('')
|
||||
@@ -444,28 +462,27 @@ async function handleRedeemInvite() {
|
||||
<!-- ======== 购买 CDK(显眼入口:后台系统设置控制显隐与链接) ========
|
||||
用真实 <a target=_blank> 而非 window.open:手机浏览器会把程序化 window.open
|
||||
当弹窗强制当前页打开,原生链接才能稳定新 tab(微信 WebView 等无 tab 环境除外) -->
|
||||
<a
|
||||
<button
|
||||
v-if="cdkBuyVisible"
|
||||
:href="cdkBuyUrl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="cdk-buy-btn press relative w-full overflow-hidden rounded-2xl p-4 flex items-center gap-3 rise-in"
|
||||
type="button"
|
||||
class="cdk-buy-btn press relative w-full overflow-hidden rounded-2xl px-4 py-5 flex items-center gap-3 rise-in"
|
||||
style="animation-delay: 80ms"
|
||||
@click="onCdkBuyClick"
|
||||
>
|
||||
<div class="relative z-10 w-11 h-11 rounded-2xl bg-white/20 ring-1 ring-white/30 flex items-center justify-center flex-shrink-0">
|
||||
<ShoppingCart class="w-5 h-5 text-white" :stroke-width="2.4" />
|
||||
<div class="relative z-10 w-12 h-12 rounded-2xl bg-white/20 ring-1 ring-white/30 flex items-center justify-center flex-shrink-0">
|
||||
<ShoppingCart class="w-6 h-6 text-white" :stroke-width="2.4" />
|
||||
</div>
|
||||
<div class="relative z-10 min-w-0 flex-1">
|
||||
<p class="text-[15px] font-bold text-white leading-tight tracking-tight">购买 CDK 兑换码</p>
|
||||
<p class="text-xs text-white/85 mt-1">次数卡 · VIP 卡 · 即买即兑</p>
|
||||
<div class="relative z-10 min-w-0 flex-1 text-left">
|
||||
<p class="text-base font-extrabold text-white leading-tight tracking-tight">购买 CDK 兑换码</p>
|
||||
<p class="text-xs text-white/90 mt-1">次数卡 · VIP 卡 · 即买即兑</p>
|
||||
</div>
|
||||
<span class="cdk-buy-hot relative z-10 flex-shrink-0 flex items-center gap-0.5 px-2 py-1 rounded-full text-[10px] font-extrabold tracking-wide">
|
||||
<Flame class="w-3 h-3" :stroke-width="2.5" />HOT
|
||||
</span>
|
||||
<span class="relative z-10 flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center">
|
||||
<ChevronRight class="w-[18px] h-[18px] text-white" :stroke-width="2.5" />
|
||||
<span class="relative z-10 flex-shrink-0 w-9 h-9 rounded-full bg-white/20 flex items-center justify-center">
|
||||
<ChevronRight class="w-5 h-5 text-white" :stroke-width="2.5" />
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
|
||||
<!-- ======== 数据三宫格:可执行次数 / 邀请积分 / 已邀请 ======== -->
|
||||
<div class="grid grid-cols-3 gap-2.5 rise-in" style="animation-delay: 120ms">
|
||||
@@ -750,6 +767,67 @@ async function handleRedeemInvite() {
|
||||
</div>
|
||||
</AppDialog>
|
||||
|
||||
<!-- ======== 购买 CDK 前说明弹窗 ========
|
||||
用户点「购买 CDK 兑换码」后先看到购买/兑换全流程说明,
|
||||
确认后才跳转外部购买平台,避免用户不清楚要准备邮箱与查询密码 -->
|
||||
<AppDialog
|
||||
:open="showCdkBuyConfirm"
|
||||
variant="center"
|
||||
panel-class="w-[88%] sm:max-w-md"
|
||||
title="购买 CDK 兑换码"
|
||||
@update:open="(v: boolean) => { if (!v) showCdkBuyConfirm = false }"
|
||||
>
|
||||
<div class="p-5">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-11 h-11 rounded-2xl cdk-buy-icon flex items-center justify-center shrink-0">
|
||||
<ShoppingCart class="w-5 h-5 text-white" :stroke-width="2.4" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base font-semibold text-gray-900">即将跳转 CDK 购买平台</h3>
|
||||
<p class="text-xs text-gray-400 mt-0.5">购买完成后请回到本站兑换</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-gray-50 p-4 space-y-3">
|
||||
<div class="flex gap-2.5">
|
||||
<span class="cdk-step-no">1</span>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-gray-800">在购买平台购买卡密</p>
|
||||
<p class="text-xs text-gray-500 mt-0.5">购买平台需要填写<strong class="text-gray-700">邮箱</strong>和<strong class="text-gray-700">查询密码</strong>,请牢记这两项</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2.5">
|
||||
<span class="cdk-step-no">2</span>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-gray-800">支付成功后查询卡密</p>
|
||||
<p class="text-xs text-gray-500 mt-0.5">在购买平台输入<strong class="text-gray-700">邮箱</strong>和<strong class="text-gray-700">查询密码</strong>查询你拿到的 CDK</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2.5">
|
||||
<span class="cdk-step-no">3</span>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-gray-800">回到本站兑换</p>
|
||||
<p class="text-xs text-gray-500 mt-0.5">在下方「兑换次数 / VIP」处粘贴 CDK 完成兑换</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-start gap-1.5 text-xs text-amber-600 bg-amber-50 rounded-lg p-2.5">
|
||||
<TriangleAlert class="w-3.5 h-3.5 mt-0.5 shrink-0" />
|
||||
<span>购买平台为独立站点,兑换码请勿泄露给他人</span>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-5">
|
||||
<Button variant="outline" class="flex-1 h-10 text-sm" @click="showCdkBuyConfirm = false">
|
||||
取消
|
||||
</Button>
|
||||
<Button class="flex-1 h-10 text-sm font-medium" @click="confirmCdkBuy">
|
||||
前往购买平台
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</AppDialog>
|
||||
|
||||
<!-- 随机绑定设备码:连续两次风险确认弹窗 -->
|
||||
<AppDialog
|
||||
:open="randBindStep > 0"
|
||||
@@ -904,7 +982,16 @@ async function handleRedeemInvite() {
|
||||
.cdk-buy-btn {
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #ff9a3d 0%, #ff5d5d 55%, #f43f5e 100%);
|
||||
box-shadow: 0 8px 20px -6px rgb(244 63 94 / 0.45);
|
||||
box-shadow: 0 10px 26px -6px rgb(244 63 94 / 0.55), 0 0 0 1px rgb(255 255 255 / 0.18) inset;
|
||||
animation: cdk-pulse 2.4s ease-in-out infinite;
|
||||
}
|
||||
/* 呼吸光环:让入口在列表中更醒目 */
|
||||
@keyframes cdk-pulse {
|
||||
0%, 100% { box-shadow: 0 10px 26px -6px rgb(244 63 94 / 0.55), 0 0 0 0 rgb(244 63 94 / 0.45); }
|
||||
50% { box-shadow: 0 10px 26px -6px rgb(244 63 94 / 0.55), 0 0 0 6px rgb(244 63 94 / 0); }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.cdk-buy-btn { animation: none; }
|
||||
}
|
||||
.cdk-buy-btn::after {
|
||||
content: '';
|
||||
@@ -924,6 +1011,28 @@ async function handleRedeemInvite() {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 弹窗内的购买图标底色(与入口按钮同色系) */
|
||||
.cdk-buy-icon {
|
||||
background: linear-gradient(135deg, #ff9a3d 0%, #ff5d5d 55%, #f43f5e 100%);
|
||||
box-shadow: 0 6px 16px -6px rgb(244 63 94 / 0.5);
|
||||
}
|
||||
|
||||
/* 弹窗内的步骤序号 */
|
||||
.cdk-step-no {
|
||||
flex-shrink: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 9999px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #ff9a3d 0%, #ff5d5d 100%);
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
/* HOT 角标:白底珊瑚红字(固定色,在渐变底上高对比) */
|
||||
.cdk-buy-hot {
|
||||
color: #e11d48;
|
||||
|
||||
Reference in New Issue
Block a user