feat(ui): 优化苹果卡支付页面及交互体验
- 新增苹果卡支付页面,采用更接近Apple风格的UI设计 - 引入TailwindCSS和GSAP动画库,实现流畅动画效果 - 设计渐变主色调,优化输入框和按钮样式 - 实现模态框(警告与详情)的显示与关闭动画 - 支持复制卡片标题功能,兼容多种复制方案并提供用户提示 - 添加跳转京东/淘宝购买按钮及其交互逻辑 - 实现智能粘贴识别,可从文本自动提取卡号和卡密 - 优化提交按钮交互,添加输入校验及请求状态反馈 - 支持移动端响应式布局和交互适配 - 隐藏滚动条,增强页面视觉美感和一致性
This commit is contained in:
BIN
static/img/apple/apple-banner.jpg
Normal file
BIN
static/img/apple/apple-banner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
924
views/index-apple-v2.html
Normal file
924
views/index-apple-v2.html
Normal file
@@ -0,0 +1,924 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>苹果卡 - 安全支付</title>
|
||||
|
||||
<!-- 引入TailwindCSS -->
|
||||
<script src="../static/js/tailwindcss.js"></script>
|
||||
|
||||
<!-- 引入GSAP动画库 -->
|
||||
<script src="../static/js/gsap.min.js"></script>
|
||||
<link rel="stylesheet" href="../static/css/index-anxin.css">
|
||||
<style>
|
||||
/* 引入更接近 Apple 风格的字体 */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
:root {
|
||||
/* 定义渐变主色调 */
|
||||
--primary-gradient: linear-gradient(135deg, #0077ed 0%, #0056b3 100%);
|
||||
--primary-color-start: #0077ed;
|
||||
/* 渐变起始色,用于 focus 等 */
|
||||
--primary-color-end: #0056b3;
|
||||
/* 渐变结束色 */
|
||||
--secondary-color: #f5f5f7;
|
||||
/* Apple Light Gray */
|
||||
--text-color: #1d1d1f;
|
||||
/* Apple Dark Gray */
|
||||
--accent-color: #ff375f;
|
||||
/* Apple Pink/Red Accent */
|
||||
--border-color: #d2d2d7;
|
||||
--bs-orange: #ff4d00;
|
||||
--bs-blue: #0364cb;
|
||||
--bs-green: #049325;
|
||||
--bs-red: #bb091b;
|
||||
--bs-yellow: #b48c13;
|
||||
--bs-purple: #4c1ea2;
|
||||
--bs-pink: #b91461;
|
||||
--bs-gray: #515d67;
|
||||
--bs-info: #0168cf;
|
||||
/* Apple Border Gray */
|
||||
--glow-color-start: rgba(0, 113, 227, 0.1);
|
||||
/* 弥散光起始颜色 */
|
||||
--glow-color-end: rgba(245, 245, 247, 0);
|
||||
/* 弥散光结束颜色 (透明) */
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
/* 添加弥散光背景 */
|
||||
background: radial-gradient(circle at top center, var(--glow-color-start) 0%, var(--glow-color-end) 60%), var(--secondary-color);
|
||||
color: var(--text-color);
|
||||
min-height: 100vh;
|
||||
overflow: auto;
|
||||
/* 允许滚动 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 模态框激活时禁止主页面滚动 */
|
||||
body.modal-active {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 主要容器 */
|
||||
.main-container {
|
||||
max-width: 420px;
|
||||
margin: 0 auto;
|
||||
padding: 1.5rem 1rem;
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* 输入框基础样式 */
|
||||
.card-input,
|
||||
.paste-area {
|
||||
transition: all 0.2s ease-in-out;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: #ffffff;
|
||||
border-radius: 0.75rem;
|
||||
padding: 0.8rem 1rem;
|
||||
font-size: 1rem;
|
||||
width: 100%;
|
||||
appearance: none;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.paste-area {
|
||||
min-height: 120px;
|
||||
resize: none;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.card-input:focus,
|
||||
.paste-area:focus {
|
||||
/* 使用渐变起始色作为 focus 颜色 */
|
||||
border-color: var(--primary-color-start);
|
||||
box-shadow: 0 0 0 3px rgba(0, 119, 237, 0.25);
|
||||
/* 调整 focus 阴影颜色 */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* 主要按钮样式 - 应用渐变 */
|
||||
.btn-primary {
|
||||
background-image: var(--primary-gradient);
|
||||
/* 应用渐变 */
|
||||
background-color: var(--primary-color-start);
|
||||
/* Fallback color */
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
padding: 0.9rem 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
transition: all 0.2s ease-in-out;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
box-shadow: 0 2px 4px rgba(0, 113, 227, 0.2);
|
||||
border: none;
|
||||
/* 移除可能存在的边框 */
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
/* 悬停时可以稍微调整渐变或增加阴影 */
|
||||
filter: brightness(1.1);
|
||||
/* 简单提亮效果 */
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 113, 227, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
filter: brightness(0.95);
|
||||
/* 按下时稍微变暗 */
|
||||
transform: translateY(0px);
|
||||
box-shadow: 0 1px 2px rgba(0, 113, 227, 0.2);
|
||||
}
|
||||
|
||||
/* 粘贴按钮样式 */
|
||||
.btn-paste {
|
||||
color: var(--primary-color-start);
|
||||
/* 使用渐变起始色 */
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.5rem;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-paste:hover {
|
||||
color: var(--primary-color-end);
|
||||
/* 悬停时使用渐变结束色 */
|
||||
}
|
||||
|
||||
/* 模态框样式 - 增强 Glassmorphism */
|
||||
.modal {
|
||||
/* 背景稍微调暗,模糊更明显 */
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
backdrop-filter: blur(12px) saturate(150%);
|
||||
/* 增加模糊度和饱和度 */
|
||||
-webkit-backdrop-filter: blur(12px) saturate(150%);
|
||||
/* Safari 兼容 */
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
/* 增加透明度,添加微妙边框 */
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
/* 更透明的背景 */
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
/* 浅色边框增加轮廓感 */
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
/* 阴影稍微加重 */
|
||||
max-width: 90%;
|
||||
width: 350px;
|
||||
overflow: hidden;
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
transition: transform 0.3s ease-out, opacity 0.3s ease-out;
|
||||
}
|
||||
|
||||
.modal.active .modal-content {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 动画类 */
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-up {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
/* 移除倒计时条样式 */
|
||||
/* .timer-container, .timer-bar { ... } */
|
||||
|
||||
/* 隐藏滚动条 */
|
||||
body::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
/* 移动端优化样式 */
|
||||
@media (max-width: 480px) {
|
||||
body {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
padding: 1rem 0.75rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* 模态框移动端优化 - 允许完整展示 */
|
||||
.modal {
|
||||
/* 移除固定定位限制 */
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* 允许页面滚动 */
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
max-width: 95%;
|
||||
width: 360px;
|
||||
margin: 1rem auto;
|
||||
/* 移除高度限制和内部滚动 */
|
||||
max-height: none;
|
||||
overflow-y: visible;
|
||||
/* 最小高度确保内容完整显示 */
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
#detailsModal .modal-content {
|
||||
width: 350px;
|
||||
max-width: 98%;
|
||||
padding: 1.5rem 1rem;
|
||||
margin: 4rem auto;
|
||||
max-height: none;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
/* 标题字体大小调整 */
|
||||
h1 {
|
||||
font-size: 2.5rem !important;
|
||||
}
|
||||
|
||||
.text-5xl {
|
||||
font-size: 3rem !important;
|
||||
}
|
||||
|
||||
/* 按钮移动端优化 */
|
||||
.btn-primary {
|
||||
padding: 1rem 1.25rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* 输入框移动端优化 */
|
||||
.card-input, .paste-area {
|
||||
font-size: 16px; /* 防止iOS缩放 */
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* 详情模态框内容移动端优化 */
|
||||
#detailsModal h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
#detailsModal .text-sm {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
#detailsModal img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* 按钮间距优化 */
|
||||
#detailsModal button {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 小屏幕手机优化 */
|
||||
@media (max-width: 375px) {
|
||||
.main-container {
|
||||
padding: 0.75rem 0.5rem;
|
||||
}
|
||||
|
||||
#detailsModal .modal-content {
|
||||
width: 320px;
|
||||
padding: 1rem;
|
||||
margin: 3rem auto;
|
||||
max-height: none;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
#detailsModal h2 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
#detailsModal img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
/* 超小屏幕优化 */
|
||||
@media (max-width: 320px) {
|
||||
#detailsModal .modal-content {
|
||||
width: 300px;
|
||||
padding: 0.75rem;
|
||||
margin: 2.5rem auto;
|
||||
max-height: none;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
#detailsModal h2 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
#detailsModal img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="flex flex-col">
|
||||
<!-- 警告模态框 -->
|
||||
<div id="warningModal"
|
||||
class="modal fixed inset-0 z-50 flex items-center justify-center opacity-0 pointer-events-none">
|
||||
<div class="modal-content p-6">
|
||||
<div class="flex flex-col items-center text-center">
|
||||
<svg class="w-12 h-12 text-yellow-500 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z">
|
||||
</path>
|
||||
</svg>
|
||||
<h3 class="text-xl font-semibold mb-2">安全提示</h3>
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
此卡为:苹果卡<br>
|
||||
请放心提交,此卡保真<br>不会偷卡,秒到账,支持录屏提交!
|
||||
<!-- <span class="font-semibold text-red-600">请注意:凡是溢价和不包邮的店铺卖的都是假卡!!!</span>-->
|
||||
</p>
|
||||
<button id="closeModal"
|
||||
class="bg-blue-500 text-white px-5 py-2 rounded-lg text-sm font-medium hover:bg-blue-600 transition-colors">
|
||||
我知道了
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 跳转详情模态框 -->
|
||||
<div id="detailsModal"
|
||||
class="modal fixed inset-0 z-50 flex items-center justify-center opacity-0 pointer-events-none">
|
||||
<div class="modal-content p-6" style="max-width: 95%; width: 380px;">
|
||||
<div class="flex flex-col text-center">
|
||||
<!-- 标题区域 - 水平布局 -->
|
||||
<div class="flex items-center justify-between gap-4 mb-6 pb-4 border-b border-gray-200">
|
||||
<div class="flex-1">
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-1">苹果卡 {{.mmValue}}</h2>
|
||||
<p class="text-xs text-gray-500">面值:{{.mmValue}}元</p>
|
||||
</div>
|
||||
<button id="copyTitleBtn"
|
||||
class="inline-flex items-center gap-2 px-3 py-2 bg-blue-500 text-white rounded-lg text-sm font-medium hover:bg-blue-600 transition-all duration-200 flex-shrink-0">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
<span id="copyBtnText">复制</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 操作说明 -->
|
||||
<div class="mb-6">
|
||||
<div class="text-left bg-gray-50 rounded-lg p-4 space-y-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="bg-blue-500 text-white rounded-full w-5 h-5 flex items-center justify-center flex-shrink-0 mt-0.5 text-xs font-bold">1</div>
|
||||
<p class="text-sm text-gray-700 leading-relaxed">请手动打开<span class="text-red-500 font-semibold">淘宝</span>或者<span class="text-red-500 font-semibold">京东</span>APP</p>
|
||||
</div>
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="bg-green-500 text-white rounded-full w-5 h-5 flex items-center justify-center flex-shrink-0 mt-0.5 text-xs font-bold">2</div>
|
||||
<p class="text-sm text-gray-700 leading-relaxed">搜索<span class="text-red-500 font-semibold">"苹果卡{{.mmValue}}元"</span>金额卡密点击购买</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 关闭按钮 -->
|
||||
<div class="mb-4">
|
||||
<button id="closeDetailsModalBtn"
|
||||
class="w-full px-6 py-3 bg-gray-500 text-white rounded-lg font-medium hover:bg-gray-600 transition-all duration-200 shadow-sm hover:shadow-md">
|
||||
购买后点击返回
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 示例图片 -->
|
||||
<div class="mb-6">
|
||||
<div class="w-full rounded-lg shadow-md border border-gray-200 bg-gray-100 overflow-hidden">
|
||||
<img src="../static/img/apple/apple-banner.jpg"
|
||||
alt="购买指南示例图"
|
||||
class="w-full h-auto object-contain"
|
||||
onerror="this.style.display='none'; this.parentElement.innerHTML='<div class=\\'flex flex-col items-center justify-center h-full text-center p-8\\'><svg class=\\'w-16 h-16 mx-auto text-gray-400 mb-2\\' fill=\\'none\\' stroke=\\'currentColor\\' viewBox=\\'0 0 24 24\\' xmlns=\\'http://www.w3.org/2000/svg\\'><path stroke-linecap=\\'round\\' stroke-linejoin=\\'round\\' stroke-width=\\'2\\' d=\\'M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\\'></path></svg><p class=\\'text-sm text-gray-500\\'>购买示例图片</p></div>';">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部信任标识 -->
|
||||
<div class="mt-4">
|
||||
<p class="text-xs text-gray-400 text-center">
|
||||
安全购物 · 正品保障 · 秒到账
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="main-container">
|
||||
<!-- 页面标题和价格 -->
|
||||
<header class="text-center mb-8 fade-in"> <!-- 增加底部边距 -->
|
||||
<h1 class="text-4xl font-bold mb-1">苹果卡</h1>
|
||||
<p class="text-2xl font-semibold text-gray-700">¥ <span
|
||||
class="text-5xl font-bold text-black">{{.mmValue}}</span></p>
|
||||
</header>
|
||||
|
||||
<!-- 添加淘宝跳转按钮 -->
|
||||
<div class="mb-6 slide-up" style="animation-delay: 0.35s;">
|
||||
<button id="shopLinkBtn" type="button"
|
||||
class="flex items-center justify-center gap-2 w-full py-3 px-4 bg-white border border-gray-200 rounded-xl shadow-sm hover:shadow-md transition-all duration-200 cursor-pointer"
|
||||
style="background-color:var(--bs-info)">
|
||||
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15l-5-5 1.41-1.41L11 14.17l7.59-7.59L20 8l-9 9z"
|
||||
fill="#ffffff"/>
|
||||
</svg>
|
||||
<span class="text-white font-medium">点击跳转京东/淘宝购买</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- <!– 智能粘贴区域 - 调整动画延迟 –>-->
|
||||
<!-- <section class="mb-6 slide-up" style="animation-delay: 0.1s;"> <!– 原延迟 0.2s –>-->
|
||||
<!-- <label for="pasteArea" class="block text-lg font-semibold text-gray-800 mb-2"></label>-->
|
||||
<!-- <textarea id="pasteArea" class="paste-area"-->
|
||||
<!-- placeholder="请将包含卡号和卡密的内容粘贴到此处,系统将尝试自动识别。"></textarea>-->
|
||||
<!-- </section>-->
|
||||
|
||||
<!-- 卡号和卡密输入表单 - 调整动画延迟 -->
|
||||
<section class="mb-6 slide-up" style="animation-delay: 0.2s;"> <!-- 原延迟 0.3s -->
|
||||
<!-- <h2 class="text-lg font-semibold mb-3">核对充值信息</h2>-->
|
||||
<div class="space-y-4">
|
||||
<!-- <div>-->
|
||||
<!-- <label for="cardNumber" class="block text-sm font-medium text-gray-700 mb-1">卡号</label>-->
|
||||
<!-- <div class="relative flex items-center">-->
|
||||
<!-- <input type="text" id="cardNumber" class="card-input pr-16" placeholder="请输入或粘贴卡号">-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div>
|
||||
<label for="cardPassword" class="block text-sm font-medium text-gray-700 mb-1">卡密</label>
|
||||
<div class="relative flex items-center">
|
||||
<input type="text" id="cardPassword" class="card-input pr-16" placeholder="请输入或粘贴卡密">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 提交按钮 - 调整动画延迟 -->
|
||||
<div class="mb-6 slide-up" style="animation-delay: 0.3s;"> <!-- 原延迟 0.4s -->
|
||||
<button id="submitBtn" class="btn-primary">确认信息并提交</button>
|
||||
</div>
|
||||
|
||||
<!-- 操作注意事项 - 调整动画延迟 -->
|
||||
<section class="text-xs text-gray-500 slide-up" style="animation-delay: 0.4s;"> <!-- 原延迟 0.5s -->
|
||||
<h3 class="font-semibold mb-2 text-sm">操作注意:</h3>
|
||||
<ul class="list-disc list-outside space-y-1 pl-4">
|
||||
<li>此卡为:苹果卡</li>
|
||||
<li>请放心提交,此卡保真,不会偷卡,秒到账,支持录屏提交!</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 底部版权信息 -->
|
||||
<footer class="text-center py-3 text-xs text-gray-400 fade-in">
|
||||
© 2025
|
||||
</footer>
|
||||
<script type="text/javascript" src="../static/js/jquery.min.js"></script>
|
||||
<script>
|
||||
function openExternalLink(link) {
|
||||
window.open(link, "_self");
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// ... existing code ...
|
||||
|
||||
// --- 模态框逻辑 ---
|
||||
const modal = document.getElementById('warningModal');
|
||||
const detailsModal = document.getElementById('detailsModal');
|
||||
const closeModalBtn = document.getElementById('closeModal');
|
||||
const modalContent = modal.querySelector('.modal-content');
|
||||
const detailsModalContent = detailsModal.querySelector('.modal-content');
|
||||
|
||||
/**
|
||||
* @function showModal
|
||||
* @description 显示模态框并应用动画
|
||||
*/
|
||||
function showModal() {
|
||||
modal.classList.remove('opacity-0', 'pointer-events-none');
|
||||
modal.classList.add('active');
|
||||
gsap.to(modal, {opacity: 1, duration: 0.3});
|
||||
gsap.to(modalContent, {scale: 1, opacity: 1, duration: 0.3, ease: 'back.out(1.7)'});
|
||||
}
|
||||
|
||||
/**
|
||||
* @function closeModal
|
||||
* @description 关闭模态框并应用动画
|
||||
*/
|
||||
function closeModal() {
|
||||
gsap.to(modalContent, {scale: 0.95, opacity: 0, duration: 0.2, ease: 'power1.in'});
|
||||
gsap.to(modal, {
|
||||
opacity: 0,
|
||||
duration: 0.3,
|
||||
delay: 0.1,
|
||||
onComplete: () => {
|
||||
modal.classList.add('opacity-0', 'pointer-events-none');
|
||||
modal.classList.remove('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 页面加载后显示模态框
|
||||
showModal();
|
||||
|
||||
// 点击关闭按钮关闭
|
||||
closeModalBtn.addEventListener('click', closeModal);
|
||||
|
||||
// 点击模态框背景关闭
|
||||
modal.addEventListener('click', function (e) {
|
||||
if (e.target === modal) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// --- 详情模态框逻辑 ---
|
||||
const copyTitleBtn = document.getElementById('copyTitleBtn');
|
||||
const copyBtnText = document.getElementById('copyBtnText');
|
||||
const closeDetailsModalBtn = document.getElementById('closeDetailsModalBtn');
|
||||
|
||||
/**
|
||||
* @function showDetailsModal
|
||||
* @description 显示详情模态框并应用动画
|
||||
*/
|
||||
function showDetailsModal() {
|
||||
console.log('显示详情模态框'); // 调试信息
|
||||
detailsModal.classList.remove('opacity-0', 'pointer-events-none');
|
||||
detailsModal.classList.add('active');
|
||||
|
||||
// 移动端:禁止主页面滚动,允许模态框滚动
|
||||
if (window.innerWidth <= 480) {
|
||||
document.body.classList.add('modal-active');
|
||||
}
|
||||
|
||||
gsap.to(detailsModal, {opacity: 1, duration: 0.3});
|
||||
gsap.to(detailsModalContent, {scale: 1, opacity: 1, duration: 0.3, ease: 'back.out(1.7)'});
|
||||
}
|
||||
|
||||
/**
|
||||
* @function closeDetailsModal
|
||||
* @description 关闭详情模态框并应用动画
|
||||
*/
|
||||
function closeDetailsModal() {
|
||||
gsap.to(detailsModalContent, {scale: 0.95, opacity: 0, duration: 0.2, ease: 'power1.in'});
|
||||
gsap.to(detailsModal, {
|
||||
opacity: 0,
|
||||
duration: 0.3,
|
||||
delay: 0.1,
|
||||
onComplete: () => {
|
||||
detailsModal.classList.add('opacity-0', 'pointer-events-none');
|
||||
detailsModal.classList.remove('active');
|
||||
// 恢复主页面滚动
|
||||
document.body.classList.remove('modal-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 复制标题功能
|
||||
copyTitleBtn.addEventListener('click', async function () {
|
||||
const title = '苹果卡 {{.mmValue}}';
|
||||
|
||||
// 按钮动画反馈
|
||||
gsap.to(this, {scale: 0.95, duration: 0.1, yoyo: true, repeat: 1});
|
||||
|
||||
// 更新按钮文本
|
||||
const originalText = copyBtnText.textContent;
|
||||
|
||||
// 尝试多种复制方法
|
||||
let copySuccess = false;
|
||||
|
||||
try {
|
||||
// 方法1: 现代clipboard API (HTTPS站点)
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(title);
|
||||
copySuccess = true;
|
||||
} else {
|
||||
throw new Error('Clipboard API not available');
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('现代clipboard API失败,尝试降级方案:', err);
|
||||
|
||||
// 方法2: 传统复制方法 (兼容HTTP站点)
|
||||
try {
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = title;
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.left = '-999999px';
|
||||
textArea.style.top = '-999999px';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
// 尝试执行复制命令
|
||||
const successful = document.execCommand('copy');
|
||||
document.body.removeChild(textArea);
|
||||
|
||||
if (successful) {
|
||||
copySuccess = true;
|
||||
} else {
|
||||
throw new Error('execCommand failed');
|
||||
}
|
||||
} catch (fallbackErr) {
|
||||
console.error('降级复制方案也失败:', fallbackErr);
|
||||
|
||||
// 方法3: 手动选择提示
|
||||
copyTitleBtn.addEventListener('click', function manualSelect() {
|
||||
// 移除事件监听器,避免重复绑定
|
||||
copyTitleBtn.removeEventListener('click', manualSelect);
|
||||
|
||||
// 创建临时显示区域让用户手动复制
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.textContent = title;
|
||||
tempDiv.style.position = 'fixed';
|
||||
tempDiv.style.top = '50%';
|
||||
tempDiv.style.left = '50%';
|
||||
tempDiv.style.transform = 'translate(-50%, -50%)';
|
||||
tempDiv.style.background = 'white';
|
||||
tempDiv.style.padding = '15px 20px';
|
||||
tempDiv.style.borderRadius = '8px';
|
||||
tempDiv.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
|
||||
tempDiv.style.zIndex = '10000';
|
||||
tempDiv.style.fontSize = '16px';
|
||||
tempDiv.style.fontWeight = 'bold';
|
||||
tempDiv.style.cursor = 'pointer';
|
||||
tempDiv.style.userSelect = 'all';
|
||||
tempDiv.style.webkitUserSelect = 'all';
|
||||
tempDiv.style.mozUserSelect = 'all';
|
||||
tempDiv.style.msUserSelect = 'all';
|
||||
|
||||
const instruction = document.createElement('div');
|
||||
instruction.textContent = '请手动复制上方文字';
|
||||
instruction.style.fontSize = '12px';
|
||||
instruction.style.color = '#666';
|
||||
instruction.style.marginTop = '8px';
|
||||
instruction.style.fontWeight = 'normal';
|
||||
tempDiv.appendChild(instruction);
|
||||
|
||||
document.body.appendChild(tempDiv);
|
||||
|
||||
// 自动选择文本
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(tempDiv);
|
||||
const selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
// 点击关闭
|
||||
tempDiv.addEventListener('click', function() {
|
||||
document.body.removeChild(tempDiv);
|
||||
});
|
||||
|
||||
// 3秒后自动关闭
|
||||
setTimeout(() => {
|
||||
if (document.body.contains(tempDiv)) {
|
||||
document.body.removeChild(tempDiv);
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
alert('请手动复制:苹果卡 {{.mmValue}}');
|
||||
}
|
||||
}
|
||||
|
||||
// 更新UI状态
|
||||
if (copySuccess) {
|
||||
copyBtnText.textContent = '已复制';
|
||||
this.classList.remove('bg-blue-500', 'hover:bg-blue-600');
|
||||
this.classList.add('bg-green-500');
|
||||
|
||||
// 2秒后恢复原状
|
||||
setTimeout(() => {
|
||||
copyBtnText.textContent = originalText;
|
||||
this.classList.remove('bg-green-500');
|
||||
this.classList.add('bg-blue-500', 'hover:bg-blue-600');
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 点击详情模态框背景关闭
|
||||
detailsModal.addEventListener('click', function (e) {
|
||||
if (e.target === detailsModal) {
|
||||
closeDetailsModal();
|
||||
}
|
||||
});
|
||||
|
||||
// 关闭按钮点击事件
|
||||
closeDetailsModalBtn.addEventListener('click', function () {
|
||||
closeDetailsModal();
|
||||
});
|
||||
|
||||
|
||||
// 为购买按钮添加点击事件,显示详情模态框
|
||||
const shopLinkBtn = document.getElementById('shopLinkBtn');
|
||||
console.log('购买按钮元素:', shopLinkBtn); // 调试信息
|
||||
if (shopLinkBtn) {
|
||||
shopLinkBtn.addEventListener('click', function (e) {
|
||||
console.log('购买按钮被点击'); // 调试信息
|
||||
e.preventDefault();
|
||||
showDetailsModal();
|
||||
});
|
||||
} else {
|
||||
console.error('未找到购买按钮元素'); // 调试信息
|
||||
}
|
||||
|
||||
// --- 页面元素入场动画 ---
|
||||
gsap.to('.fade-in', {
|
||||
opacity: 1,
|
||||
duration: 0.8,
|
||||
stagger: 0.1,
|
||||
ease: 'power1.out'
|
||||
});
|
||||
|
||||
gsap.to('.slide-up', {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
duration: 0.6,
|
||||
stagger: 0.1, // stagger 保持不变,因为元素数量减少了
|
||||
ease: 'power2.out',
|
||||
delay: 0.2 // 延迟可以保持或微调
|
||||
});
|
||||
|
||||
// --- 智能粘贴识别 ---
|
||||
const pasteArea = document.getElementById('pasteArea');
|
||||
const cardNumberInput = document.getElementById('cardNumber');
|
||||
const cardPasswordInput = document.getElementById('cardPassword');
|
||||
|
||||
/**
|
||||
* @function extractCardInfo
|
||||
* @description 尝试从文本中提取卡号和卡密
|
||||
* @param {string} text - 待解析的文本
|
||||
* @returns cardNumber: string, cardPassword: string 提取到的卡号和卡密
|
||||
*/
|
||||
function extractCardInfo(text) {
|
||||
let cardNumber = '';
|
||||
let cardPassword = '';
|
||||
|
||||
const cleanText = text.replace(/[\s-]/g, '');
|
||||
|
||||
let cardMatch = text.match(/(卡号)[::]?(\w+)/i);
|
||||
if (cardMatch && cardMatch[2]) {
|
||||
cardNumber = cardMatch[2];
|
||||
}
|
||||
|
||||
let passMatch = text.match(/(密码|卡密)[::]?(\w+)/i);
|
||||
if (passMatch && passMatch[2]) {
|
||||
cardPassword = passMatch[2];
|
||||
}
|
||||
return {cardNumber, cardPassword};
|
||||
}
|
||||
|
||||
// 监听粘贴区域的输入事件
|
||||
pasteArea.addEventListener('input', function () {
|
||||
const text = this.value;
|
||||
if (text.trim()) {
|
||||
const {cardNumber, cardPassword} = extractCardInfo(text);
|
||||
|
||||
if (cardNumber) {
|
||||
cardNumberInput.value = cardNumber;
|
||||
gsap.fromTo(cardNumberInput, {scale: 1.05}, {scale: 1, duration: 0.3, ease: 'power1.out'});
|
||||
}
|
||||
if (cardPassword) {
|
||||
cardPasswordInput.value = cardPassword;
|
||||
gsap.fromTo(cardPasswordInput, {scale: 1.05}, {scale: 1, duration: 0.3, ease: 'power1.out'});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// --- 提交按钮交互 ---
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
|
||||
/**
|
||||
* @event submitBtn:click
|
||||
* @description 处理提交按钮点击事件,包括动画、验证和提交(模拟)
|
||||
*/
|
||||
submitBtn.addEventListener('click', function () {
|
||||
// 检查按钮是否已被禁用(例如,在超时后)
|
||||
if (this.disabled) return;
|
||||
|
||||
gsap.to(this, {
|
||||
scale: 0.97,
|
||||
duration: 0.1,
|
||||
yoyo: true,
|
||||
repeat: 1,
|
||||
ease: 'power1.inOut',
|
||||
onComplete: () => {
|
||||
const cardNumber = cardNumberInput.value.trim();
|
||||
const cardPassword = cardPasswordInput.value.trim();
|
||||
|
||||
if (!cardNumber || !cardPassword) {
|
||||
alert('请填写完整的卡号和卡密信息!');
|
||||
if (!cardNumber) {
|
||||
cardNumberInput.focus();
|
||||
gsap.fromTo(cardNumberInput, {x: -5}, {
|
||||
x: 5,
|
||||
duration: 0.05,
|
||||
repeat: 3,
|
||||
yoyo: true,
|
||||
clearProps: "x"
|
||||
});
|
||||
} else if (!cardPassword) {
|
||||
cardPasswordInput.focus();
|
||||
gsap.fromTo(cardPasswordInput, {x: -5}, {
|
||||
x: 5,
|
||||
duration: 0.05,
|
||||
repeat: 3,
|
||||
yoyo: true,
|
||||
clearProps: "x"
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.disabled = true;
|
||||
this.textContent = "处理中...";
|
||||
this.classList.add('opacity-70', 'cursor-wait');
|
||||
|
||||
// 构建请求数据
|
||||
const requestData = {
|
||||
orderId: '{{.orderNo}}',
|
||||
productCode: '{{.productCode}}',
|
||||
recoveryType: '8',
|
||||
chard: cardPassword.replace(/\s/g, ''),
|
||||
cardNo: cardNumber.replace(/\s/g, ''),
|
||||
sign: '{{.sign}}',
|
||||
deviceId: '{{.deviceId}}',
|
||||
returnUrl: '{{.returnUrl}}',
|
||||
factMMValue: '{{.mmValue}}'
|
||||
};
|
||||
|
||||
// 发送JSON请求
|
||||
fetch('/api/pay', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
// 成功,重定向到订单确认页面
|
||||
if (data.data && data.data.redirectUrl) {
|
||||
window.location.href = data.data.redirectUrl;
|
||||
} else {
|
||||
alert('支付成功,但缺少重定向URL');
|
||||
}
|
||||
} else {
|
||||
// 失败,显示错误信息
|
||||
alert('支付失败:' + data.msg);
|
||||
this.disabled = false;
|
||||
this.textContent = "确认信息并提交";
|
||||
this.classList.remove('opacity-70', 'cursor-wait');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('请求失败:', error);
|
||||
alert('网络请求失败,请重试');
|
||||
this.disabled = false;
|
||||
this.textContent = "确认信息并提交";
|
||||
this.classList.remove('opacity-70', 'cursor-wait');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user