ui-ux-pro-max重构页面

支持支付宝免输备注
This commit is contained in:
chackylee
2026-02-13 11:12:47 +08:00
parent 55a25c2bef
commit 67bb240aae
13 changed files with 2482 additions and 2364 deletions

View File

@@ -28,6 +28,9 @@ public class Config implements WebMvcConfigurer {
viewResolver.addStaticVariable("title",payConfig.getTitle());
viewResolver.addStaticVariable("indexTitle",payConfig.getIndexTitle());
viewResolver.addStaticVariable("site",payConfig.getSite());
viewResolver.addStaticVariable("alipayUserId",payConfig.getAlipayUserId());
viewResolver.addStaticVariable("alipayCustomQrUrl",payConfig.getAlipayCustomQrUrl());
viewResolver.addStaticVariable("mobile",payConfig.getMobile());
}
}

View File

@@ -48,6 +48,22 @@ public class PayProConfig implements WebMvcConfigurer {
/** 项目下载地址 */
private String downloadUrl;
/**
* 阿里的用户id
* */
private String alipayUserId;
/**
* 阿里的自定义收款码
* */
private String alipayCustomQrUrl;
/**
* mobile
* */
private String mobile;
/**
* 邮箱配置内部类
*/

View File

@@ -72,10 +72,13 @@ mybatis-plus:
logic-not-delete-value: 0
paypro:
alipayCustomQrUrl: https://qr.alipay.com/fkx17492eze99maemka1u81
alipayUserId: 2088122989840531
indexTitle: PayPro个人收款系统 # 网站首页标题
name: codewendao
title: PayPro个人收款系统 # 邮件标题
site: http://localhost:8889
mobile: xxxxxx
email:
receiver: 958625993@qq.com
sender: codewendao@163.com

View File

@@ -96,14 +96,28 @@ class HttpUtil {
}
}
// 延迟创建全局实例确保API_CONFIG已加载
let httpUtil;
// 全局单例实例
let httpUtil = null;
// 初始化函数
// 初始化函数 - 确保只初始化一次
function initHttpUtil() {
if (!httpUtil && typeof API_CONFIG !== 'undefined') {
// 检查是否已经初始化
if (httpUtil) {
return httpUtil;
}
// 检查API_CONFIG是否已加载
if (typeof API_CONFIG === 'undefined') {
console.error('API_CONFIG未定义请确保api-config.js已正确加载');
return null;
}
try {
httpUtil = new HttpUtil();
console.log('HttpUtil初始化成功');
console.log('HttpUtil初始化成功(全局单例)');
} catch (error) {
console.error('HttpUtil初始化失败:', error);
httpUtil = null;
}
return httpUtil;
}
@@ -113,13 +127,54 @@ function getHttpUtil() {
return httpUtil || initHttpUtil();
}
// 简化的HTTP请求方法自动处理初始化和错误
async function httpRequest(endpoint, options = {}) {
try {
// 确保httpUtil已初始化单例模式
const util = getHttpUtil();
if (!util) {
throw new Error('HTTP工具初始化失败');
}
// 根据请求类型调用相应方法
if (options.method === 'GET' || options.method === 'DELETE') {
return await util.get(endpoint, options.params);
} else {
return await util.post(endpoint, options.data);
}
} catch (error) {
console.error('HTTP请求失败:', error);
throw error;
}
}
// 便捷的POST请求方法
async function postRequest(endpoint, data = {}) {
return httpRequest(endpoint, {
method: 'POST',
data: data
});
}
// 便捷的GET请求方法
async function getRequest(endpoint, params = {}) {
return httpRequest(endpoint, {
method: 'GET',
params: params
});
}
// 导出工具类
if (typeof module !== 'undefined' && module.exports) {
module.exports = { HttpUtil, getHttpUtil, initHttpUtil };
module.exports = { HttpUtil, getHttpUtil, initHttpUtil, httpRequest, postRequest, getRequest };
} else {
window.HttpUtil = HttpUtil;
window.getHttpUtil = getHttpUtil;
window.initHttpUtil = initHttpUtil;
window.httpRequest = httpRequest;
window.postRequest = postRequest;
window.getRequest = getRequest;
// 在DOM加载完成后初始化
if (document.readyState === 'loading') {

View File

@@ -0,0 +1,145 @@
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
:root {
/* Base Colors - Slate Dark Theme */
--bg-color: #020617; /* Slate 950 */
--surface-color: #0f172a; /* Slate 900 */
--text-color: #f8fafc; /* Slate 50 */
--text-muted: #94a3b8; /* Slate 400 */
/* Brand Colors - Indigo/Violet for Fintech */
--primary-color: #6366f1; /* Indigo 500 */
--primary-hover: #4f46e5; /* Indigo 600 */
--secondary-color: #8b5cf6; /* Violet 500 */
--accent-color: #38bdf8; /* Sky 400 */
/* Glassmorphism */
--glass-bg: rgba(30, 41, 59, 0.4); /* Slate 800 with opacity */
--glass-border: 1px solid rgba(255, 255, 255, 0.08);
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3);
--glass-highlight: rgba(255, 255, 255, 0.05);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: 'Plus Jakarta Sans', sans-serif;
background-color: var(--bg-color);
background-image:
radial-gradient(circle at 15% 50%, rgba(99, 102, 241, 0.15) 0%, transparent 25%),
radial-gradient(circle at 85% 30%, rgba(139, 92, 246, 0.15) 0%, transparent 25%);
color: var(--text-color);
line-height: 1.6;
min-height: 100vh;
overflow-x: hidden;
}
/* Layout Utilities */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
/* Glass Component */
.glass {
background: var(--glass-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: var(--glass-border);
box-shadow: var(--glass-shadow);
border-radius: 20px;
transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
.glass:hover {
border-color: rgba(255, 255, 255, 0.15);
background: linear-gradient(145deg, rgba(30, 41, 59, 0.6), rgba(30, 41, 59, 0.4));
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
border-radius: 12px;
font-weight: 600;
font-size: 1rem;
text-decoration: none;
transition: all 0.2s ease;
cursor: pointer;
border: none;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
color: white;
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(99, 102, 241, 0.4);
}
.btn-ghost {
background: transparent;
color: var(--text-muted);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.btn-ghost:hover {
color: var(--text-color);
border-color: rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.05);
}
/* Typography */
.text-gradient {
background: linear-gradient(to right, #fff, #cbd5e1);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.text-accent-gradient {
background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Animations */
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
.animate-float {
animation: float 6s ease-in-out infinite;
}
.footer {
text-align: center;
color: var(--text-muted);
margin-top: 80px;
padding: 40px 0;
border-top: 1px solid rgba(255,255,255,0.05);
}

View File

@@ -3,295 +3,195 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>帮助中心</title>
<!-- 引入Vue 3 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js"></script>
<title>帮助中心 - PayPro</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js" defer></script>
<link href="https://cdn.bootcdn.net/ajax/libs/remixicon/3.5.0/remixicon.css" rel="stylesheet">
<link rel="stylesheet" href="/css/common.css">
<script src="/assets/js/api-config.js"></script>
<script src="/assets/js/http-util.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
color: white;
margin-bottom: 30px;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.main-content {
background: white;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
overflow: hidden;
}
.nav-tabs {
display: flex;
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
}
.nav-tab {
flex: 1;
padding: 15px 20px;
text-align: center;
cursor: pointer;
border: none;
background: none;
font-size: 16px;
color: #666;
transition: all 0.3s ease;
text-decoration: none;
}
.nav-tab:hover {
background: #e9ecef;
color: #333;
}
.nav-tab.active {
background: #007bff;
color: white;
}
.page-content {
padding: 30px;
min-height: 500px;
}
.help-section {
margin-bottom: 30px;
padding: 25px;
background: #f8f9fa;
border-radius: 12px;
border-left: 4px solid #007bff;
transition: all 0.3s ease;
}
.help-section:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.help-section h3 {
margin-bottom: 15px;
color: #333;
display: flex;
align-items: center;
gap: 10px;
}
.help-section p,
.help-section li {
line-height: 1.8;
color: #555;
margin-bottom: 8px;
}
.help-section ul {
padding-left: 20px;
}
.contact-info {
background: linear-gradient(135deg, #007bff, #0056b3);
color: white;
text-align: center;
border-radius: 12px;
padding: 30px;
margin-top: 40px;
}
.contact-info h3 {
margin-bottom: 20px;
font-size: 1.5rem;
}
.contact-item {
display: inline-block;
margin: 10px 20px;
padding: 10px 20px;
background: rgba(255,255,255,0.1);
border-radius: 25px;
transition: all 0.3s ease;
}
.contact-item:hover {
background: rgba(255,255,255,0.2);
transform: translateY(-2px);
}
.faq-item {
margin-bottom: 20px;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.faq-question {
background: #007bff;
color: white;
padding: 15px 20px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
display: flex;
justify-content: space-between;
align-items: center;
}
.faq-question:hover {
background: #0056b3;
}
.faq-answer {
background: white;
padding: 20px;
border-left: 3px solid #007bff;
display: none;
}
.faq-answer.active {
display: block;
animation: slideDown 0.3s ease;
}
@keyframes slideDown {
from {
opacity: 0;
max-height: 0;
}
to {
opacity: 1;
max-height: 200px;
}
}
.footer {
text-align: center;
color: white;
margin-top: 30px;
opacity: 0.8;
.page-wrap { padding-top: 40px; padding-bottom: 60px; }
.header { text-align: center; margin-bottom: 32px; }
.title { font-size: 2.5rem; font-weight: 800; margin-bottom: 12px; }
.subtitle { font-size: 1.1rem; color: var(--text-muted); }
.glass-card { background: rgba(255,255,255,0.03); border-radius: 16px; border: 1px solid rgba(255,255,255,0.08); backdrop-filter: blur(10px); padding: 24px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); }
.nav-tabs { display: flex; gap: 12px; margin-bottom: 24px; border-radius: 12px; overflow: hidden; background: rgba(255,255,255,0.05); }
.nav-tab { flex: 1; padding: 14px 20px; text-align: center; cursor: pointer; border: none; background: transparent; font-size: 16px; font-weight: 500; color: var(--text-muted); transition: all .3s ease; border-radius: 8px; text-decoration: none; }
.nav-tab:hover { background: rgba(255,255,255,0.08); color: var(--text-color); }
.nav-tab.active { background: var(--primary-color); color: white; }
.page-content { min-height: 600px; }
.section-title { font-size: 1.75rem; font-weight: 700; margin-bottom: 32px; text-align: center; color: var(--text-color); }
.help-grid { display: grid; gap: 24px; margin-bottom: 40px; }
.help-card { background: rgba(255,255,255,0.03); border-radius: 16px; border: 1px solid rgba(255,255,255,0.08); padding: 28px; transition: all .3s ease; border-left: 4px solid var(--primary-color); }
.help-card:hover { background: rgba(255,255,255,0.05); transform: translateY(-4px); box-shadow: 0 12px 24px rgba(0,0,0,0.15); }
.help-card h3 { font-size: 1.25rem; font-weight: 600; margin-bottom: 16px; color: var(--text-color); display: flex; align-items: center; gap: 12px; }
.help-card p, .help-card li { line-height: 1.7; color: var(--text-muted); margin-bottom: 12px; }
.help-card ul { padding-left: 24px; }
.help-card li { margin-bottom: 8px; }
.faq-section { margin: 40px 0; }
.faq-item { margin-bottom: 16px; border-radius: 12px; overflow: hidden; border: 1px solid rgba(255,255,255,0.08); background: rgba(255,255,255,0.03); }
.faq-question { background: rgba(255,255,255,0.05); color: var(--text-color); padding: 20px 24px; cursor: pointer; font-weight: 600; transition: all .3s ease; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid rgba(255,255,255,0.06); }
.faq-question:hover { background: rgba(255,255,255,0.08); }
.faq-question.active { background: var(--primary-color); color: white; border-bottom: none; }
.faq-answer { padding: 0 24px; max-height: 0; overflow: hidden; transition: all .3s ease; }
.faq-answer.active { padding: 24px; max-height: 300px; }
.contact-card { background: linear-gradient(135deg, rgba(99,102,241,0.2), rgba(79,70,229,0.2)); border-radius: 16px; border: 1px solid rgba(99,102,241,0.3); padding: 32px; text-align: center; margin-top: 40px; }
.contact-card h3 { font-size: 1.5rem; font-weight: 700; margin-bottom: 24px; color: var(--text-color); }
.contact-info { display: inline-block; padding: 12px 24px; background: rgba(255,255,255,0.05); border-radius: 999px; border: 1px solid rgba(255,255,255,0.1); transition: all .3s ease; }
.contact-info:hover { background: rgba(255,255,255,0.08); transform: translateY(-2px); }
.icon { font-size: 1.5rem; }
@media (max-width: 768px) {
.page-wrap { padding-top: 24px; padding-bottom: 40px; }
.title { font-size: 2rem; }
.nav-tabs { flex-direction: column; gap: 8px; }
.nav-tab { padding: 12px 16px; }
.page-content { padding: 20px; }
.section-title { font-size: 1.5rem; margin-bottom: 24px; }
.help-card { padding: 20px; }
.help-card h3 { font-size: 1.1rem; }
.faq-question { padding: 16px 20px; }
.faq-answer.active { padding: 20px; }
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<div class="header">
<h1>💳 充值中心</h1>
<p>安全、快捷的个人支付系统</p>
</div>
<div class="main-content">
<nav class="nav-tabs">
<a href="recharge.html" class="nav-tab">💰 充值</a>
<!-- <a href="history.html" class="nav-tab">📋 充值记录</a>-->
<a href="help.html" class="nav-tab active">❓ 帮助中心</a>
</nav>
<div class="page-content">
<h2 style="text-align: center; margin-bottom: 30px; color: #333;">❓ 帮助中心</h2>
<div id="app">
<div class="container page-wrap">
<div class="header">
<h1 class="title">
<i class="ri-question-line"></i> 帮助中心
</h1>
<p class="subtitle">解决您的支付疑问,提供专业的技术支持</p>
</div>
<div class="glass-card">
<nav class="nav-tabs">
<a href="recharge.html" class="nav-tab">
<i class="ri-credit-card-line"></i> 捐赠
</a>
<a href="history.html" class="nav-tab">
<i class="ri-history-line"></i> 捐赠记录
</a>
<a href="help.html" class="nav-tab active">
<i class="ri-question-line"></i> 帮助中心
</a>
</nav>
<div class="page-content">
<h2 class="section-title">
<i class="ri-question-circle-line"></i> 常见问题
</h2>
<div class="help-grid">
<div class="help-card">
<h3>
<i class="ri-shield-check-line icon"></i> 支付安全
</h3>
<p>
我们不依赖任何第三方平台,自助完成支付。所有支付都通过官方支付渠道处理,资金安全有保障。
</p>
</div>
<div class="help-card">
<h3>
<i class="ri-payment-line icon"></i> 支付方式说明
</h3>
<ul>
<li><strong style="color: var(--text-color);">支付宝转账:</strong>打开支付宝APP扫描二维码完成支付支持余额、银行卡</li>
<li><strong style="color: var(--text-color);">微信支付:</strong>打开微信APP扫描二维码完成支付支持零钱、银行卡等付款方式</li>
<li><strong style="color: var(--text-color);">支付宝扫码:</strong>打开支付宝APP扫描二维码完成支付支持余额、银行卡</li>
</ul>
</div>
<div class="help-card">
<h3>
<i class="ri-error-warning-line icon"></i> 支付失败处理
</h3>
<ul>
<li>检查网络连接是否正常</li>
<li>确认支付账户余额是否充足</li>
<li>尝试刷新页面重新支付</li>
<li>更换其他支付方式</li>
</ul>
</div>
</div>
<div class="faq-section">
<h3 style="font-size: 1.3rem; font-weight: 600; margin-bottom: 24px; color: var(--text-color); text-align: center;">
<i class="ri-question-answer-line"></i> 常见问题解答
</h3>
<div style="max-width: 900px; margin: 0 auto;">
<div class="help-section">
<h3>🔒 支付安全</h3>
<p>
不依赖任何第三方平台,自助完成支付。所有支付都通过官方支付渠道处理,资金安全有保障。
</p>
<div class="faq-item" v-for="(faq, index) in faqList" :key="index">
<div class="faq-question" :class="{ active: faq.isOpen }" @click="toggleFaq(index)">
<span>{{ faq.question }}</span>
<i :class="['ri', faq.isOpen ? 'ri-chevron-up' : 'ri-chevron-down']"></i>
</div>
<div class="help-section">
<h3>💰 支付方式说明</h3>
<ul>
<li><strong>支付宝转账:</strong>打开支付宝APP扫描二维码完成支付支持余额、银行卡、花呗等多种付款方式</li>
<li><strong>微信支付:</strong>打开微信APP扫描二维码完成支付支持零钱、银行卡等付款方式</li>
<li><strong>支付宝扫码:</strong>打开支付宝APP扫描二维码完成支付支持余额、银行卡、花呗等多种付款方式</li>
</ul>
</div>
<div class="help-section">
<h3>❌ 支付失败处理</h3>
<ul>
<li>检查网络连接是否正常</li>
<li>确认支付账户余额是否充足</li>
<li>尝试刷新页面重新支付</li>
<li>更换其他支付方式</li>
<li>如仍无法解决,请联系客服</li>
</ul>
</div>
<div class="help-section">
<h3>💡 常见问题</h3>
<div class="faq-item" v-for="(faq, index) in faqList" :key="index">
<div class="faq-question" @click="toggleFaq(index)">
<span>{{ faq.question }}</span>
<span>{{ faq.isOpen ? '' : '+' }}</span>
</div>
<div class="faq-answer" :class="{ active: faq.isOpen }">
<p>{{ faq.answer }}</p>
</div>
</div>
</div>
<div class="contact-info">
<div class="faq-answer" :class="{ active: faq.isOpen }">
<p>{{ faq.answer }}</p>
</div>
</div>
</div>
</div>
<div class="footer">
<p>&copy; 充值中心 - 安全可靠的支付服务</p>
<div class="contact-card">
<h3>
<i class="ri-headset-line"></i> 联系客服
</h3>
<div class="contact-info">
<strong>邮箱支持:</strong>[[${supportMail}]]
</div>
</div>
</div>
</div>
<div class="footer">
<p>&copy; 2026 PayPro 捐赠中心. 安全可靠的支付服务</p>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
<script>
window.addEventListener('DOMContentLoaded', function() {
if (typeof Vue === 'undefined') {
console.error('Vue未加载请检查网络连接');
return;
}
const app = createApp({
data() {
return {
faqList: [
{
question: '支付后多久到账?',
answer: '正常情况下是秒到账,因为使用的是官方的渠道。',
isOpen: false
},
{
question: '支付有手续费吗?',
answer: '平台不收取任何充值手续费。微信和支付宝转账付款是直接到你本人的余额的不会产生手续费但是支付宝扫码会产生手续费大约是0.6%。',
isOpen: false
}
]
}
},
methods: {
toggleFaq(index) {
this.faqList[index].isOpen = !this.faqList[index].isOpen;
}
const { createApp } = Vue;
createApp({
data() {
return {
faqList: [
{
question: '支付后多久到账?',
answer: '正常情况下是秒到账,因为使用的是官方的渠道。系统会实时处理您的支付请求,一旦支付成功,资金会立即到账。',
isOpen: false
},
{
question: '支付有手续费吗?',
answer: '平台不收取任何充值手续费。微信和支付宝转账付款是直接到你本人的余额的不会产生手续费但是支付宝扫码会产生手续费大约是0.6%。',
isOpen: false
},
{
question: '如何查询我的支付记录?',
answer: '您可以在"捐赠记录"页面查看所有的支付历史,包括支付状态、金额、时间等详细信息。系统会保存您的所有支付记录,方便您随时查询。',
isOpen: false
},
{
question: '支付限额是多少?',
answer: '支付限额取决于您选择的支付方式和银行/支付平台的限制。一般情况下支付宝和微信支付的单笔限额为5000元单日限额为20000元。具体限额请参考您的支付账户设置。',
isOpen: false
}
]
}
});
app.mount('#app');
</script>
},
methods: {
toggleFaq(index) {
this.faqList[index].isOpen = !this.faqList[index].isOpen;
}
}
}).mount('#app');
});
</script>
</body>
</html>

View File

@@ -3,253 +3,105 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>捐赠记录</title>
<title>捐赠记录 - PayPro</title>
<!-- 引入Vue 3 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js" defer></script>
<!-- 引入图标库 (使用国内CDN) -->
<link href="https://cdn.bootcdn.net/ajax/libs/remixicon/3.5.0/remixicon.css" rel="stylesheet">
<!-- 引入公共样式 -->
<link rel="stylesheet" href="/css/common.css">
<!-- 引入API配置 -->
<script src="assets/js/api-config.js"></script>
<script src="/assets/js/api-config.js"></script>
<!-- 引入HTTP工具 -->
<script src="assets/js/http-util.js"></script>
<script src="/assets/js/http-util.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
color: white;
margin-bottom: 30px;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.main-content {
background: white;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
overflow: hidden;
}
.nav-tabs {
display: flex;
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
}
.nav-tab {
flex: 1;
padding: 15px 20px;
text-align: center;
cursor: pointer;
border: none;
background: none;
font-size: 16px;
color: #666;
transition: all 0.3s ease;
text-decoration: none;
}
.nav-tab:hover {
background: #e9ecef;
color: #333;
}
.nav-tab.active {
background: #007bff;
color: white;
}
.page-content {
padding: 30px;
min-height: 500px;
}
.history-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.history-table th,
.history-table td {
padding: 15px;
text-align: left;
border-bottom: 1px solid #e9ecef;
}
.history-table th {
background: #f8f9fa;
font-weight: 600;
color: #333;
}
.history-table tr:hover {
background: #f8f9fa;
}
.state-success {
color: #28a745;
font-weight: 600;
}
.state-pending {
color: #ffc107;
font-weight: 600;
}
.state-failed {
color: #dc3545;
font-weight: 600;
}
.empty-state {
text-align: center;
padding: 50px;
color: #666;
}
.empty-state .icon {
font-size: 4rem;
margin-bottom: 20px;
opacity: 0.5;
}
/* 分页样式 */
.pagination {
display: flex;
justify-content: center;
align-items: center;
margin-top: 30px;
gap: 10px;
}
.pagination button {
padding: 8px 16px;
border: 1px solid #ddd;
background: white;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
}
.pagination button:hover:not(:disabled) {
background: #007bff;
color: white;
border-color: #007bff;
}
.pagination button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.page-info {
color: #666;
font-size: 14px;
}
.page-size-selector {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}
.page-size-selector select {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
background: white;
}
.loading {
text-align: center;
padding: 40px;
color: #666;
}
.loading-spinner {
display: inline-block;
width: 40px;
height: 40px;
border: 3px solid #f3f3f3;
border-top: 3px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.footer {
text-align: center;
color: white;
margin-top: 30px;
opacity: 0.8;
}
.page-wrap { padding-top: 40px; padding-bottom: 60px; }
.header { text-align: center; margin-bottom: 32px; }
.title { font-size: 2.5rem; font-weight: 800; margin-bottom: 12px; }
.subtitle { font-size: 1.1rem; color: var(--text-muted); }
.glass-card { background: rgba(255,255,255,0.03); border-radius: 16px; border: 1px solid rgba(255,255,255,0.08); backdrop-filter: blur(10px); padding: 24px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); }
.nav-tabs { display: flex; gap: 12px; margin-bottom: 24px; border-radius: 12px; overflow: hidden; background: rgba(255,255,255,0.05); }
.nav-tab { flex: 1; padding: 14px 20px; text-align: center; cursor: pointer; border: none; background: transparent; font-size: 16px; font-weight: 500; color: var(--text-muted); transition: all .3s ease; border-radius: 8px; text-decoration: none; }
.nav-tab:hover { background: rgba(255,255,255,0.08); color: var(--text-color); }
.nav-tab.active { background: var(--primary-color); color: white; }
.page-content { min-height: 500px; }
.section-title { font-size: 1.5rem; font-weight: 700; margin-bottom: 24px; text-align: center; color: var(--text-color); }
.table-wrapper { overflow-x: auto; margin: 24px 0; border-radius: 12px; border: 1px solid rgba(255,255,255,0.08); }
.history-table { width: 100%; border-collapse: collapse; background: rgba(255,255,255,0.03); }
.history-table th, .history-table td { padding: 16px 20px; text-align: left; border-bottom: 1px solid rgba(255,255,255,0.06); }
.history-table th { background: rgba(255,255,255,0.05); font-weight: 600; color: var(--text-muted); font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px; }
.history-table tr:hover { background: rgba(255,255,255,0.04); }
.status-badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: 999px; font-size: 0.85rem; font-weight: 600; }
.status-success { background: rgba(34,197,94,0.2); color: #22c55e; border: 1px solid rgba(34,197,94,0.3); }
.status-pending { background: rgba(245,158,11,0.2); color: #f59e0b; border: 1px solid rgba(245,158,11,0.3); }
.status-failed { background: rgba(239,68,68,0.2); color: #ef4444; border: 1px solid rgba(239,68,68,0.3); }
.empty-state { text-align: center; padding: 80px 24px; color: var(--text-muted); }
.empty-icon { font-size: 4rem; margin-bottom: 20px; opacity: 0.5; }
.empty-title { font-size: 1.25rem; font-weight: 600; margin-bottom: 8px; color: var(--text-color); }
.empty-desc { font-size: 1rem; margin-bottom: 24px; }
.pagination { display: flex; justify-content: center; align-items: center; gap: 8px; margin: 32px 0; flex-wrap: wrap; }
.page-btn { padding: 8px 16px; border: 1px solid rgba(255,255,255,0.08); background: rgba(255,255,255,0.03); color: var(--text-color); border-radius: 8px; cursor: pointer; transition: all .2s ease; font-size: 0.9rem; }
.page-btn:hover:not(:disabled) { background: var(--primary-color); border-color: var(--primary-color); color: white; }
.page-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.page-info { padding: 8px 16px; color: var(--text-muted); font-size: 0.9rem; }
.page-size-selector { display: flex; align-items: center; gap: 12px; margin-bottom: 24px; justify-content: flex-end; }
.page-size-selector select { padding: 8px 12px; border: 1px solid rgba(255,255,255,0.08); background: rgba(255,255,255,0.03); color: var(--text-color); border-radius: 8px; font-size: 0.9rem; }
.loading { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 24px; color: var(--text-muted); }
.loading-spinner { width: 40px; height: 40px; border: 3px solid rgba(255,255,255,0.1); border-top: 3px solid var(--primary-color); border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 16px; }
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
.stats-card { background: rgba(255,255,255,0.03); border-radius: 12px; border: 1px solid rgba(255,255,255,0.08); padding: 20px; margin-bottom: 24px; }
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; }
.stat-item { text-align: center; }
.stat-value { font-size: 1.8rem; font-weight: 800; color: var(--primary-color); margin-bottom: 4px; }
.stat-label { font-size: 0.9rem; color: var(--text-muted); }
.filter-bar { display: flex; gap: 12px; margin-bottom: 24px; flex-wrap: wrap; align-items: center; }
.filter-btn { padding: 8px 16px; border: 1px solid rgba(255,255,255,0.08); background: rgba(255,255,255,0.03); color: var(--text-color); border-radius: 8px; cursor: pointer; transition: all .2s ease; font-size: 0.9rem; }
.filter-btn.active { background: var(--primary-color); border-color: var(--primary-color); color: white; }
@media (max-width: 768px) {
.history-table {
font-size: 14px;
}
.history-table th,
.history-table td {
padding: 10px 8px;
}
.pagination {
flex-wrap: wrap;
}
.page-wrap { padding-top: 24px; padding-bottom: 40px; }
.title { font-size: 2rem; }
.nav-tabs { flex-direction: column; gap: 8px; }
.nav-tab { padding: 12px 16px; }
.table-wrapper { border-radius: 8px; }
.history-table th, .history-table td { padding: 12px 16px; font-size: 0.9rem; }
.stats-grid { grid-template-columns: repeat(2, 1fr); }
.filter-bar { justify-content: center; }
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<div class="container page-wrap">
<div class="header">
<h1>💳 捐赠中心</h1>
<p>安全、快捷的在线捐赠服务</p>
<h1 class="title">
<i class="ri-wallet-3-line"></i> 捐赠中心
</h1>
<p class="subtitle">安全、便捷的在线捐赠服务</p>
</div>
<div class="main-content">
<div class="glass-card">
<nav class="nav-tabs">
<a href="recharge.html" class="nav-tab">💰 捐赠</a>
<a href="history.html" class="nav-tab active">📋 捐赠记录</a>
<a href="help.html" class="nav-tab">❓ 帮助中心</a>
<a href="recharge.html" class="nav-tab">
<i class="ri-credit-card-line"></i> 捐赠
</a>
<a href="history.html" class="nav-tab active">
<i class="ri-history-line"></i> 捐赠记录
</a>
<a href="help.html" class="nav-tab">
<i class="ri-question-line"></i> 帮助中心
</a>
</nav>
<div class="page-content">
<h2 style="text-align: center; margin-bottom: 30px; color: #333;">📋 捐赠记录</h2>
<h2 class="section-title">
<i class="ri-list-check"></i> 捐赠记录
</h2>
<!-- 每页显示数量选择器 -->
<div class="page-size-selector" v-if="rechargeHistory.length > 0">
<span>每页显示:</span>
<div class="page-size-selector" v-if="total > 0">
<span style="color: var(--text-muted);">每页显示:</span>
<select v-model="pageSize" @change="loadRechargeHistory(1)">
<option value="5">5条</option>
<option value="10">10条</option>
@@ -258,184 +110,234 @@
</select>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading">
<div class="loading-spinner"></div>
<p>加载中...</p>
<p>加载中,请稍候...</p>
</div>
<!-- 空状态 -->
<div v-else-if="rechargeHistory.length === 0" class="empty-state">
<div class="icon">📭</div>
<h3>暂无捐赠记录</h3>
<p>您还没有任何捐赠记录</p>
<a href="recharge.html" style="color: #007bff; text-decoration: none; margin-top: 15px; display: inline-block;">立即捐赠 →</a>
<div class="empty-icon">
<i class="ri-inbox-line"></i>
</div>
<h3 class="empty-title">暂无捐赠记录</h3>
<p class="empty-desc">您还没有任何捐赠记录</p>
<a href="recharge.html" class="btn btn-primary">
<i class="ri-credit-card-line"></i> 立即捐赠
</a>
</div>
<template v-else>
<!-- 捐赠记录表格 -->
<div v-else class="table-wrapper">
<table class="history-table">
<thead>
<tr>
<th>订单号</th>
<th>捐赠金额</th>
<th>支付方式</th>
<th>状态</th>
<th>时间</th>
</tr>
<tr>
<th>订单号</th>
<th>捐赠金额</th>
<th>支付方式</th>
<th>状态</th>
<th>捐赠时间</th>
</tr>
</thead>
<tbody>
<tr v-for="record in rechargeHistory" :key="record.id">
<td>{{ record.id }}</td>
<td style="font-weight: bold; color: #007bff;">¥{{ record.money }}</td>
<td>{{ getPayTypeText(record.payType) }}</td>
<td :class="getStateClass(record.state)">
{{ getStateText(record.state) }}
</td>
<td>{{ formatTime(record.createTime) }}</td>
</tr>
<tr v-for="record in rechargeHistory" :key="record.id">
<td>{{ record.id }}</td>
<td style="font-weight: 600; color: var(--primary-color);">¥{{ record.money }}</td>
<td>{{ getPayTypeText(record.payType) }}</td>
<td>
<span :class="['status-badge', getStatusClass(record.state)]">
<i :class="getStatusIcon(record.state)"></i>
{{ getStatusText(record.state) }}
</span>
</td>
<td>{{ formatTime(record.createTime) }}</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<div class="pagination">
<button
@click="loadRechargeHistory(1)"
:disabled="current === 1">
首页
</button>
<button
@click="loadRechargeHistory(current - 1)"
:disabled="current === 1">
上一页
</button>
<!-- 分页控件 -->
<div v-if="total > 0" class="pagination">
<button
class="page-btn"
@click="loadRechargeHistory(1)"
:disabled="currentPage === 1"
>
<i class="ri-arrow-left-double-line"></i> 首页
</button>
<button
class="page-btn"
@click="loadRechargeHistory(currentPage - 1)"
:disabled="currentPage === 1"
>
<i class="ri-arrow-left-line"></i> 上一页
</button>
<span class="page-info">
第 {{ currentPage }} 页 / 共 {{ totalPages }} 页
</span>
<button
class="page-btn"
@click="loadRechargeHistory(currentPage + 1)"
:disabled="currentPage >= totalPages"
>
下一页 <i class="ri-arrow-right-line"></i>
</button>
<button
class="page-btn"
@click="loadRechargeHistory(totalPages)"
:disabled="currentPage >= totalPages"
>
末页 <i class="ri-arrow-right-double-line"></i>
</button>
</div>
<span class="page-info">
第 {{ current }} 页 / 共 {{ pages }} 页
</span>
<button
@click="loadRechargeHistory(current + 1)"
:disabled="current === pages">
下一页
</button>
<button
@click="loadRechargeHistory(pages)"
:disabled="current === pages">
末页
</button>
</div>
<div style="text-align: center; margin-top: 30px; color: #666;">
<p>💡 提示:共 {{ total }} 条记录,当前显示第 {{ (current - 1) * pageSize + 1 }} - {{ Math.min(current * pageSize, total) }} 条</p>
</div>
</template>
<!-- 分页信息 -->
<div v-if="total > 0" style="text-align: center; margin-top: 16px; color: var(--text-muted); font-size: 0.9rem;">
<p>
<i class="ri-information-line"></i> 共 {{ total }} 条记录,当前显示第 {{ (currentPage - 1) * pageSize + 1 }} - {{ Math.min(currentPage * pageSize, total) }} 条
</p>
</div>
</div>
</div>
<div class="footer">
<p>&copy; 捐赠中心 - 安全可靠的支付服务</p>
<p>&copy; 2026 PayPro 捐赠中心. 安全可靠的支付服务</p>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
// 优化页面加载速度
window.addEventListener('DOMContentLoaded', function() {
// 检查Vue是否加载完成
if (typeof Vue === 'undefined') {
console.error('Vue未加载请检查网络连接');
return;
}
const app = createApp({
data() {
return {
rechargeHistory: [],
loading: false,
// 分页相关
current: 1,
pageSize: 10,
total: 0,
pages: 0
}
},
computed: {
// 计算总页数
pages() {
return Math.ceil(this.total / this.pageSize);
}
},
mounted() {
// 检查httpUtil是否可用
if (typeof httpUtil === 'undefined' || !httpUtil) {
console.error('httpUtil不可用尝试重新初始化...');
if (typeof initHttpUtil === 'function') {
window.httpUtil = initHttpUtil();
}
if (!window.httpUtil) {
this.showError('HTTP工具初始化失败请刷新页面重试');
return;
}
}
this.loadRechargeHistory(1);
},
methods: {
async loadRechargeHistory(pageIndex) {
this.loading = true;
try {
// 调用API获取分页数据
const response = await httpUtil.post(API_CONFIG.ENDPOINTS.PAY_LIST, {
pageIndex: pageIndex,
pageSize: this.pageSize,
states: [1]
});
if (response.code === 200) {
this.rechargeHistory = response.data.records;
this.total = response.data.total;
this.current = response.data.current;
this.pageSize = response.data.size;
this.pages = response.data.pages
} else {
console.error('加载捐赠记录失败:', response.message);
this.rechargeHistory = [];
}
} catch (error) {
console.error('请求失败:', error)
} finally {
this.loading = false;
}
},
getStateClass(state) {
const stateMap = {
0: 'state-pending',
1: 'state-success',
2: 'state-failed'
};
return stateMap[state] || 'state-pending';
},
getStateText(state) {
const stateMap = {
0: '未支付',
1: '成功'
};
return stateMap[state] || '未知状态';
},
getPayTypeText(payType) {
const typeMap = {
'alipay': '支付宝',
'wechat': '微信支付',
'wechat_zs': '微信赞赏',
'alipay_dfm': '支付宝当面付'
};
return typeMap[payType] || payType;
},
formatTime(time) {
if (!time) return '';
const date = new Date(time);
return date.toLocaleString('zh-CN');
},
const { createApp } = Vue;
createApp({
data() {
return {
rechargeHistory: [],
loading: false,
currentPage: 1,
pageSize: 10,
total: 0,
totalPages: 0,
totalAmount: 0,
successCount: 0
}
});
},
mounted() {
// 延迟初始化,让页面先渲染
setTimeout(() => {
this.loadRechargeHistory(1);
}, 100);
},
methods: {
async loadRechargeHistory(pageIndex) {
this.loading = true;
try {
// 构建请求参数states固定为[1]
const requestParams = {
pageIndex: pageIndex,
pageSize: this.pageSize,
states: [1]
};
app.mount('#app');
</script>
// 调用API获取数据
const response = await postRequest(API_CONFIG.ENDPOINTS.PAY_LIST, requestParams);
if (response.code === 200) {
this.rechargeHistory = response.data.records || [];
this.total = response.data.total || 0;
this.currentPage = response.data.current || 1;
this.pageSize = response.data.size || 10;
this.totalPages = response.data.pages || 0;
// 计算统计信息
this.calculateStats();
} else {
console.error('加载捐赠记录失败:', response.message);
this.rechargeHistory = [];
this.total = 0;
this.currentPage = 1;
this.totalPages = 0;
}
} catch (error) {
console.error('请求失败:', error);
this.rechargeHistory = [];
this.total = 0;
this.currentPage = 1;
this.totalPages = 0;
} finally {
this.loading = false;
}
},
calculateStats() {
// 计算总金额和成功记录数
this.totalAmount = this.rechargeHistory.reduce((sum, record) => sum + parseFloat(record.money || 0), 0);
this.successCount = this.rechargeHistory.filter(record => record.state === 1).length;
},
getStatusClass(state) {
const classMap = {
0: 'status-pending',
1: 'status-success',
2: 'status-failed'
};
return classMap[state] || 'status-pending';
},
getStatusIcon(state) {
const iconMap = {
0: 'ri-time-line',
1: 'ri-check-circle-line',
2: 'ri-close-circle-line'
};
return iconMap[state] || 'ri-help-circle-line';
},
getStatusText(state) {
const textMap = {
0: '处理中',
1: '成功',
2: '失败'
};
return textMap[state] || '未知状态';
},
getPayTypeText(payType) {
const typeMap = {
'alipay': '支付宝',
'wechat': '微信支付',
'alipay_dmf': '支付宝当面付',
'wechat_zs': '微信赞赏'
};
return typeMap[payType] || payType;
},
formatTime(time) {
if (!time) return '';
const date = new Date(time);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
}
}).mount('#app');
});
</script>
</body>
</html>

View File

@@ -3,386 +3,361 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人支付系统 - 无需签约,全自动收款</title>
<title>PayPro - 个人支付系统</title>
<!-- 引入Vue 3 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js"></script>
<!-- 引入 Remix Icons -->
<link href="https://cdn.bootcdn.net/ajax/libs/remixicon/3.5.0/remixicon.css" rel="stylesheet">
<link rel="stylesheet" href="/css/common.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
color: white;
margin-bottom: 50px;
padding: 40px 0;
position: relative;
}
/* Header & Nav */
.top-nav {
position: absolute;
top: 20px;
right: 20px;
display: flex;
justify-content: flex-end;
padding: 24px 0;
}
.btn-top {
background: rgba(255, 255, 255, 0.2);
color: white;
.btn-ghost {
color: var(--text-color);
padding: 10px 20px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 25px;
border: 1px solid rgba(255,255,255,0.1);
border-radius: 50px;
text-decoration: none;
font-size: 0.95rem;
font-weight: 500;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
display: flex;
align-items: center;
gap: 8px;
}
.btn-top:hover {
background: rgba(255, 255, 255, 0.3);
border-color: rgba(255, 255, 255, 0.5);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
.btn-ghost:hover {
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.2);
}
.header h1 {
font-size: 3rem;
margin-bottom: 15px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
.hero {
text-align: center;
padding: 60px 0 80px;
}
.header .subtitle {
font-size: 1.5rem;
opacity: 0.9;
margin-bottom: 10px;
.hero-badge {
display: inline-block;
padding: 6px 16px;
background: rgba(139, 92, 246, 0.1);
border: 1px solid rgba(139, 92, 246, 0.2);
color: #A78BFA;
border-radius: 20px;
font-size: 0.85rem;
font-weight: 600;
margin-bottom: 24px;
letter-spacing: 0.5px;
}
.header .description {
font-size: 1.1rem;
opacity: 0.8;
.hero h1 {
font-size: 3.5rem;
line-height: 1.1;
margin-bottom: 24px;
background: linear-gradient(to right, #fff, #94a3b8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
letter-spacing: -1px;
}
.hero .subtitle {
font-size: 1.25rem;
color: var(--text-muted);
max-width: 600px;
margin: 0 auto;
line-height: 1.6;
margin: 0 auto 40px;
line-height: 1.8;
}
/* Features Grid */
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin-bottom: 50px;
gap: 24px;
margin-bottom: 80px;
}
.feature-card {
background: white;
border-radius: 15px;
padding: 30px;
text-align: center;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
transition: all 0.3s ease;
padding: 32px;
height: 100%;
position: relative;
overflow: hidden;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0,0,0,0.3);
background: var(--glass-hover-bg);
border-color: rgba(255,255,255,0.15);
}
.feature-icon {
font-size: 4rem;
margin-bottom: 20px;
display: block;
}
.feature-title {
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 15px;
color: #333;
}
.feature-desc {
color: #666;
line-height: 1.6;
}
.highlight {
color: #007bff;
font-weight: bold;
}
.action-section {
background: white;
border-radius: 20px;
padding: 50px;
text-align: center;
box-shadow: 0 15px 50px rgba(0,0,0,0.2);
margin-bottom: 30px;
}
.action-title {
font-size: 2.5rem;
margin-bottom: 20px;
color: #333;
}
.action-desc {
font-size: 1.2rem;
color: #666;
margin-bottom: 40px;
line-height: 1.6;
}
.btn-primary {
background: linear-gradient(135deg, #007bff, #0056b3);
color: white;
padding: 20px 50px;
font-size: 1.3rem;
border: none;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
display: inline-block;
box-shadow: 0 5px 20px rgba(0,123,255,0.3);
}
.btn-primary:hover {
transform: translateY(-3px);
box-shadow: 0 10px 30px rgba(0,123,255,0.4);
}
.payment-methods {
display: flex;
justify-content: center;
gap: 20px;
margin: 30px 0;
}
.payment-method {
background: #f8f9fa;
padding: 15px 25px;
border-radius: 25px;
.feature-icon-wrapper {
width: 56px;
height: 56px;
background: rgba(245, 158, 11, 0.1);
border-radius: 12px;
display: flex;
align-items: center;
gap: 10px;
font-weight: 500;
justify-content: center;
margin-bottom: 24px;
color: var(--primary-color);
font-size: 1.75rem;
}
.advantages {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 40px 0;
}
.advantage {
background: rgba(255,255,255,0.1);
.feature-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 12px;
color: white;
padding: 20px;
border-radius: 10px;
}
.feature-desc {
color: var(--text-muted);
font-size: 0.95rem;
line-height: 1.6;
}
/* Stats/Advantages Row */
.stats-row {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
gap: 30px;
padding: 40px;
margin-bottom: 80px;
text-align: center;
}
.advantage-icon {
.stat-item h3 {
font-size: 2rem;
margin-bottom: 10px;
display: block;
}
.footer {
text-align: center;
color: white;
margin-top: 50px;
opacity: 0.8;
margin-bottom: 8px;
}
.stat-item p {
color: var(--text-muted);
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 1px;
}
/* CTA Section */
.cta-section {
text-align: center;
padding: 80px 40px;
position: relative;
overflow: hidden;
}
/* Abstract decoration behind CTA */
.cta-section::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(139, 92, 246, 0.15) 0%, transparent 70%);
z-index: -1;
pointer-events: none;
}
.cta-title {
font-size: 2.5rem;
margin-bottom: 20px;
color: white;
}
.cta-desc {
font-size: 1.1rem;
color: var(--text-muted);
margin-bottom: 40px;
max-width: 500px;
margin-left: auto;
margin-right: auto;
}
.payment-logos {
display: flex;
justify-content: center;
gap: 30px;
margin-top: 40px;
opacity: 0.7;
}
.payment-logo {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
font-size: 0.85rem;
color: var(--text-muted);
}
.payment-logo i {
font-size: 2rem;
color: white;
}
@media (max-width: 768px) {
.header h1 {
font-size: 2rem;
}
.header .subtitle {
font-size: 1.2rem;
}
.action-section {
padding: 30px 20px;
}
.action-title {
font-size: 2rem;
}
.payment-methods {
flex-direction: column;
align-items: center;
}
.top-nav {
position: static;
margin-bottom: 20px;
}
.hero h1 { font-size: 2.5rem; }
.cta-title { font-size: 2rem; }
.stats-row { flex-direction: column; gap: 40px; }
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<div class="header">
<div class="top-nav">
<a href="recharge.html" class="btn-top">💰 体验支付</a>
</div>
<h1>💰 个人支付系统</h1>
<div class="subtitle">无需签约第三方 · 全自动收款解决方案</div>
<div class="description">
专为个人和小微商户设计的智能收款系统,支持支付宝、微信支付多种方式,
实现全自动/半自动收款,无需复杂的企业资质和第三方签约流程
</div>
</div>
<div class="features">
<div class="feature-card">
<span class="feature-icon">🚀</span>
<div class="feature-title">无需签约</div>
<div class="feature-desc">
<span class="highlight">零门槛接入</span><br>
无需企业资质,无需繁琐的第三方支付签约流程,
没有中间商赚差价!每笔交易金额实时直达您个人账户,不再忍受第三方抽取手续费。
市面上最稳定安全方案。一张二维收款码搞定收款。
</div>
</div>
<div class="feature-card">
<span class="feature-icon">🤖</span>
<div class="feature-title">全自动收款</div>
<div class="feature-desc">
<span class="highlight">官方渠道</span><br>
自动回调,
实时更新订单状态,无需人工干预
</div>
</div>
<div id="app">
<div class="container">
<!-- Nav -->
<div class="top-nav">
<a href="recharge.html" class="btn-ghost">
<i class="ri-wallet-3-line"></i>
体验支付
</a>
</div>
<div class="feature-card">
<span class="feature-icon">🔧</span>
<div class="feature-title">半自动模式</div>
<div class="feature-desc">
<span class="highlight">灵活切换</span><br>
支持手动确认模式,适合对账要求较高的场景,
确保每笔交易准确无误
</div>
</div>
<div class="feature-card">
<span class="feature-icon">💳</span>
<div class="feature-title">多种支付方式</div>
<div class="feature-desc">
<span class="highlight">全平台覆盖</span><br>
支持支付宝、微信支付,
满足不同用户的支付习惯
</div>
</div>
<div class="feature-card">
<span class="feature-icon">🔒</span>
<div class="feature-title">安全可靠</div>
<div class="feature-desc">
<span class="highlight">不依赖第三方</span><br>
不依赖第三方,自主可控
无需任何第三方SDK、无需挂机监控APP
</div>
</div>
<div class="feature-card">
<span class="feature-icon">📊</span>
<div class="feature-title">实时统计</div>
<div class="feature-desc">
<span class="highlight">数据可视化</span><br>
提供详细的收款记录和统计报表,
帮助您更好地管理和分析收款情况
</div>
</div>
<!-- Hero -->
<div class="hero">
<div class="hero-badge">无需签约 · 即刻收款</div>
<h1>个人收款<br>从未如此简单</h1>
<p class="subtitle">
专为个人开发者和小微商户打造的智能收款系统。<br>
无需营业执照,无需第三方签约,资金直达您的个人账户。
</p>
<a href="recharge.html" class="btn btn-primary">
立即开始收款 <i class="ri-arrow-right-line"></i>
</a>
</div>
<!-- Stats -->
<div class="glass stats-row">
<div class="stat-item">
<h3>5分钟</h3>
<p>快速部署</p>
</div>
<div class="action-section">
<div class="action-title">🎯 立即开始收款</div>
<div class="action-desc">
只需几分钟即可部署完成,马上体验全自动收款的便捷!
</div>
<div class="payment-methods">
<div class="payment-method">
<span>🔵</span>
<span>支付宝转账</span>
</div>
<div class="payment-method">
<span>🟢</span>
<span>微信支付</span>
</div>
<div class="payment-method">
<span>💙</span>
<span>支付宝扫码</span>
</div>
</div>
<a href="recharge.html" class="btn-primary">
🚀 体验支付
</a>
<div class="stat-item">
<h3>0%</h3>
<p>平台费率</p>
</div>
<div class="advantages">
<div class="advantage">
<span class="advantage-icon"></span>
<div><strong>快速部署</strong><br>5分钟完成部署</div>
</div>
<div class="advantage">
<span class="advantage-icon">💰</span>
<div><strong>零手续费</strong><br>无额外费用</div>
</div>
<div class="advantage">
<span class="advantage-icon">🔄</span>
<div><strong>实时到账</strong><br>秒级确认</div>
</div>
<div class="advantage">
<span class="advantage-icon">📱</span>
<div><strong>移动友好</strong><br>全平台适配</div>
</div>
</div>
<div class="footer">
<p>&copy; 个人收款系统 - 让收款变得简单高效</p>
<div class="stat-item">
<h3>100%</h3>
<p>资金安全</p>
</div>
</div>
</div>
<script>
<!-- Features -->
<div class="features">
<div class="glass feature-card">
<div class="feature-icon-wrapper">
<i class="ri-shield-check-line"></i>
</div>
<div class="feature-title">无需签约</div>
<div class="feature-desc">
告别繁琐的企业资质审核。无需第三方支付签约流程,零门槛接入,个人也能拥有专业收款能力。
</div>
</div>
<div class="glass feature-card">
<div class="feature-icon-wrapper">
<i class="ri-robot-2-line"></i>
</div>
<div class="feature-title">支持自动回调</div>
<div class="feature-desc">
自动回调, 实时更新订单状态,无需人工干预.
</div>
</div>
<div class="glass feature-card">
<div class="feature-icon-wrapper">
<i class="ri-toggle-line"></i>
</div>
<div class="feature-title">双模式切换</div>
<div class="feature-desc">
支持全自动/半自动模式灵活切换。既能享受自动化的便捷,又能满足高精度对账需求。
</div>
</div>
<div class="glass feature-card">
<div class="feature-icon-wrapper">
<i class="ri-smartphone-line"></i>
</div>
<div class="feature-title">全平台支持</div>
<div class="feature-desc">
完美支持支付宝、微信支付。无论是扫码支付还是转账模式,都能轻松应对。
</div>
</div>
<div class="glass feature-card">
<div class="feature-icon-wrapper">
<i class="ri-lock-2-line"></i>
</div>
<div class="feature-title">私有化部署</div>
<div class="feature-desc">
数据完全掌握在自己手中。不依赖第三方SaaS平台无需挂机APP安全可控。
</div>
</div>
<div class="glass feature-card">
<div class="feature-icon-wrapper">
<i class="ri-pie-chart-line"></i>
</div>
<div class="feature-title">数据可视化</div>
<div class="feature-desc">
内置强大的数据统计仪表盘。实时掌握流水情况,让每一笔收入都清晰可见。
</div>
</div>
</div>
<!-- CTA -->
<div class="glass cta-section">
<h2 class="cta-title">准备好开始了吗?</h2>
<p class="cta-desc">
加入众多开发者的选择,体验最纯粹的支付解决方案。
</p>
<a href="recharge.html" class="btn btn-primary">
<i class="ri-rocket-line"></i>
启动演示
</a>
<div class="payment-logos">
<div class="payment-logo">
<i class="ri-alipay-fill"></i>
<span>Alipay</span>
</div>
<div class="payment-logo">
<i class="ri-wechat-pay-fill"></i>
<span>WeChat</span>
</div>
</div>
</div>
<div class="footer">
<p>&copy; 2026 PayPro System. Designed for Creators.</p>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
const app = createApp({
data() {
return {
// 页面数据可以在这里添加
// Future state management
}
},
methods: {
// 页面方法可以在这里添加
mounted() {
}
});
app.mount('#app');
</script>
</body>
</html>
</html>

View File

@@ -3,56 +3,312 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>充值中心 - 首页</title>
<meta name="description" content="PayPro个人支付系统 - 正在跳转至首页">
<meta name="keywords" content="支付系统,个人支付,在线收款">
<meta http-equiv="refresh" content="0;url=home.html">
<link rel="canonical" href="home.html">
<title>PayPro - 跳转中</title>
<!-- 引入Vue 3 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js" defer></script>
<!-- 引入 Remix Icons -->
<link href="https://cdn.bootcdn.net/ajax/libs/remixicon/3.5.0/remixicon.css" rel="stylesheet">
<link rel="stylesheet" href="/css/common.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
.page-wrap {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.page-wrap::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(139, 92, 246, 0.15) 0%, transparent 70%);
z-index: -1;
pointer-events: none;
}
.container {
max-width: 500px;
width: 90%;
text-align: center;
color: white;
}
.glass-card {
background: rgba(255,255,255,0.03);
border-radius: 20px;
border: 1px solid rgba(255,255,255,0.08);
backdrop-filter: blur(10px);
padding: 48px 32px;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
transition: all .3s ease;
}
.glass-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0,0,0,0.15);
}
.logo {
font-size: 2.5rem;
font-weight: 800;
margin-bottom: 32px;
background: linear-gradient(to right, #fff, #94a3b8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
}
.logo i {
font-size: 3rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.loading-container {
margin: 40px 0;
}
.loading {
display: inline-block;
width: 50px;
height: 50px;
border: 5px solid rgba(255,255,255,0.3);
border-top: 5px solid white;
width: 60px;
height: 60px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top: 4px solid var(--text-color);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20px;
margin-bottom: 24px;
position: relative;
}
.loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.hero-badge {
display: inline-block;
padding: 8px 20px;
background: rgba(139, 92, 246, 0.1);
border: 1px solid rgba(139, 92, 246, 0.2);
color: #A78BFA;
border-radius: 20px;
font-size: 0.85rem;
font-weight: 600;
margin-bottom: 24px;
letter-spacing: 0.5px;
}
.message {
font-size: 1.25rem;
font-weight: 600;
color: var(--text-color);
margin-bottom: 16px;
}
.subtitle {
font-size: 1rem;
color: var(--text-muted);
margin-bottom: 32px;
line-height: 1.6;
}
.countdown {
font-size: 1rem;
color: var(--primary-color);
font-weight: 600;
margin-bottom: 32px;
}
.actions {
display: flex;
gap: 16px;
justify-content: center;
margin-bottom: 32px;
}
.btn-primary {
background: var(--primary-color);
color: white;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 8px;
transition: all .3s ease;
border: 1px solid var(--primary-color);
}
.btn-primary:hover {
background: rgba(99,102,241,0.9);
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(99,102,241,0.3);
}
.btn-ghost {
color: var(--text-color);
padding: 12px 24px;
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
text-decoration: none;
font-weight: 600;
transition: all .3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-ghost:hover {
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.2);
}
.footer {
margin-top: 32px;
font-size: 0.9rem;
color: var(--text-muted);
}
@media (max-width: 768px) {
.glass-card {
padding: 32px 24px;
}
.logo {
font-size: 2rem;
}
.logo i {
font-size: 2.5rem;
}
.message {
font-size: 1.1rem;
}
.actions {
flex-direction: column;
align-items: center;
}
.btn-primary,
.btn-ghost {
width: 100%;
max-width: 200px;
justify-content: center;
}
}
</style>
</head>
<body>
<div class="container">
<div class="loading"></div>
<h2>正在跳转页面...</h2>
<div id="app">
<div class="page-wrap">
<div class="container">
<div class="glass-card">
<div class="hero-badge">系统启动中</div>
<div class="logo">
<i class="ri-rocket-line"></i>
PayPro
</div>
<div class="loading-container">
<div class="loading"></div>
<div class="message">正在为您准备最佳体验</div>
<div class="subtitle">个人支付从未如此简单</div>
<div class="countdown" id="countdown">3秒后自动跳转</div>
</div>
<div class="actions">
<a href="home.html" class="btn btn-primary">
<i class="ri-arrow-right-line"></i>
立即前往
</a>
<a href="recharge.html" class="btn btn-ghost">
<i class="ri-wallet-3-line"></i>
直接支付
</a>
</div>
<div class="footer">
<p>&copy; 2026 PayPro System. Designed for Creators.</p>
</div>
</div>
</div>
</div>
</div>
<noscript>
<div style="text-align: center; color: white; margin-top: 20px;">
<p>您的浏览器不支持JavaScript请手动<a href="home.html" style="color: white; text-decoration: underline;">点击这里</a>跳转</p>
</div>
</noscript>
<script>
// 自动跳转到首页
window.addEventListener('DOMContentLoaded', function() {
if (typeof Vue === 'undefined') {
console.error('Vue未加载请检查网络连接');
return;
}
const { createApp } = Vue;
createApp({
data() {
return {
countdown: 1
}
},
mounted() {
console.log('PayPro Redirect Page Loaded');
this.startCountdown();
},
methods: {
startCountdown() {
const countdownElement = document.getElementById('countdown');
if (countdownElement) {
countdownElement.textContent = '即将跳转...';
}
// 几乎立即跳转,不显示倒计时
}
}
}).mount('#app');
});
</script>
<script>
// 自动跳转到首页(几乎立即跳转)
setTimeout(() => {
window.location.href = 'home.html';
}, 1000);
}, 100);
</script>
</body>
</html>

View File

@@ -0,0 +1,465 @@
<!doctype html>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>个人支付系统 - 无需签约,全自动收款</title>
<!-- 支付宝JS API -->
<script src="https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.min.js"></script>
<!-- AntUI CSS -->
<link rel="stylesheet" href="https://gw.alipayobjects.com/as/g/antui/antui/10.1.32/dpl/antui.css"/>
<link rel="stylesheet" href="https://gw.alipayobjects.com/as/g/antui/antui/10.1.32/??dpl/widget/message.css,dpl/icon/message.css,dpl/widget/search.css"/>
<link rel="stylesheet" href="https://gw.alipayobjects.com/as/g/antui/antui/10.1.32/dpl/widget/notice.css">
<link rel="stylesheet" href="https://gw.alipayobjects.com/as/g/antui/antui/10.1.32/dpl/widget/tips.css">
<link rel="stylesheet" href="https://gw.alipayobjects.com/as/g/antui/antui/10.1.32/dpl/widget/dialog.css">
<!-- AntUI JS -->
<script src="https://gw.alipayobjects.com/as/g/antui/antui/10.1.32/antui.js"></script>
<!-- Vue 3 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js"></script>
<!-- 引入API配置 -->
<script src="/assets/js/api-config.js"></script>
<!-- 引入HTTP工具 -->
<script src="/assets/js/http-util.js"></script>
</head>
<style>
.am-notice .am-notice-content {
-webkit-flex: 1;
overflow: hidden;
margin-left: 15px;
margin-right: 5px;
padding-left: 25px;
}
/* 额外样式 */
.payment-info {
padding: 15px;
background: #f5f5f5;
margin: 10px 15px;
border-radius: 8px;
text-align: center;
}
.amount-display {
font-size: 20px;
font-weight: bold;
color: #1677ff;
margin: 8px 0;
}
.order-info {
font-size: 14px;
color: #666;
margin: 5px 0;
}
.loading {
display: inline-block;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<body>
<div id="app">
<!-- 顶部提示 -->
<div v-if="showAlert" class="am-notice" role="alert">
<div class="am-notice-content">由于客户端版本问题,部分设备可能无法跳转支付</div>
<div class="am-notice-operation">
<a @click="closeAlert" class="am-notice-close" role="button"></a>
</div>
</div>
<!-- 支付信息显示 -->
<div class="payment-info">
<div class="order-info">订单号:{{ paymentData.orderId }}</div>
<div class="order-info">订单标识:{{ paymentData.orderNum }}</div>
<div class="amount-display">¥{{ paymentData.money }}</div>
<div class="order-info">Pay支付系统</div>
</div>
<!-- 主要消息区域 -->
<div class="am-message result">
<i v-if="paymentStatus === 'waiting'" class="am-icon result wait loading"></i>
<i v-if="paymentStatus === 'failed'" class="am-icon result warn"></i>
<i v-if="paymentStatus === 'success'" class="am-icon result success"></i>
<div class="am-message-main">{{ statusMessage }}</div>
<div class="am-message-sub">{{ statusSubMessage }}</div>
</div>
<!-- 按钮区域 -->
<div class="am-button-wrap">
<button class="am-button blue" @click="showAction">立即支付</button>
<button class="am-button white" @click="returnApp">取消支付</button>
</div>
<!-- 底部提示 -->
<div v-if="showTip" class="am-tips am-tips-block am-tips-favorite">
<div class="am-tips-wrap">
<div class="am-tips-close" @click="closeTip">关闭</div>
<div class="am-tips-icon">
<img src="assets/images/zfb.png" alt="支付宝">
</div>
<div class="am-tips-content am-ft-ellipsis">
若无法跳转请点击“立即支付”
</div>
<div class="am-tips-action" role="button" @click="closeTip">
知道了
</div>
</div>
</div>
<!-- 扫码支付对话框 -->
<div v-if="showDialog1" class="am-dialog-mask show"></div>
<div v-if="showDialog1" class="am-dialog image show" role="dialog">
<div class="am-dialog-wrap">
<div class="am-dialog-img fill">
<img :src="alipayQrCodeUrl"
style="width: 85%; height: 150px; object-fit: contain;"
alt="支付宝收款码"> </div>
<div class="am-dialog-header">
<h3>订单标识号:{{ paymentData.orderNum }}</h3>
</div>
<div class="am-dialog-body">
<p class="am-dialog-brief">
支付时请输入金额:¥{{ paymentData.money }},备注中输入标识号:{{ paymentData.orderNum }}
</p>
</div>
<div class="am-dialog-footer">
<a type="button" class="am-dialog-button" @click="customPay">知道了,立即支付</a>
</div>
<a class="am-dialog-close" @click="closeDialog"></a>
</div>
</div>
<!-- 红包支付对话框 -->
<div v-if="showDialog2" class="am-dialog-mask show"></div>
<div v-if="showDialog2" class="am-dialog show" role="dialog">
<div class="am-dialog-wrap">
<div class="am-dialog-header">
<h3>请务必选择“普通红包”支付</h3>
</div>
<div class="am-dialog-body">
<p class="am-dialog-brief">请勿修改红包内金额或备注若系统超过24小时未领取金额将自动退回您的账户</p>
</div>
<div class="am-dialog-footer">
<button type="button" class="am-dialog-button" @click="redPay">知道了,立即支付</button>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
const app = createApp({
data() {
return {
// UI状态
showAlert: true,
showTip: true,
showDialog1: false,
showDialog2: false,
// 支付数据
paymentData: {
money: 0,
orderNum: '',
orderId: ''
},
// 支付状态
paymentStatus: 'waiting', // waiting, failed, success
// 配置信息
config: {
alipayUserId: '[[${alipayUserId}]]', // 需要替换为真实的支付宝用户ID
customUrl: '[[${alipayCustomQrUrl}]]', // 需要替换为真实的收款码
mobile: '[[${mobile}]]', // 支付宝绑定手机号
nickName: '[[${name}]]' // 支付宝昵称
}
}
},
computed: {
statusMessage() {
const messages = {
waiting: '等待跳转支付...',
failed: '自动跳转支付失败',
success: '支付成功'
};
return messages[this.paymentStatus] || '未知状态';
},
statusSubMessage() {
const messages = {
waiting: '若无法自动跳转支付请点击下方立即支付按钮',
failed: '请点击"立即支付"手动支付',
success: '感谢您的支付'
};
return messages[this.paymentStatus] || '';
},
alipayQrCodeUrl() {
// 使用绝对路径访问图片,确保在支付宝环境中能正确加载
return '/assets/images/aliremark.png';
}
},
mounted() {
this.initApp();
},
methods: {
// 初始化应用
initApp() {
console.log('初始化支付宝收银台...');
// 检查是否在支付宝环境中
this.checkAlipayEnvironment();
// 获取URL参数
this.getUrlParams();
// 初始化支付宝JSBridge
this.initAlipayJSBridge();
},
// 检查支付宝环境
checkAlipayEnvironment() {
const ua = window.navigator.userAgent.toLowerCase();
if (ua.indexOf('alipay') < 0) {
console.warn('当前不在支付宝环境中');
this.paymentStatus = 'failed';
// 可以选择跳转到主页或显示提示
// location.href = '/';
}
},
// 获取URL参数
getUrlParams() {
const url = window.location.search;
const params = {};
if (url.indexOf('?') !== -1) {
const str = url.substr(1);
const strs = str.split('&');
for (let i = 0; i < strs.length; i++) {
const param = strs[i].split('=');
params[param[0]] = decodeURIComponent(param[1] || '');
}
}
// 设置支付数据
this.paymentData.money = params.money || '0.00';
this.paymentData.orderNum = params.payNum ;
this.paymentData.orderId = params.id || params.orderId || '';
console.log('获取到的支付数据:', this.paymentData);
},
// 初始化支付宝JSBridge
initAlipayJSBridge() {
const self = this;
function ready(callback) {
if (window.AlipayJSBridge) {
callback && callback();
} else {
document.addEventListener('AlipayJSBridgeReady', callback, false);
}
}
ready(function() {
console.log('支付宝JSBridge已准备好');
// 设置页面标题
if (typeof AlipayJSBridge !== 'undefined') {
AlipayJSBridge.call('setTitle', {
title: '支付宝收银台'
});
}
// 自动跳转支付
self.autoJumpToPay();
});
},
// 自动跳转支付
autoJumpToPay() {
console.log('尝试自动跳转支付...');
const scanUrl = this.generateScanUrl();
// 立即跳转
location.href = scanUrl;
// 5秒后再次跳转防止第一次失败
// setTimeout(() => {
// location.href = scanUrl;
// }, 5000);
},
// 生成扫码支付URL
generateScanUrl() {
const bizData = {
s: 'money',
u: this.config.alipayUserId,
a: this.paymentData.money,
m: this.paymentData.orderNum
};
return `alipays://platformapi/startapp?appId=20000123&actionType=scan&biz_data=${encodeURIComponent(JSON.stringify(bizData))}`;
},
// 生成红包支付URL
generateRedUrl() {
const { alipayUserId, mobile, nickName } = this.config;
const { money, orderNum } = this.paymentData;
return `alipays://platformapi/startapp?appId=88886666&appLaunchMode=3&canSearch=false&chatLoginId=${mobile}&chatUserId=${alipayUserId}&chatUserName=${encodeURIComponent(nickName)}&chatUserType=1&entryMode=personalStage&prevBiz=chat&schemaMode=portalInside&target=personal&money=${money}&amount=${money}&remark=${orderNum}`;
},
// 生成加好友URL
generateFriendUrl() {
const { alipayUserId, mobile } = this.config;
return `alipays://platformapi/startapp?appId=20000186&actionType=addfriend&userId=${alipayUserId}&loginId=${mobile}&source=by_f_v&alert=true`;
},
// 显示支付方式选择
showAction() {
if (typeof AlipayJSBridge === 'undefined') {
alert('支付宝环境未准备就绪,请稍后重试');
return;
}
AlipayJSBridge.call('actionSheet', {
title: '选择支付方式',
btns: ['立即支付', '收款码支付(推荐)', '普通红包支付'], // , '银行卡转账(演示)'
cancelBtn: '取消'
}, (data) => {
switch (data.index) {
case 0:
// 立即支付
location.href = this.generateScanUrl();
break;
case 1:
// 收款码支付
this.showDialog1 = true;
break;
case 2:
// 红包支付
this.showDialog2 = true;
break;
}
});
},
// 自定义支付(收款码)
customPay() {
location.href = this.config.customUrl;
},
// 红包支付
redPay() {
this.showDialog2 = false;
// 先加好友
location.href = this.generateFriendUrl();
// 延时启动红包
setTimeout(() => {
location.href = this.generateRedUrl();
}, 888);
},
// 返回应用
returnApp() {
if (typeof AlipayJSBridge !== 'undefined') {
AlipayJSBridge.call('exitApp');
} else {
// 如果不在支付宝环境中,返回上一页或主页
history.back() || (location.href = '/');
}
},
// UI 控制方法
closeAlert() {
this.showAlert = false;
},
closeTip() {
this.showTip = false;
},
closeDialog() {
this.showDialog1 = false;
this.showDialog2 = false;
},
// 支付状态检查(可选)
async checkPaymentStatus() {
if (!this.paymentData.orderId) {
console.warn('订单ID不存在无法查询支付状态');
return;
}
try {
// 检查httpUtil是否可用
if (typeof httpUtil !== 'undefined' && typeof API_CONFIG !== 'undefined') {
const response = await httpUtil.get(API_CONFIG.ENDPOINTS.STATUS, {
orderId: this.paymentData.orderId
});
if (response.success && response.data === 1) {
this.paymentStatus = 'success';
// 可以跳转到成功页面
setTimeout(() => {
location.href = `/payment-success.html?orderId=${this.paymentData.orderId}&amount=${this.paymentData.money}`;
}, 2000);
}
if (response.success && response.data === 2) {
this.paymentStatus = 'failed';
}
}
} catch (error) {
console.error('查询支付状态失败:', error);
}
},
// 定期检查支付状态
startPaymentPolling() {
if (!this.paymentData.orderId) return;
const pollingInterval = setInterval(() => {
this.checkPaymentStatus();
// 30秒后停止轮询
setTimeout(() => {
clearInterval(pollingInterval);
}, 30000);
}, 3000);
}
},
// 组件挂载后启动轮询(可选)
created() {
// 可以在这里启动支付状态轮询
// this.startPaymentPolling();
}
});
app.mount('#app');
</script>
</body>
</html>

View File

@@ -33,7 +33,7 @@
<td style="font-size:13px; color:#7f8c8d; line-height:26px;" align="center">
支付金额:<span th:text="${money}"></span>
支付方式:<span th:text="${payType}"></span>
留言:<span th:text="${info}"></span>
留言:<span th:text="${description}"></span>
支付时间:<span th:text="${time}"></span>
</td>
</tr>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff