mirror of
https://github.com/codewendao/PayPro.git
synced 2026-09-03 06:13:46 +08:00
ui-ux-pro-max重构页面
支持支付宝免输备注
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,22 @@ public class PayProConfig implements WebMvcConfigurer {
|
||||
/** 项目下载地址 */
|
||||
private String downloadUrl;
|
||||
|
||||
/**
|
||||
* 阿里的用户id
|
||||
* */
|
||||
private String alipayUserId;
|
||||
|
||||
/**
|
||||
* 阿里的自定义收款码
|
||||
* */
|
||||
private String alipayCustomQrUrl;
|
||||
|
||||
/**
|
||||
* mobile
|
||||
* */
|
||||
private String mobile;
|
||||
|
||||
|
||||
/**
|
||||
* 邮箱配置内部类
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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') {
|
||||
|
||||
145
src/main/resources/static/css/common.css
Normal file
145
src/main/resources/static/css/common.css
Normal 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);
|
||||
}
|
||||
@@ -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>© 充值中心 - 安全可靠的支付服务</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>© 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>
|
||||
@@ -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>© 捐赠中心 - 安全可靠的支付服务</p>
|
||||
<p>© 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>
|
||||
@@ -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>© 个人收款系统 - 让收款变得简单高效</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>© 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>
|
||||
|
||||
@@ -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>© 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>
|
||||
465
src/main/resources/templates/openAlipay.html
Normal file
465
src/main/resources/templates/openAlipay.html
Normal 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>
|
||||
@@ -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
Reference in New Issue
Block a user