1、在线支付

This commit is contained in:
2025-07-07 19:03:16 +08:00
parent d49337ba4f
commit 4d02138893

View File

@ -16,6 +16,8 @@
<link rel="stylesheet" href="static/css/public.css" />
<!-- <link rel="stylesheet" href="static/translate/css/public.css?v=4"> -->
<link rel="stylesheet" href="static/css/layui.css" />
<!-- <link rel="stylesheet" href="static/js/css/buefy.min.css"> -->
<script src="static/js/jquery-1.11.0.min.js"></script>
<script src="static/js/axios.min.js"></script>
<script src="static/translate/js/echarts.min.js"></script>
@ -26,6 +28,8 @@
<script src="static/js/common.js"></script>
<script src="https://cdn.jsdelivr.net/npm/qrcode@1.4.4/build/qrcode.min.js"></script>
<script src="static/js/countdown.js"></script>
<!-- <script src="static/js/buefy.min.js"></script> -->
<title>聚合翻译</title>
<script>
var _hmt = _hmt || [];
@ -196,7 +200,7 @@
<div class="cell"><span>{{item.price}}</span></div>
<div class="cell">
<div class="act">
<span class="recharge" @click="show">充值</span
<span class="recharge" @click="show(item)">充值</span
><span class="view" @click="look(item.apiKey,index)"
>查看API密钥</span
>
@ -297,27 +301,61 @@
</div>
</div>
<div class="modal-overlay" style="display: none">
<div class="service-modal">
<div class="content">
<div class="close" @click="close"></div>
<div class="contact">TRX BLOCK</div>
<div class="contact-user">
<div class="contact-user-text">用户ID : {{userInfo.id}}</div>
<div class="modal">
<button class="close-btn" @click="close">&times;</button>
<div
class="modal-content"
:style="loadingQr ? 'opacity: 0.4; pointer-events: none;' : ''"
>
<h3 v-if="rechargeData.step === 1">Step 1: 输入购买数量</h3>
<h3 v-else>Step 2: 支付信息</h3>
<!-- Step 1 -->
<div v-if="rechargeData.step === 1" class="step">
<label>购买数量:</label>
<input type="number" v-model.number="rechargeData.count" min="1" />
</div>
<!-- Step 2 -->
<div v-else class="step">
<div class="qr-code">
<div id="qrcode"></div>
<!-- <div v-if="loadingQr" class="loading-spinner"></div> -->
<!-- <img v-else-if="qrCodeUrl" :src="qrCodeUrl" alt="二维码"
@load="onQrLoadSuccess" @error="onQrLoadError"
style="width: 100%; height: 100%; border-radius: 8px;" />
<span v-else style="font-size: 12px; color: #999;">加载失败</span> -->
</div>
<div class="wallet-info">
<p>主链:<strong>{{ rechargeData.blockChain }}</strong></p>
<p>钱包地址: <strong>{{ rechargeData.receiveAddress }}</strong></p>
<p>支付金额: <strong>{{ rechargeData.amount }} USDT</strong></p>
<p>
<countdown :time="(rechargeData.expireUnix * 1000) - Date.now()"
v-if="rechargeData.expireUnix && (rechargeData.expireUnix * 1000) > Date.now()" >
<template slot-scope="props">
倒计时:
<span v-if="props.minutes>0||props.hours>0||props.days>0">{{ props.minutes }} 分</span>
<span v-if="props.seconds>0||props.minutes>0||props.hours>0||props.days>0">{{ props.seconds }} 秒</span>
<span v-if="props.days==0&&props.hours==0&&props.minutes==0&&props.seconds==0">订单已过期,请勿支付!</span>
</template>
</countdown>
</p>
</div>
</div>
<div class="btn-group">
<!-- <button class="btn btn-secondary" @click="close">关闭</button> -->
<button class="btn btn-secondary" v-if="rechargeData.step === 2" @click="prevStep">上一步</button>
<button class="btn btn-primary" v-if="rechargeData.step === 1" :disabled="!rechargeData.count" @click="nextStep">下一步</button>
</div>
<div
id="qrcode"
style="text-align: center;height: 214px;"
class="border border-gray-200 rounded-lg p-2 flex justify-center items-center"
>
<!-- 二维码将在这里生成 -->
<!-- <p class="text-gray-500">点击按钮生成二维码</p> -->
</div>
<!-- <img
src="/static/picture/p23.jpg"
alt=""
class="qrcode-img"
/> -->
<p>{{receiveAddress}}</p>
</div>
<!-- loading 遮罩层 -->
<div class="modal-loading-overlay" v-if="loadingQr">
<div class="spinner"></div>
</div>
</div>
</div>
@ -346,7 +384,167 @@
</div>
</div>
</div>
</div>
<style>
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.modal {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
padding: 24px 28px;
width: 400px;
max-width: 90%;
animation: fadeIn 0.3s ease;
position:relative;
}
.modal-content {
transition: opacity 0.2s;
}
.modal-loading-overlay {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background-color: rgba(255, 255, 255, 0.6);
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
border-radius: 12px;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #409eff;
border-radius: 50%;
width: 32px;
height: 32px;
animation: spin 0.8s linear infinite;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
.modal h3 {
margin-top: 0;
font-size: 20px;
color: #333;
}
input[type="number"] {
width: 100%;
padding: 10px 12px;
font-size: 16px;
margin-top: 8px;
border: 1px solid #ccc;
border-radius: 6px;
transition: border-color 0.2s;
}
input[type="number"]:focus {
border-color: #409eff;
outline: none;
}
button{
cursor: pointer;
}
.step {
padding-top: 16px;
margin-bottom: 16px;
}
.qr-code {
width: 150px;
height: 150px;
background: #f8f8f8;
border: 1px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
border-radius: 8px;
}
.loading-spinner {
border: 3px solid #f3f3f3;
border-top: 3px solid #409eff;
border-radius: 50%;
width: 28px;
height: 28px;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.btn-group {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 16px;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
transition: background-color 0.2s ease;
}
.btn-primary {
background-color: #409eff;
color: #fff;
}
.btn-primary:disabled {
background-color: #a0cfff;
cursor: not-allowed;
}
.btn-secondary {
background-color: #e0e0e0;
color: #333;
}
.wallet-info {
font-size: 14px;
color: #555;
text-align: center;
margin-top: 12px;
}
.close-btn {
position: absolute;
top: 12px;
right: 12px;
background: transparent;
border: none;
font-size: 20px;
color: #999;
cursor: pointer;
transition: color 0.2s ease;
}
.close-btn:hover {
color: #333;
}
</style>
<script type="text/javascript">
// 工具函数:将十六进制颜色转换为 RGBA 格式
function hexToRgba(hex, alpha) {
@ -373,6 +571,18 @@
token: "",
userMoney: 0,
userInfo: {},
activeStep:"2",
showRecharge:false,
loadingQr:false,
rechargeData:{
platformId:null,
name:null,
count:1,
amount:null,
receiveAddress:null,
step:1,
expireUnix:undefined
},
// ECharts 图表数据
myChart: null, // 用于存储 ECharts 实例
@ -407,7 +617,7 @@
this.getUserPlatforms();
this.getStatistics();
this.getReceiveAddress();
// this.getReceiveAddress();
},
beforeDestroy() {
// 销毁 ECharts 实例并移除事件监听器
@ -453,20 +663,20 @@
}
});
},
getReceiveAddress() {
axios
.get("/configKey/trx_receive_address", {
headers: { Authorization: `Bearer ${this.token}` },
})
.then((res) => {
if (res.data.code == 200) {
this.receiveAddress = res.data.data.configValue;
this.generateQRCode();
} else {
layer.msg(response.data.msg);
}
});
},
// getReceiveAddress() {
// axios
// .get("/configKey/trx_receive_address", {
// headers: { Authorization: `Bearer ${this.token}` },
// })
// .then((res) => {
// if (res.data.code == 200) {
// this.receiveAddress = res.data.data.configValue;
// this.generateQRCode();
// } else {
// layer.msg(response.data.msg);
// }
// });
// },
getMemberAdvent(platformId){
axios
.get("/tm-member/member-advent", {
@ -540,11 +750,57 @@
'" >复制</i></div></div>',
});
},
show() {
show(item) {
$(".modal-overlay").fadeIn();
this.rechargeData.platformId=item.platformId;
this.rechargeData.name=item.name;
},
close() {
$(".modal-overlay").fadeOut();
this.rechargeData={
platformId:null,
name:null,
count:1,
amount:null,
receiveAddress:null,
step:1,
expireUnix:undefined
};
console.log(this.rechargeData);
},
prevStep(){
this.rechargeData.step=1;
},
nextStep(){
if(this.rechargeData.count<=0){
layer.msg("数量不能小于0");
return;
}
this.loadingQr=true;
axios.post("/tm-member/recharge",this.rechargeData,{headers: { Authorization: `Bearer ${this.token}` }})
.then(res => {
console.log("sss",res);
if(res.data.code===200){
this.rechargeData.step=2;
this.rechargeData.amount=res.data.data.amount;
this.rechargeData.receiveAddress=res.data.data.receiveAddress;
this.rechargeData.blockChain=res.data.data.blockChain;
this.rechargeData.expireUnix=res.data.data.expireUnix;
let _that=this;
this.$nextTick(() => {
_that.generateQRCode(_that.rechargeData.receiveAddress);
})
}else{
layer.msg(res.data.msg);
}
}).finally(() => {
this.loadingQr=false;
});
},
showRecord(platformId){
$(".modal-overlay-record").fadeIn();
@ -779,11 +1035,12 @@
this.myChart.resize();
}
},
generateQRCode() {
const text = this.receiveAddress.trim(); // 获取输入框内容并去除首尾空格
generateQRCode(qrString) {
const text = qrString.trim(); // 获取输入框内容并去除首尾空格
const qrcodeContainer = document.getElementById('qrcode');
if (text) {
console.log('container',qrcodeContainer)
// 1. 清空容器内的所有内容,包括旧的二维码或提示信息
qrcodeContainer.innerHTML = '';
this.showPlaceholder = false;
@ -797,7 +1054,7 @@
// 3. 使用 QRCode.toCanvas 在新创建的 canvas 上生成二维码
QRCode.toCanvas(canvasElement, text, { // 将 canvasElement 传递给 toCanvas
width: 214, // 设置二维码宽度
width: 150, // 设置二维码宽度
color: {
dark: '#000000', // 二维码颜色
light:'#ffffff' // 背景颜色