Files
kami_shop/views/index-hongfu.html
danial 543f0a474c feat(payment): 将支付表单提交方式改为fetch请求
- 替换原有的HTML表单提交方式为JSON格式的fetch请求
- 统一所有页面的支付请求接口为/api/pay- 添加请求错误处理和用户提示信息
-优化支付成功后的页面跳转逻辑- 增加网络异常时的重试机制和按钮状态恢复
- 补充deviceId参数传递支持- 修复部分页面提交按钮状态未重置的问题
2025-09-26 19:55:01 +08:00

521 lines
20 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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);
height: 100vh;
overflow: hidden;
/* 禁止滚动,强制单屏 */
display: flex;
flex-direction: column;
}
/* 主要容器 */
.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;
}
</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">
1.此卡为:鸿福卡!!!<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 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>
<!-- 添加淘宝跳转按钮 -->
{{range.profitMarginList}}
<div class="mb-6 slide-up" style="animation-delay: 0.35s;">
<a href="{{.LinkID}}" target="_self" rel="noopener noreferrer"
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"
style="background-color: var({{.Color}});">
<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">点击跳转{{.PlatformLabel}}购买</span>
</a>
</div>
{{ end }}
<!-- 智能粘贴区域 - 调整动画延迟 -->
<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>
<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 closeModalBtn = document.getElementById('closeModal');
const modalContent = modal.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();
}
});
// --- 页面元素入场动画 ---
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>